init
This commit is contained in:
@@ -0,0 +1,341 @@
|
||||
-- Copyright (c) 2022-2024 dyphire <qimoge@gmail.com>
|
||||
-- License: MIT
|
||||
-- link: https://github.com/dyphire/mpv-scripts
|
||||
|
||||
--[[
|
||||
The script calls up a window in mpv to quickly load the folder/files/iso/clipboard (support url)/other subtitles/other audio tracks/other video tracks.
|
||||
Usage, add bindings to input.conf:
|
||||
key script-message-to open_dialog import_folder
|
||||
key script-message-to open_dialog import_files
|
||||
key script-message-to open_dialog import_files <type> # vid, aid, sid (video/audio/subtitle track)
|
||||
key script-message-to open_dialog import_clipboard
|
||||
key script-message-to open_dialog import_clipboard <type> # vid, aid, sid (video/audio/subtitle track)
|
||||
key script-message-to open_dialog set_clipboard <text> # text can be mpv properties as ${path}
|
||||
|
||||
Also supports open dialog to select folder/files for other scripts.
|
||||
Scripting Example:
|
||||
-- open a folder select dialog
|
||||
mp.commandv('script-message-to', 'open_dialog', 'select_folder', mp.get_script_name())
|
||||
-- receive the selected folder reply
|
||||
mp.register_script_message('select_folder_reply', function(folder_path)
|
||||
if folder_path and folder_path ~= '' then
|
||||
-- do something with folder_path
|
||||
end
|
||||
end)
|
||||
-- open a xml file select dialog
|
||||
mp.commandv('script-message-to', 'open_dialog', 'select_files', mp.get_script_name(), 'XML File|*.xml')
|
||||
-- receive the selected files reply
|
||||
mp.register_script_message('select_files_reply', function(file_paths)
|
||||
for i, file_path in ipairs(utils.parse_json(file_paths)) do
|
||||
-- do something with file_path
|
||||
end
|
||||
end)
|
||||
|
||||
]]--
|
||||
|
||||
local msg = require 'mp.msg'
|
||||
local utils = require 'mp.utils'
|
||||
local options = require 'mp.options'
|
||||
|
||||
o = {
|
||||
video_types = '3g2,3gp,asf,avi,f4v,flv,h264,h265,m2ts,m4v,mkv,mov,mp4,mp4v,mpeg,mpg,ogm,ogv,rm,rmvb,ts,vob,webm,wmv,y4m',
|
||||
audio_types = 'aac,ac3,aiff,ape,au,cue,dsf,dts,flac,m4a,mid,midi,mka,mp3,mp4a,oga,ogg,opus,spx,tak,tta,wav,weba,wma,wv',
|
||||
image_types = 'apng,avif,bmp,gif,j2k,jp2,jfif,jpeg,jpg,jxl,mj2,png,svg,tga,tif,tiff,webp',
|
||||
subtitle_types = 'aqt,ass,gsub,idx,jss,lrc,mks,pgs,pjs,psb,rt,sbv,slt,smi,sub,sup,srt,ssa,ssf,ttxt,txt,usf,vt,vtt',
|
||||
playlist_types = 'm3u,m3u8,pls,cue',
|
||||
iso_types = 'iso',
|
||||
}
|
||||
options.read_options(o)
|
||||
|
||||
local function split(input)
|
||||
local ret = {}
|
||||
for str in string.gmatch(input, "([^,]+)") do
|
||||
ret[#ret + 1] = string.format("*.%s", str)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
-- pre-defined file types
|
||||
local file_types = {
|
||||
video = table.concat(split(o.video_types), ';'),
|
||||
audio = table.concat(split(o.audio_types), ';'),
|
||||
image = table.concat(split(o.image_types), ';'),
|
||||
iso = table.concat(split(o.iso_types), ';'),
|
||||
subtitle = table.concat(split(o.subtitle_types), ';'),
|
||||
playlist = table.concat(split(o.playlist_types), ';'),
|
||||
}
|
||||
|
||||
local powershell = nil
|
||||
|
||||
local function pwsh_check()
|
||||
local arg = {"cmd", "/c", "pwsh", "--version"}
|
||||
local res = mp.command_native({name = "subprocess", capture_stdout = true, playback_only = false, args = arg})
|
||||
if res.status ~= 0 or res.stdout:match("^PowerShell") == nil then
|
||||
powershell = "powershell"
|
||||
else
|
||||
powershell = "pwsh"
|
||||
end
|
||||
end
|
||||
|
||||
-- escapes a string so that it can be inserted into powershell as a string literal
|
||||
local function escape_powershell(str)
|
||||
if not str then return '""' end
|
||||
str = str:gsub('[$"`]', '`%1'):gsub('“', '`%1'):gsub('”', '`%1')
|
||||
return '"'..str..'"'
|
||||
end
|
||||
|
||||
local function end_file(event)
|
||||
mp.unregister_event(end_file)
|
||||
if event["reason"] == "eof" or event["reason"] == "stop" or event["reason"] == "error" then
|
||||
local bd_device = mp.get_property_native("bluray-device")
|
||||
local dvd_device = mp.get_property_native("dvd-device")
|
||||
if event["reason"] == "error" and bd_device and bd_device ~= "" then
|
||||
loaded_fail = true
|
||||
else
|
||||
loaded_fail = false
|
||||
end
|
||||
if bd_device then mp.set_property("bluray-device", "") end
|
||||
if dvd_device then mp.set_property("dvd-device", "") end
|
||||
end
|
||||
end
|
||||
|
||||
-- open bluray iso or dir
|
||||
local function open_bluray(path)
|
||||
mp.set_property('bluray-device', path)
|
||||
mp.commandv('loadfile', 'bd://')
|
||||
end
|
||||
|
||||
-- open dvd iso or dir
|
||||
local function open_dvd(path)
|
||||
mp.set_property('dvd-device', path)
|
||||
mp.commandv('loadfile', 'dvd://')
|
||||
end
|
||||
|
||||
-- open folder
|
||||
local function open_folder(path, i)
|
||||
local fpath, dir = utils.split_path(path)
|
||||
if utils.file_info(utils.join_path(path, "BDMV")) then
|
||||
open_bluray(path)
|
||||
elseif utils.file_info(utils.join_path(path, "VIDEO_TS")) then
|
||||
open_dvd(path)
|
||||
elseif dir:upper() == "BDMV" then
|
||||
open_bluray(fpath)
|
||||
elseif dir:upper() == "VIDEO_TS" then
|
||||
open_dvd(fpath)
|
||||
else
|
||||
mp.commandv('loadfile', path, i == 1 and 'replace' or 'append')
|
||||
end
|
||||
end
|
||||
|
||||
-- open files
|
||||
local function open_files(path, type, i, is_clip)
|
||||
local ext = string.match(path, "%.([^%.]+)$"):lower()
|
||||
if file_types['subtitle']:match(ext) then
|
||||
mp.commandv('sub-add', path, 'cached')
|
||||
elseif type == 'vid' and (not is_clip or (file_types['video']:match(ext) or file_types['image']:match(ext))) then
|
||||
mp.commandv('video-add', path, 'cached')
|
||||
elseif type == 'aid' and (not is_clip or file_types['audio']:match(ext)) then
|
||||
mp.commandv('audio-add', path, 'cached')
|
||||
elseif file_types['iso']:match(ext) then
|
||||
local idle = mp.get_property('idle')
|
||||
if idle ~= 'yes' then mp.set_property('idle', 'yes') end
|
||||
mp.register_event("end-file", end_file)
|
||||
open_bluray(path)
|
||||
mp.add_timeout(1.0, function()
|
||||
if idle ~= 'yes' then mp.set_property('idle', idle) end
|
||||
if loaded_fail then
|
||||
loaded_fail = false
|
||||
open_dvd(path)
|
||||
end
|
||||
end)
|
||||
else
|
||||
mp.commandv('loadfile', path, i == 1 and 'replace' or 'append')
|
||||
end
|
||||
end
|
||||
|
||||
local function select_folder()
|
||||
if not powershell then pwsh_check() end
|
||||
local powershell_script = string.format([[&{
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
$fbd = New-Object System.Windows.Forms.FolderBrowserDialog
|
||||
$fbd.RootFolder = "Desktop"
|
||||
$fbd.ShowNewFolderButton = $true
|
||||
$owner = New-Object System.Windows.Forms.NativeWindow
|
||||
$owner.AssignHandle((Get-Process -Id %d).MainWindowHandle)
|
||||
try {
|
||||
if ($fbd.ShowDialog($owner) -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||
$u8 = [System.Text.Encoding]::UTF8
|
||||
$out = [Console]::OpenStandardOutput()
|
||||
$selectedFolder = $fbd.SelectedPath
|
||||
$u8selectedFolder = $u8.GetBytes("$selectedFolder`n")
|
||||
$out.Write($u8selectedFolder, 0, $u8selectedFolder.Length)
|
||||
}
|
||||
} finally {
|
||||
$owner.ReleaseHandle()
|
||||
$fbd.Dispose()
|
||||
}
|
||||
}]], mp.get_property_number('pid'))
|
||||
local res = mp.command_native({
|
||||
name = 'subprocess',
|
||||
playback_only = false,
|
||||
capture_stdout = true,
|
||||
args = { powershell, '-NoProfile', '-Command', powershell_script },
|
||||
})
|
||||
if res.status ~= 0 then
|
||||
mp.osd_message("Failed to open folder dialog.")
|
||||
return nil
|
||||
end
|
||||
local folder_path = res.stdout:match("(.-)[\r\n]?$") -- Trim any trailing newline
|
||||
return folder_path
|
||||
end
|
||||
|
||||
local function select_files(filter)
|
||||
if not powershell then pwsh_check() end
|
||||
local powershell_script = string.format([[&{
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
||||
$ofd.Multiselect = $true
|
||||
$ofd.Filter = %s
|
||||
$owner = New-Object System.Windows.Forms.NativeWindow
|
||||
$owner.AssignHandle((Get-Process -Id %d).MainWindowHandle)
|
||||
try {
|
||||
if ($ofd.ShowDialog($owner) -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||
$u8 = [System.Text.Encoding]::UTF8
|
||||
$out = [Console]::OpenStandardOutput()
|
||||
ForEach ($filename in $ofd.FileNames) {
|
||||
$u8filename = $u8.GetBytes("$filename`n")
|
||||
$out.Write($u8filename, 0, $u8filename.Length)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$owner.ReleaseHandle()
|
||||
$ofd.Dispose()
|
||||
}
|
||||
}]], escape_powershell(filter), mp.get_property_number('pid'))
|
||||
local res = mp.command_native({
|
||||
name = 'subprocess',
|
||||
playback_only = false,
|
||||
capture_stdout = true,
|
||||
args = { powershell, '-NoProfile', '-Command', powershell_script },
|
||||
})
|
||||
local file_paths = {}
|
||||
if res.status ~= 0 then
|
||||
mp.osd_message("Failed to open files dialog.")
|
||||
return file_paths
|
||||
end
|
||||
for file_path in string.gmatch(res.stdout, '[^\r\n]+') do
|
||||
table.insert(file_paths, file_path)
|
||||
end
|
||||
return file_paths
|
||||
end
|
||||
|
||||
-- import folder
|
||||
local function import_folder()
|
||||
local folder_path = select_folder()
|
||||
if folder_path and folder_path ~= '' then open_folder(folder_path, 1) end
|
||||
end
|
||||
|
||||
-- import files
|
||||
local function import_files(type)
|
||||
local filter = ''
|
||||
if type == 'vid' then
|
||||
filter = string.format("Video Files|%s|Image Files|%s", file_types['video'], file_types['image'])
|
||||
elseif type == 'aid' then
|
||||
filter = string.format("Audio Files|%s", file_types['audio'])
|
||||
elseif type == 'sid' then
|
||||
filter = string.format("Subtitle Files|%s", file_types['subtitle'])
|
||||
else
|
||||
filter = string.format("All Files (*.*)|*.*|Video Files|%s|Audio Files|%s|Image Files|%s|ISO Files|%s|Subtitle Files|%s|Playlist Files|%s",
|
||||
file_types['video'], file_types['audio'], file_types['image'], file_types['iso'], file_types['subtitle'], file_types['playlist'])
|
||||
end
|
||||
for i, file_path in ipairs(select_files(filter)) do
|
||||
open_files(file_path, type, i, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns a string of UTF-8 text from the clipboard
|
||||
local function get_clipboard()
|
||||
if mp.get_property('clipboard-backends') ~= nil or mp.get_property_bool('clipboard-enable') then
|
||||
return mp.get_property('clipboard/text', '')
|
||||
end
|
||||
local res = mp.command_native({
|
||||
name = 'subprocess',
|
||||
playback_only = false,
|
||||
capture_stdout = true,
|
||||
args = { 'powershell', '-NoProfile', '-Command', [[& {
|
||||
Trap {
|
||||
Write-Error -ErrorRecord $_
|
||||
Exit 1
|
||||
}
|
||||
$clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText
|
||||
if (-not $clip) {
|
||||
$clip = Get-Clipboard -Raw -Format FileDropList
|
||||
}
|
||||
$u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip)
|
||||
[Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
|
||||
}]] }
|
||||
})
|
||||
if not res.error then
|
||||
return res.stdout
|
||||
end
|
||||
return ''
|
||||
end
|
||||
|
||||
-- open files from clipboard
|
||||
local function open_clipboard(path, type, i)
|
||||
local path = path:gsub("^[\'\"]", ""):gsub("[\'\"]$", ""):gsub('^%s+', ''):gsub('%s+$', '')
|
||||
if path:find('^%a[%w.+-]-://') then
|
||||
mp.commandv('loadfile', path, i == 1 and 'replace' or 'append')
|
||||
else
|
||||
local meta = utils.file_info(path)
|
||||
if not meta then
|
||||
mp.osd_message('Clipboard path is invalid')
|
||||
msg.warn('Clipboard path is invalid')
|
||||
elseif meta.is_dir then
|
||||
open_folder(path, i)
|
||||
elseif meta.is_file then
|
||||
open_files(path, type, i, true)
|
||||
else
|
||||
mp.osd_message('Clipboard path is invalid')
|
||||
msg.warn('Clipboard path is invalid')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- import clipboard
|
||||
local function import_clipboard(type)
|
||||
local clip = get_clipboard()
|
||||
if clip ~= '' then
|
||||
local i = 0
|
||||
for path in string.gmatch(clip, '[^\r\n]+') do
|
||||
i = i + 1
|
||||
open_clipboard(path, type, i)
|
||||
end
|
||||
else
|
||||
mp.osd_message('Clipboard is empty')
|
||||
msg.warn('Clipboard is empty')
|
||||
end
|
||||
end
|
||||
|
||||
-- sets the contents of the clipboard to the given string
|
||||
local function set_clipboard(text)
|
||||
msg.verbose('setting clipboard text:', text)
|
||||
if mp.get_property('clipboard-backends') ~= nil or mp.get_property_bool('clipboard-enable') then
|
||||
mp.commandv('set', 'clipboard/text', text)
|
||||
else
|
||||
mp.commandv('run', 'powershell', '-NoProfile', '-command', 'set-clipboard', escape_powershell(text))
|
||||
end
|
||||
end
|
||||
|
||||
mp.register_script_message('import_folder', import_folder)
|
||||
mp.register_script_message('import_files', import_files)
|
||||
mp.register_script_message('import_clipboard', import_clipboard)
|
||||
mp.register_script_message('set_clipboard', set_clipboard)
|
||||
mp.register_script_message('select_folder', function(script_name)
|
||||
local folder_path = select_folder()
|
||||
mp.commandv('script-message-to', script_name, 'select_folder_reply', folder_path)
|
||||
end)
|
||||
mp.register_script_message('select_files', function(script_name, filter)
|
||||
local file_paths = select_files(filter)
|
||||
mp.commandv('script-message-to', script_name, 'select_files_reply', utils.format_json(file_paths))
|
||||
end)
|
||||
Reference in New Issue
Block a user