diff --git a/.gitmodules b/.gitmodules index 8f41a50..af0f685 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,6 +16,3 @@ [submodule "scripts/autosubsync-mpv"] path = scripts/autosubsync-mpv url = git@github.com:Ajatt-Tools/autosubsync-mpv.git -[submodule "scripts/immersive"] - path = scripts/immersive - url = git@github.com:Ben-Kerman/immersive.git diff --git a/mpv-anilist-updater b/mpv-anilist-updater deleted file mode 160000 index 6cc573e..0000000 --- a/mpv-anilist-updater +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6cc573ec7dadaec4acca58b7e1b91f86c8e54e95 diff --git a/script-opts/immersive-dictionaries.conf b/script-opts/immersive-dictionaries.conf deleted file mode 100644 index fe2b64c..0000000 --- a/script-opts/immersive-dictionaries.conf +++ /dev/null @@ -1,71 +0,0 @@ -# this line is here so the file is encoded as UTF−8 -# do not delete it unless you know what that means - -# example dictionary config for JMdict - -[JMdict] -location=/home/sudacode/Documents/jmdict/ -type=yomichan - - -# Only the two entries above are strictly required for each dictionary. -# optional entries: - -# cf. doc/lookup-transformations.md, empty by default: -#transformations=deinflect-japanese,deinflect-migaku(ja.json),kana - -# cf. doc/dictionaries.md for details -#preload=<...> -#insert_cjk_breaks=no -exporter=default -quick_def_template={{readings:::・}}{{variants:【:】:・}}: {{definitions:::; }} - -export:digits=0123456789 -export:reading_template={{reading}}{{variants:【:】:・}} -export:definition_template={{tags::
:, }}{{num}}. {{keywords:::; }} -export:template={{readings[1]}}:{{readings[2:] (:): }}
{{definitions:::
}} -export:use_single_template=false -export:single_template={{readings[1]}}:{{readings[2:] (:): }}
{{definitions:::
}} - -# -------------------- - -# example config for Daijirin, probably usable for any EPWING exported by -# yomichan-import - -# also set 'definition_substitutions=\
<\n' in your target config -# to add HTML line breaks to the definition - -#[大辞林] -#location= -#type=yomichan - -# to make text more readable in mpv -#insert_cjk_breaks=yes - -# there is only one definition for EPWINGs exported to Yomichan -# and it already includes the word -#quick_def_template={{definitions}} - -# same as for quick_def_template -#export:definition_template={{keywords}} -#export:template={{definitions}} - -# these aren't needed since the reading and word are already in the definition -#export:reading_template= -#export:use_single_template=no - -# -------------------- - -# example config for a Migaku dictionary - -#[Migaku Dictionary] -#location= -#type=migaku -#exporter=default -#quick_def_template={{definitions}} -#export:template=[[ -#{{terms[1]}}{{terms[2:] (:):, }}:
-#{{altterms::
:, }}{{pronunciations::
:, }}{{positions::
:, }} -#{{definition}} -#{{examples:::, }} -#]] diff --git a/script-opts/immersive-keys.conf b/script-opts/immersive-keys.conf deleted file mode 100644 index 014cd57..0000000 --- a/script-opts/immersive-keys.conf +++ /dev/null @@ -1,4 +0,0 @@ -open_global_menu=ctrl+i -show_dict_target=ctrl+I -export_active_line_instant=ctrl+e -export_active_line_menua=ctrl+E diff --git a/script-opts/immersive-series.conf b/script-opts/immersive-series.conf deleted file mode 100644 index f5941ac..0000000 --- a/script-opts/immersive-series.conf +++ /dev/null @@ -1,12 +0,0 @@ -# this line is here so the file is encoded as UTF−8 -# do not delete it unless you know what that means - -## streamed video; something similar should work for any platform youtube-dl supports -#[youtube] -#title={{media_title}} -#keywords=youtu be -# -## local video file -#[kaguya-sama] -#title=かぐや様は告らせたい -#keywords=kaguya sama kokurasetai diff --git a/script-opts/immersive-style.conf b/script-opts/immersive-style.conf deleted file mode 100644 index 61f1a40..0000000 --- a/script-opts/immersive-style.conf +++ /dev/null @@ -1,143 +0,0 @@ -# this line is here so the file is encoded as UTF−8 -# do not delete it unless you know what that means - -# Global entries serve as the basis for all other styles. -#align =5 -#bold = -#italic = -#underline =no -#strikeout =no -#border = -#border_x = -#border_y = -#shadow = -#shadow_x = -#shadow_y = -#blur = -#font_name = -#font_size =30 -#letter_spacing = -#primary_color = -#secondary_color =808080 -#border_color = -#shadow_color = -#all_alpha =FF -#primary_alpha = -#secondary_alpha =00 -#border_alpha = -#shadow_alpha = - -# -------------------- - -# message log at the top right -#[messages] -#align=9 - -#[messages/fatal] -#bold=yes -#primary_color=5791F9 - -#[messages/error] -#primary_color=7A77F2 - -#[messages/warn] -#primary_color=66CCFF - -#[messages/info] -# none - -#[messages/verbose] -#primary_color=99CC99 - -#[messages/debug] -#primary_color=A09F93 - -#[messages/trace] -# none - -# -------------------- - -# menu help ("Press h to show key bindings") -#[menu_help] -#align=7 - -# key bindings -#[menu_help/key] -#bold=yes - -# top line of the menu help -#[menu_help/hint] -#italic=yes - -# -------------------- - -# menu info (timings, active target, etc.) -#[menu_info] -#align=1 - -# description of an info item -#[menu_info/key] -#bold=yes - -# unset/unknown/automatically generated values -#[menu_info/unset] -#italic=yes - -# -------------------- - -# line selection -#[line_select] -# none - -# actively selected line -#[line_select/selection] -#bold=yes -#primary_color=FFD0D0 - -# -------------------- - -# text selection -# applied on top of line_select during target selection -#[text_select] -# none - -# selected text -#[text_select/selection] -#primary_color=FF8080 - -# -------------------- - -# Forvo audio selection -# applied on top of line_select -#[word_audio_select] -# none - -# pronunciations that have not been loaded yet -#[word_audio_select/unloaded] -#primary_color=808080 - -# pronunciations that are currently loading -#[word_audio_select/loading] -#primary_color=8080FF - -# pronunciations that are ready to play -#[word_audio_select/loaded] -# none - -# -------------------- - -# overlay of selected subtitles during subtitle selection -#[selection_overlay] -#align=3 - -# -------------------- - -# overlay shown when Immersive is blocked, e.g. while importing dictionaries -#[info_overlay] -#align=1 - - -# overlay for hiding the video during and after target selection -#[blackout] -#primary_color= -#primary_alpha= diff --git a/script-opts/immersive-targets.conf b/script-opts/immersive-targets.conf deleted file mode 100644 index 62dcf70..0000000 --- a/script-opts/immersive-targets.conf +++ /dev/null @@ -1,139 +0,0 @@ -# this line is here so the file is encoded as UTF−8 -# do not delete it unless you know what that means - -[target name] -# Anki profile the target will use -# Can be taken from the window title of the main Anki window or from the profile -# menu (Ctrl+Shift+P in Anki) -profile=sudacode - -# Anki deck the target will use -# Subdecks use the same syntax as in Anki itself -# e.g. Root::Subdeck::Subsubdeck -deck=Minecraft - -# note type the target will use -note_type=Lapis - -# -------------------- - -# example field definitions - -# uncomment (remove the #) and change so they fit your note type -# Anki field names go between 'field:' and '=', exactly as they are -# in Anki, including spaces. -# Template variables come after the '=', like in the examples. - -#field:Front={{sentences}} -#field:Back={{definitions}} -#field:Word={{words[1]}} -#field:Words={{words::: }} -#field:Audio={{audio}} -#field:Word Audio={{word_audio}} -#field:Image={{image}} - -field:SentenceAudio={{audio}} -field:Picture={{image}} -field:MiscInfo={{series_title}} - -# Everything below this line has default values and is not required. -# It is recommended to change image/max_width or image/max_height in order to -# reduce file sizes, however. -# -------------------- - -# how export data will be added to existing notes -# allowed values: 'append', 'prepend', 'overwrite' -# overwrite replaces fields (but cf. template variable {{prev_content}}) -add_mode=append - -# template used for formatting notes within mpv -# when selecting which existing note to export to -#note_template={{type}}: {{id}} - -# Anki media dir override, optional and normally derived from system default -# Must be an absolute path to the directory that encoded images/audio clips -# should be placed in (i.e., to collection.media). -#media_directory= - -# space-separated list of tags that will be added to exported notes -#tags=immersive - -# can be set dynamically using field template variables, e.g.: -#tags={{series_id}} - -# -------------------- - -# substitutions to apply to the {{sentences}} variable -# for more information, see doc/card-export.md -#sentence_substitutions=[[ -#<(.-%) -#<(.-%) -#]] - -# same as sentence_substitutions but for {{definitions}} -#definition_substitutions= - -# -------------------- - -# audio clip file extension -# unrelated to the format used, but should match it (especially on Windows) -audio/extension=mp3 - -# audio container format -# e.g. 'matroska' (MKV/MKA), 'ogg', 'mp3' -audio/format=mp3 - -# audio codec -# e.g. 'libopus' (NOT 'opus'), 'aac', 'vorbis', 'libmp3lame' (MP3) -audio/codec=libmp3lame - -# audio bitrate -# Uses the same syntax as mpv/ffmpeg bitrates. -# Sensible values are 32ki-64ki for libopus and 128ki for AAC and MP3. -audio/bitrate=128ki - -# how many seconds of padding to include before the start of audio clips -#audio/pad_start=0.1 - -# same as above, but after the end of the clip -#audio/pad_end=0.1 - -# -------------------- - -# image file extension -image/extension=webp - -# image codec -# supported values are 'mjpeg' (JPG), 'libwebp' (WebP), and 'png' -# Technically, any codec that works with ffmpeg's image2 format can be used. -image/codec=libwebp - -# maximum image width/height -# If one option is set to a negative value aspect ratio will be preserved. -# If both are negative the video's resolution will be used. -#image/max_width=-1 -#image/max_height=-1 - -# quality of JPG (mjpeg) images -# valid range: 1-69 -# lower is better (but files will be larger) -# Values above 5-10 result in noticeable artifacting. -image/jpeg/qscale=5 - -# whether to use lossless compression for WebP -image/webp/lossless=yes - -# libwebp quality factor -# valid range: 0-100 -# higher is better -image/webp/quality=90 - -# libwebp compression level -# valid range: 0-6 -# Higher values result in better compression but take longer to encode. -image/webp/compression=4 - -# PNG compression level -# valid range: 0-9 -# higher is better -#image/png/compression=9 diff --git a/script-opts/immersive.conf b/script-opts/immersive.conf deleted file mode 100644 index f33b99f..0000000 --- a/script-opts/immersive.conf +++ /dev/null @@ -1,82 +0,0 @@ -# this line is here so the file is encoded as UTF−8 -# do not delete it unless you know what that means - -# the mpv executable to use for audio previews and encoding -# if unset (default), the executable of the current process will be used -#mpv_executable=<...> - -# if set to 'yes', load dictionaries when mpv starts -preload_dictionaries=no - -# show the dictionary loading overlay when loading dicts at startup -startup_dict_overlay=yes - -# maximum number of target words per card -# set to 0 to disable limit -#max_targets=1 - -# always show minutes when displaying times, -# even if playback has not reached 01:00 yet -#always_show_minutes=yes - -# black out the screen during and after target selection -#target_select_blackout=yes - -# black out the screen when looking up words from the active subtitle -#active_sub_blackout=yes - -# language code to use when searching Forvo audio -forvo_language=ja - -# Automatically load Forvo audio instead of waiting until attempting to play it. -forvo_preload_audio=no - -# download mp3 files from Forvo instead of Ogg/Vorbis -forvo_prefer_mp3=yes - -# prefix for Forvo filenames in the Anki media directory -# Files will be named '-.'. -#forvo_prefix=word_audio - -# reencode Forvo audio files since they are unnecessarily large -forvo_reencode=yes - -# Forvo audio encoding options -# These behave like the corresponding options in target configs. -forvo_extension=mp3 -forvo_format=mp3 -forvo_codec=libmp3lame -forvo_bitrate=128ki - -# AnkiConnect host and port -ankiconnect_host=localhost -ankiconnect_port=8765 - -# Windows clipboard copy mode -# "exact" takes longer (200ms-1s), but preserves the text exactly, -# i.e. it also copies line breaks. -# "quick" is much faster (<50ms), but might not copy the text -# with 100% accuracy. This method sometimes causes encoding issues -# and is known to sporadically copy corrupted text. -#windows_copy_mode=exact - -# enable automatic subtitle copying by default -#enable_autocopy=no - -# make subtitle autoselect toggle global instead of -# being tied to each subtitle select menu -#global_autoselect=yes - -# enable subtitle autoselect by default -#enable_autoselect=yes - -# same as above but for the menu help toggle -#global_help=yes -#enable_help=no - -# enable screenshots by default -take_screenshots=yes - -# Hide the menu info at the bottom left if the help overlay is active. -# Useful if the two collide due to large font sizes. -#hide_infos_if_help_active=no diff --git a/scripts/animecards.lua b/scripts/animecards.lua new file mode 100644 index 0000000..d546192 --- /dev/null +++ b/scripts/animecards.lua @@ -0,0 +1,496 @@ +------------- Instructions ------------- +-- -- Video Demonstration: https://www.youtube.com/watch?v=M4t7HYS73ZQ +-- IF USING WEBSOCKET (RECOMMENDED) +-- -- Install the mpv_webscoket extension: https://github.com/kuroahna/mpv_websocket +-- -- Open a LOCAL copy of https://github.com/Renji-XD/texthooker-ui +-- -- Configure the script (if you're not using the Lapis note format) +-- IF USING CLIPBOARD INSERTER (NOT RECOMMENDED) +-- -- Install the clipboard inserter plugin: https://github.com/laplus-sadness/lap-clipboard-inserter +-- -- Open the texthooker UI, enable the plugin and enable clipboard pasting: https://github.com/Renji-XD/texthooker-ui +-- BOTH +-- -- Wait for an unknown word and create the card with Yomichan. +-- -- Select all the subtitle lines you wish to add to the card and copy with Ctrl + c. +-- -- Press Ctrl + v in MPV to add the lines, their Audio and the currently paused image to the back of the card. +--------------------------------------- + +------------- Credits ------------- +-- Credits and copyright go to Anacreon DJT: https://anacreondjt.gitlab.io/ +------------------------------------ + +------------- Original Credits (Outdated) ------------- +-- This script was made by users of 4chan's Daily Japanese Thread (DJT) on /jp/ +-- More information can be found here http://animecards.site/ +-- Message @Anacreon with bug reports and feature requests on Discord (https://animecards.site/discord/) or 4chan (https://boards.4channel.org/jp/#s=djt) +-- +-- If you like this work please consider subscribing on Patreon! +-- https://www.patreon.com/Quizmaster +------------------------------------ + +local utils = require("mp.utils") +local msg = require("mp.msg") + +------------- User Config ------------- +-- Set these to match your field names in Anki +local FRONT_FIELD = "Expression" +local SENTENCE_AUDIO_FIELD = "SentenceAudio" +local SENTENCE_FIELD = "Sentence" +local IMAGE_FIELD = "Picture" +-- Optional padding and fade settings in seconds. +-- Padding grabs extra audio around your selected subs. +-- Fade does a volume fade effect at the beginning and end of the resulting audio. +local AUDIO_CLIP_FADE = 0.2 +local AUDIO_CLIP_PADDING = 0.75 +-- Optional play sentence audio automatically after card update +local AUTOPLAY_AUDIO = false +-- Optional screenshot image format. Valid options: "webp" or "png" +-- Change to "png" if you plan to view cards on iOS or Mac. +local IMAGE_FORMAT = "png" +-- Optional set to true if you want your volume in mpv to affect Anki card volume. +local USE_MPV_VOLUME = false +-- Set to true if you want writing to clipboard to be enabled by default. +-- The more modern and recommended alternative is to use the websocket. +local ENABLE_SUBS_TO_CLIP = false + +--------------------------------------- + +------------- Internal Variables ------------- +local subs = {} +local debug_mode = false +local use_powershell_clipboard = nil +local prefix = "" +--------------------------------------- + +------------- Setup ------------- +if unpack ~= nil then + table.unpack = unpack +end + +local o = {} +-- Possible platforms: windows, linux, macos +local platform = mp.get_property_native("platform") +if platform == "darwin" then + platform = "macos" +end + +local display_server +if os.getenv("WAYLAND_DISPLAY") then + display_server = "wayland" +elseif platform == "linux" then + display_server = "xorg" +else + display_server = "" +end + +local function dlog(...) + if debug_mode then + print(...) + end +end + +local function verfiy_libmp3lame() + local encoderlist = mp.get_property("encoder-list") + if not encoderlist or not string.find(encoderlist, "libmp3lame") then + mp.osd_message( + "Error: libmp3lame encoder not found. Audio export will not work.\nPlease use a build of mpv with libmp3lame support.", + 10 + ) + msg.error("Error: libmp3lame encoder not found. MP3 audio export will not work.") + else + dlog("libmp3lame encoder found.") + end +end + +mp.register_event("file-loaded", verfiy_libmp3lame) + +dlog("Detected Platform: " .. platform) +dlog("Detected display server: " .. display_server) + +--------------------------------------- +-- Handle requests to AnkiConnect +local function anki_connect(action, params) + local request = utils.format_json({ action = action, params = params, version = 6 }) + local args = { "curl", "-s", "localhost:8765", "-X", "POST", "-d", request } + + dlog("AnkiConnect request: " .. request) + + local result = utils.subprocess({ args = args, cancellable = false, capture_stderr = true }) + + if result.status ~= 0 then + msg.error("Curl command failed with status: " .. tostring(result.status)) + msg.error("Stderr: " .. (result.stderr or "none")) + return nil + end + + if not result.stdout or result.stdout == "" then + msg.error("Empty response from AnkiConnect") + return nil + end + + dlog("AnkiConnect response: " .. result.stdout) + + local success, parsed_result = pcall(function() + return utils.parse_json(result.stdout) + end) + if not success or not parsed_result then + msg.error("Failed to parse JSON response: " .. (result.stdout or "empty")) + return nil + end + + return parsed_result +end + +-- Get media directory path from AnkiConnect +local function set_media_dir() + local media_dir_response = anki_connect("getMediaDirPath") + if not media_dir_response then + msg.error("Failed to communicate with AnkiConnect. Is Anki running and do you have AnkiConnect installed?") + mp.osd_message( + "Error: Failed to communicate with AnkiConnect. Is Anki running and do you have AnkiConnect installed?", + 5 + ) + return + elseif media_dir_response["error"] then + msg.error("AnkiConnect error: " .. tostring(media_dir_response["error"])) + mp.osd_message("AnkiConnect error: " .. tostring(media_dir_response["error"]), 5) + return + elseif media_dir_response["result"] then + prefix = media_dir_response["result"] + dlog("Got media directory path from AnkiConnect: " .. prefix) + else + msg.error("Unexpected response format from AnkiConnect") + mp.osd_message("Error: Unexpected response from AnkiConnect", 5) + return + end +end + +local function clean(s) + for _, ws in ipairs({ + "%s", + " ", + "᠎", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "​", + " ", + " ", + " ", + "", + "‪", + }) do + s = s:gsub(ws .. "+", "") + end + return s +end + +local function get_name(s, e) + return mp.get_property("filename"):gsub("%W", "") .. tostring(s) .. tostring(e) +end + +local function get_clipboard() + local res + if platform == "windows" then + 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) + }]], + }, + }) + elseif platform == "macos" then + return io.popen("LANG=en_US.UTF-8 pbpaste"):read("*a") + else -- platform == 'linux' + if display_server == "wayland" then + res = utils.subprocess({ args = { + "wl-paste", + } }) + else -- display_server == 'xorg' + res = utils.subprocess({ args = { + "xclip", + "-selection", + "clipboard", + "-out", + } }) + end + end + if not res.error then + return res.stdout + end +end + +local function powershell_set_clipboard(text) + utils.subprocess({ + args = { + "powershell", + "-NoProfile", + "-Command", + [[Set-Clipboard -Value @"]] .. "\n" .. text .. "\n" .. [["@]], + }, + }) +end + +local function cmd_set_clipboard(text) + local cmd = "echo " .. text .. " | clip" + mp.command("run cmd /D /C " .. cmd) +end + +local function determine_clip_type() + powershell_set_clipboard([[Anacreon様]]) + use_powershell_clipboard = get_clipboard() == [[Anacreon様]] +end + +local function linux_set_clipboard(text) + if display_server == "wayland" then + os.execute("wl-copy < %s : %s", subs[newtext][1], subs[newtext][2], newtext)) + if ENABLE_SUBS_TO_CLIP then + -- Remove newlines from text before sending it to clipboard. + -- This way pressing control+v without copying from texthooker page + -- will always give last line. + text = string.gsub(text, "[\n\r]+", " ") + if platform == "windows" then + if use_powershell_clipboard == nil then + determine_clip_type() + end + if use_powershell_clipboard then + powershell_set_clipboard(text) + else + cmd_set_clipboard(text) + end + elseif platform == "macos" then + macos_set_clipboard(text) + else + linux_set_clipboard(text) + end + end + end +end + +local function create_audio(s, e) + if s == nil or e == nil then + return + end + + local name = get_name(s, e) + local destination = utils.join_path(prefix, name .. ".mp3") + s = s - AUDIO_CLIP_PADDING + local t = e - s + AUDIO_CLIP_PADDING + local source = mp.get_property("path") + local aid = mp.get_property("aid") + + 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_selected = mp.get_property(string.format("track-list/%d/selected", i)) + if track_type == "audio" and track_selected == "yes" then + if mp.get_property(string.format("track-list/%d/external-filename", i), o) ~= o then + source = mp.get_property(string.format("track-list/%d/external-filename", i)) + aid = "auto" + end + break + end + end + + local cmd = { + "run", + "mpv", + source, + "--loop-file=no", + "--video=no", + "--no-ocopy-metadata", + "--no-sub", + "--audio-channels=1", + string.format("--start=%.3f", s), + string.format("--length=%.3f", t), + string.format("--aid=%s", aid), + string.format("--volume=%s", USE_MPV_VOLUME and mp.get_property("volume") or "100"), + string.format("--af-append=afade=t=in:curve=ipar:st=%.3f:d=%.3f", s, AUDIO_CLIP_FADE), + string.format("--af-append=afade=t=out:curve=ipar:st=%.3f:d=%.3f", s + t - AUDIO_CLIP_FADE, AUDIO_CLIP_FADE), + string.format("-o=%s", destination), + } + mp.commandv(table.unpack(cmd)) + dlog(utils.to_string(cmd)) +end + +local function create_screenshot(s, e) + local source = mp.get_property("path") + local img = utils.join_path(prefix, get_name(s, e) .. "." .. IMAGE_FORMAT) + + local cmd = { + "run", + "mpv", + source, + "--loop-file=no", + "--audio=no", + "--no-ocopy-metadata", + "--no-sub", + "--frames=1", + } + if IMAGE_FORMAT == "webp" then + table.insert(cmd, "--ovc=libwebp") + table.insert(cmd, "--ovcopts-add=lossless=0") + table.insert(cmd, "--ovcopts-add=compression_level=6") + table.insert(cmd, "--ovcopts-add=preset=drawing") + elseif IMAGE_FORMAT == "png" then + table.insert(cmd, "--vf-add=format=rgb24") + end + table.insert(cmd, "--vf-add=scale=480*iw*sar/ih:480") + table.insert(cmd, string.format("--start=%.3f", mp.get_property_number("time-pos"))) + table.insert(cmd, string.format("-o=%s", img)) + mp.commandv(table.unpack(cmd)) + dlog(utils.to_string(cmd)) +end + +local function add_to_last_added(ifield, afield, tfield) + local added_notes = anki_connect("findNotes", { query = "added:1" })["result"] + table.sort(added_notes) + local noteid = added_notes[#added_notes] + local note = anki_connect("notesInfo", { notes = { noteid } }) + + if note ~= nil then + local word = note["result"][1]["fields"][FRONT_FIELD]["value"] + local new_fields = { + [SENTENCE_AUDIO_FIELD] = afield, + [SENTENCE_FIELD] = tfield, + [IMAGE_FIELD] = ifield, + } + + anki_connect("updateNoteFields", { + note = { + id = noteid, + fields = new_fields, + }, + }) + + mp.osd_message("Updated note: " .. word, 3) + msg.info("Updated note: " .. word) + 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) + dlog(line) + if subs[line] ~= nil then + 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 + else + mp.osd_message("ERR! Line not found: " .. line, 3) + return + end + end + dlog(string.format("s=%d, e=%d", s, e)) + if e ~= 0 then + create_screenshot(s, e) + create_audio(s, e) + local ifield = "" + local afield = "[sound:" .. get_name(s, e) .. ".mp3]" + local tfield = string.gsub(string.gsub(lines, "\n+", "
"), "\r", "") + add_to_last_added(ifield, afield, tfield) + if AUTOPLAY_AUDIO then + local name = get_name(s, e) + local audio = utils.join_path(prefix, name .. ".mp3") + local cmd = { "run", "mpv", audio, "--loop-file=no", "--load-scripts=no" } + mp.commandv(table.unpack(cmd)) + end + end +end + +local function ex() + if not prefix or prefix == "" then + set_media_dir() + end + + if debug_mode then + get_extract() + else + pcall(get_extract) + end +end + +local function rec(...) + if debug_mode then + record_sub(...) + else + pcall(record_sub, ...) + end +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 + +local function toggle_debug_mode() + debug_mode = not debug_mode + mp.osd_message("Debug mode " .. (debug_mode and "activated" or "deactived"), 3) +end + +local function clear_subs(_) + subs = {} +end + +mp.observe_property("sub-text", "string", rec) +mp.observe_property("filename", "string", clear_subs) + +mp.add_key_binding("ctrl+v", "update-anki-card", ex) +mp.add_key_binding("ctrl+t", "toggle-clipboard-insertion", toggle_sub_to_clipboard) +mp.add_key_binding("ctrl+d", "toggle-debug-mode", toggle_debug_mode) +mp.add_key_binding("ctrl+V", ex) +mp.add_key_binding("ctrl+T", toggle_sub_to_clipboard) +mp.add_key_binding("ctrl+D", toggle_debug_mode) diff --git a/scripts/immersive b/scripts/immersive deleted file mode 160000 index 9bde59a..0000000 --- a/scripts/immersive +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9bde59a0abaa018096de5b6f38c3ad409b9cfdf1