summaryrefslogtreecommitdiff
path: root/mac/.config/mpv/scripts/fuzzydir.lua
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-08-23 12:42:37 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-08-23 12:42:37 +0900
commit07d294425a98ee5d1e22d03e2b24ae2c76e487c0 (patch)
treea6818f0d64438c5fdb88b00a35d944f80c056213 /mac/.config/mpv/scripts/fuzzydir.lua
parent6fc28cdb3529ca8ee864cb5c41674cb0a4af72a1 (diff)
updates
Diffstat (limited to 'mac/.config/mpv/scripts/fuzzydir.lua')
-rw-r--r--mac/.config/mpv/scripts/fuzzydir.lua278
1 files changed, 278 insertions, 0 deletions
diff --git a/mac/.config/mpv/scripts/fuzzydir.lua b/mac/.config/mpv/scripts/fuzzydir.lua
new file mode 100644
index 0000000..22119da
--- /dev/null
+++ b/mac/.config/mpv/scripts/fuzzydir.lua
@@ -0,0 +1,278 @@
+--[[
+ fuzzydir / by sibwaf / https://github.com/sibwaf/mpv-scripts
+
+ Allows using "**" wildcards in sub-file-paths and audio-file-paths
+ so you don't have to specify all the possible directory names.
+
+ Basically, allows you to do this and never have the need to edit any paths ever again:
+ audio-file-paths = **
+ sub-file-paths = **
+
+ MIT license - do whatever you want, but I'm not responsible for any possible problems.
+ Please keep the URL to the original repository. Thanks!
+]]
+
+--[[
+ Configuration:
+
+ # max_search_depth
+
+ Determines the max depth of recursive search, should be >= 1
+
+ Examples for "sub-file-paths = **":
+ "max_search_depth = 1" => mpv will be able to find [xyz.ass, subs/xyz.ass]
+ "max_search_depth = 2" => mpv will be able to find [xyz.ass, subs/xyz.ass, subs/moresubs/xyz.ass]
+
+ Please be careful when setting this value too high as it can result in awful performance or even stack overflow
+
+
+ # discovery_threshold
+
+ fuzzydir will skip paths which contain more than discovery_threshold directories in them
+
+ This is done to keep at least some garbage from getting into *-file-paths properties in case of big collections:
+ - dir1 <- will be ignored on opening video.mp4 as it's probably unrelated to the file
+ - ...
+ - dir999 <- will be ignored
+ - video.mp4
+
+ Use 0 to disable this behavior completely
+
+
+ # use_powershell
+
+ fuzzydir will use PowerShell to traverse directories when it's available
+
+ Can be faster in some cases, but can also be significantly slower
+]]
+
+local max_search_depth = 3
+local discovery_threshold = 10
+local use_powershell = false
+
+----------
+
+local utils = require("mp.utils")
+local msg = require("mp.msg")
+
+local default_audio_paths = mp.get_property_native("options/audio-file-paths")
+local default_sub_paths = mp.get_property_native("options/sub-file-paths")
+
+function foreach(list, action)
+ for _, item in pairs(list) do
+ action(item)
+ end
+end
+
+function starts_with(str, prefix)
+ return string.sub(str, 1, string.len(prefix)) == prefix
+end
+
+function ends_with(str, suffix)
+ return suffix == "" or string.sub(str, -string.len(suffix)) == suffix
+end
+
+function add_all(to, from)
+ for index, element in pairs(from) do
+ table.insert(to, element)
+ end
+end
+
+function contains(t, e)
+ for index, element in pairs(t) do
+ if element == e then
+ return true
+ end
+ end
+ return false
+end
+
+function normalize(path)
+ if path == "." then
+ return ""
+ end
+
+ if starts_with(path, "./") or starts_with(path, ".\\") then
+ path = string.sub(path, 3, -1)
+ end
+ if ends_with(path, "/") or ends_with(path, "\\") then
+ path = string.sub(path, 1, -2)
+ end
+
+ return path
+end
+
+function call_command(command)
+ local command_string = ""
+ for _, part in pairs(command) do
+ command_string = command_string .. part .. " "
+ end
+
+ msg.trace("Calling external command:", command_string)
+
+ local process = mp.command_native({
+ name = "subprocess",
+ playback_only = false,
+ capture_stdout = true,
+ capture_stderr = true,
+ args = command,
+ })
+
+ if process.status ~= 0 then
+ msg.verbose("External command failed with status " .. process.status .. ": " .. command_string)
+ if process.stderr ~= "" then
+ msg.debug(process.stderr)
+ end
+
+ return nil
+ end
+
+ local result = {}
+ for line in string.gmatch(process.stdout, "([^\r\n]+)") do
+ table.insert(result, line)
+ end
+ return result
+end
+
+-- Platform-dependent optimization
+
+local powershell_version = nil
+if use_powershell then
+ powershell_version = call_command({
+ "powershell",
+ "-NoProfile",
+ "-Command",
+ "$Host.Version.Major",
+ })
+end
+if powershell_version ~= nil then
+ powershell_version = tonumber(powershell_version[1])
+end
+if powershell_version == nil then
+ powershell_version = -1
+end
+msg.debug("PowerShell version", powershell_version)
+
+function fast_readdir(path)
+ if powershell_version >= 3 then
+ msg.trace("Scanning", path, "with PowerShell")
+ result = call_command({
+ "powershell",
+ "-NoProfile",
+ "-Command",
+ [[
+ $dirs = Get-ChildItem -LiteralPath ]] .. string.format("%q", path) .. [[ -Directory
+ foreach($dir in $dirs) {
+ $u8clip = [System.Text.Encoding]::UTF8.GetBytes($dir.Name)
+ [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
+ Write-Host ""
+ } ]],
+ })
+ msg.trace("Finished scanning", path, "with PowerShell")
+ return result
+ end
+
+ msg.trace("Scanning", path, "with default readdir")
+ result = utils.readdir(path, "dirs")
+ msg.trace("Finished scanning", path, "with default readdir")
+ return result
+end
+
+-- Platform-dependent optimization end
+
+function traverse(search_path, current_path, level, cache)
+ local full_path = utils.join_path(search_path, current_path)
+
+ if level > max_search_depth then
+ msg.trace("Traversed too deep, skipping scan for", full_path)
+ return {}
+ end
+
+ if cache[full_path] ~= nil then
+ msg.trace("Returning from cache for", full_path)
+ return cache[full_path]
+ end
+
+ local result = {}
+
+ local discovered_paths = fast_readdir(full_path)
+ if discovered_paths == nil then
+ -- noop
+ msg.debug("Unable to scan " .. full_path .. ", skipping")
+ elseif discovery_threshold > 0 and #discovered_paths > discovery_threshold then
+ -- noop
+ msg.debug("Too many directories in " .. full_path .. ", skipping")
+ else
+ for _, discovered_path in pairs(discovered_paths) do
+ local new_path = utils.join_path(current_path, discovered_path)
+
+ table.insert(result, new_path)
+ add_all(result, traverse(search_path, new_path, level + 1, cache))
+ end
+ end
+
+ cache[full_path] = result
+
+ return result
+end
+
+function explode(raw_paths, search_path, cache)
+ local result = {}
+ for _, raw_path in pairs(raw_paths) do
+ local parent, leftover = utils.split_path(raw_path)
+ if leftover == "**" then
+ msg.trace("Expanding wildcard for", raw_path)
+ table.insert(result, parent)
+ add_all(result, traverse(search_path, parent, 1, cache))
+ else
+ msg.trace("Path", raw_path, "doesn't have a wildcard, keeping as-is")
+ table.insert(result, raw_path)
+ end
+ end
+
+ local normalized = {}
+ for index, path in pairs(result) do
+ local normalized_path = normalize(path)
+ if not contains(normalized, normalized_path) and normalized_path ~= "" then
+ table.insert(normalized, normalized_path)
+ end
+ end
+
+ return normalized
+end
+
+function explode_all()
+ msg.debug("max_search_depth = " .. max_search_depth .. ", discovery_threshold = " .. discovery_threshold)
+
+ local video_path = mp.get_property("path")
+ local search_path, _ = utils.split_path(video_path)
+ msg.debug("search_path = " .. search_path)
+
+ local cache = {}
+
+ foreach(default_audio_paths, function(it)
+ msg.debug("audio-file-paths:", it)
+ end)
+ local audio_paths = explode(default_audio_paths, search_path, cache)
+ foreach(audio_paths, function(it)
+ msg.debug("Adding to audio-file-paths:", it)
+ end)
+ mp.set_property_native("options/audio-file-paths", audio_paths)
+
+ msg.verbose("Done expanding audio-file-paths")
+
+ foreach(default_sub_paths, function(it)
+ msg.debug("sub-file-paths:", it)
+ end)
+ local sub_paths = explode(default_sub_paths, search_path, cache)
+ foreach(sub_paths, function(it)
+ msg.debug("Adding to sub-file-paths:", it)
+ end)
+ mp.set_property_native("options/sub-file-paths", sub_paths)
+
+ msg.verbose("Done expanding sub-file-paths")
+
+ msg.debug("Done expanding paths")
+end
+
+mp.add_hook("on_load", 50, explode_all)