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