mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-02-28 00:22:41 -08:00
update
This commit is contained in:
@@ -78,7 +78,7 @@ exec-once = uwsm app -sb -t service -- nm-applet
|
||||
exec-once = uwsm app -sb -t service -- waybar -c ~/.config/waybar/catppuccin-macchiato/config.jsonc -s ~/.config/waybar/catppuccin-macchiato/style.css
|
||||
exec-once = uwsm app -sb -t service -- hyprsunset
|
||||
exec-once = uwsm app -sb -t service -- /usr/lib/polkit-kde-authentication-agent-1
|
||||
exec-once = uwsm app -sb -t service -- variety
|
||||
# exec-once = uwsm app -sb -t service -- variety
|
||||
exec-once = ~/.local/bin/aria
|
||||
# exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ profile-restore=copy-equal
|
||||
title=' '
|
||||
keepaspect=no
|
||||
|
||||
[immersion]
|
||||
[subminer]
|
||||
cookies=yes
|
||||
cookies-file=/truenas/sudacode/japanese/youtube-cookies.txt
|
||||
ytdl-format=bestvideo+bestaudio/best
|
||||
@@ -157,6 +157,9 @@ ytdl-raw-options-append=write-auto-subs=
|
||||
ytdl-raw-options-append=sub-langs=ja.*|en|ja-en
|
||||
ytdl-raw-options-append=cookies=/truenas/sudacode/japanese/youtube-cookies.txt
|
||||
sub-auto=fuzzy
|
||||
sid=auto
|
||||
secondary-sid=auto
|
||||
secondary-sub-visibility=no
|
||||
alang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
|
||||
slang=ja,jp,jpn,japanese,en,eng,english,English,enUS,en-US
|
||||
vlang=ja,jpn
|
||||
|
||||
@@ -1,405 +0,0 @@
|
||||
----------------------
|
||||
-- #example ytdl_preload.conf
|
||||
-- # make sure lines do not have trailing whitespace
|
||||
-- # ytdl_opt has no sanity check and should be formatted exactly how it would appear in yt-dlp CLI, they are split into a key/value pair on whitespace
|
||||
-- # at least on Windows, do not escape '\' in temp, just us a single one for each divider
|
||||
|
||||
-- #temp=R:\ytdltest
|
||||
-- #ytdl_opt1=-r 50k
|
||||
-- #ytdl_opt2=-N 5
|
||||
-- #ytdl_opt#=etc
|
||||
----------------------
|
||||
local nextIndex
|
||||
local caught = true
|
||||
-- local pop = false
|
||||
local ytdl = "yt-dlp"
|
||||
local utils = require 'mp.utils'
|
||||
|
||||
local options = require 'mp.options'
|
||||
local opts = {
|
||||
temp = "/tmp/ytdl-preload",
|
||||
ytdl_opt1 = "",
|
||||
ytdl_opt2 = "",
|
||||
ytdl_opt3 = "",
|
||||
ytdl_opt4 = "",
|
||||
ytdl_opt5 = "",
|
||||
ytdl_opt6 = "",
|
||||
ytdl_opt7 = "",
|
||||
ytdl_opt8 = "",
|
||||
ytdl_opt9 = "",
|
||||
}
|
||||
options.read_options(opts, "ytdl_preload")
|
||||
local additionalOpts = {}
|
||||
for k, v in pairs(opts) do
|
||||
if k:find("ytdl_opt%d") and v ~= "" then
|
||||
additionalOpts[k] = v
|
||||
-- print("entry")
|
||||
-- print(k .. v)
|
||||
end
|
||||
end
|
||||
local cachePath = opts.temp
|
||||
|
||||
local chapter_list = {}
|
||||
local json = ""
|
||||
local filesToDelete = {}
|
||||
|
||||
local function exists(file)
|
||||
local ok, err, code = os.rename(file, file)
|
||||
if not ok then
|
||||
if code == 13 then -- Permission denied, but it exists
|
||||
return true
|
||||
end
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
local function useNewLoadfile()
|
||||
for _, c in pairs(mp.get_property_native("command-list")) do
|
||||
if c["name"] == "loadfile" then
|
||||
for _, a in pairs(c["args"]) do
|
||||
if a["name"] == "index" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--from ytdl_hook
|
||||
local function time_to_secs(time_string)
|
||||
local ret
|
||||
local a, b, c = time_string:match("(%d+):(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 3600 + b * 60 + c)
|
||||
else
|
||||
a, b = time_string:match("(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 60 + b)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local function extract_chapters(data, video_length)
|
||||
local ret = {}
|
||||
for line in data:gmatch("[^\r\n]+") do
|
||||
local time = time_to_secs(line)
|
||||
if time and (time < video_length) then
|
||||
table.insert(ret, { time = time, title = line })
|
||||
end
|
||||
end
|
||||
table.sort(ret, function(a, b) return a.time < b.time end)
|
||||
return ret
|
||||
end
|
||||
local function chapters()
|
||||
if json.chapters then
|
||||
for i = 1, #json.chapters do
|
||||
local chapter = json.chapters[i]
|
||||
local title = chapter.title or ""
|
||||
if title == "" then
|
||||
title = string.format('Chapter %02d', i)
|
||||
end
|
||||
table.insert(chapter_list, { time = chapter.start_time, title = title })
|
||||
end
|
||||
elseif not (json.description == nil) and not (json.duration == nil) then
|
||||
chapter_list = extract_chapters(json.description, json.duration)
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
local title = ""
|
||||
local fVideo = ""
|
||||
local fAudio = ""
|
||||
local function load_files(dtitle, destination, audio, wait)
|
||||
if wait then
|
||||
if exists(destination .. ".mka") then
|
||||
print("---wait success: found mka---")
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
else
|
||||
print("---could not find mka after wait, audio may be missing---")
|
||||
end
|
||||
end
|
||||
-- if audio ~= "" then
|
||||
-- table.insert(filesToDelete, destination .. ".mka")
|
||||
-- end
|
||||
-- table.insert(filesToDelete, destination .. ".mkv")
|
||||
dtitle = dtitle:gsub("-" .. ("[%w_-]"):rep(11) .. "$", "")
|
||||
dtitle = dtitle:gsub("^" .. ("%d"):rep(10) .. "%-", "")
|
||||
if useNewLoadfile() then
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append", -1,
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no')
|
||||
else
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append",
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no') --,sub-file="..destination..".en.vtt") --in case they are not set up to autoload
|
||||
end
|
||||
mp.commandv("playlist_move", mp.get_property("playlist-count") - 1, nextIndex)
|
||||
mp.commandv("playlist_remove", nextIndex + 1)
|
||||
caught = true
|
||||
title = ""
|
||||
-- pop = true
|
||||
end
|
||||
|
||||
local listenID = ""
|
||||
local function listener(event)
|
||||
if not caught and event.prefix == mp.get_script_name() and string.find(event.text, listenID) then
|
||||
local destination = string.match(event.text, "%[download%] Destination: (.+).mkv") or
|
||||
string.match(event.text, "%[download%] (.+).mkv has already been downloaded")
|
||||
-- if destination then print("---"..cachePath) end;
|
||||
if destination and string.find(destination, string.gsub(cachePath, '~/', '')) then
|
||||
-- print(listenID)
|
||||
mp.unregister_event(listener)
|
||||
_, title = utils.split_path(destination)
|
||||
local audio = ""
|
||||
if fAudio == "" then
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
if exists(destination .. ".mka") then
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
print("---expected mka but could not find it, waiting for 2 seconds---")
|
||||
mp.add_timeout(2, function()
|
||||
load_files(title, destination, audio, true)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--from ytdl_hook
|
||||
mp.add_hook("on_preloaded", 10, function()
|
||||
if string.find(mp.get_property("path"), cachePath) then
|
||||
chapters()
|
||||
if next(chapter_list) ~= nil then
|
||||
mp.set_property_native("chapter-list", chapter_list)
|
||||
chapter_list = {}
|
||||
json = ""
|
||||
end
|
||||
end
|
||||
end)
|
||||
--end ytdl_hook
|
||||
function dump(o)
|
||||
if type(o) == 'table' then
|
||||
local s = '{ '
|
||||
for k, v in pairs(o) do
|
||||
if type(k) ~= 'number' then k = '"' .. k .. '"' end
|
||||
s = s .. '[' .. k .. '] = ' .. dump(v) .. ','
|
||||
end
|
||||
return s .. '} '
|
||||
else
|
||||
return tostring(o)
|
||||
end
|
||||
end
|
||||
|
||||
local function addOPTS(old)
|
||||
for k, v in pairs(additionalOpts) do
|
||||
-- print(k)
|
||||
if string.find(v, "%s") then
|
||||
for l, w in string.gmatch(v, "([-%w]+) (.+)") do
|
||||
table.insert(old, l)
|
||||
table.insert(old, w)
|
||||
end
|
||||
else
|
||||
table.insert(old, v)
|
||||
end
|
||||
end
|
||||
-- print(dump(old))
|
||||
return old
|
||||
end
|
||||
|
||||
local AudioDownloadHandle = {}
|
||||
local VideoDownloadHandle = {}
|
||||
local JsonDownloadHandle = {}
|
||||
local function download_files(id, success, result, error)
|
||||
if result.killed_by_us then
|
||||
return
|
||||
end
|
||||
local jfile = cachePath .. "/" .. id .. ".json"
|
||||
|
||||
local jfileIO = io.open(jfile, "w")
|
||||
jfileIO:write(result.stdout)
|
||||
jfileIO:close()
|
||||
json = utils.parse_json(result.stdout)
|
||||
-- print(dump(json))
|
||||
if json.requested_downloads[1].requested_formats ~= nil then
|
||||
local args = { ytdl, "--no-continue", "-q", "-f", fAudio, "--restrict-filenames", "--no-playlist", "--no-part",
|
||||
"-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mka", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
AudioDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
else
|
||||
fAudio = ""
|
||||
fVideo = fVideo:gsub("bestvideo", "best")
|
||||
fVideo = fVideo:gsub("bv", "best")
|
||||
end
|
||||
|
||||
local args = { ytdl, "--no-continue", "-f", fVideo .. '/best', "--restrict-filenames", "--no-playlist",
|
||||
"--no-part", "-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mkv", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
VideoDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
end
|
||||
|
||||
local function DL()
|
||||
local index = tonumber(mp.get_property("playlist-pos"))
|
||||
if mp.get_property("playlist/" .. index .. "/filename"):find("/videos$") and mp.get_property("playlist/" .. index + 1 .. "/filename"):find("/shorts$") then
|
||||
return
|
||||
end
|
||||
if tonumber(mp.get_property("playlist-pos-1")) > 0 and mp.get_property("playlist-pos-1") ~= mp.get_property("playlist-count") then
|
||||
nextIndex = index + 1
|
||||
local nextFile = mp.get_property("playlist/" .. nextIndex .. "/filename")
|
||||
if nextFile and caught and nextFile:find("://", 0, false) then
|
||||
caught = false
|
||||
mp.enable_messages("info")
|
||||
mp.register_event("log-message", listener)
|
||||
local ytFormat = mp.get_property("ytdl-format")
|
||||
fVideo = string.match(ytFormat, '(.+)%+.+//?') or 'bestvideo'
|
||||
fAudio = string.match(ytFormat, '.+%+(.+)//?') or 'bestaudio'
|
||||
-- print("start"..nextFile)
|
||||
listenID = tostring(os.time())
|
||||
local args = { ytdl, "--dump-single-json", "--no-simulate", "--skip-download",
|
||||
"--restrict-filenames",
|
||||
"--no-playlist", "--sub-lang", "en", "--write-sub", "--no-part", "-o",
|
||||
cachePath .. "/" .. listenID .. "-%(title)s-%(id)s.%(ext)s", nextFile }
|
||||
args = addOPTS(args)
|
||||
-- print(dump(args))
|
||||
table.insert(filesToDelete, listenID)
|
||||
JsonDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true,
|
||||
playback_only = false
|
||||
}, function(...)
|
||||
download_files(listenID, ...)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clearCache()
|
||||
-- print(pop)
|
||||
|
||||
--if pop == true then
|
||||
mp.abort_async_command(AudioDownloadHandle)
|
||||
mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
-- for k, v in pairs(filesToDelete) do
|
||||
-- print("remove: " .. v)
|
||||
-- os.remove(v)
|
||||
-- end
|
||||
local ftd = io.open(cachePath .. "/temp.files", "a")
|
||||
for k, v in pairs(filesToDelete) do
|
||||
ftd:write(v .. "\n")
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. v .. '*"')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. v .. "*")
|
||||
end
|
||||
end
|
||||
ftd:close()
|
||||
print('clear')
|
||||
mp.command("quit")
|
||||
--end
|
||||
end
|
||||
mp.add_hook("on_unload", 50, function()
|
||||
-- mp.abort_async_command(AudioDownloadHandle)
|
||||
-- mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
mp.unregister_event(listener)
|
||||
caught = true
|
||||
listenID = "resetYtdlPreloadListener"
|
||||
-- print(listenID)
|
||||
end)
|
||||
|
||||
local skipInitial
|
||||
mp.observe_property("playlist-count", "number", function()
|
||||
if skipInitial then
|
||||
DL()
|
||||
else
|
||||
skipInitial = true
|
||||
end
|
||||
end)
|
||||
|
||||
--from ytdl_hook
|
||||
local platform_is_windows = (package.config:sub(1, 1) == "\\")
|
||||
local o = {
|
||||
exclude = "",
|
||||
try_ytdl_first = false,
|
||||
use_manifests = false,
|
||||
all_formats = false,
|
||||
force_all_formats = true,
|
||||
ytdl_path = "",
|
||||
}
|
||||
local paths_to_search = { "yt-dlp", "yt-dlp_x86", "youtube-dl" }
|
||||
--local options = require 'mp.options'
|
||||
options.read_options(o, "ytdl_hook")
|
||||
|
||||
local separator = platform_is_windows and ";" or ":"
|
||||
if o.ytdl_path:match("[^" .. separator .. "]") then
|
||||
paths_to_search = {}
|
||||
for path in o.ytdl_path:gmatch("[^" .. separator .. "]+") do
|
||||
table.insert(paths_to_search, path)
|
||||
end
|
||||
end
|
||||
|
||||
local function exec(args)
|
||||
local ret = mp.command_native({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true
|
||||
})
|
||||
return ret.status, ret.stdout, ret, ret.killed_by_us
|
||||
end
|
||||
|
||||
local msg = require 'mp.msg'
|
||||
local command = {}
|
||||
for _, path in pairs(paths_to_search) do
|
||||
-- search for youtube-dl in mpv's config dir
|
||||
local exesuf = platform_is_windows and ".exe" or ""
|
||||
local ytdl_cmd = mp.find_config_file(path .. exesuf)
|
||||
if ytdl_cmd then
|
||||
msg.verbose("Found youtube-dl at: " .. ytdl_cmd)
|
||||
ytdl = ytdl_cmd
|
||||
break
|
||||
else
|
||||
msg.verbose("No youtube-dl found with path " .. path .. exesuf .. " in config directories")
|
||||
--search in PATH
|
||||
command[1] = path
|
||||
es, json, result, aborted = exec(command)
|
||||
if result.error_string == "init" then
|
||||
msg.verbose("youtube-dl with path " .. path .. exesuf .. " not found in PATH or not enough permissions")
|
||||
else
|
||||
msg.verbose("Found youtube-dl with path " .. path .. exesuf .. " in PATH")
|
||||
ytdl = path
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
|
||||
mp.register_event("start-file", DL)
|
||||
mp.register_event("shutdown", clearCache)
|
||||
local ftd = io.open(cachePath .. "/temp.files", "r")
|
||||
while ftd ~= nil do
|
||||
local line = ftd:read()
|
||||
if line == nil or line == "" then
|
||||
ftd:close()
|
||||
io.open(cachePath .. "/temp.files", "w"):close()
|
||||
break
|
||||
end
|
||||
-- print("DEL::"..line)
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. line .. '*" >nul 2>nul')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. line .. "* &> /dev/null")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
1
.config/mpv/scripts/ytdl-preload.lua
Symbolic link
1
.config/mpv/scripts/ytdl-preload.lua
Symbolic link
@@ -0,0 +1 @@
|
||||
ytdl-preload.lua##os.Linux
|
||||
@@ -1,405 +0,0 @@
|
||||
----------------------
|
||||
-- #example ytdl_preload.conf
|
||||
-- # make sure lines do not have trailing whitespace
|
||||
-- # ytdl_opt has no sanity check and should be formatted exactly how it would appear in yt-dlp CLI, they are split into a key/value pair on whitespace
|
||||
-- # at least on Windows, do not escape '\' in temp, just us a single one for each divider
|
||||
|
||||
-- #temp=R:\ytdltest
|
||||
-- #ytdl_opt1=-r 50k
|
||||
-- #ytdl_opt2=-N 5
|
||||
-- #ytdl_opt#=etc
|
||||
----------------------
|
||||
local nextIndex
|
||||
local caught = true
|
||||
-- local pop = false
|
||||
local ytdl = "yt-dlp"
|
||||
local utils = require 'mp.utils'
|
||||
|
||||
local options = require 'mp.options'
|
||||
local opts = {
|
||||
temp = "/tmp/ytdl-preload",
|
||||
ytdl_opt1 = "",
|
||||
ytdl_opt2 = "",
|
||||
ytdl_opt3 = "",
|
||||
ytdl_opt4 = "",
|
||||
ytdl_opt5 = "",
|
||||
ytdl_opt6 = "",
|
||||
ytdl_opt7 = "",
|
||||
ytdl_opt8 = "",
|
||||
ytdl_opt9 = "",
|
||||
}
|
||||
options.read_options(opts, "ytdl_preload")
|
||||
local additionalOpts = {}
|
||||
for k, v in pairs(opts) do
|
||||
if k:find("ytdl_opt%d") and v ~= "" then
|
||||
additionalOpts[k] = v
|
||||
-- print("entry")
|
||||
-- print(k .. v)
|
||||
end
|
||||
end
|
||||
local cachePath = opts.temp
|
||||
|
||||
local chapter_list = {}
|
||||
local json = ""
|
||||
local filesToDelete = {}
|
||||
|
||||
local function exists(file)
|
||||
local ok, err, code = os.rename(file, file)
|
||||
if not ok then
|
||||
if code == 13 then -- Permission denied, but it exists
|
||||
return true
|
||||
end
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
local function useNewLoadfile()
|
||||
for _, c in pairs(mp.get_property_native("command-list")) do
|
||||
if c["name"] == "loadfile" then
|
||||
for _, a in pairs(c["args"]) do
|
||||
if a["name"] == "index" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--from ytdl_hook
|
||||
local function time_to_secs(time_string)
|
||||
local ret
|
||||
local a, b, c = time_string:match("(%d+):(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 3600 + b * 60 + c)
|
||||
else
|
||||
a, b = time_string:match("(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 60 + b)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local function extract_chapters(data, video_length)
|
||||
local ret = {}
|
||||
for line in data:gmatch("[^\r\n]+") do
|
||||
local time = time_to_secs(line)
|
||||
if time and (time < video_length) then
|
||||
table.insert(ret, { time = time, title = line })
|
||||
end
|
||||
end
|
||||
table.sort(ret, function(a, b) return a.time < b.time end)
|
||||
return ret
|
||||
end
|
||||
local function chapters()
|
||||
if json.chapters then
|
||||
for i = 1, #json.chapters do
|
||||
local chapter = json.chapters[i]
|
||||
local title = chapter.title or ""
|
||||
if title == "" then
|
||||
title = string.format('Chapter %02d', i)
|
||||
end
|
||||
table.insert(chapter_list, { time = chapter.start_time, title = title })
|
||||
end
|
||||
elseif not (json.description == nil) and not (json.duration == nil) then
|
||||
chapter_list = extract_chapters(json.description, json.duration)
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
local title = ""
|
||||
local fVideo = ""
|
||||
local fAudio = ""
|
||||
local function load_files(dtitle, destination, audio, wait)
|
||||
if wait then
|
||||
if exists(destination .. ".mka") then
|
||||
print("---wait success: found mka---")
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
else
|
||||
print("---could not find mka after wait, audio may be missing---")
|
||||
end
|
||||
end
|
||||
-- if audio ~= "" then
|
||||
-- table.insert(filesToDelete, destination .. ".mka")
|
||||
-- end
|
||||
-- table.insert(filesToDelete, destination .. ".mkv")
|
||||
dtitle = dtitle:gsub("-" .. ("[%w_-]"):rep(11) .. "$", "")
|
||||
dtitle = dtitle:gsub("^" .. ("%d"):rep(10) .. "%-", "")
|
||||
if useNewLoadfile() then
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append", -1,
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no')
|
||||
else
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append",
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no') --,sub-file="..destination..".en.vtt") --in case they are not set up to autoload
|
||||
end
|
||||
mp.commandv("playlist_move", mp.get_property("playlist-count") - 1, nextIndex)
|
||||
mp.commandv("playlist_remove", nextIndex + 1)
|
||||
caught = true
|
||||
title = ""
|
||||
-- pop = true
|
||||
end
|
||||
|
||||
local listenID = ""
|
||||
local function listener(event)
|
||||
if not caught and event.prefix == mp.get_script_name() and string.find(event.text, listenID) then
|
||||
local destination = string.match(event.text, "%[download%] Destination: (.+).mkv") or
|
||||
string.match(event.text, "%[download%] (.+).mkv has already been downloaded")
|
||||
-- if destination then print("---"..cachePath) end;
|
||||
if destination and string.find(destination, string.gsub(cachePath, '~/', '')) then
|
||||
-- print(listenID)
|
||||
mp.unregister_event(listener)
|
||||
_, title = utils.split_path(destination)
|
||||
local audio = ""
|
||||
if fAudio == "" then
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
if exists(destination .. ".mka") then
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
print("---expected mka but could not find it, waiting for 2 seconds---")
|
||||
mp.add_timeout(2, function()
|
||||
load_files(title, destination, audio, true)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--from ytdl_hook
|
||||
mp.add_hook("on_preloaded", 10, function()
|
||||
if string.find(mp.get_property("path"), cachePath) then
|
||||
chapters()
|
||||
if next(chapter_list) ~= nil then
|
||||
mp.set_property_native("chapter-list", chapter_list)
|
||||
chapter_list = {}
|
||||
json = ""
|
||||
end
|
||||
end
|
||||
end)
|
||||
--end ytdl_hook
|
||||
function dump(o)
|
||||
if type(o) == 'table' then
|
||||
local s = '{ '
|
||||
for k, v in pairs(o) do
|
||||
if type(k) ~= 'number' then k = '"' .. k .. '"' end
|
||||
s = s .. '[' .. k .. '] = ' .. dump(v) .. ','
|
||||
end
|
||||
return s .. '} '
|
||||
else
|
||||
return tostring(o)
|
||||
end
|
||||
end
|
||||
|
||||
local function addOPTS(old)
|
||||
for k, v in pairs(additionalOpts) do
|
||||
-- print(k)
|
||||
if string.find(v, "%s") then
|
||||
for l, w in string.gmatch(v, "([-%w]+) (.+)") do
|
||||
table.insert(old, l)
|
||||
table.insert(old, w)
|
||||
end
|
||||
else
|
||||
table.insert(old, v)
|
||||
end
|
||||
end
|
||||
-- print(dump(old))
|
||||
return old
|
||||
end
|
||||
|
||||
local AudioDownloadHandle = {}
|
||||
local VideoDownloadHandle = {}
|
||||
local JsonDownloadHandle = {}
|
||||
local function download_files(id, success, result, error)
|
||||
if result.killed_by_us then
|
||||
return
|
||||
end
|
||||
local jfile = cachePath .. "/" .. id .. ".json"
|
||||
|
||||
local jfileIO = io.open(jfile, "w")
|
||||
jfileIO:write(result.stdout)
|
||||
jfileIO:close()
|
||||
json = utils.parse_json(result.stdout)
|
||||
-- print(dump(json))
|
||||
if json.requested_downloads[1].requested_formats ~= nil then
|
||||
local args = { ytdl, "--no-continue", "-q", "-f", fAudio, "--restrict-filenames", "--no-playlist", "--no-part",
|
||||
"-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mka", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
AudioDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
else
|
||||
fAudio = ""
|
||||
fVideo = fVideo:gsub("bestvideo", "best")
|
||||
fVideo = fVideo:gsub("bv", "best")
|
||||
end
|
||||
|
||||
local args = { ytdl, "--no-continue", "-f", fVideo .. '/best', "--restrict-filenames", "--no-playlist",
|
||||
"--no-part", "-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mkv", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
VideoDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
end
|
||||
|
||||
local function DL()
|
||||
local index = tonumber(mp.get_property("playlist-pos"))
|
||||
if mp.get_property("playlist/" .. index .. "/filename"):find("/videos$") and mp.get_property("playlist/" .. index + 1 .. "/filename"):find("/shorts$") then
|
||||
return
|
||||
end
|
||||
if tonumber(mp.get_property("playlist-pos-1")) > 0 and mp.get_property("playlist-pos-1") ~= mp.get_property("playlist-count") then
|
||||
nextIndex = index + 1
|
||||
local nextFile = mp.get_property("playlist/" .. nextIndex .. "/filename")
|
||||
if nextFile and caught and nextFile:find("://", 0, false) then
|
||||
caught = false
|
||||
mp.enable_messages("info")
|
||||
mp.register_event("log-message", listener)
|
||||
local ytFormat = mp.get_property("ytdl-format")
|
||||
fVideo = string.match(ytFormat, '(.+)%+.+//?') or 'bestvideo'
|
||||
fAudio = string.match(ytFormat, '.+%+(.+)//?') or 'bestaudio'
|
||||
-- print("start"..nextFile)
|
||||
listenID = tostring(os.time())
|
||||
local args = { ytdl, "--dump-single-json", "--no-simulate", "--skip-download",
|
||||
"--restrict-filenames",
|
||||
"--no-playlist", "--sub-lang", "en", "--write-sub", "--no-part", "-o",
|
||||
cachePath .. "/" .. listenID .. "-%(title)s-%(id)s.%(ext)s", nextFile }
|
||||
args = addOPTS(args)
|
||||
-- print(dump(args))
|
||||
table.insert(filesToDelete, listenID)
|
||||
JsonDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true,
|
||||
playback_only = false
|
||||
}, function(...)
|
||||
download_files(listenID, ...)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clearCache()
|
||||
-- print(pop)
|
||||
|
||||
--if pop == true then
|
||||
mp.abort_async_command(AudioDownloadHandle)
|
||||
mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
-- for k, v in pairs(filesToDelete) do
|
||||
-- print("remove: " .. v)
|
||||
-- os.remove(v)
|
||||
-- end
|
||||
local ftd = io.open(cachePath .. "/temp.files", "a")
|
||||
for k, v in pairs(filesToDelete) do
|
||||
ftd:write(v .. "\n")
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. v .. '*"')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. v .. "*")
|
||||
end
|
||||
end
|
||||
ftd:close()
|
||||
print('clear')
|
||||
mp.command("quit")
|
||||
--end
|
||||
end
|
||||
mp.add_hook("on_unload", 50, function()
|
||||
-- mp.abort_async_command(AudioDownloadHandle)
|
||||
-- mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
mp.unregister_event(listener)
|
||||
caught = true
|
||||
listenID = "resetYtdlPreloadListener"
|
||||
-- print(listenID)
|
||||
end)
|
||||
|
||||
local skipInitial
|
||||
mp.observe_property("playlist-count", "number", function()
|
||||
if skipInitial then
|
||||
DL()
|
||||
else
|
||||
skipInitial = true
|
||||
end
|
||||
end)
|
||||
|
||||
--from ytdl_hook
|
||||
local platform_is_windows = (package.config:sub(1, 1) == "\\")
|
||||
local o = {
|
||||
exclude = "",
|
||||
try_ytdl_first = false,
|
||||
use_manifests = false,
|
||||
all_formats = false,
|
||||
force_all_formats = true,
|
||||
ytdl_path = "",
|
||||
}
|
||||
local paths_to_search = { "yt-dlp", "yt-dlp_x86", "youtube-dl" }
|
||||
--local options = require 'mp.options'
|
||||
options.read_options(o, "ytdl_hook")
|
||||
|
||||
local separator = platform_is_windows and ";" or ":"
|
||||
if o.ytdl_path:match("[^" .. separator .. "]") then
|
||||
paths_to_search = {}
|
||||
for path in o.ytdl_path:gmatch("[^" .. separator .. "]+") do
|
||||
table.insert(paths_to_search, path)
|
||||
end
|
||||
end
|
||||
|
||||
local function exec(args)
|
||||
local ret = mp.command_native({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true
|
||||
})
|
||||
return ret.status, ret.stdout, ret, ret.killed_by_us
|
||||
end
|
||||
|
||||
local msg = require 'mp.msg'
|
||||
local command = {}
|
||||
for _, path in pairs(paths_to_search) do
|
||||
-- search for youtube-dl in mpv's config dir
|
||||
local exesuf = platform_is_windows and ".exe" or ""
|
||||
local ytdl_cmd = mp.find_config_file(path .. exesuf)
|
||||
if ytdl_cmd then
|
||||
msg.verbose("Found youtube-dl at: " .. ytdl_cmd)
|
||||
ytdl = ytdl_cmd
|
||||
break
|
||||
else
|
||||
msg.verbose("No youtube-dl found with path " .. path .. exesuf .. " in config directories")
|
||||
--search in PATH
|
||||
command[1] = path
|
||||
es, json, result, aborted = exec(command)
|
||||
if result.error_string == "init" then
|
||||
msg.verbose("youtube-dl with path " .. path .. exesuf .. " not found in PATH or not enough permissions")
|
||||
else
|
||||
msg.verbose("Found youtube-dl with path " .. path .. exesuf .. " in PATH")
|
||||
ytdl = path
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
|
||||
mp.register_event("start-file", DL)
|
||||
mp.register_event("shutdown", clearCache)
|
||||
local ftd = io.open(cachePath .. "/temp.files", "r")
|
||||
while ftd ~= nil do
|
||||
local line = ftd:read()
|
||||
if line == nil or line == "" then
|
||||
ftd:close()
|
||||
io.open(cachePath .. "/temp.files", "w"):close()
|
||||
break
|
||||
end
|
||||
-- print("DEL::"..line)
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. line .. '*" >nul 2>nul')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. line .. "* &> /dev/null")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,405 +0,0 @@
|
||||
----------------------
|
||||
-- #example ytdl_preload.conf
|
||||
-- # make sure lines do not have trailing whitespace
|
||||
-- # ytdl_opt has no sanity check and should be formatted exactly how it would appear in yt-dlp CLI, they are split into a key/value pair on whitespace
|
||||
-- # at least on Windows, do not escape '\' in temp, just us a single one for each divider
|
||||
|
||||
-- #temp=R:\ytdltest
|
||||
-- #ytdl_opt1=-r 50k
|
||||
-- #ytdl_opt2=-N 5
|
||||
-- #ytdl_opt#=etc
|
||||
----------------------
|
||||
local nextIndex
|
||||
local caught = true
|
||||
-- local pop = false
|
||||
local ytdl = "yt-dlp"
|
||||
local utils = require 'mp.utils'
|
||||
|
||||
local options = require 'mp.options'
|
||||
local opts = {
|
||||
temp = "/tmp/ytdl-preload",
|
||||
ytdl_opt1 = "",
|
||||
ytdl_opt2 = "",
|
||||
ytdl_opt3 = "",
|
||||
ytdl_opt4 = "",
|
||||
ytdl_opt5 = "",
|
||||
ytdl_opt6 = "",
|
||||
ytdl_opt7 = "",
|
||||
ytdl_opt8 = "",
|
||||
ytdl_opt9 = "",
|
||||
}
|
||||
options.read_options(opts, "ytdl_preload")
|
||||
local additionalOpts = {}
|
||||
for k, v in pairs(opts) do
|
||||
if k:find("ytdl_opt%d") and v ~= "" then
|
||||
additionalOpts[k] = v
|
||||
-- print("entry")
|
||||
-- print(k .. v)
|
||||
end
|
||||
end
|
||||
local cachePath = opts.temp
|
||||
|
||||
local chapter_list = {}
|
||||
local json = ""
|
||||
local filesToDelete = {}
|
||||
|
||||
local function exists(file)
|
||||
local ok, err, code = os.rename(file, file)
|
||||
if not ok then
|
||||
if code == 13 then -- Permission denied, but it exists
|
||||
return true
|
||||
end
|
||||
end
|
||||
return ok, err
|
||||
end
|
||||
local function useNewLoadfile()
|
||||
for _, c in pairs(mp.get_property_native("command-list")) do
|
||||
if c["name"] == "loadfile" then
|
||||
for _, a in pairs(c["args"]) do
|
||||
if a["name"] == "index" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--from ytdl_hook
|
||||
local function time_to_secs(time_string)
|
||||
local ret
|
||||
local a, b, c = time_string:match("(%d+):(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 3600 + b * 60 + c)
|
||||
else
|
||||
a, b = time_string:match("(%d%d?):(%d%d)")
|
||||
if a ~= nil then
|
||||
ret = (a * 60 + b)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local function extract_chapters(data, video_length)
|
||||
local ret = {}
|
||||
for line in data:gmatch("[^\r\n]+") do
|
||||
local time = time_to_secs(line)
|
||||
if time and (time < video_length) then
|
||||
table.insert(ret, { time = time, title = line })
|
||||
end
|
||||
end
|
||||
table.sort(ret, function(a, b) return a.time < b.time end)
|
||||
return ret
|
||||
end
|
||||
local function chapters()
|
||||
if json.chapters then
|
||||
for i = 1, #json.chapters do
|
||||
local chapter = json.chapters[i]
|
||||
local title = chapter.title or ""
|
||||
if title == "" then
|
||||
title = string.format('Chapter %02d', i)
|
||||
end
|
||||
table.insert(chapter_list, { time = chapter.start_time, title = title })
|
||||
end
|
||||
elseif not (json.description == nil) and not (json.duration == nil) then
|
||||
chapter_list = extract_chapters(json.description, json.duration)
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
local title = ""
|
||||
local fVideo = ""
|
||||
local fAudio = ""
|
||||
local function load_files(dtitle, destination, audio, wait)
|
||||
if wait then
|
||||
if exists(destination .. ".mka") then
|
||||
print("---wait success: found mka---")
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
else
|
||||
print("---could not find mka after wait, audio may be missing---")
|
||||
end
|
||||
end
|
||||
-- if audio ~= "" then
|
||||
-- table.insert(filesToDelete, destination .. ".mka")
|
||||
-- end
|
||||
-- table.insert(filesToDelete, destination .. ".mkv")
|
||||
dtitle = dtitle:gsub("-" .. ("[%w_-]"):rep(11) .. "$", "")
|
||||
dtitle = dtitle:gsub("^" .. ("%d"):rep(10) .. "%-", "")
|
||||
if useNewLoadfile() then
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append", -1,
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no')
|
||||
else
|
||||
mp.commandv("loadfile", destination .. ".mkv", "append",
|
||||
audio .. 'force-media-title="' .. dtitle .. '",demuxer-max-back-bytes=1MiB,demuxer-max-bytes=3MiB,ytdl=no') --,sub-file="..destination..".en.vtt") --in case they are not set up to autoload
|
||||
end
|
||||
mp.commandv("playlist_move", mp.get_property("playlist-count") - 1, nextIndex)
|
||||
mp.commandv("playlist_remove", nextIndex + 1)
|
||||
caught = true
|
||||
title = ""
|
||||
-- pop = true
|
||||
end
|
||||
|
||||
local listenID = ""
|
||||
local function listener(event)
|
||||
if not caught and event.prefix == mp.get_script_name() and string.find(event.text, listenID) then
|
||||
local destination = string.match(event.text, "%[download%] Destination: (.+).mkv") or
|
||||
string.match(event.text, "%[download%] (.+).mkv has already been downloaded")
|
||||
-- if destination then print("---"..cachePath) end;
|
||||
if destination and string.find(destination, string.gsub(cachePath, '~/', '')) then
|
||||
-- print(listenID)
|
||||
mp.unregister_event(listener)
|
||||
_, title = utils.split_path(destination)
|
||||
local audio = ""
|
||||
if fAudio == "" then
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
if exists(destination .. ".mka") then
|
||||
audio = "audio-file=" .. destination .. '.mka,'
|
||||
load_files(title, destination, audio, false)
|
||||
else
|
||||
print("---expected mka but could not find it, waiting for 2 seconds---")
|
||||
mp.add_timeout(2, function()
|
||||
load_files(title, destination, audio, true)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--from ytdl_hook
|
||||
mp.add_hook("on_preloaded", 10, function()
|
||||
if string.find(mp.get_property("path"), cachePath) then
|
||||
chapters()
|
||||
if next(chapter_list) ~= nil then
|
||||
mp.set_property_native("chapter-list", chapter_list)
|
||||
chapter_list = {}
|
||||
json = ""
|
||||
end
|
||||
end
|
||||
end)
|
||||
--end ytdl_hook
|
||||
function dump(o)
|
||||
if type(o) == 'table' then
|
||||
local s = '{ '
|
||||
for k, v in pairs(o) do
|
||||
if type(k) ~= 'number' then k = '"' .. k .. '"' end
|
||||
s = s .. '[' .. k .. '] = ' .. dump(v) .. ','
|
||||
end
|
||||
return s .. '} '
|
||||
else
|
||||
return tostring(o)
|
||||
end
|
||||
end
|
||||
|
||||
local function addOPTS(old)
|
||||
for k, v in pairs(additionalOpts) do
|
||||
-- print(k)
|
||||
if string.find(v, "%s") then
|
||||
for l, w in string.gmatch(v, "([-%w]+) (.+)") do
|
||||
table.insert(old, l)
|
||||
table.insert(old, w)
|
||||
end
|
||||
else
|
||||
table.insert(old, v)
|
||||
end
|
||||
end
|
||||
-- print(dump(old))
|
||||
return old
|
||||
end
|
||||
|
||||
local AudioDownloadHandle = {}
|
||||
local VideoDownloadHandle = {}
|
||||
local JsonDownloadHandle = {}
|
||||
local function download_files(id, success, result, error)
|
||||
if result.killed_by_us then
|
||||
return
|
||||
end
|
||||
local jfile = cachePath .. "/" .. id .. ".json"
|
||||
|
||||
local jfileIO = io.open(jfile, "w")
|
||||
jfileIO:write(result.stdout)
|
||||
jfileIO:close()
|
||||
json = utils.parse_json(result.stdout)
|
||||
-- print(dump(json))
|
||||
if json.requested_downloads[1].requested_formats ~= nil then
|
||||
local args = { ytdl, "--no-continue", "-q", "-f", fAudio, "--restrict-filenames", "--no-playlist", "--no-part",
|
||||
"-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mka", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
AudioDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
else
|
||||
fAudio = ""
|
||||
fVideo = fVideo:gsub("bestvideo", "best")
|
||||
fVideo = fVideo:gsub("bv", "best")
|
||||
end
|
||||
|
||||
local args = { ytdl, "--no-continue", "-f", fVideo .. '/best', "--restrict-filenames", "--no-playlist",
|
||||
"--no-part", "-o", cachePath .. "/" .. id .. "-%(title)s-%(id)s.mkv", "--load-info-json", jfile }
|
||||
args = addOPTS(args)
|
||||
VideoDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
playback_only = false
|
||||
}, function()
|
||||
end)
|
||||
end
|
||||
|
||||
local function DL()
|
||||
local index = tonumber(mp.get_property("playlist-pos"))
|
||||
if mp.get_property("playlist/" .. index .. "/filename"):find("/videos$") and mp.get_property("playlist/" .. index + 1 .. "/filename"):find("/shorts$") then
|
||||
return
|
||||
end
|
||||
if tonumber(mp.get_property("playlist-pos-1")) > 0 and mp.get_property("playlist-pos-1") ~= mp.get_property("playlist-count") then
|
||||
nextIndex = index + 1
|
||||
local nextFile = mp.get_property("playlist/" .. nextIndex .. "/filename")
|
||||
if nextFile and caught and nextFile:find("://", 0, false) then
|
||||
caught = false
|
||||
mp.enable_messages("info")
|
||||
mp.register_event("log-message", listener)
|
||||
local ytFormat = mp.get_property("ytdl-format")
|
||||
fVideo = string.match(ytFormat, '(.+)%+.+//?') or 'bestvideo'
|
||||
fAudio = string.match(ytFormat, '.+%+(.+)//?') or 'bestaudio'
|
||||
-- print("start"..nextFile)
|
||||
listenID = tostring(os.time())
|
||||
local args = { ytdl, "--dump-single-json", "--no-simulate", "--skip-download",
|
||||
"--restrict-filenames",
|
||||
"--no-playlist", "--sub-lang", "en", "--write-sub", "--no-part", "-o",
|
||||
cachePath .. "/" .. listenID .. "-%(title)s-%(id)s.%(ext)s", nextFile }
|
||||
args = addOPTS(args)
|
||||
-- print(dump(args))
|
||||
table.insert(filesToDelete, listenID)
|
||||
JsonDownloadHandle = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true,
|
||||
playback_only = false
|
||||
}, function(...)
|
||||
download_files(listenID, ...)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function clearCache()
|
||||
-- print(pop)
|
||||
|
||||
--if pop == true then
|
||||
mp.abort_async_command(AudioDownloadHandle)
|
||||
mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
-- for k, v in pairs(filesToDelete) do
|
||||
-- print("remove: " .. v)
|
||||
-- os.remove(v)
|
||||
-- end
|
||||
local ftd = io.open(cachePath .. "/temp.files", "a")
|
||||
for k, v in pairs(filesToDelete) do
|
||||
ftd:write(v .. "\n")
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. v .. '*"')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. v .. "*")
|
||||
end
|
||||
end
|
||||
ftd:close()
|
||||
print('clear')
|
||||
mp.command("quit")
|
||||
--end
|
||||
end
|
||||
mp.add_hook("on_unload", 50, function()
|
||||
-- mp.abort_async_command(AudioDownloadHandle)
|
||||
-- mp.abort_async_command(VideoDownloadHandle)
|
||||
mp.abort_async_command(JsonDownloadHandle)
|
||||
mp.unregister_event(listener)
|
||||
caught = true
|
||||
listenID = "resetYtdlPreloadListener"
|
||||
-- print(listenID)
|
||||
end)
|
||||
|
||||
local skipInitial
|
||||
mp.observe_property("playlist-count", "number", function()
|
||||
if skipInitial then
|
||||
DL()
|
||||
else
|
||||
skipInitial = true
|
||||
end
|
||||
end)
|
||||
|
||||
--from ytdl_hook
|
||||
local platform_is_windows = (package.config:sub(1, 1) == "\\")
|
||||
local o = {
|
||||
exclude = "",
|
||||
try_ytdl_first = false,
|
||||
use_manifests = false,
|
||||
all_formats = false,
|
||||
force_all_formats = true,
|
||||
ytdl_path = "",
|
||||
}
|
||||
local paths_to_search = { "yt-dlp", "yt-dlp_x86", "youtube-dl" }
|
||||
--local options = require 'mp.options'
|
||||
options.read_options(o, "ytdl_hook")
|
||||
|
||||
local separator = platform_is_windows and ";" or ":"
|
||||
if o.ytdl_path:match("[^" .. separator .. "]") then
|
||||
paths_to_search = {}
|
||||
for path in o.ytdl_path:gmatch("[^" .. separator .. "]+") do
|
||||
table.insert(paths_to_search, path)
|
||||
end
|
||||
end
|
||||
|
||||
local function exec(args)
|
||||
local ret = mp.command_native({
|
||||
name = "subprocess",
|
||||
args = args,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true
|
||||
})
|
||||
return ret.status, ret.stdout, ret, ret.killed_by_us
|
||||
end
|
||||
|
||||
local msg = require 'mp.msg'
|
||||
local command = {}
|
||||
for _, path in pairs(paths_to_search) do
|
||||
-- search for youtube-dl in mpv's config dir
|
||||
local exesuf = platform_is_windows and ".exe" or ""
|
||||
local ytdl_cmd = mp.find_config_file(path .. exesuf)
|
||||
if ytdl_cmd then
|
||||
msg.verbose("Found youtube-dl at: " .. ytdl_cmd)
|
||||
ytdl = ytdl_cmd
|
||||
break
|
||||
else
|
||||
msg.verbose("No youtube-dl found with path " .. path .. exesuf .. " in config directories")
|
||||
--search in PATH
|
||||
command[1] = path
|
||||
es, json, result, aborted = exec(command)
|
||||
if result.error_string == "init" then
|
||||
msg.verbose("youtube-dl with path " .. path .. exesuf .. " not found in PATH or not enough permissions")
|
||||
else
|
||||
msg.verbose("Found youtube-dl with path " .. path .. exesuf .. " in PATH")
|
||||
ytdl = path
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
--end ytdl_hook
|
||||
|
||||
mp.register_event("start-file", DL)
|
||||
mp.register_event("shutdown", clearCache)
|
||||
local ftd = io.open(cachePath .. "/temp.files", "r")
|
||||
while ftd ~= nil do
|
||||
local line = ftd:read()
|
||||
if line == nil or line == "" then
|
||||
ftd:close()
|
||||
io.open(cachePath .. "/temp.files", "w"):close()
|
||||
break
|
||||
end
|
||||
-- print("DEL::"..line)
|
||||
if package.config:sub(1, 1) ~= '/' then
|
||||
os.execute('del /Q /F "' .. cachePath .. "\\" .. line .. '*" >nul 2>nul')
|
||||
else
|
||||
os.execute('rm -f ' .. cachePath .. "/" .. line .. "* &> /dev/null")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"keybindings": [],
|
||||
"auto_start_overlay": false,
|
||||
"texthooker": {
|
||||
"openBrowser": false,
|
||||
},
|
||||
"websocket": {
|
||||
"enabled": "auto",
|
||||
"port": 6677,
|
||||
},
|
||||
"ankiConnect": {
|
||||
"enabled": true,
|
||||
"url": "http://127.0.0.1:8765",
|
||||
"pollingRate": 500,
|
||||
"fields": {
|
||||
"audio": "ExpressionAudio",
|
||||
"image": "Picture",
|
||||
"sentence": "Sentence",
|
||||
"miscInfo": "MiscInfo",
|
||||
"translation": "SelectionText",
|
||||
},
|
||||
"openRouter": {
|
||||
"enabled": true,
|
||||
"alwaysUseAiTranslation": true,
|
||||
"apiKey": "",
|
||||
"model": "openai/gpt-oss-120b:free",
|
||||
"baseUrl": "https://openrouter.ai/api/v1",
|
||||
"sourceLanguage": "Japanese",
|
||||
"systemPrompt": "You are a translation engine for translating Japanese into natural-sounding, context-aware English. Return only the translated text with no extra explanations or commentary. The translation must preserve the original tone and intent of the source. If the input is not in the target language, translate it to the target language. If the input is already in the target language, return it as is.",
|
||||
},
|
||||
"media": {
|
||||
"generateAudio": true,
|
||||
"generateImage": true,
|
||||
"imageType": "avif",
|
||||
"imageFormat": "webp",
|
||||
"animatedFps": 24,
|
||||
"animatedMaxWidth": 640,
|
||||
"animatedMaxHeight": null,
|
||||
"animatedCrf": 35,
|
||||
"audioPadding": 0.5,
|
||||
"fallbackDuration": 3,
|
||||
},
|
||||
"behavior": {
|
||||
"overwriteAudio": false,
|
||||
"overwriteImage": true,
|
||||
"mediaInsertMode": "append",
|
||||
"highlightWord": true,
|
||||
"notificationType": "system",
|
||||
"showNotificationOnUpdate": true,
|
||||
"autoUpdateNewCards": false,
|
||||
},
|
||||
"metadata": {
|
||||
"pattern": "[SubMiner] %f (%t)",
|
||||
},
|
||||
"isLapis": {
|
||||
"enabled": true,
|
||||
"sentenceCardModel": "Lapis Morph",
|
||||
"sentenceCardSentenceField": "Sentence",
|
||||
"sentenceCardAudioField": "SentenceAudio",
|
||||
},
|
||||
"isKiku": {
|
||||
"enabled": true,
|
||||
"fieldGrouping": "manual",
|
||||
"deleteDuplicateInAuto": true,
|
||||
},
|
||||
},
|
||||
"subtitles": {
|
||||
"primarySubLanguages": ["ja", "jpn"],
|
||||
"secondarySubLanguages": ["en", "eng"],
|
||||
"autoLoadSecondarySub": true,
|
||||
"defaultMode": "hover",
|
||||
"style": {
|
||||
"fontFamily": "Noto Sans CJK JP Regular, Noto Sans CJK JP, Arial Unicode MS, Arial, sans-serif",
|
||||
"fontSize": 35,
|
||||
"fontColor": "#cad3f5",
|
||||
"fontWeight": "normal",
|
||||
"fontStyle": "normal",
|
||||
"backgroundColor": "rgba(54, 58, 79, 0.69)",
|
||||
"secondary": {
|
||||
"fontSize": 24,
|
||||
"fontColor": "#ffffff",
|
||||
"backgroundColor": "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
"subsync": {
|
||||
"defaultMode": "manual",
|
||||
"alass_path": "/Users/sudacode/.local/bin/alass-cli",
|
||||
"ffsubsync_path": "/Users/sudacode/.local/bin/ffsubsync",
|
||||
"ffmpeg_path": "/opt/homebrew/bin/ffmpeg",
|
||||
},
|
||||
"subtitleStyle": {
|
||||
"fontFamily": "Noto Sans CJK JP Regular, Noto Sans CJK JP, Arial Unicode MS, Arial, sans-serif",
|
||||
"fontSize": 24,
|
||||
"fontColor": "#cad3f5",
|
||||
"fontWeight": "normal",
|
||||
"fontStyle": "normal",
|
||||
"backgroundColor": "rgb(30, 32, 48, 0.88)",
|
||||
"secondary": {
|
||||
"fontSize": 24,
|
||||
"fontColor": "#cad3f5",
|
||||
"backgroundColor": "transparent",
|
||||
},
|
||||
},
|
||||
"jimaku": {
|
||||
// "apiKey": "YOUR_API_KEY",
|
||||
// or use a command that outputs the key:
|
||||
"apiKeyCommand": "cat ~/.jimaku-api-key",
|
||||
"apiBaseUrl": "https://jimaku.cc",
|
||||
"languagePreference": "ja",
|
||||
"maxEntryResults": 10,
|
||||
},
|
||||
"shortcuts": {
|
||||
"copySubtitle": "CommandOrControl+C",
|
||||
"copySubtitleMultiple": "CommandOrControl+Shift+C",
|
||||
"updateLastCardFromClipboard": "CommandOrControl+V",
|
||||
"triggerFieldGrouping": "CommandOrControl+G",
|
||||
"triggerSubsync": "CommandOrControl+Alt+S",
|
||||
"mineSentence": "CommandOrControl+S",
|
||||
"mineSentenceMultiple": "CommandOrControl+Shift+S",
|
||||
"multiCopyTimeoutMs": 3000,
|
||||
"toggleSecondarySub": "CommandOrControl+Shift+V",
|
||||
"markAudioCard": "CommandOrControl+Shift+A",
|
||||
"openRuntimeOptions": "CommandOrControl+Shift+O",
|
||||
},
|
||||
}
|
||||
@@ -17,6 +17,7 @@ export XDG_CONFIG_HOME=$HOME/.config
|
||||
export COMPOSE_BAKE=true
|
||||
export ANKI_WAYLAND=1
|
||||
export SUDO_PROMPT=$'\a[sudo] password for %u: '
|
||||
export ELECTRON_OZONE_PLATFORM_HINT=x11
|
||||
|
||||
# nvidia
|
||||
export NVD_BACKEND=direct
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"custom/mpd-scroll",
|
||||
"custom/mpv-scroll",
|
||||
"custom/firefox-scroll",
|
||||
"hyprland/submap"
|
||||
"hyprland/submap",
|
||||
],
|
||||
// "modules-center": ["hyprland/window"],
|
||||
"modules-center": ["custom/notification"],
|
||||
@@ -32,7 +32,7 @@
|
||||
"network",
|
||||
"pulseaudio",
|
||||
"clock",
|
||||
"custom/weather",
|
||||
"custom/weather"
|
||||
],
|
||||
|
||||
"hyprland/workspaces": {
|
||||
|
||||
Reference in New Issue
Block a user