Last active
April 26, 2024 04:03
-
-
Save nainemom/0ac55c458f5a644959a069a16ccfb00b to your computer and use it in GitHub Desktop.
MPV script to translate current line of subtitle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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