summaryrefslogtreecommitdiffstats
path: root/player/lua/osc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'player/lua/osc.lua')
-rw-r--r--player/lua/osc.lua615
1 files changed, 424 insertions, 191 deletions
diff --git a/player/lua/osc.lua b/player/lua/osc.lua
index af59470335..4718be44c1 100644
--- a/player/lua/osc.lua
+++ b/player/lua/osc.lua
@@ -11,6 +11,7 @@ local utils = require 'mp.utils'
local user_opts = {
showwindowed = true, -- show OSC when windowed?
showfullscreen = true, -- show OSC when fullscreen?
+ idlescreen = true, -- show mpv logo on idle
scalewindowed = 1, -- scaling of the controller when windowed
scalefullscreen = 1, -- scaling of the controller when fullscreen
scaleforcedwindow = 2, -- scaling when rendered on a forced window
@@ -34,20 +35,43 @@ local user_opts = {
seekbarstyle = "bar", -- bar, diamond or knob
seekbarhandlesize = 0.6, -- size ratio of the diamond and knob handle
seekrangestyle = "inverted",-- bar, line, slider, inverted or none
- seekrangeseparate = true, -- wether the seekranges overlay on the bar-style seekbar
+ seekrangeseparate = true, -- whether the seekranges overlay on the bar-style seekbar
seekrangealpha = 200, -- transparency of seekranges
seekbarkeyframes = true, -- use keyframes when dragging the seekbar
+ scrollcontrols = true, -- allow scrolling when hovering certain OSC elements
title = "${media-title}", -- string compatible with property-expansion
-- to be shown as OSC title
tooltipborder = 1, -- border of tooltip in bottom/topbar
timetotal = false, -- display total time instead of remaining time?
+ remaining_playtime = true, -- display the remaining time in playtime or video-time mode
+ -- playtime takes speed into account, whereas video-time doesn't
timems = false, -- display timecodes with milliseconds?
+ tcspace = 100, -- timecode spacing (compensate font size estimation)
visibility = "auto", -- only used at init to set visibility_mode(...)
boxmaxchars = 80, -- title crop threshold for box layout
boxvideo = false, -- apply osc_param.video_margins to video
windowcontrols = "auto", -- whether to show window controls
windowcontrols_alignment = "right", -- which side to show window controls on
+ windowcontrols_title = "${media-title}", -- same as title but for windowcontrols
greenandgrumpy = false, -- disable santa hat
+ livemarkers = true, -- update seekbar chapter markers on duration change
+ chapters_osd = true, -- whether to show chapters OSD on next/prev
+ playlist_osd = true, -- whether to show playlist OSD on next/prev
+ playlist_media_title = true, -- whether to use media titles as playlist entry names
+ chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable
+ unicodeminus = false, -- whether to use the Unicode minus sign character
+
+ background_color = "#000000", -- background color of the osc
+ timecode_color = "#FFFFFF", -- color of the progress bar and time color
+ title_color = "#FFFFFF", -- color of the title
+ time_pos_color = "#FFFFFF", -- color of the timecode at hovered position
+ buttons_color = "#FFFFFF", -- color of big buttons, wc buttons, and bar small buttons
+ small_buttonsL_color = "#FFFFFF", -- color of left small buttons
+ small_buttonsR_color = "#FFFFFF", -- color of right small buttons
+ top_buttons_color = "#FFFFFF", -- color of top buttons
+ held_element_color = "#999999", -- color of an element while held down
+
+ time_pos_outline_color = "#000000" -- color of the border timecodes in slimbox and TimePosBar
}
-- read options from config and command-line
@@ -64,27 +88,31 @@ local osc_param = { -- calculated by osc_init()
},
}
+function osc_color_convert(color)
+ return color:sub(6,7) .. color:sub(4,5) .. color:sub(2,3)
+end
+
local osc_styles = {
- bigButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}",
- smallButtonsL = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}",
+ bigButtons = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\3c&HFFFFFF\\fs50\\fnmpv-osd-symbols}",
+ smallButtonsL = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.small_buttonsL_color) .. "\\3c&HFFFFFF\\fs19\\fnmpv-osd-symbols}",
smallButtonsLlabel = "{\\fscx105\\fscy105\\fn" .. mp.get_property("options/osd-font") .. "}",
- smallButtonsR = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}",
- topButtons = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}",
-
- elementDown = "{\\1c&H999999}",
- timecodes = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs20}",
- vidtitle = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs12\\q2}",
- box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}",
-
- topButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}",
- smallButtonsBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}",
- timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}",
- timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}",
- vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}",
-
- wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}",
- wcTitle = "{\\1c&HFFFFFF\\fs24\\q2}",
- wcBar = "{\\1c&H000000}",
+ smallButtonsR = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.small_buttonsR_color) .. "\\3c&HFFFFFF\\fs30\\fnmpv-osd-symbols}",
+ topButtons = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.top_buttons_color) .. "\\3c&HFFFFFF\\fs12\\fnmpv-osd-symbols}",
+
+ elementDown = "{\\1c&H" .. osc_color_convert(user_opts.held_element_color) .."}",
+ timecodes = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.timecode_color) .. "\\3c&HFFFFFF\\fs20}",
+ vidtitle = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\3c&HFFFFFF\\fs12\\q2}",
+ box = "{\\rDefault\\blur0\\bord1\\1c&H" .. osc_color_convert(user_opts.background_color) .. "\\3c&HFFFFFF}",
+
+ topButtonsBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.top_buttons_color) .. "\\3c&HFFFFFF\\fs18\\fnmpv-osd-symbols}",
+ smallButtonsBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\3c&HFFFFFF\\fs28\\fnmpv-osd-symbols}",
+ timecodesBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.timecode_color) .."\\3c&HFFFFFF\\fs27}",
+ timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&H" .. osc_color_convert(user_opts.time_pos_color) .. "\\3c&H" .. osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs30}",
+ vidtitleBar = "{\\blur0\\bord0\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\3c&HFFFFFF\\fs18\\q2}",
+
+ wcButtons = "{\\1c&H" .. osc_color_convert(user_opts.buttons_color) .. "\\fs24\\fnmpv-osd-symbols}",
+ wcTitle = "{\\1c&H" .. osc_color_convert(user_opts.title_color) .. "\\fs24\\q2}",
+ wcBar = "{\\1c&H" .. osc_color_convert(user_opts.background_color) .. "}",
}
-- internal states, do not touch
@@ -101,6 +129,7 @@ local state = {
tc_ms = user_opts.timems, -- Should the timecodes display their time with milliseconds
mp_screen_sizeX, mp_screen_sizeY, -- last screen-resolution, to detect resolution changes to issue reINITs
initREQ = false, -- is a re-init request pending?
+ marginsREQ = false, -- is a margins update pending?
last_mouseX, last_mouseY, -- last mouse position, to detect significant mouse movement
mouse_in_window = false,
message_text,
@@ -114,11 +143,14 @@ local state = {
enabled = true,
input_enabled = true,
showhide_enabled = false,
+ windowcontrols_buttons = false,
+ windowcontrols_title = false,
dmx_cache = 0,
using_video_margins = false,
border = true,
maximized = false,
osd = mp.create_osd_overlay("ass-events"),
+ chapter_list = {}, -- sorted by time
}
local window_control_box_width = 80
@@ -130,7 +162,13 @@ local is_december = os.date("*t").month == 12
-- Helperfunctions
--
-function set_osd(res_x, res_y, text)
+function kill_animation()
+ state.anistart = nil
+ state.animation = nil
+ state.anitype = nil
+end
+
+function set_osd(res_x, res_y, text, z)
if state.osd.res_x == res_x and
state.osd.res_y == res_y and
state.osd.data == text then
@@ -139,7 +177,7 @@ function set_osd(res_x, res_y, text)
state.osd.res_x = res_x
state.osd.res_y = res_y
state.osd.data = text
- state.osd.z = 1000
+ state.osd.z = z
state.osd:update()
end
@@ -262,7 +300,7 @@ function get_slider_value(element)
end
function countone(val)
- if not (user_opts.iamaprogrammer) then
+ if not user_opts.iamaprogrammer then
val = val + 1
end
return val
@@ -283,7 +321,7 @@ end
function add_area(name, x1, y1, x2, y2)
-- create area if needed
- if (osc_param.areas[name] == nil) then
+ if osc_param.areas[name] == nil then
osc_param.areas[name] = {}
end
table.insert(osc_param.areas[name], {x1=x1, y1=y1, x2=x2, y2=y2})
@@ -338,7 +376,7 @@ function update_tracklist()
tracks_mpv = {}
tracks_mpv.video, tracks_mpv.audio, tracks_mpv.sub = {}, {}, {}
for n = 1, #tracktable do
- if not (tracktable[n].type == "unknown") then
+ if tracktable[n].type ~= "unknown" then
local type = tracktable[n].type
local mpv_id = tonumber(tracktable[n].id)
@@ -355,15 +393,15 @@ end
-- return a nice list of tracks of the given type (video, audio, sub)
function get_tracklist(type)
local msg = "Available " .. nicetypes[type] .. " Tracks: "
- if #tracks_osc[type] == 0 then
+ if not tracks_osc or #tracks_osc[type] == 0 then
msg = msg .. "none"
else
for n = 1, #tracks_osc[type] do
local track = tracks_osc[type][n]
local lang, title, selected = "unknown", "", "○"
- if not(track.lang == nil) then lang = track.lang end
- if not(track.title == nil) then title = track.title end
- if (track.id == tonumber(mp.get_property(type))) then
+ 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
msg = msg.."\n"..selected.." "..n..": ["..lang.."] "..title
@@ -376,7 +414,7 @@ end
--(+1 -> next, -1 -> previous)
function set_track(type, next)
local current_track_mpv, current_track_osc
- if (mp.get_property(type) == "no") then
+ if mp.get_property(type) == "no" then
current_track_osc = 0
else
current_track_mpv = tonumber(mp.get_property(type))
@@ -392,10 +430,10 @@ function set_track(type, next)
mp.commandv("set", type, new_track_mpv)
- if (new_track_osc == 0) then
+ if new_track_osc == 0 then
show_message(nicetypes[type] .. " Track: none")
else
- show_message(nicetypes[type] .. " Track: "
+ 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 ""))
@@ -418,7 +456,7 @@ end
function window_controls_enabled()
val = user_opts.windowcontrols
if val == "auto" then
- return not state.border
+ return not (state.border and state.title_bar)
else
return val ~= "no"
end
@@ -436,10 +474,10 @@ local elements = {}
function prepare_elements()
- -- remove elements without layout or invisble
+ -- remove elements without layout or invisible
local elements2 = {}
for n, element in pairs(elements) do
- if not (element.layout == nil) and (element.visible) then
+ if element.layout ~= nil and element.visible then
table.insert(elements2, element)
end
end
@@ -474,14 +512,14 @@ function prepare_elements()
local static_ass = assdraw.ass_new()
- if (element.type == "box") then
+ if element.type == "box" then
--draw box
static_ass:draw_start()
ass_draw_rr_h_cw(static_ass, 0, 0, elem_geo.w, elem_geo.h,
element.layout.box.radius, element.layout.box.hexagon)
static_ass:draw_stop()
- elseif (element.type == "slider") then
+ elseif element.type == "slider" then
--draw static slider parts
local r1 = 0
@@ -491,13 +529,13 @@ function prepare_elements()
local foV = slider_lo.border + slider_lo.gap
-- calculate positions of min and max points
- if (slider_lo.stype ~= "bar") then
+ if slider_lo.stype ~= "bar" then
r1 = elem_geo.h / 2
element.slider.min.ele_pos = elem_geo.h / 2
element.slider.max.ele_pos = elem_geo.w - (elem_geo.h / 2)
- if (slider_lo.stype == "diamond") then
+ if slider_lo.stype == "diamond" then
r2 = (elem_geo.h - 2 * slider_lo.border) / 2
- elseif (slider_lo.stype == "knob") then
+ elseif slider_lo.stype == "knob" then
r2 = r1
end
else
@@ -525,45 +563,45 @@ function prepare_elements()
r2, slider_lo.stype == "diamond")
-- marker nibbles
- if not (element.slider.markerF == nil) and (slider_lo.gap > 0) then
+ if element.slider.markerF ~= nil and slider_lo.gap > 0 then
local markers = element.slider.markerF()
for _,marker in pairs(markers) do
- if (marker > element.slider.min.value) and
- (marker < element.slider.max.value) then
+ if marker > element.slider.min.value and
+ marker < element.slider.max.value then
local s = get_slider_ele_pos_for(element, marker)
- if (slider_lo.gap > 1) then -- draw triangles
+ if slider_lo.gap > 1 then -- draw triangles
local a = slider_lo.gap / 0.5 --0.866
--top
- if (slider_lo.nibbles_top) then
- static_ass:move_to(s - (a/2), slider_lo.border)
- static_ass:line_to(s + (a/2), slider_lo.border)
+ if slider_lo.nibbles_top then
+ static_ass:move_to(s - (a / 2), slider_lo.border)
+ static_ass:line_to(s + (a / 2), slider_lo.border)
static_ass:line_to(s, foV)
end
--bottom
- if (slider_lo.nibbles_bottom) then
- static_ass:move_to(s - (a/2),
+ if slider_lo.nibbles_bottom then
+ static_ass:move_to(s - (a / 2),
elem_geo.h - slider_lo.border)
static_ass:line_to(s,
elem_geo.h - foV)
- static_ass:line_to(s + (a/2),
+ static_ass:line_to(s + (a / 2),
elem_geo.h - slider_lo.border)
end
else -- draw 2x1px nibbles
--top
- if (slider_lo.nibbles_top) then
+ if slider_lo.nibbles_top then
static_ass:rect_cw(s - 1, slider_lo.border,
s + 1, slider_lo.border + slider_lo.gap);
end
--bottom
- if (slider_lo.nibbles_bottom) then
+ if slider_lo.nibbles_bottom then
static_ass:rect_cw(s - 1,
elem_geo.h -slider_lo.border -slider_lo.gap,
s + 1, elem_geo.h - slider_lo.border);
@@ -579,7 +617,7 @@ function prepare_elements()
-- if the element is supposed to be disabled,
-- style it accordingly and kill the eventresponders
- if not (element.enabled) then
+ if not element.enabled then
element.layout.alpha[1] = 136
element.eventresponder = nil
end
@@ -591,8 +629,35 @@ end
-- Element Rendering
--
+-- returns nil or a chapter element from the native property chapter-list
+function get_chapter(possec)
+ local cl = state.chapter_list -- sorted, get latest before possec, if any
+
+ for n=#cl,1,-1 do
+ if possec >= cl[n].time then
+ return cl[n]
+ end
+ end
+end
+
function render_elements(master_ass)
+ -- when the slider is dragged or hovered and we have a target chapter name
+ -- then we use it instead of the normal title. we calculate it before the
+ -- render iterations because the title may be rendered before the slider.
+ state.forced_title = nil
+ local se, ae = state.slider_element, elements[state.active_element]
+ if user_opts.chapter_fmt ~= "no" and se and (ae == se or (not ae and mouse_hit(se))) then
+ local dur = mp.get_property_number("duration", 0)
+ if dur > 0 then
+ local possec = get_slider_value(se) * dur / 100 -- of mouse pos
+ local ch = get_chapter(possec)
+ if ch and ch.title and ch.title ~= "" then
+ state.forced_title = string.format(user_opts.chapter_fmt, ch.title)
+ end
+ end
+ end
+
for n=1, #elements do
local element = elements[n]
@@ -603,18 +668,18 @@ function render_elements(master_ass)
if element.eventresponder and (state.active_element == n) then
-- run render event functions
- if not (element.eventresponder.render == nil) then
+ if element.eventresponder.render ~= nil then
element.eventresponder.render(element)
end
if mouse_hit(element) then
-- mouse down styling
- if (element.styledown) then
+ if element.styledown then
style_ass:append(osc_styles.elementDown)
end
- if (element.softrepeat) and (state.mouse_down_counter >= 15
- and state.mouse_down_counter % 5 == 0) then
+ if element.softrepeat and state.mouse_down_counter >= 15
+ and state.mouse_down_counter % 5 == 0 then
element.eventresponder[state.active_event_source.."_down"](element)
end
@@ -627,11 +692,11 @@ function render_elements(master_ass)
elem_ass:merge(style_ass)
- if not (element.type == "button") then
+ if element.type ~= "button" then
elem_ass:merge(element.static_ass)
end
- if (element.type == "slider") then
+ if element.type == "slider" then
local slider_lo = element.layout.slider
local elem_geo = element.layout.geometry
@@ -749,8 +814,7 @@ function render_elements(master_ass)
elem_ass:draw_stop()
-- add tooltip
- if not (element.slider.tooltipF == nil) then
-
+ if element.slider.tooltipF ~= nil then
if mouse_hit(element) then
local sliderpos = get_slider_value(element)
local tooltiplabel = element.slider.tooltipF(sliderpos)
@@ -759,21 +823,21 @@ function render_elements(master_ass)
local ty
- if (an == 2) then
+ if an == 2 then
ty = element.hitbox.y1 - slider_lo.border
else
- ty = element.hitbox.y1 + elem_geo.h/2
+ ty = element.hitbox.y1 + elem_geo.h / 2
end
local tx = get_virt_mouse_pos()
- if (slider_lo.adjust_tooltip) then
- if (an == 2) then
- if (sliderpos < (s_min + 3)) then
+ if slider_lo.adjust_tooltip then
+ if an == 2 then
+ if sliderpos < (s_min + 3) then
an = an - 1
- elseif (sliderpos > (s_max - 3)) then
+ elseif sliderpos > (s_max - 3) then
an = an + 1
end
- elseif (sliderpos > (s_max-s_min)/2) then
+ elseif sliderpos > (s_max+s_min) / 2 then
an = an + 1
tx = tx - 5
else
@@ -793,20 +857,20 @@ function render_elements(master_ass)
end
end
- elseif (element.type == "button") then
+ elseif element.type == "button" then
local buttontext
if type(element.content) == "function" then
buttontext = element.content() -- function objects
- elseif not (element.content == nil) then
+ elseif element.content ~= nil then
buttontext = element.content -- text objects
end
local maxchars = element.layout.button.maxchars
- if not (maxchars == nil) and (#buttontext > maxchars) then
+ if maxchars ~= nil and #buttontext > maxchars then
local max_ratio = 1.25 -- up to 25% more chars while shrinking
local limit = math.max(0, math.floor(maxchars * max_ratio) - 3)
- if (#buttontext > limit) then
+ if #buttontext > limit then
while (#buttontext > limit) do
buttontext = buttontext:gsub(".[\128-\191]*$", "")
end
@@ -866,7 +930,7 @@ function get_playlist()
for i, v in ipairs(limlist) do
local title = v.title
local _, filename = utils.split_path(v.filename)
- if title == nil then
+ if not user_opts.playlist_media_title or title == nil then
title = filename
end
message = string.format('%s %s %s\n', message,
@@ -908,10 +972,7 @@ function show_message(text, duration)
-- may slow down massively on huge input
text = string.sub(text, 0, 4000)
- -- replace actual linebreaks with ASS linebreaks
- text = string.gsub(text, "\n", "\\N")
-
- state.message_text = text
+ 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)
@@ -962,7 +1023,7 @@ function new_element(name, type)
elements[name].styledown = (type == "button")
elements[name].state = {}
- if (type == "slider") then
+ if type == "slider" then
elements[name].slider = {min = {value = 0}, max = {value = 100}}
end
@@ -971,7 +1032,7 @@ function new_element(name, type)
end
function add_layout(name)
- if not (elements[name] == nil) then
+ if elements[name] ~= nil then
-- new layout
elements[name].layout = {}
@@ -979,11 +1040,11 @@ function add_layout(name)
elements[name].layout.layer = 50
elements[name].layout.alpha = {[1] = 0, [2] = 255, [3] = 255, [4] = 255}
- if (elements[name].type == "button") then
+ if elements[name].type == "button" then
elements[name].layout.button = {
maxchars = nil,
}
- elseif (elements[name].type == "slider") then
+ elseif elements[name].type == "slider" then
-- slider defaults
elements[name].layout.slider = {
border = 1,
@@ -996,7 +1057,7 @@ function add_layout(name)
tooltip_an = 2,
alpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255},
}
- elseif (elements[name].type == "box") then
+ elseif elements[name].type == "box" then
elements[name].layout.box = {radius = 0, hexagon = false}
end
@@ -1099,9 +1160,8 @@ function window_controls(topbar)
-- deadzone below window controls
local sh_area_y0, sh_area_y1
sh_area_y0 = user_opts.barmargin
- sh_area_y1 = (wc_geo.y + (wc_geo.h / 2)) +
- get_align(1 - (2 * user_opts.deadzonesize),
- osc_param.playresy - (wc_geo.y + (wc_geo.h / 2)), 0, 0)
+ sh_area_y1 = wc_geo.y + get_align(1 - (2 * user_opts.deadzonesize),
+ osc_param.playresy - wc_geo.y, 0, 0)
add_area("showhide_wc", wc_geo.x, sh_area_y0, wc_geo.w, sh_area_y1)
if topbar then
@@ -1115,10 +1175,9 @@ function window_controls(topbar)
-- Window Title
ne = new_element("wctitle", "button")
ne.content = function ()
- local title = mp.command_native({"expand-text", user_opts.title})
- -- escape ASS, and strip newlines and trailing slashes
- title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{")
- return not (title == "") and title or "mpv"
+ local title = mp.command_native({"expand-text", user_opts.windowcontrols_title})
+ title = title:gsub("\n", " ")
+ return title ~= "" and mp.command_native({"escape-ass", title}) or "mpv"
end
local left_pad = 5
local right_pad = 10
@@ -1152,8 +1211,8 @@ layouts["box"] = function ()
}
-- make sure the OSC actually fits into the video
- if (osc_param.playresx < (osc_geo.w + (2 * osc_geo.p))) then
- osc_param.playresy = (osc_geo.w+(2*osc_geo.p))/osc_param.display_aspect
+ if osc_param.playresx < (osc_geo.w + (2 * osc_geo.p)) then
+ osc_param.playresy = (osc_geo.w + (2 * osc_geo.p)) / osc_param.display_aspect
osc_param.playresx = osc_param.playresy * osc_param.display_aspect
end
@@ -1327,8 +1386,8 @@ layouts["slimbox"] = function ()
}
-- make sure the OSC actually fits into the video
- if (osc_param.playresx < (osc_geo.w)) then
- osc_param.playresy = (osc_geo.w)/osc_param.display_aspect
+ if osc_param.playresx < (osc_geo.w) then
+ osc_param.playresy = (osc_geo.w) / osc_param.display_aspect
osc_param.playresx = osc_param.playresy * osc_param.display_aspect
end
@@ -1365,9 +1424,9 @@ layouts["slimbox"] = function ()
-- styles
local styles = {
- box = "{\\rDefault\\blur0\\bord1\\1c&H000000\\3c&HFFFFFF}",
- timecodes = "{\\1c&HFFFFFF\\3c&H000000\\fs20\\bord2\\blur1}",
- tooltip = "{\\1c&HFFFFFF\\3c&H000000\\fs12\\bord1\\blur0.5}",
+ box = "{\\rDefault\\blur0\\bord1\\1c&H" .. osc_color_convert(user_opts.background_color) .. "\\3c&HFFFFFF}",
+ timecodes = "{\\1c&H" .. osc_color_convert(user_opts.timecode_color) .. "\\3c&H" .. osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs20\\bord2\\blur1}",
+ tooltip = "{\\1c&H" .. osc_color_convert(user_opts.time_pos_color).. "\\3c&H" .. osc_color_convert(user_opts.time_pos_outline_color) .. "\\fs12\\bord1\\blur0.5}",
}
@@ -1379,7 +1438,7 @@ layouts["slimbox"] = function ()
lo.style = osc_styles.box
lo.alpha[1] = user_opts.boxalpha
lo.alpha[3] = 0
- if not (user_opts["seekbarstyle"] == "bar") then
+ if user_opts["seekbarstyle"] ~= "bar" then
lo.box.radius = osc_geo.r
lo.box.hexagon = user_opts["seekbarstyle"] == "diamond"
end
@@ -1439,6 +1498,11 @@ function bar_layout(direction)
local padY = 3
local buttonW = 27
local tcW = (state.tc_ms) and 170 or 110
+ if user_opts.tcspace >= 50 and user_opts.tcspace <= 200 then
+ -- adjust our hardcoded font size estimation
+ tcW = tcW * user_opts.tcspace / 100
+ end
+
local tsW = 90
local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2
@@ -1456,7 +1520,7 @@ function bar_layout(direction)
padwc_r = window_control_box_width
end
- if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then
+ if osc_param.display_aspect > 0 and osc_param.playresx < minW then
osc_param.playresy = minW / osc_param.display_aspect
osc_param.playresx = osc_param.playresy * osc_param.display_aspect
end
@@ -1479,13 +1543,11 @@ function bar_layout(direction)
if direction > 0 then
-- deadzone below OSC
sh_area_y0 = user_opts.barmargin
- sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) +
- get_align(1 - (2*user_opts.deadzonesize),
- osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0)
+ sh_area_y1 = osc_geo.y + get_align(1 - (2 * user_opts.deadzonesize),
+ osc_param.playresy - osc_geo.y, 0, 0)
else
-- deadzone above OSC
- sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize),
- osc_geo.y - (osc_geo.h / 2), 0, 0)
+ sh_area_y0 = get_align(-1 + (2 * user_opts.deadzonesize), osc_geo.y, 0, 0)
sh_area_y1 = osc_param.playresy - user_opts.barmargin
end
add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1)
@@ -1607,7 +1669,7 @@ function bar_layout(direction)
lo.style = osc_styles.timecodesBar
lo.alpha[1] =
math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8)
- if not (user_opts["seekbarstyle"] == "bar") then
+ if user_opts["seekbarstyle"] ~= "bar" then
lo.box.radius = geo.h / 2
lo.box.hexagon = user_opts["seekbarstyle"] == "diamond"
end
@@ -1681,15 +1743,31 @@ function validate_user_opts()
user_opts.windowcontrols_alignment .. "\". Ignoring.")
user_opts.windowcontrols_alignment = "right"
end
+
+ local colors = {
+ user_opts.background_color, user_opts.top_buttons_color,
+ user_opts.small_buttonsL_color, user_opts.small_buttonsR_color,
+ user_opts.buttons_color, user_opts.title_color,
+ user_opts.timecode_color, user_opts.time_pos_color,
+ user_opts.held_element_color, user_opts.time_pos_outline_color,
+ }
+ for _, color in pairs(colors) do
+ if color:find("^#%x%x%x%x%x%x$") == nil then
+ msg.warn("'" .. color .. "' is not a valid color")
+ end
+ end
end
function update_options(list)
validate_user_opts()
request_tick()
visibility_mode(user_opts.visibility, true)
+ update_duration_watch()
request_init()
end
+local UNICODE_MINUS = string.char(0xe2, 0x88, 0x92) -- UTF-8 for U+2212 MINUS SIGN
+
-- OSC INIT
function osc_init()
msg.debug("osc_init")
@@ -1699,7 +1777,7 @@ function osc_init()
local display_w, display_h, display_aspect = mp.get_osd_size()
local scale = 1
- if (mp.get_property("video") == "no") then -- dummy/forced window
+ if mp.get_property("video") == "no" then -- dummy/forced window
scale = user_opts.scaleforcedwindow
elseif state.fullscreen then
scale = user_opts.scalefullscreen
@@ -1713,7 +1791,7 @@ function osc_init()
osc_param.unscaled_y = display_h
end
osc_param.playresy = osc_param.unscaled_y / scale
- if (display_aspect > 0) then
+ if display_aspect > 0 then
osc_param.display_aspect = display_aspect
end
osc_param.playresx = osc_param.playresy * osc_param.display_aspect
@@ -1738,15 +1816,15 @@ function osc_init()
ne = new_element("title", "button")
ne.content = function ()
- local title = mp.command_native({"expand-text", user_opts.title})
- -- escape ASS, and strip newlines and trailing slashes
- title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{")
- return not (title == "") and title or "mpv"
+ local title = state.forced_title or
+ mp.command_native({"expand-text", user_opts.title})
+ title = title:gsub("\n", " ")
+ return title ~= "" and mp.command_native({"escape-ass", title}) or "mpv"
end
ne.eventresponder["mbtn_left_up"] = function ()
local title = mp.get_property_osd("media-title")
- if (have_pl) then
+ if have_pl then
title = string.format("[%d/%d] %s", countone(pl_pos - 1),
pl_count, title)
end
@@ -1766,7 +1844,9 @@ function osc_init()
ne.eventresponder["mbtn_left_up"] =
function ()
mp.commandv("playlist-prev", "weak")
- show_message(get_playlist(), 3)
+ if user_opts.playlist_osd then
+ show_message(get_playlist(), 3)
+ end
end
ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_playlist(), 3) end
@@ -1781,7 +1861,9 @@ function osc_init()
ne.eventresponder["mbtn_left_up"] =
function ()
mp.commandv("playlist-next", "weak")
- show_message(get_playlist(), 3)
+ if user_opts.playlist_osd then
+ show_message(get_playlist(), 3)
+ end
end
ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_playlist(), 3) end
@@ -1796,7 +1878,11 @@ function osc_init()
ne.content = function ()
if mp.get_property("pause") == "yes" then
- return ("\238\132\129")
+ if mp.get_property("play-direction", "forward") ~= "backward" then
+ return ("\238\132\129")
+ else
+ return ("\238\132\144")
+ end
else
return ("\238\128\130")
end
@@ -1836,7 +1922,9 @@ function osc_init()
ne.eventresponder["mbtn_left_up"] =
function ()
mp.commandv("add", "chapter", -1)
- show_message(get_chapterlist(), 3)
+ if user_opts.chapters_osd then
+ show_message(get_chapterlist(), 3)
+ end
end
ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_chapterlist(), 3) end
@@ -1851,7 +1939,9 @@ function osc_init()
ne.eventresponder["mbtn_left_up"] =
function ()
mp.commandv("add", "chapter", 1)
- show_message(get_chapterlist(), 3)
+ if user_opts.chapters_osd then
+ show_message(get_chapterlist(), 3)
+ end
end
ne.eventresponder["shift+mbtn_left_up"] =
function () show_message(get_chapterlist(), 3) end
@@ -1867,7 +1957,7 @@ function osc_init()
ne.enabled = (#tracks_osc.audio > 0)
ne.content = function ()
local aid = "–"
- if not (get_track("audio") == 0) then
+ if get_track("audio") ~= 0 then
aid = get_track("audio")
end
return ("\238\132\134" .. osc_styles.smallButtonsLlabel
@@ -1880,13 +1970,20 @@ function osc_init()
ne.eventresponder["shift+mbtn_left_down"] =
function () show_message(get_tracklist("audio"), 2) end
+ if user_opts.scrollcontrols then
+ ne.eventresponder["wheel_down_press"] =
+ function () set_track("audio", 1) end
+ ne.eventresponder["wheel_up_press"] =
+ function () set_track("audio", -1) end
+ end
+
--cy_sub
ne = new_element("cy_sub", "button")
ne.enabled = (#tracks_osc.sub > 0)
ne.content = function ()
local sid = "–"
- if not (get_track("sub") == 0) then
+ if get_track("sub") ~= 0 then
sid = get_track("sub")
end
return ("\238\132\135" .. osc_styles.smallButtonsLlabel
@@ -1899,10 +1996,17 @@ function osc_init()
ne.eventresponder["shift+mbtn_left_down"] =
function () show_message(get_tracklist("sub"), 2) end
+ if user_opts.scrollcontrols then
+ ne.eventresponder["wheel_down_press"] =
+ function () set_track("sub", 1) end
+ ne.eventresponder["wheel_up_press"] =
+ function () set_track("sub", -1) end
+ end
+
--tog_fs
ne = new_element("tog_fs", "button")
ne.content = function ()
- if (state.fullscreen) then
+ if state.fullscreen then
return ("\238\132\137")
else
return ("\238\132\136")
@@ -1914,10 +2018,11 @@ function osc_init()
--seekbar
ne = new_element("seekbar", "slider")
- ne.enabled = not (mp.get_property("percent-pos") == nil)
+ ne.enabled = mp.get_property("percent-pos") ~= nil
+ state.slider_element = ne.enabled and ne or nil -- used for forced_title
ne.slider.markerF = function ()
local duration = mp.get_property_number("duration", nil)
- if not (duration == nil) then
+ if duration ~= nil then
local chapters = mp.get_property_native("chapter-list", {})
local markers = {}
for n = 1, #chapters do
@@ -1932,7 +2037,7 @@ function osc_init()
function () return mp.get_property_number("percent-pos", nil) end
ne.slider.tooltipF = function (pos)
local duration = mp.get_property_number("duration", nil)
- if not ((duration == nil) or (pos == nil)) then
+ if duration ~= nil and pos ~= nil then
possec = duration * (pos / 100)
return mp.format_time(possec)
else
@@ -1948,7 +2053,7 @@ function osc_init()
return nil
end
local duration = mp.get_property_number("duration", nil)
- if (duration == nil) or duration <= 0 then
+ if duration == nil or duration <= 0 then
return nil
end
local ranges = cache_state["seekable-ranges"]
@@ -1970,8 +2075,8 @@ function osc_init()
-- sent when the user is done seeking, so we need to throw away
-- identical seeks
local seekto = get_slider_value(element)
- if (element.state.lastseek == nil) or
- (not (element.state.lastseek == seekto)) then
+ if element.state.lastseek == nil or
+ element.state.lastseek ~= seekto then