Advertisement
Guest User

cards v10

a guest
Oct 6th, 2020
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.35 KB | None | 0 0
  1. â™Ș〜-- -- Open clipboard inserter
  2. -- -- Wait for unknown word and add it to anki through yomichan
  3. -- -- Select all the subtitle lines to add to the card.
  4. -- -- Ctrl + c
  5. -- -- Tab back to MPV and Ctrl + v
  6. -- -- Done. The lines, their respective Audio and the current paused image
  7. -- -- will be added to the back of the card.
  8. -- -- Ctrl + t will toggle clipboard inserter on and off.
  9.  
  10. local utils = require 'mp.utils'
  11. local msg = require 'mp.msg'
  12. local subs = {}
  13. local enable_subs_to_clip = true
  14.  
  15. ------------- User Config -------------
  16. -- Set these to match your field names in Anki
  17. local FRONT_FIELD = "Word"
  18. local SENTENCE_AUDIO_FIELD = "Audio"
  19. local SENTENCE_FIELD = "Sentence"
  20. local IMAGE_FIELD = "Picture"
  21. -- Download ffmpeg and put the full path to executable here
  22. local FFMPEG_PATH = [[C:\Users\xxx\ffmpeg\ffmpeg\bin\ffmpeg.exe]]
  23. -- Anki collection media path. Ensure Anki user name is correct and this path ends with \
  24. local prefix = [[C:\Users\]] .. os.getenv('USERNAME') .. [[\AppData\Roaming\Anki2\User 1\collection.media\]]
  25. -- Optional padding and fade settings in seconds
  26. local AUDIO_CLIP_FADE = 0.2
  27. local AUDIO_CLIP_PADDING = 0.75
  28. -- Don't touch unless you know what you're doing
  29. local tmpdir = [[C:\Users\]] .. os.getenv('USERNAME') .. [[\AppData\Local\Temp\]]
  30. ---------------------------------------
  31.  
  32. local function clean(s)
  33. local newtext = string.gsub(s, "\n", "")
  34. newtext = string.gsub(newtext, "\r", "")
  35. return string.gsub(newtext, "^%s*(.-)%s*$", "%1")
  36. end
  37.  
  38. local function get_name(s, e)
  39. return mp.get_property("filename"):gsub('%W','').. tostring(s) .. tostring(e)
  40. end
  41.  
  42. local function hms_to_seconds(hms)
  43. local total_seconds = 0
  44. local mult = 3600
  45. for i in hms:gmatch("[0-9.]+") do
  46. total_seconds = total_seconds + tonumber(i) * mult
  47. mult = mult / 60
  48. end
  49. return total_seconds
  50. end
  51.  
  52. local function is_softlinked_mkv()
  53. local source = mp.get_property("path")
  54. local args = {
  55. FFMPEG_PATH,
  56. "-i", source
  57. }
  58. local res = utils.subprocess({ args = args, capture_stderr = true })
  59. local file_duration
  60. for line in res.stderr:gmatch("[^\r\n]+") do
  61. if string.find(line, 'Duration') then
  62. file_duration = hms_to_seconds(line:match('[0-9.]+:[0-9.]+:[0-9.]+'))
  63. break
  64. end
  65. end
  66. local full_duration = mp.get_property('duration')
  67. return math.abs(full_duration - file_duration) > 1
  68. end
  69.  
  70.  
  71. local function get_chapter_offset()
  72. if not is_softlinked_mkv() then
  73. return 0
  74. end
  75.  
  76. local chapter_offset = 0
  77. if mp.get_property_number('chapters') > 0 then
  78. chapter_offset = mp.get_property_number('chapter-list/' .. mp.get_property_number('chapter') .. '/time')
  79. end
  80. return chapter_offset
  81. end
  82.  
  83. local function record_sub(name, text)
  84. if text and mp.get_property_number('sub-start') and mp.get_property_number('sub-end') then
  85. local sub_delay = mp.get_property_native("sub-delay")
  86. local chapter_offset = get_chapter_offset()
  87. newtext = clean(text)
  88. if newtext == '' then
  89. return
  90. end
  91.  
  92. subs[newtext] = { mp.get_property_number('sub-start') + sub_delay - chapter_offset, mp.get_property_number('sub-end') + sub_delay - chapter_offset }
  93. if enable_subs_to_clip then
  94. res = utils.subprocess({ args = {
  95. 'powershell', '-NoProfile', '-Command', [[Set-Clipboard -Value @"]] .. "\n" .. newtext .. "\n" .. [["@]]
  96. }})
  97. end
  98. end
  99. end
  100.  
  101. local function create_audio(s, e)
  102.  
  103. if s == nil or e == nil then
  104. return
  105. end
  106.  
  107. local ff_aid = 0
  108. local tracks_count = mp.get_property_number("track-list/count")
  109. for i = 1, tracks_count do
  110. local track_type = mp.get_property(string.format("track-list/%d/type", i))
  111. local track_index = mp.get_property_number(string.format("track-list/%d/ff-index", i))
  112. local track_selected = mp.get_property(string.format("track-list/%d/selected", i))
  113.  
  114. if track_type == "audio" and track_selected == "yes" then
  115. ff_aid = track_index - 1
  116. break
  117. end
  118. end
  119.  
  120. local name = get_name(s, e)
  121. s = s - AUDIO_CLIP_PADDING
  122. local t = e - s + AUDIO_CLIP_PADDING
  123. local source = mp.get_property("path")
  124. local destination = prefix .. name .. '.mp3'
  125. local args = {
  126. FFMPEG_PATH,
  127. "-y",
  128. "-ss", tostring(s),
  129. "-i", source,
  130. "-t", string.format("%.3f", t),
  131. "-map", string.format("0:a:%d?", ff_aid),
  132. "-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),
  133. destination
  134. }
  135. utils.subprocess_detached({ args=args })
  136. end
  137.  
  138. local function get_clipboard()
  139. local res = utils.subprocess({ args = {
  140. 'powershell', '-NoProfile', '-Command', [[& {
  141. Trap {
  142. Write-Error -ErrorRecord $_
  143. Exit 1
  144. }
  145. $clip = ""
  146. if (Get-Command "Get-Clipboard" -errorAction SilentlyContinue) {
  147. $clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText
  148. } else {
  149. Add-Type -AssemblyName PresentationCore
  150. $clip = [Windows.Clipboard]::GetText()
  151. }
  152. $clip = $clip -Replace "`r",""
  153. $u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip)
  154. [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
  155. }]]
  156. } })
  157. if not res.error then
  158. return res.stdout
  159. end
  160. end
  161.  
  162. local function create_screenshot(s, e)
  163. local chapter_offset = get_chapter_offset()
  164. local source = mp.get_property("path")
  165. local img = prefix .. get_name(s,e) .. '.webp'
  166. local args = {
  167. FFMPEG_PATH,
  168. "-y",
  169. "-ss", tostring(mp.get_property_number("time-pos") - chapter_offset),
  170. "-i", source,
  171. "-vframes", "1",
  172. "-vf", "scale=-2:480",
  173. "-vcodec", "libwebp",
  174. "-compression_level", "6",
  175. "-preset", "drawing",
  176. img
  177. }
  178. utils.subprocess_detached({ args=args })
  179. end
  180.  
  181. local function get(request)
  182. local file = io.open(tmpdir .. "tmpankiconnect.txt", "w")
  183. file:write(request)
  184. io.close(file)
  185. local curl = "curl.exe "..
  186. "localhost:8765 "..
  187. '-H "Content-Type: application/json; charset=UTF-8" '..
  188. "-d @"..tmpdir.."tmpankiconnect.txt"
  189. local args = {
  190. 'powershell', '-NoProfile', '-Command', curl
  191. }
  192.  
  193. local result =
  194. utils.subprocess(
  195. {
  196. args = args,
  197. cancellable = true
  198. }
  199. )
  200.  
  201. return utils.parse_json(result.stdout)
  202. end
  203.  
  204. local function add_to_last_added(ifield, afield, tfield)
  205. local noteid = math.max(unpack(get('{"action": "findNotes", "params": {"query": "added:1"}, "version": 6}')["result"]))
  206. local note = get('{"action": "notesInfo", "params": {"notes": ['.. noteid.. ']}, "version": 6}')
  207.  
  208. ifield = string.gsub(ifield, "\"", "\\\"")
  209. afield = string.gsub(afield, "\"", "\\\"")
  210. tfield = string.gsub(tfield, "\"", "\\\"")
  211.  
  212. if note ~= nil then
  213. get('{"action": "updateNoteFields", "version": 6, "params": {"note": {"id": ' .. noteid.. ', "fields": {"' .. SENTENCE_AUDIO_FIELD .. '": "' .. afield .. '","' .. SENTENCE_FIELD .. '": "' .. tfield .. '","' .. IMAGE_FIELD .. '": "' .. ifield .. '"} } } }')
  214.  
  215. mp.osd_message("Updated note: " .. note["result"][1]["fields"][FRONT_FIELD]["value"], 3)
  216. msg.info("Updated note: " .. note["result"][1]["fields"][FRONT_FIELD]["value"])
  217. end
  218. end
  219.  
  220. local function get_extract()
  221. local lines = get_clipboard()
  222. local e = 0
  223. local s = 0
  224. for line in lines:gmatch("[^\r\n]+") do
  225. line = clean(line)
  226. if subs[line]~= nil then
  227. msg.info(lines)
  228. if subs[line][1] ~= nil and subs[line][2] ~= nil then
  229. if s == 0 then
  230. s = subs[line][1]
  231. else
  232. s = math.min(s, subs[line][1])
  233. end
  234. e = math.max(e, subs[line][2])
  235. end
  236. end
  237. end
  238. if e ~= 0 then
  239. create_screenshot(s, e)
  240. create_audio(s, e)
  241. local ifield = '<img src='.. get_name(s,e) ..'.webp>'
  242. local afield = "[sound:".. get_name(s,e) .. ".mp3]"
  243. local tfield = string.gsub(string.gsub(lines,"\n+", "<br />"), "\r", "")
  244. add_to_last_added(ifield, afield, tfield)
  245. end
  246. end
  247.  
  248. local function ex()
  249. pcall(get_extract)
  250. end
  251.  
  252. local function rec(...)
  253. pcall(record_sub, ...)
  254. end
  255.  
  256. local function toggle_sub_to_clipboard()
  257. enable_subs_to_clip = not enable_subs_to_clip
  258. mp.osd_message("Clipboard inserter " .. (enable_subs_to_clip and "activated" or "deactived"), 3)
  259. end
  260.  
  261. mp.observe_property("sub-text", 'string', rec)
  262. mp.add_key_binding("ctrl+v", ex)
  263. mp.add_key_binding("ctrl+t", toggle_sub_to_clipboard)
  264.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement