Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- âȘă-- -- Open clipboard inserter
- -- -- Wait for unknown word and add it to anki through yomichan
- -- -- Select all the subtitle lines to add to the card.
- -- -- Ctrl + c
- -- -- Tab back to MPV and Ctrl + v
- -- -- Done. The lines, their respective Audio and the current paused image
- -- -- will be added to the back of the card.
- -- -- Ctrl + t will toggle clipboard inserter on and off.
- local utils = require 'mp.utils'
- local msg = require 'mp.msg'
- local subs = {}
- local enable_subs_to_clip = true
- ------------- User Config -------------
- -- Set these to match your field names in Anki
- local FRONT_FIELD = "Word"
- local SENTENCE_AUDIO_FIELD = "Audio"
- local SENTENCE_FIELD = "Sentence"
- local IMAGE_FIELD = "Picture"
- -- Download ffmpeg and put the full path to executable here
- local FFMPEG_PATH = [[C:\Users\xxx\ffmpeg\ffmpeg\bin\ffmpeg.exe]]
- -- Anki collection media path. Ensure Anki user name is correct and this path ends with \
- local prefix = [[C:\Users\]] .. os.getenv('USERNAME') .. [[\AppData\Roaming\Anki2\User 1\collection.media\]]
- -- Optional padding and fade settings in seconds
- local AUDIO_CLIP_FADE = 0.2
- local AUDIO_CLIP_PADDING = 0.75
- -- Don't touch unless you know what you're doing
- local tmpdir = [[C:\Users\]] .. os.getenv('USERNAME') .. [[\AppData\Local\Temp\]]
- ---------------------------------------
- local function clean(s)
- local newtext = string.gsub(s, "\n", "")
- newtext = string.gsub(newtext, "\r", "")
- return string.gsub(newtext, "^%s*(.-)%s*$", "%1")
- end
- local function get_name(s, e)
- return mp.get_property("filename"):gsub('%W','').. tostring(s) .. tostring(e)
- end
- local function hms_to_seconds(hms)
- local total_seconds = 0
- local mult = 3600
- for i in hms:gmatch("[0-9.]+") do
- total_seconds = total_seconds + tonumber(i) * mult
- mult = mult / 60
- end
- return total_seconds
- end
- local function is_softlinked_mkv()
- local source = mp.get_property("path")
- local args = {
- FFMPEG_PATH,
- "-i", source
- }
- local res = utils.subprocess({ args = args, capture_stderr = true })
- local file_duration
- for line in res.stderr:gmatch("[^\r\n]+") do
- if string.find(line, 'Duration') then
- file_duration = hms_to_seconds(line:match('[0-9.]+:[0-9.]+:[0-9.]+'))
- break
- end
- end
- local full_duration = mp.get_property('duration')
- return math.abs(full_duration - file_duration) > 1
- end
- local function get_chapter_offset()
- if not is_softlinked_mkv() then
- return 0
- end
- local chapter_offset = 0
- if mp.get_property_number('chapters') > 0 then
- chapter_offset = mp.get_property_number('chapter-list/' .. mp.get_property_number('chapter') .. '/time')
- end
- return chapter_offset
- end
- local function record_sub(name, text)
- if text and mp.get_property_number('sub-start') and mp.get_property_number('sub-end') then
- local sub_delay = mp.get_property_native("sub-delay")
- local chapter_offset = get_chapter_offset()
- newtext = clean(text)
- if newtext == '' then
- return
- end
- subs[newtext] = { mp.get_property_number('sub-start') + sub_delay - chapter_offset, mp.get_property_number('sub-end') + sub_delay - chapter_offset }
- if enable_subs_to_clip then
- res = utils.subprocess({ args = {
- 'powershell', '-NoProfile', '-Command', [[Set-Clipboard -Value @"]] .. "\n" .. newtext .. "\n" .. [["@]]
- }})
- end
- end
- end
- local function create_audio(s, e)
- if s == nil or e == nil then
- return
- end
- local ff_aid = 0
- local tracks_count = mp.get_property_number("track-list/count")
- for i = 1, tracks_count do
- local track_type = mp.get_property(string.format("track-list/%d/type", i))
- local track_index = mp.get_property_number(string.format("track-list/%d/ff-index", i))
- local track_selected = mp.get_property(string.format("track-list/%d/selected", i))
- if track_type == "audio" and track_selected == "yes" then
- ff_aid = track_index - 1
- break
- end
- end
- local name = get_name(s, e)
- s = s - AUDIO_CLIP_PADDING
- local t = e - s + AUDIO_CLIP_PADDING
- local source = mp.get_property("path")
- local destination = prefix .. name .. '.mp3'
- local args = {
- FFMPEG_PATH,
- "-y",
- "-ss", tostring(s),
- "-i", source,
- "-t", string.format("%.3f", t),
- "-map", string.format("0:a:%d?", ff_aid),
- "-af", string.format("afade=t=in:curve=ipar:st=%.3f:d=%.3f,afade=t=out:curve=ipar:st=%.3f:d=%.3f", 0, AUDIO_CLIP_FADE, t - AUDIO_CLIP_FADE, AUDIO_CLIP_FADE),
- destination
- }
- utils.subprocess_detached({ args=args })
- end
- local function get_clipboard()
- local res = utils.subprocess({ args = {
- 'powershell', '-NoProfile', '-Command', [[& {
- Trap {
- Write-Error -ErrorRecord $_
- Exit 1
- }
- $clip = ""
- if (Get-Command "Get-Clipboard" -errorAction SilentlyContinue) {
- $clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText
- } else {
- Add-Type -AssemblyName PresentationCore
- $clip = [Windows.Clipboard]::GetText()
- }
- $clip = $clip -Replace "`r",""
- $u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip)
- [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
- }]]
- } })
- if not res.error then
- return res.stdout
- end
- end
- local function create_screenshot(s, e)
- local chapter_offset = get_chapter_offset()
- local source = mp.get_property("path")
- local img = prefix .. get_name(s,e) .. '.webp'
- local args = {
- FFMPEG_PATH,
- "-y",
- "-ss", tostring(mp.get_property_number("time-pos") - chapter_offset),
- "-i", source,
- "-vframes", "1",
- "-vf", "scale=-2:480",
- "-vcodec", "libwebp",
- "-compression_level", "6",
- "-preset", "drawing",
- img
- }
- utils.subprocess_detached({ args=args })
- end
- local function get(request)
- local file = io.open(tmpdir .. "tmpankiconnect.txt", "w")
- file:write(request)
- io.close(file)
- local curl = "curl.exe "..
- "localhost:8765 "..
- '-H "Content-Type: application/json; charset=UTF-8" '..
- "-d @"..tmpdir.."tmpankiconnect.txt"
- local args = {
- 'powershell', '-NoProfile', '-Command', curl
- }
- local result =
- utils.subprocess(
- {
- args = args,
- cancellable = true
- }
- )
- return utils.parse_json(result.stdout)
- end
- local function add_to_last_added(ifield, afield, tfield)
- local noteid = math.max(unpack(get('{"action": "findNotes", "params": {"query": "added:1"}, "version": 6}')["result"]))
- local note = get('{"action": "notesInfo", "params": {"notes": ['.. noteid.. ']}, "version": 6}')
- ifield = string.gsub(ifield, "\"", "\\\"")
- afield = string.gsub(afield, "\"", "\\\"")
- tfield = string.gsub(tfield, "\"", "\\\"")
- if note ~= nil then
- get('{"action": "updateNoteFields", "version": 6, "params": {"note": {"id": ' .. noteid.. ', "fields": {"' .. SENTENCE_AUDIO_FIELD .. '": "' .. afield .. '","' .. SENTENCE_FIELD .. '": "' .. tfield .. '","' .. IMAGE_FIELD .. '": "' .. ifield .. '"} } } }')
- mp.osd_message("Updated note: " .. note["result"][1]["fields"][FRONT_FIELD]["value"], 3)
- msg.info("Updated note: " .. note["result"][1]["fields"][FRONT_FIELD]["value"])
- end
- end
- local function get_extract()
- local lines = get_clipboard()
- local e = 0
- local s = 0
- for line in lines:gmatch("[^\r\n]+") do
- line = clean(line)
- if subs[line]~= nil then
- msg.info(lines)
- if subs[line][1] ~= nil and subs[line][2] ~= nil then
- if s == 0 then
- s = subs[line][1]
- else
- s = math.min(s, subs[line][1])
- end
- e = math.max(e, subs[line][2])
- end
- end
- end
- if e ~= 0 then
- create_screenshot(s, e)
- create_audio(s, e)
- local ifield = '<img src='.. get_name(s,e) ..'.webp>'
- local afield = "[sound:".. get_name(s,e) .. ".mp3]"
- local tfield = string.gsub(string.gsub(lines,"\n+", "<br />"), "\r", "")
- add_to_last_added(ifield, afield, tfield)
- end
- end
- local function ex()
- pcall(get_extract)
- end
- local function rec(...)
- pcall(record_sub, ...)
- end
- local function toggle_sub_to_clipboard()
- enable_subs_to_clip = not enable_subs_to_clip
- mp.osd_message("Clipboard inserter " .. (enable_subs_to_clip and "activated" or "deactived"), 3)
- end
- mp.observe_property("sub-text", 'string', rec)
- mp.add_key_binding("ctrl+v", ex)
- mp.add_key_binding("ctrl+t", toggle_sub_to_clipboard)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement