changed mpv settings and added ivtc on D key

This commit is contained in:
gaitas13 2024-04-28 17:14:08 +02:00
parent a1849bbeb4
commit 9b3cc564d2
5 changed files with 844 additions and 37 deletions

View file

@ -1 +1,2 @@
#d script-message cycle-profiles "bwdifdeint;deinterlace-no"
#d script-message cycle-profiles "bwdifdeint;deinterlace-no" #only needed if using hwdec that has its own deinterlacer and is not bwdif
D vf toggle "pullup,dejudder"

View file

@ -0,0 +1,421 @@
--[[
mpv-dvd-browser
This script uses the `lsdvd` commandline utility to allow users to view and select titles
for DVDs from directly within mpv. The browser is interractive and allows for both playing
the selected title, or appending it to the playlist.
For full documentation see: https://github.com/CogentRedTester/mpv-dvd-browser
]]--
local mp = require 'mp'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
local o = {
lsdvd = 'lsdvd',
--path to the dvd device to send to lsdvd, leaving this blank will set the script to
--use the --dvd-device option.
--It is recommended that this be left blank unless using wsl
dvd_device = "",
--number of titles to display on the screen at once
num_entries = 20,
--by default the player enters an infinite loop, usually of the DVD menu screen, after moving
--past the last second of the file. If this option is enabled, then the script will
--automatically configure mpv to end playback before entering the loop
escape_loop = true,
--changes default mpv behaviour and loads the first title instead of the longest when
--the title isn't specified
start_from_first_title = true,
---------------------
--playlist options:
---------------------
--adds the previous and subsequent titles to the playlist when playing a dvd
--only does this when there is only one item in the playlist
create_playlist = true,
--when dvd:// (no specified title) is loaded the script will always insert all of the
--titles into the playlist, regardless of the playlist length
--similar to loading a directory or playlist file
treat_root_as_playlist = true,
------------------------------------------
--wsl options for limitted windows support
------------------------------------------
wsl = false,
wsl_password = "",
--------------
--ass options
---------------
ass_header = "{\\q2\\fs35\\c&00ccff&}",
ass_body = "{\\q2\\fs25\\c&Hffffff&}",
ass_selected = "{\\c&Hfce788&}",
ass_playing = "{\\c&H33ff66&}",
ass_footerheader = "{\\c&00ccff&\\fs16}",
ass_cursor = "{\\c&00ccff&}",
ass_length = "{\\fs20\\c&aaaaaa&}"
}
opt.read_options(o, 'dvd_browser')
--[[
lsdvd returns a JSON object with a number of details about the dvd
some notable values are:
title = title of the dvd
longest_track = longest track on the dvd
device = path to the dvd mount point
track = array of 'titles'/tracks on the disc
length = length of each title
ix = numerical id of the title starting from 1
chapter = array of chapters in the title
num_chapters = length of chapters array (added by me)
]]--
--if the script name includes file_browser, then the script is being loaded
--as an addon, and hence we can skip loading several things
local STANDALONE = not mp.get_script_name():find("file_browser")
local list = {}
if STANDALONE then
package.path = mp.command_native( {"expand-path", "~~/script-modules/?.lua;" } ) .. package.path
list = require "scroll-list"
list.header_style = o.ass_header
list.list_style = o.ass_body
list.wrapper_style = o.ass_footerheader
list.empty_text = "insert DVD"
end
local dvd = {}
local state = {
playing_disc = false,
selected = 1,
flag_update = false
}
--automatically match to the current dvd device
if (o.dvd_device == "") then
mp.observe_property('dvd-device', 'string', function(_, device)
if device == "" then device = "/dev/dvd" end
o.dvd_device = device
--we set this to false to force a dvd rescan
state.playing_disc = false
end)
end
local function get_header_str()
local title
if dvd == nil then title = ""
else title = dvd.title end
return '📀 dvd://'..title
end
local function get_line_str(v)
return "Title "..(v.ix-1)..o.ass_length.."["..v.length.."]"..v.num_chapters.." chapters"
end
function list:format_header()
self.ass.data = o.ass_header..get_header_str().."\\N ---------------------------------------------------- \\N"
end
--simple function to append to the ass string
function list:format_line(i, v)
self:append(o.ass_body)
--the below text contains unicode whitespace characters
if i == list.selected then self:append(o.ass_cursor..[[➤\h]]..o.ass_selected)
else self:append([[\h\h\h\h]]) end
--prints the currently-playing icon and style
if mp.get_property('filename', "0") == tostring(i-1) then
self:append(o.ass_playing)
end
self:append(get_line_str(v))
self:newline()
end
--sends a call to lsdvd to read the contents of the disc
local function read_disc()
msg.verbose('reading contents of ' .. o.dvd_device)
local args
if o.wsl then
msg.verbose('wsl compatibility mode enabled')
--if wsl password is not set then we'll assume the user has mounted manually
if o.wsl_password ~= "" then
local dvd_device = mp.get_property('dvd-device', ''):gsub([[\]], [[/]])
msg.verbose('mounting '..dvd_device..' at '..o.dvd_device)
mp.command_native({
name = 'subprocess',
playback_only = false,
args = {'wsl', 'echo', o.wsl_password, '|', 'sudo', '-S', 'mount', '-t', 'drvfs', dvd_device, o.dvd_device}
})
end
--setting wsl arguments
args = {'wsl', o.lsdvd, o.dvd_device, '-Oy', '-c'}
else
args = {o.lsdvd, o.dvd_device, '-Oy', '-c'}
end
local cmd = mp.command_native({
name = 'subprocess',
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
})
--making the python string JSON compatible
local result = cmd.stdout:gsub("'", '"')
result = result:gsub('lsdvd = ', '')
dvd = utils.parse_json(result)
if (not dvd) then
msg.error(cmd.stderr)
state.playing_disc = false
return
end
msg.trace(utils.to_string(dvd))
--creating a fallback for the title
-- if dvd.title == "unknown" then dvd.title = "dvd://" end
--making modifications to all the entries
for i = 1, #dvd.track do
local v = dvd.track[i]
--saving the chapter count
v.num_chapters = #v.chapter
--modifying the length
local l = v.length
local lstr = tostring(l)
--adding the microseconds as is
local index = tostring(l):find([[.[^.]*$]])
local str
if index == 1 then str = "00"
else
str = tostring(lstr:sub(index+1))
str = string.format('%02d', str)
end
l = math.floor(l)
local seconds = l%60
str = string.format('%02d', seconds) .. '.' .. str
l = (l - seconds)/60
local mins = l%60
str = string.format('%02d', mins) .. ':' .. str
l = (l-mins)/60
local hours = l%24
str = string.format('%02d', hours) .. ':' .. str
msg.debug('changing length string for title '..(i-1)..' to '..str)
v.length = str
end
state.playing_disc = true
list.list = dvd.track
end
--this function updates dvd information and updates the browser
local function update()
read_disc()
list:update()
end
--appends the specified playlist item along with the desired options
local function load_dvd_title(title, flag)
local i = title.ix-1
mp.commandv("loadfile", "dvd://"..i, flag)
end
--handles actions when dvd:// paths are played directly
--updates dvd information and inserts disc titles into the playlist
local function load_disc()
local path = mp.get_property('stream-open-filename', '')
if path:find('dvd://') ~= 1 then
state.playing_disc = false
return
end
msg.verbose('playing dvd')
--if we have not stopped playing a disc then there's no need to parse the disc again
if not state.playing_disc then read_disc() end
--if we still can't detect a disc then return
if (not state.playing_disc) then return end
--if we successfully loaded info about the disc it's time to do some other stuff:
--this code block finds the default title of the disc
local curr_title
--if the user specified a title number we use that
if path ~= "dvd://" then
--treating whatever comes after "dvd://" as the title number
curr_title = tonumber(path:sub(7))
--if dvd:// was sent and this option is set we set the default ourselves
elseif o.start_from_first_title then
mp.set_property('stream-open-filename', "dvd://0")
curr_title = 0
--otherwise if just dvd:// was sent we need to find the longest title
else
curr_title = dvd.longest_track
end
mp.set_property('file-local-options/title', dvd.title.." - Title "..curr_title)
--if o.create_playlist is false then the function can end here
if not o.create_playlist then return end
--offsetting curr_title by one to account for lua arrays being 1-based
curr_title = curr_title+1
local length = mp.get_property_number('playlist-count', 1)
--load files in the playlist under the specified conditions
if (path == "dvd://" and o.treat_root_as_playlist) or length == 1 then
local pos = mp.get_property_number('playlist-pos', 1)
--add all of the files to the playlist
for i = 1, #dvd.track do
if i ~= curr_title then
load_dvd_title(dvd.track[i], "append")
length = length + 1
--we need slightly different behaviour when prepending vs appending a playlist entry
if (i < curr_title) then
mp.commandv("playlist-move", length-1, pos)
pos = pos+1
elseif (i > curr_title) then
mp.commandv("playlist-move", length-1, pos+(i-curr_title))
end
end
end
--if the path is dvd, then we actually need to fully replace this entry in the playlist,
--otherwise the whole disc will be added to the playlist again if moving back to this entry
if (path == "dvd://") then
msg.verbose('replacing dvd:// with playlist')
load_dvd_title(dvd.track[curr_title], "append")
length = length+1
mp.commandv('playlist-move', length-1, pos+1)
mp.commandv('playlist-remove', 'current')
end
end
end
--opens the currently selected file
local function open_file(flag)
load_dvd_title(dvd.track[list.selected], flag)
if flag == 'replace' then
list:close()
end
end
--opens the browser and declares dynamic keybinds
function list:open()
self.hidden = false
if not state.playing_disc then
update()
else
self:open_list()
end
self:add_keybinds()
end
list.keybinds = {
{"ESC", "exit", function() list:close() end, {}},
{"ENTER", "open", function() open_file('replace') end, {}},
{"Shift+ENTER", "append_playlist", function() open_file('append') end, {}},
{'DOWN', 'scroll_down', function() list:scroll_down() end, {repeatable = true}},
{'UP', 'scroll_up', function() list:scroll_up() end, {repeatable = true}},
{'Ctrl+r', 'reload', function() read_disc() ; list:update() end, {}}
}
--modifies track length to escape infinite loop
if o.escape_loop then
mp.add_hook('on_preloaded', 50, function()
if mp.get_property("path", ""):find("dvd://") ~= 1 then return end
if mp.get_property('end', 'none') ~= 'none' then return end
local chapters = mp.get_property_native('chapter-list')
if not chapters then return end
local num_chapters = #chapters
-- occurs if there are no chapters
if not chapters[num_chapters] then return end
if (mp.get_property_number('duration', 0) - (chapters[num_chapters].time or 0)) > 1 then return end
msg.verbose('modifying end of the title to escape infinite loop')
mp.set_property('file-local-options/end', "#"..num_chapters)
end)
end
--if we're playing a disc then read it and modify playlist appropriately
mp.add_hook('on_load', 50, load_disc)
--if these events are disabled then the list gui functions are never called
if STANDALONE then
mp.observe_property('path', 'string', function(_,path)
if state.playing_disc then list:update() end
end)
mp.register_script_message('browse-dvd', function() list:open() end)
mp.add_key_binding('MENU', 'dvd-browser', function() list:toggle() end)
end
--module functions when loading as file_browser addon
local dvd_module = {
priority = 50
}
function dvd_module:can_parse(directory)
return directory:sub(1,6) == "dvd://" or directory == self.get_dvd_device()
end
function dvd_module:parse()
read_disc()
local list = {}
if dvd then
for i = 1, #dvd.track do
list[i] = {
ass = get_line_str(dvd.track[i]),
name = tostring(dvd.track[i].ix-1),
path = "dvd://"..(dvd.track[i].ix-1),
type = "file"
}
end
end
return list, {
empty_text = "insert DVD",
directory_label = get_header_str(),
filtered = true,
sorted = true
}
end
return dvd_module

View file

@ -0,0 +1,65 @@
#################################################################
######### Default configuration file for mpv-dvd-browser ########
####### https://github.com/CogentRedTester/mpv-dvd-browser ######
#################################################################
#path to the lsdvd executable
#searches the system path by default
lsdvd=lsdvd
#path to the dvd device to send to lsdvd, leaving this blank will set the script to
#use the --dvd-device option.
#It is recommended that this be left blank unless using wsl
dvd_device=
#number of titles to display on the screen at once
num_entries=20
#by default the player enters an infinite loop, usually of the DVD menu screen, after moving
#past the last second of the file. If this option is enabled, then the script will
#automatically configure mpv to end playback before entering the loop
escape_loop=yes
#changes default mpv behaviour and loads the first title instead of the longest when
#the title isn't specified
start_from_first_title=yes
########################
### playlist options ###
########################
#adds the previous and subsequent titles to the playlist when playing a dvd
#only does this when there is only one item in the playlist
create_playlist=yes
#when dvd:// (no specified title) is loaded the script will always insert all of the
#titles into the playlist, regardless of the playlist length
#similar to loading a directory or playlist file
treat_root_as_playlist=yes
##################################################
#### wsl options for limitted windows support ####
##################################################
#enable wsl compatibility mode
wsl=no
#your WSL user password for running the `sudo mount` command
#leaving this blank will disable the auto-mounting command
wsl_password=
###########################################################################################
# ass tags to change the look of the menu
# For information see: http://docs.aegisub.org/3.2/ASS_Tags/
#
# It's recommended not to put these in your config file unless you know what you're doing,
# otherwise any improvements I make to the default theme will be overwritten
###########################################################################################
ass_header={\q2\fs35\c&00ccff&}
ass_body={\q2\fs25\c&Hffffff&}
ass_selected={\c&Hfce788&}
ass_playing={\c&H33ff66&}
ass_footerheader={\c&00ccff&\fs16}
ass_cursor={\c&00ccff&}
ass_length={\fs20\c&aaaaaa&}

View file

@ -19,6 +19,7 @@ local ext = {
local double_page_check = false
local first_start = true
local filedims = {}
local format = {}
local initiated = false
local input = ""
local jump = false
@ -34,11 +35,11 @@ local opts = {
double = false,
manga = true,
pan_size = 0.05,
similar_height_threshold = 50,
similar_height_threshold = 200,
skip_size = 10,
trigger_zone = 0.05,
zoom_multiplier = 1,
}
local lavfi_format = {}
local lavfi_scale = {}
local similar_height = {}
local valid_width = {}
@ -50,25 +51,6 @@ function add_tracks(start, finish)
end
end
function calculate_zoom_level(dims, pages)
local display_width = mp.get_property_number("display-width")
local display_height = mp.get_property_number("display-height")
local display_dpi = mp.get_property_number("display-hidpi-scale")
display_width = display_width / display_dpi
display_height = display_height / display_dpi
dims[0] = tonumber(dims[0])
dims[1] = tonumber(dims[1]) * opts.continuous_size
local scaled_width = display_height/dims[1] * dims[0]
if display_width >= opts.continuous_size*scaled_width then
return pages
else
return display_width / scaled_width
end
end
function check_aspect_ratio(index)
local a = filedims[index]
local b = filedims[index+1]
@ -106,6 +88,14 @@ function check_double_page_dims(index)
double_page_check = false
end
function check_gray_format(name)
if name and string.sub(name, 1, 4) == "gray" then
return true
else
return false
end
end
function check_images()
local audio = mp.get_property("audio-params")
local image = mp.get_property_bool("current-tracks/video/image")
@ -128,6 +118,9 @@ function set_custom_title(last_index)
end
function create_modes()
if first_start and not opts.auto_start then
return
end
local index = mp.get_property_number("playlist-pos")
local len = mp.get_property_number("playlist-count")
local pages
@ -143,7 +136,7 @@ function create_modes()
finish = len - 1
end
add_tracks(index, finish)
store_file_dims(index, finish)
store_file_props(index, finish)
if opts.double then
check_double_page_dims(index)
set_lavfi_complex_double()
@ -160,7 +153,7 @@ function create_modes()
end
end
function store_file_dims(start, finish)
function store_file_props(start, finish)
local len = mp.get_property_number("playlist-count")
local needs_dims = false
for i=start, finish do
@ -191,12 +184,21 @@ function store_file_dims(start, finish)
dims[0] = width
dims[1] = height
filedims[i+start] = dims
format[i+start] = mp.get_property("track-list/"..tostring(i).."/format-name")
-- special case any yuvj formats to avoid ffmpeg deprecation warning spam
if format[i+start] and string.sub(format[i+start], 1, 4) == "yuvj" then
format[i+start] = string.gsub(format[i+start], "j", "")
end
end
for i=start, finish - 1 do
valid_width[i] = check_aspect_ratio(i)
if filedims[i][1] ~= filedims[i+1][1] then
lavfi_scale[i] = true
end
if format[i] ~= format[i+1] and check_gray_format(format[i]) or check_gray_format(format[i+1]) then
-- if one page is gray, we need to forcibly convert it
lavfi_format[i] = check_gray_format(format[i]) and format[i+1] or format[i]
end
if math.abs(filedims[i][1] - filedims[i+1][1]) < opts.similar_height_threshold then
similar_height[i] = true
else
@ -232,6 +234,27 @@ function set_lavfi_complex_continuous(arg, finish)
local index = mp.get_property_number("playlist-pos")
local pages = finish - index
local max_width = find_max_width(pages)
local has_gray = false
local has_color = false
local color_format = ""
for i=0, pages do
if check_gray_format(format[index+i]) then
has_gray = true
else
has_color = true
color_format = format[index+i]
end
end
-- if at least one page is color, any gray pages must be converted
if has_gray and has_color then
for i=0, pages do
if check_gray_format(format[index+i]) then
local split_format = string.gsub(split[i], "]", "_format]")
vstack = vstack..split[i].." format="..color_format.. " "..split_format.."; "
split[i] = split_format
end
end
end
for i=0, pages do
if filedims[index+i][0] ~= max_width then
local split_pad = string.gsub(split[i], "]", "_pad]")
@ -245,8 +268,6 @@ function set_lavfi_complex_continuous(arg, finish)
vstack = vstack.."vstack=inputs="..tostring(pages + 1).." [vo]"
mp.set_property("lavfi-complex", vstack)
local index = mp.get_property_number("playlist-pos")
local zoom_level = calculate_zoom_level(filedims[index], pages+1)
mp.set_property_number("video-zoom", opts.zoom_multiplier * log2(zoom_level))
mp.set_property_number("video-pan-y", 0)
if upwards then
mp.set_property_number("video-align-y", 1)
@ -265,18 +286,26 @@ function set_lavfi_complex_double()
end
return
end
local hstack
local external_vid = "[vid2]"
local hstack = ""
local vid1 = "[vid1]"
local vid2 = "[vid2]"
if lavfi_format[index] then
if check_gray_format(format[index]) then
hstack = vid1.." format="..lavfi_format[index].." [vid1_format]; "
vid1 = "[vid1_format]"
else
hstack = vid2.." format="..lavfi_format[index].." [vid2_format]; "
vid2 = "[vid2_format]"
end
end
if lavfi_scale[index] then
external_vid = string.sub(external_vid, 0, 5).."_scale]"
hstack = hstack..vid2.." scale="..filedims[index][0].."x"..filedims[index][1]..":flags=lanczos [vid2_scale]; "
vid2 = "[vid2_scale]"
end
if opts.manga then
hstack = external_vid.." [vid1] hstack [vo]"
hstack = hstack..vid2.." "..vid1.. " hstack [vo]"
else
hstack = "[vid1] "..external_vid.." hstack [vo]"
end
if lavfi_scale[index] then
hstack = "[vid2] scale="..filedims[index][0].."x"..filedims[index][1]..":flags=lanczos [vid2_scale]; "..hstack
hstack = hstack..vid1.." "..vid2.. " hstack [vo]"
end
mp.set_property("lavfi-complex", hstack)
end
@ -631,6 +660,7 @@ function toggle_reader()
set_properties()
mp.observe_property("playlist-count", number, remove_non_images)
mp.osd_message("Manga Reader Started")
mp.add_hook("on_preloaded", 50, create_modes)
mp.add_key_binding("c", "toggle-continuous-mode", toggle_continuous_mode)
mp.add_key_binding("d", "toggle-double-page", toggle_double_page)
mp.add_key_binding("m", "toggle-manga-mode", toggle_manga_mode)
@ -642,7 +672,6 @@ function toggle_reader()
restore_properties()
mp.unobserve_property(check_y_pos)
mp.unobserve_property(remove_non_images)
mp.set_property_number("video-zoom", 0)
mp.set_property_number("video-align-y", 0)
mp.set_property_number("video-pan-y", 0)
mp.set_property("lavfi-complex", "")
@ -723,7 +752,6 @@ function toggle_continuous_mode()
opts.continuous = false
mp.unobserve_property(check_y_pos)
mp.set_property("lavfi-complex", "")
mp.set_property_number("video-zoom", 0)
mp.set_property_number("video-align-y", 0)
mp.set_property_number("video-pan-y", 0)
else
@ -764,7 +792,6 @@ function toggle_manga_mode()
mp.commandv("playlist-play-index", index)
end
mp.add_hook("on_preloaded", 50, create_modes)
mp.register_event("file-loaded", init)
mp.add_key_binding("y", "toggle-reader", toggle_reader)
require "mp.options".read_options(opts, "manga-reader")

View file

@ -0,0 +1,293 @@
local mp = require 'mp'
local scroll_list = {
global_style = [[]],
header_style = [[{\q2\fs35\c&00ccff&}]],
list_style = [[{\q2\fs25\c&Hffffff&}]],
wrapper_style = [[{\c&00ccff&\fs16}]],
cursor_style = [[{\c&00ccff&}]],
selected_style = [[{\c&Hfce788&}]],
cursor = [[➤\h]],
indent = [[\h\h\h\h]],
num_entries = 16,
wrap = false,
empty_text = "no entries"
}
--formats strings for ass handling
--this function is based on a similar function from https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L110
function scroll_list.ass_escape(str, replace_newline)
if replace_newline == true then replace_newline = "\\\239\187\191n" end
--escape the invalid single characters
str = str:gsub('[\\{}\n]', {
-- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if
-- it isn't followed by a recognised character, so add a zero-width
-- non-breaking space
['\\'] = '\\\239\187\191',
['{'] = '\\{',
['}'] = '\\}',
-- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
-- consecutive newlines
['\n'] = '\239\187\191\\N',
})
-- Turn leading spaces into hard spaces to prevent ASS from stripping them
str = str:gsub('\\N ', '\\N\\h')
str = str:gsub('^ ', '\\h')
if replace_newline then
str = str:gsub("\\N", replace_newline)
end
return str
end
--format and return the header string
function scroll_list:format_header_string(str)
return str
end
--appends the entered text to the overlay
function scroll_list:append(text)
if text == nil then return end
self.ass.data = self.ass.data .. text
end
--appends a newline character to the osd
function scroll_list:newline()
self.ass.data = self.ass.data .. '\\N'
end
--re-parses the list into an ass string
--if the list is closed then it flags an update on the next open
function scroll_list:update()
if self.hidden then self.flag_update = true
else self:update_ass() end
end
--prints the header to the overlay
function scroll_list:format_header()
self:append(self.header_style)
self:append(self:format_header_string(self.header))
self:newline()
end
--formats each line of the list and prints it to the overlay
function scroll_list:format_line(index, item)
self:append(self.list_style)
if index == self.selected then self:append(self.cursor_style..self.cursor..self.selected_style)
else self:append(self.indent) end
self:append(item.style)
self:append(item.ass)
self:newline()
end
--refreshes the ass text using the contents of the list
function scroll_list:update_ass()
self.ass.data = self.global_style
self:format_header()
if #self.list < 1 then
self:append(self.empty_text)
self.ass:update()
return
end
local start = 1
local finish = start+self.num_entries-1
--handling cursor positioning
local mid = math.ceil(self.num_entries/2)+1
if self.selected+mid > finish then
local offset = self.selected - finish + mid
--if we've overshot the end of the list then undo some of the offset
if finish + offset > #self.list then
offset = offset - ((finish+offset) - #self.list)
end
start = start + offset
finish = finish + offset
end
--making sure that we don't overstep the boundaries
if start < 1 then start = 1 end
local overflow = finish < #self.list
--this is necessary when the number of items in the dir is less than the max
if not overflow then finish = #self.list end
--adding a header to show there are items above in the list
if start > 1 then self:append(self.wrapper_style..(start-1)..' item(s) above\\N\\N') end
for i=start, finish do
self:format_line(i, self.list[i])
end
if overflow then self:append('\\N'..self.wrapper_style..#self.list-finish..' item(s) remaining') end
self.ass:update()
end
--moves the selector down the list
function scroll_list:scroll_down()
if self.selected < #self.list then
self.selected = self.selected + 1
self:update_ass()
elseif self.wrap then
self.selected = 1
self:update_ass()
end
end
--moves the selector up the list
function scroll_list:scroll_up()
if self.selected > 1 then
self.selected = self.selected - 1
self:update_ass()
elseif self.wrap then
self.selected = #self.list
self:update_ass()
end
end
--moves the selector to the list next page
function scroll_list:move_pagedown()
if #self.list > self.num_entries then
self.selected = self.selected + self.num_entries
if self.selected > #self.list then self.selected = #self.list end
self:update_ass()
end
end
--moves the selector to the list previous page
function scroll_list:move_pageup()
if #self.list > self.num_entries then
self.selected = self.selected - self.num_entries
if self.selected < 1 then self.selected = 1 end
self:update_ass()
end
end
--moves the selector to the list begin
function scroll_list:move_begin()
if #self.list > 1 then
self.selected = 1
self:update_ass()
end
end
--moves the selector to the list end
function scroll_list:move_end()
if #self.list > 1 then
self.selected = #self.list
self:update_ass()
end
end
--adds the forced keybinds
function scroll_list:add_keybinds()
for _,v in ipairs(self.keybinds) do
mp.add_forced_key_binding(v[1], 'dynamic/'..self.ass.id..'/'..v[2], v[3], v[4])
end
end
--removes the forced keybinds
function scroll_list:remove_keybinds()
for _,v in ipairs(self.keybinds) do
mp.remove_key_binding('dynamic/'..self.ass.id..'/'..v[2])
end
end
--opens the list and sets the hidden flag
function scroll_list:open_list()
self.hidden = false
if not self.flag_update then self.ass:update()
else self.flag_update = false ; self:update_ass() end
end
--closes the list and sets the hidden flag
function scroll_list:close_list()
self.hidden = true
self.ass:remove()
end
--modifiable function that opens the list
function scroll_list:open()
if self.hidden then self:add_keybinds() end
self:open_list()
end
--modifiable function that closes the list
function scroll_list:close()
self:remove_keybinds()
self:close_list()
end
--toggles the list
function scroll_list:toggle()
if self.hidden then self:open()
else self:close() end
end
--clears the list in-place
function scroll_list:clear()
local i = 1
while self.list[i] do
self.list[i] = nil
i = i + 1
end
end
--added alias for ipairs(list.list) for lua 5.1
function scroll_list:ipairs()
return ipairs(self.list)
end
--append item to the end of the list
function scroll_list:insert(item)
self.list[#self.list + 1] = item
end
local metatable = {
__index = function(t, key)
if scroll_list[key] ~= nil then return scroll_list[key]
elseif key == "__current" then return t.list[t.selected]
elseif type(key) == "number" then return t.list[key] end
end,
__newindex = function(t, key, value)
if type(key) == "number" then rawset(t.list, key, value)
else rawset(t, key, value) end
end,
__scroll_list = scroll_list,
__len = function(t) return #t.list end,
__ipairs = function(t) return ipairs(t.list) end
}
--creates a new list object
function scroll_list:new()
local vars
vars = {
ass = mp.create_osd_overlay('ass-events'),
hidden = true,
flag_update = true,
header = "header \\N ----------------------------------------------",
list = {},
selected = 1,
keybinds = {
{'DOWN', 'scroll_down', function() vars:scroll_down() end, {repeatable = true}},
{'UP', 'scroll_up', function() vars:scroll_up() end, {repeatable = true}},
{'PGDWN', 'move_pagedown', function() vars:move_pagedown() end, {}},
{'PGUP', 'move_pageup', function() vars:move_pageup() end, {}},
{'HOME', 'move_begin', function() vars:move_begin() end, {}},
{'END', 'move_end', function() vars:move_end() end, {}},
{'ESC', 'close_browser', function() vars:close() end, {}}
}
}
return setmetatable(vars, metatable)
end
return scroll_list:new()