Skip to content

Instantly share code, notes, and snippets.

@nainemom
Last active April 26, 2024 04:03
Show Gist options
  • Save nainemom/0ac55c458f5a644959a069a16ccfb00b to your computer and use it in GitHub Desktop.
Save nainemom/0ac55c458f5a644959a069a16ccfb00b to your computer and use it in GitHub Desktop.
MPV script to translate current line of subtitle
-- Simple mpv script to translate subtitle using crow (online) or sdcv (offline) dictionaries.
-- INSTALLATION:
-- To install it, first install crow (https://crow-translate.github.io) and/or sdcv (http://dushistov.github.io/sdcv/) on your marchine with your favorite dicts and then,
-- copy this file to '~/.config/mpv/scripts/' (Linux) or '%AppData%\mpv\scripts\' (Windows).
-- sdcv help:
-- you can download offline dicts from http://download.huzheng.org/Quick/ (or anywhere else) and copy extracted dic folder to '~/.stardict/dic/'
-- CONFIGURATION:
local config = {
auto_start = false, -- false means this app need to start via key_binding. true means this app starts automatickly when video pauses.
key_binding = 'CTRL+SPACE', -- key binding to manual start this app.
dictionary = 'crow', -- one of 'sdcv', 'crow'.
crow_options = { -- no need to care if you are using sdcv.
source_language = 'en', -- check crow cli app for more options.
target_language = 'fa' -- check crow cli app for more options.
},
sdvc_options = { -- no need to care if you are using crow.
dictionary_name = 'quick_eng-persian-e2009', -- sdcv dictionary (need to be installed in '~/.stardict/dic/' or '%AppData%\stardict\dic\' on your marchine and should be accessable by sdcv). Tip: you can download mentioned dict from http://download.huzheng.org/Quick
},
}
-- USAGE:
-- To use it, when subtitle is showing something just press CTRL+SPACE key and select your favorite
-- part of visibled subtitle with CTRL+ARROW_KEYS and hit CTRL+ENTER to translate.
local utils = require 'mp.utils'
local ass = {
start = mp.get_property_osd('osd-ass-cc/0')..'{\\a2}',
stop = mp.get_property_osd('osd-ass-cc/1'),
color = '{\\1c&H00CCFF&}',
white = '{\\1c&HFFFFFF&}'
}
function split (input)
local t = {}
for _str in string.gmatch(input, '([^'..'\n'..']+)') do
for str in string.gmatch(_str, '([^'..' '..']+)') do
local replaced_str = str:gsub('[^a-zA-Z0-9_-\\ \']', '')
table.insert(t, replaced_str)
end
end
return t
end
function length(input)
local count = 0
for _ in pairs(input) do count = count + 1 end
return count
end
function show(str)
mp.osd_message(str, 9999)
end
function clear()
mp.osd_message('')
end
function _draw(input, highlighted, translated)
local result = ''
if highlighted == nil then
result = result..ass.color..input..ass.white
else
result = result..ass.white..input:gsub(highlighted, ass.color..highlighted..ass.white)
end
clear()
show(ass.start..translated..'\n---------------------------\n'..result..ass.stop)
end
function _translate(input)
local ret = ''
if config.dictionary == 'sdcv' then
local script = { args = {'sdcv' ,'-n', '-u', config.sdvc_options.dictionary_name, input } }
local result = utils.subprocess(script)
local i = 1
for str in string.gmatch(result.stdout:gsub('<BR>', '\n'), '([^'..'\n'..']+)') do
if i > 2 then
ret = ret..str..' \n'
end
i = i + 1
end
ret = ret:sub(1, -2)
ret = ret..'،'
else
local script = { args = { 'crow', '-l', config.crow_options.source_language, '-t', config.crow_options.target_language, '-b', input } }
local result = utils.subprocess(script)
ret = result.stdout:sub(1, -2)
end
return ret
end
function _get_range(arr, start_index, end_index)
local ret = ''
for k, v in pairs(arr) do
if k == start_index then
ret = v
elseif (k > start_index and k <= end_index) then
ret = ret..' '..v
end
end
return ret
end
local selection_start = 0
local selection_end = 0
local translated = nil
local is_showing = false
local sub = ''
local parsed_sub = {}
local sub_length = 0
function auto_draw()
local highlighted = _get_range(parsed_sub, selection_start, selection_end)
if translated == nil then
_draw(sub, highlighted, 'Press CTRL+ENTER to translate.')
else
_draw(sub, highlighted, translated)
end
end
function start()
mp.set_property_bool('pause', true)
mp.add_timeout(0.1, function ()
clear()
mp.set_property_bool('sub-visibility', false)
is_showing = true
selection_start = 1
selection_end = 1
sub = mp.get_property('sub-text')
parsed_sub = split(sub)
sub_length = length(parsed_sub)
translated = nil
auto_draw()
mp.add_key_binding('CTRL+LEFT', 'move_prev_1', move_prev, 'repeatable')
mp.add_key_binding('LEFT', 'move_prev_2', move_prev, 'repeatable')
mp.add_key_binding('CTRL+UP', 'move_prev_3', move_prev, 'repeatable')
mp.add_key_binding('UP', 'move_prev_4', move_prev, 'repeatable')
mp.add_key_binding('SHIFT+LEFT', 'add_prev_1', add_prev, 'repeatable')
mp.add_key_binding('SHIFT+UP', 'add_prev_2', add_prev, 'repeatable')
mp.add_key_binding('CTRL+RIGHT', 'move_next_1', move_next, 'repeatable')
mp.add_key_binding('RIGHT', 'move_next_2', move_next, 'repeatable')
mp.add_key_binding('CTRL+DOWN', 'move_next_3', move_next, 'repeatable')
mp.add_key_binding('DOWN', 'move_next_4', move_next, 'repeatable')
mp.add_key_binding('SHIFT+RIGHT', 'add_next_1', add_next, 'repeatable')
mp.add_key_binding('SHIFT+DOWN', 'add_next_2', add_next, 'repeatable')
mp.add_key_binding('CTRL+ENTER', 'translate_1', translate)
mp.add_key_binding('ENTER', 'translate_2', translate)
mp.add_key_binding('SHIFT+ENTER', 'translate_3', translate)
mp.add_key_binding('CTRL+ESC', 'stop_1', stop)
mp.add_key_binding('ESC', 'stop_2', stop)
mp.add_key_binding('SHIFT+ESC', 'stop_3', stop)
end)
end
function stop()
clear()
mp.set_property_bool('sub-visibility', true)
mp.remove_key_binding('move_prev_1')
mp.remove_key_binding('move_prev_2')
mp.remove_key_binding('move_prev_3')
mp.remove_key_binding('move_prev_4')
mp.remove_key_binding('add_prev_1')
mp.remove_key_binding('add_prev_2')
mp.remove_key_binding('move_next_1')
mp.remove_key_binding('move_next_2')
mp.remove_key_binding('move_next_3')
mp.remove_key_binding('move_next_4')
mp.remove_key_binding('add_next_1')
mp.remove_key_binding('add_next_2')
mp.remove_key_binding('translate_1')
mp.remove_key_binding('translate_2')
mp.remove_key_binding('translate_3')
mp.remove_key_binding('stop_1')
mp.remove_key_binding('stop_2')
mp.remove_key_binding('stop_3')
is_showing = false
end
function move_next()
if is_showing == false then
return
end
selection_start = selection_start + 1
selection_end = selection_start
if selection_start > sub_length then
selection_start = 1
selection_end = 1
end
translated = nil
auto_draw()
end
function add_next()
if is_showing == false then
return
end
selection_end = selection_end + 1
if selection_end > sub_length then
selection_end = sub_length
end
translated = nil
auto_draw()
end
function move_prev()
if is_showing == false then
return
end
selection_start = selection_end - 1
selection_end = selection_start
if selection_start < 1 then
selection_start = sub_length
selection_end = sub_length
end
translated = nil
auto_draw()
end
function add_prev()
if is_showing == false then
return
end
selection_end = selection_end - 1
if selection_end < selection_start then
selection_end = selection_start
end
translated = nil
auto_draw()
end
function translate()
local highlighted = _get_range(parsed_sub, selection_start, selection_end)
if config.dictionary == 'sdcv' then
translated = _translate(highlighted)
else
local waiting_text = 'Translating...'
_draw(sub, highlighted, waiting_text)
translated = _translate(highlighted)
end
_draw(sub, highlighted, translated)
end
function on_pause_change(name, value)
if value == false then
stop()
elseif value == true and config.auto_start == true then
start()
end
end
mp.observe_property('pause', 'bool', on_pause_change)
mp.add_key_binding(config.key_binding, 'start', start)
@cu1tur4l
Copy link

cu1tur4l commented Mar 24, 2024

Hello,
I can't get it to work. I installed crow, changed the .lua to my language and script does not work. It shows up, but does not output anything after displaying "translating" message. Do I need to change anything in crow? (I've never used it before). I'm using windows, when I was trying to look up codes using CLI I found out that cli usage for windows is kinda broken, so I suspect that's the reason why it is not working.
crow-translate/crow-translate#296
This is what I found, so it probably needs "| more"? But I don't know how to do it, I do not know how to code or anything, my "skills" end on cmd commands like cd, ping, ipconfig xd.
I tried to redneck this:

local script = { args = { 'crow', '-l', config.crow_options.source_language, '-t', config.crow_options.target_language, '-b', input, '| more' } }

but surprise surprise, it did not work.
send help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment