osc.lua: remove NIH list formatting

All of the code to format playlist/track-list/chapter-list is
unnecessary when mpv's core can already show-text these properties.

Also an issue with this custom formatting is that showing fewer entries
than can fit on the OSD can make it seem like the playlist ends there
and there are no entries afterwards.

Also remove lots of pointless code around the track-list (mpv's track id
and the osc_id are exactly the same).

This simplification will make it easier to bind customizable commands,
otherwise yet another script message to call set_track would have to be
added, when cycle sub/audio already output information about the new
track on their own.
This commit is contained in:
Guido Cella 2024-10-11 20:24:23 +02:00 committed by Kacper Michajłow
parent 65135e0f44
commit 1a558bf5c2
2 changed files with 45 additions and 285 deletions

View File

@ -493,10 +493,6 @@ Script Commands
The OSC script listens to certain script commands. These commands can bound The OSC script listens to certain script commands. These commands can bound
in ``input.conf``, or sent by other scripts. in ``input.conf``, or sent by other scripts.
``osc-message``
Show a message on screen using the OSC. First argument is the message,
second the duration in seconds.
``osc-visibility`` ``osc-visibility``
Controls visibility mode ``never`` / ``auto`` (on mouse move) / ``always`` Controls visibility mode ``never`` / ``auto`` (on mouse move) / ``always``
and also ``cycle`` to cycle between the modes. and also ``cycle`` to cycle between the modes.
@ -515,8 +511,3 @@ to set auto mode (the default) with ``b``::
``osc-idlescreen`` ``osc-idlescreen``
Controls the visibility of the mpv logo on idle. Valid arguments are ``yes``, Controls the visibility of the mpv logo on idle. Valid arguments are ``yes``,
``no``, and ``cycle`` to toggle between yes and no. ``no``, and ``cycle`` to toggle between yes and no.
``osc-playlist``, ``osc-chapterlist``, ``osc-tracklist``
Shows a limited view of the respective type of list using the OSC. First
argument is duration in seconds.

View File

@ -1,7 +1,6 @@
local assdraw = require 'mp.assdraw' local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg' local msg = require 'mp.msg'
local opt = require 'mp.options' local opt = require 'mp.options'
local utils = require 'mp.utils'
-- --
-- Parameters -- Parameters
@ -27,9 +26,6 @@ local user_opts = {
deadzonesize = 0.5, -- size of deadzone deadzonesize = 0.5, -- size of deadzone
minmousemove = 0, -- minimum amount of pixels the mouse has to minmousemove = 0, -- minimum amount of pixels the mouse has to
-- move between ticks to make the OSC show up -- move between ticks to make the OSC show up
iamaprogrammer = false, -- use native mpv values and disable OSC
-- internal track list management (and some
-- functions that depend on it)
layout = "bottombar", layout = "bottombar",
seekbarstyle = "bar", -- bar, diamond or knob seekbarstyle = "bar", -- bar, diamond or knob
seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle
@ -94,8 +90,8 @@ local margins_opts = {
} }
local tick_delay = 1 / 60 local tick_delay = 1 / 60
local tracks_osc = {} local audio_track_count = 0
local tracks_mpv = {} local sub_track_count = 0
local window_control_box_width = 80 local window_control_box_width = 80
local layouts = {} local layouts = {}
local is_december = os.date("*t").month == 12 local is_december = os.date("*t").month == 12
@ -152,8 +148,6 @@ local state = {
marginsREQ = false, -- is a margins update pending? marginsREQ = false, -- is a margins update pending?
last_mouseX = nil, last_mouseY = nil, -- last mouse position, to detect significant mouse movement last_mouseX = nil, last_mouseY = nil, -- last mouse position, to detect significant mouse movement
mouse_in_window = false, mouse_in_window = false,
message_text = nil,
message_hide_timer = nil,
fullscreen = false, fullscreen = false,
tick_timer = nil, tick_timer = nil,
tick_last_time = 0, -- when the last tick() was run tick_last_time = 0, -- when the last tick() was run
@ -343,13 +337,6 @@ local function get_slider_value(element)
return get_slider_value_at(element, get_virt_mouse_pos()) return get_slider_value_at(element, get_virt_mouse_pos())
end end
local function countone(val)
if not user_opts.iamaprogrammer then
val = val + 1
end
return val
end
-- align: -1 .. +1 -- align: -1 .. +1
-- frame: size of the containing area -- frame: size of the containing area
-- obj: size of the object that should be positioned inside the area -- obj: size of the object that should be positioned inside the area
@ -505,224 +492,23 @@ local function render_wipe()
end end
--
-- Message display
--
-- pos is 1 based
local function limited_list(prop, pos)
local proplist = mp.get_property_native(prop, {})
local count = #proplist
if count == 0 then
return count, proplist
end
local fs = tonumber(mp.get_property('options/osd-font-size'))
local max = math.ceil(osc_param.unscaled_y*0.75 / fs)
if max % 2 == 0 then
max = max - 1
end
local delta = math.ceil(max / 2) - 1
local begi = math.max(math.min(pos - delta, count - max + 1), 1)
local endi = math.min(begi + max - 1, count)
local reslist = {}
for i=begi, endi do
local item = proplist[i]
item.current = (i == pos) and true or nil
table.insert(reslist, item)
end
return count, reslist
end
local function get_playlist()
local pos = mp.get_property_number('playlist-pos', 0) + 1
local count, limlist = limited_list('playlist', pos)
if count == 0 then
return 'Empty playlist.'
end
local message = string.format('Playlist [%d/%d]:\n', pos, count)
local show = mp.get_property_native('osd-playlist-entry')
local trailing_slash_pattern = mp.get_property("platform") == "windows"
and "[/\\]+$" or "/+$"
for _, v in ipairs(limlist) do
local entry = v.title
if not entry or show ~= 'title' then
entry = v.filename
if not entry:find("://") then
entry = select(2, utils.split_path(
entry:gsub(trailing_slash_pattern, "")))
end
end
if v.title and show == 'both' then
entry = string.format('%s (%s)', v.title, entry)
end
message = string.format('%s %s %s\n', message,
(v.current and '' or ''), entry)
end
return message
end
local function get_chapterlist()
local pos = mp.get_property_number('chapter', 0) + 1
local count, limlist = limited_list('chapter-list', pos)
if count == 0 then
return 'No chapters.'
end
local message = string.format('Chapters [%d/%d]:\n', pos, count)
for i, v in ipairs(limlist) do
local time = mp.format_time(v.time)
local title = v.title
if title == nil then
title = string.format('Chapter %02d', i)
end
message = string.format('%s[%s] %s %s\n', message, time,
(v.current and '' or ''), title)
end
return message
end
local function render_message(ass)
if state.message_hide_timer and state.message_hide_timer:is_enabled() and
state.message_text
then
local _, lines = string.gsub(state.message_text, "\\N", "")
local fontsize = tonumber(mp.get_property("options/osd-font-size"))
local outline = tonumber(mp.get_property("options/osd-border-size"))
local maxlines = math.ceil(osc_param.unscaled_y*0.75 / fontsize)
local counterscale = osc_param.playresy / osc_param.unscaled_y
fontsize = fontsize * counterscale / math.max(0.65 + math.min(lines/maxlines, 1), 1)
outline = outline * counterscale / math.max(0.75 + math.min(lines/maxlines, 1)/2, 1)
local style = "{\\bord" .. outline .. "\\fs" .. fontsize .. "}"
ass:new_event()
ass:append(style .. state.message_text)
else
state.message_text = nil
end
end
local function show_message(text, duration)
--print("text: "..text.." duration: " .. duration)
if duration == nil then
duration = tonumber(mp.get_property("options/osd-duration")) / 1000
elseif type(duration) ~= "number" then
print("duration: " .. duration)
end
-- cut the text short, otherwise the following functions
-- may slow down massively on huge input
text = string.sub(text, 0, 4000)
state.message_text = mp.command_native({"escape-ass", text})
if not state.message_hide_timer then
state.message_hide_timer = mp.add_timeout(0, request_tick)
end
state.message_hide_timer:kill()
state.message_hide_timer.timeout = duration
state.message_hide_timer:resume()
request_tick()
end
-- --
-- Tracklist Management -- Tracklist Management
-- --
local nicetypes = {video = "Video", audio = "Audio", sub = "Subtitle"}
-- updates the OSC internal playlists, should be run each time the track-layout changes -- updates the OSC internal playlists, should be run each time the track-layout changes
local function update_tracklist() local function update_tracklist()
local tracktable = mp.get_property_native("track-list", {}) audio_track_count, sub_track_count = 0, 0
-- by osc_id for _, track in pairs(mp.get_property_native("track-list")) do
tracks_osc.video, tracks_osc.audio, tracks_osc.sub = {}, {}, {} if track.type == "audio" then
-- by mpv_id audio_track_count = audio_track_count + 1
tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {} elseif track.type == "sub" then
for n = 1, #tracktable do sub_track_count = sub_track_count + 1
if tracktable[n].type ~= "unknown" then
local type = tracktable[n].type
local mpv_id = tonumber(tracktable[n].id)
-- by osc_id
table.insert(tracks_osc[type], tracktable[n])
-- by mpv_id
tracks_mpv[type][mpv_id] = tracktable[n]
tracks_mpv[type][mpv_id].osc_id = #tracks_osc[type]
end end
end end
end end
-- return a nice list of tracks of the given type (video, audio, sub)
local function get_tracklist(type)
local message = "Available " .. nicetypes[type] .. " Tracks: "
if #tracks_osc[type] == 0 then
message = message .. "none"
else
for n = 1, #tracks_osc[type] do
local track = tracks_osc[type][n]
local lang, title, selected = "unknown", "", ""
if track.lang ~= nil then lang = track.lang end
if track.title ~= nil then title = track.title end
if track.id == tonumber(mp.get_property(type)) then
selected = ""
end
message = message.."\n"..selected.." "..n..": ["..lang.."] "..title
end
end
return message
end
-- relatively change the track of given <type> by <next> tracks
--(+1 -> next, -1 -> previous)
local function set_track(type, next)
local current_track_mpv, current_track_osc
if mp.get_property(type) == "no" then
current_track_osc = 0
else
current_track_mpv = tonumber(mp.get_property(type))
current_track_osc = tracks_mpv[type][current_track_mpv].osc_id
end
local new_track_osc = (current_track_osc + next) % (#tracks_osc[type] + 1)
local new_track_mpv
if new_track_osc == 0 then
new_track_mpv = "no"
else
new_track_mpv = tracks_osc[type][new_track_osc].id
end
mp.commandv("set", type, new_track_mpv)
if new_track_osc == 0 then
show_message(nicetypes[type] .. " Track: none")
else
show_message(nicetypes[type] .. " Track: "
.. new_track_osc .. "/" .. #tracks_osc[type]
.. " [".. (tracks_osc[type][new_track_osc].lang or "unknown") .."] "
.. (tracks_osc[type][new_track_osc].title or ""))
end
end
-- get the currently selected track of <type>, OSC-style counted
local function get_track(type)
local track = mp.get_property(type)
if track ~= "no" and track ~= nil then
local tr = tracks_mpv[type][tonumber(track)]
if tr then
return tr.osc_id
end
end
return 0
end
-- WindowControl helpers -- WindowControl helpers
local function window_controls_enabled() local function window_controls_enabled()
local val = user_opts.windowcontrols local val = user_opts.windowcontrols
@ -1917,16 +1703,11 @@ local function osc_init()
end end
ne.eventresponder["mbtn_left_up"] = function () ne.eventresponder["mbtn_left_up"] = function ()
local title = mp.get_property_osd("media-title") mp.command("show-text '[${playlist-pos-1}/${playlist-count}] ${media-title}'")
if have_pl then
title = string.format("[%d/%d] %s", countone(pl_pos - 1),
pl_count, title)
end
show_message(title)
end end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () show_message(mp.get_property_osd("filename")) end function () mp.command("show-text ${filename}") end
-- playlist buttons -- playlist buttons
@ -1939,13 +1720,13 @@ local function osc_init()
function () function ()
mp.commandv("playlist-prev", "weak") mp.commandv("playlist-prev", "weak")
if user_opts.playlist_osd then if user_opts.playlist_osd then
show_message(get_playlist(), 3) mp.command("show-text ${playlist} 3000")
end end
end end
ne.eventresponder["shift+mbtn_left_up"] = ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_playlist(), 3) end function () mp.command("show-text ${playlist} 3000") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () show_message(get_playlist(), 3) end function () mp.command("show-text ${playlist} 3000") end
--next --next
ne = new_element("pl_next", "button") ne = new_element("pl_next", "button")
@ -1956,13 +1737,13 @@ local function osc_init()
function () function ()
mp.commandv("playlist-next", "weak") mp.commandv("playlist-next", "weak")
if user_opts.playlist_osd then if user_opts.playlist_osd then
show_message(get_playlist(), 3) mp.command("show-text ${playlist} 3000")
end end
end end
ne.eventresponder["shift+mbtn_left_up"] = ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_playlist(), 3) end function () mp.command("show-text ${playlist} 3000") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () show_message(get_playlist(), 3) end function () mp.command("show-text ${playlist} 3000") end
-- big buttons -- big buttons
@ -2017,13 +1798,13 @@ local function osc_init()
function () function ()
mp.commandv("add", "chapter", -1) mp.commandv("add", "chapter", -1)
if user_opts.chapters_osd then if user_opts.chapters_osd then
show_message(get_chapterlist(), 3) mp.command("show-text ${chapter-list} 3000")
end end
end end
ne.eventresponder["shift+mbtn_left_up"] = ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_chapterlist(), 3) end function () mp.command("show-text ${chapter-list} 3000") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () show_message(get_chapterlist(), 3) end function () mp.command("show-text ${chapter-list} 3000") end
--ch_next --ch_next
ne = new_element("ch_next", "button") ne = new_element("ch_next", "button")
@ -2034,13 +1815,13 @@ local function osc_init()
function () function ()
mp.commandv("add", "chapter", 1) mp.commandv("add", "chapter", 1)
if user_opts.chapters_osd then if user_opts.chapters_osd then
show_message(get_chapterlist(), 3) mp.command("show-text ${chapter-list} 3000")
end end
end end
ne.eventresponder["shift+mbtn_left_up"] = ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_chapterlist(), 3) end function () mp.command("show-text ${chapter-list} 3000") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () show_message(get_chapterlist(), 3) end function () mp.command("show-text ${chapter-list} 3000") end
-- --
update_tracklist() update_tracklist()
@ -2048,53 +1829,45 @@ local function osc_init()
--cy_audio --cy_audio
ne = new_element("cy_audio", "button") ne = new_element("cy_audio", "button")
ne.enabled = (#tracks_osc.audio > 0) ne.enabled = audio_track_count > 0
ne.content = function () ne.content = function ()
local aid = "" return ("\238\132\134" .. osc_styles.smallButtonsLlabel .. " " ..
if get_track("audio") ~= 0 then (mp.get_property_native("aid") or "-") .. "/" .. audio_track_count)
aid = get_track("audio")
end
return ("\238\132\134" .. osc_styles.smallButtonsLlabel
.. " " .. aid .. "/" .. #tracks_osc.audio)
end end
ne.eventresponder["mbtn_left_up"] = ne.eventresponder["mbtn_left_up"] =
function () set_track("audio", 1) end function () mp.command("cycle audio") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () set_track("audio", -1) end function () mp.command("cycle audio down") end
ne.eventresponder["shift+mbtn_left_down"] = ne.eventresponder["shift+mbtn_left_down"] =
function () show_message(get_tracklist("audio"), 2) end function () mp.command("show-text ${track-list/audio} 2000") end
if user_opts.scrollcontrols then if user_opts.scrollcontrols then
ne.eventresponder["wheel_down_press"] = ne.eventresponder["wheel_down_press"] =
function () set_track("audio", 1) end function () mp.command("cycle audio") end
ne.eventresponder["wheel_up_press"] = ne.eventresponder["wheel_up_press"] =
function () set_track("audio", -1) end function () mp.command("cycle audio down") end
end end
--cy_sub --cy_sub
ne = new_element("cy_sub", "button") ne = new_element("cy_sub", "button")
ne.enabled = (#tracks_osc.sub > 0) ne.enabled = sub_track_count > 0
ne.content = function () ne.content = function ()
local sid = "" return ("\238\132\135" .. osc_styles.smallButtonsLlabel .. " " ..
if get_track("sub") ~= 0 then (mp.get_property_native("sid") or "-") .. "/" .. sub_track_count)
sid = get_track("sub")
end
return ("\238\132\135" .. osc_styles.smallButtonsLlabel
.. " " .. sid .. "/" .. #tracks_osc.sub)
end end
ne.eventresponder["mbtn_left_up"] = ne.eventresponder["mbtn_left_up"] =
function () set_track("sub", 1) end function () mp.command("cycle sub") end
ne.eventresponder["mbtn_right_up"] = ne.eventresponder["mbtn_right_up"] =
function () set_track("sub", -1) end function () mp.command("cycle sub down") end
ne.eventresponder["shift+mbtn_left_down"] = ne.eventresponder["shift+mbtn_left_down"] =
function () show_message(get_tracklist("sub"), 2) end function () mp.command("show-text ${track-list/sub} 2000") end
if user_opts.scrollcontrols then if user_opts.scrollcontrols then
ne.eventresponder["wheel_down_press"] = ne.eventresponder["wheel_down_press"] =
function () set_track("sub", 1) end function () mp.command("cycle sub") end
ne.eventresponder["wheel_up_press"] = ne.eventresponder["wheel_up_press"] =
function () set_track("sub", -1) end function () mp.command("cycle sub down") end
end end
--tog_fs --tog_fs
@ -2632,9 +2405,6 @@ local function render()
-- actual rendering -- actual rendering
local ass = assdraw.ass_new() local ass = assdraw.ass_new()
-- Messages
render_message(ass)
-- actual OSC -- actual OSC
if state.osc_visible then if state.osc_visible then
render_elements(ass) render_elements(ass)
@ -2776,19 +2546,18 @@ mp.observe_property("chapter-list", "native", function(_, list)
request_init() request_init()
end) end)
mp.register_script_message("osc-message", show_message) -- These are for backwards compatibility only.
mp.register_script_message("osc-message", function(message, dur)
mp.osd_message(message, dur)
end)
mp.register_script_message("osc-chapterlist", function(dur) mp.register_script_message("osc-chapterlist", function(dur)
show_message(get_chapterlist(), dur) mp.command("show-text ${chapter-list} " .. (dur and dur * 1000 or ""))
end) end)
mp.register_script_message("osc-playlist", function(dur) mp.register_script_message("osc-playlist", function(dur)
show_message(get_playlist(), dur) mp.command("show-text ${playlist} " .. (dur and dur * 1000 or ""))
end) end)
mp.register_script_message("osc-tracklist", function(dur) mp.register_script_message("osc-tracklist", function(dur)
local message = {} mp.command("show-text ${track-list} " .. (dur and dur * 1000 or ""))
for k in pairs(nicetypes) do
table.insert(message, get_tracklist(k))
end
show_message(table.concat(message, '\n\n'), dur)
end) end)
mp.observe_property("fullscreen", "bool", function(_, val) mp.observe_property("fullscreen", "bool", function(_, val)