[WIP] mpv osc.lua theme
Ever since my GPU died, I've been using mpv since my super-old GPU has terrible OpenGL support (so I'm stuck with vo=x11). Past few days I've been trying to turn the bomi/mpvz look into an osc.lua theme which can be used with mpv itself. It'll be far more complicated to code, but it'll work for anyone who just want's it to look nice without losing mpv's feature set.

Here's the base osc.lua we can copy to ~/.config/mpv/scripts/osc.lua.
- https://github.com/mpv-player/mpv/blob/master/player/lua/osc.lua
osc_tethys.luaWIP: https://gist.github.com/Zren/53afba67b4c6cd27eabe47d11a729815
Then I added this to ~/.config/mpv/mpv.conf
keep-open=yes
sub-scale-with-window=no
osd-scale-by-window=no
keepaspect-window=no
osc=no
border=no
Layout
I created a new layout section based on bottombar.
local user_opts = {
...
-- layout = "bottombar",
layout = "tethys",
}
layouts["tethys"] = function()
local direction = -1
local seekbarHeight = 20
local controlsHeight = 64
...
end
I basically ended doing the buttons like so:
---- Left Section (Added Left-to-Right)
-- Playback control buttons
geo = {
x = leftX + leftSectionWidth + buttonW/2,
y = line1Y + buttonH/2,
an = 5, -- x,y is center
w = buttonW,
h = buttonH,
}
lo = add_layout("playpause")
lo.geometry = geo
lo.style = buttonStyle
setButtonTooltip(lo, "Play (p / Space)")
leftSectionWidth = leftSectionWidth + geo.w
anstands for alignment, which adds{\\an(5)}to the ass text.- https://github.com/mpv-player/mpv/blob/master/player/lua/assdraw.lua#L43
- https://github.com/libass/libass/wiki/ASSv5-Override-Tags#alignment---ainteger2-x
1means the (x,y) is the bottom-left,4iscenter-left,7is top-left.5is center and9is top-right.- When aligning a button to the top-left, it's text inside the button is also aligned to the top-left (which is annoying).
Icons
- The
mpv-osd-symbolsfont is bundled, and basically forced for the OSD.- https://github.com/mpv-player/mpv/blob/master/sub/osd_libass.c#L57
- I tried creating a modified font with the tethys play icon. I installed it to the local user using KFontView. Then I placed
{\\fn(tethys-osd-symbols)}}in front of the playpause icon contents. It doesn't appear to have worked. Creating a custom font and distributing it is too complicated anyways, but was an annoying setback. - https://github.com/mpv-player/mpv/blob/master/player/lua/osc.lua#L1839-L1850
Eventually I noticed the mpv icon (and santa hat during December) when mpv is launched with no video is drawn using a path!
local logo_lines = {
-- White border
"{\\c&HE5E5E5&\\p6}m 895 10 b 401 10 0 410 0 905 0 1399 401 1800 895 1800 1390 1800 1790 1399 1790 905 1790 410 1390 10 895 10 {\\p0}",
-- Purple fill
"{\\c&H682167&\\p6}m 925 42 b 463 42 87 418 87 880 87 1343 463 1718 925 1718 1388 1718 1763 1343 1763 880 1763 418 1388 42 925 42{\\p0}",
...
}
...
local ass = assdraw.ass_new()
-- mpv logo
for i, line in ipairs(logo_lines) do
ass:new_event()
ass:append(line_prefix .. line)
end
I tried taking the path in the SVG and placing it there. Unfortunately, the SVG path is a little different. I noticed that mpv used the b command which doesn't appear in the mozilla docs.
However even if we assume the b is the same as a bezier curve, the SVG path uses delta c coordinates instead of absolute C coordinates which is what the b seems to be using.
<path d="m 31.000001,21 c 2.964454,2.052317 2.964454,2.947684 0,5.000001 C 20.963866,32.948092 12,39 9.9999997,39 8,39 8,36 8,23.499999 8,12 8,9 9.9999997,9 12,9 20.963866,14.051906 31.000001,21 Z">
<path d="m 31 21 c 3 2 3 3 0 5 C 21 33 12 39 10 39 8 39 8 36 8 23 8 12 8 9 10 9 12 9 21 14 31 21">
I ended up needing to export the svg as an .html file with Inkscape, then manually convert
ctx.moveTo(31.000001, 21.000000);
ctx.bezierCurveTo(33.964455, 23.052317, 33.964455, 23.947684, 31.000001, 26.000001);
ctx.bezierCurveTo(20.963866, 32.948092, 12.000000, 39.000000, 10.000000, 39.000000);
ctx.bezierCurveTo(8.000000, 39.000000, 8.000000, 36.000000, 8.000000, 23.499999);
ctx.bezierCurveTo(8.000000, 12.000000, 8.000000, 9.000000, 10.000000, 9.000000);
ctx.bezierCurveTo(12.000000, 9.000000, 20.963866, 14.051906, 31.000001, 21.000000);
to the following path:
local tethys_icon_play = {
"{\\c&HC0C0C0&\\p1}m 31 21 b 34 23 34 24 31 26 b 21 33 12 39 10 39 b 8 39 8 36 8 23.5 b 8 12 8 9 10 9 b 12 9 21 14 31 21{\\p0}",
}
As a final note, it seems the {\\p1} stands for scale. The mpv/santa hat icons use {\\p6} which I assume stands for 1/6th scale since the coordinates given are huge (401 10 0 410 0 905). I needed to change it to 1/1 scale to even see my 44x44 icon.
I still need to adjust the icon position a little, so it's not a drop in replacement.

Hover Effect
mpv doesn't have any hover animations, the only hover effect is for the seekbar timestamp.
I Managed to create a hover effect by adding the following to the bottom of render_elements() under the button section.
local buttonHovered = mouse_hit(element)
if buttonHovered then
buttontext = "{\\c&HFFFFFF}" .. buttontext
local shadow_ass = assdraw.ass_new()
shadow_ass:merge(style_ass)
shadow_ass:append("{\\blur5}" .. buttontext .. "{\\blur0}")
master_ass:merge(shadow_ass)
end
elem_ass:append(buttontext)
- It seems the
{{\\blur0}}formatting accepts a value between0and20.- https://github.com/mpv-player/mpv/blob/master/sub/osd.c#L63
Tooltips
I added rough tooltips by adding this to render_elements() under the button section.
elem_ass:append(buttontext)
-- Tooltip
local button_lo = element.layout.button
if buttonHovered and (not (button_lo.tooltip == nil)) then
-- tooltip label
local tx = button_lo.tooltip_geo.x -- element.hitbox.x1
local ty = button_lo.tooltip_geo.y -- element.hitbox.y1
local tooltipAlpha = {[1] = 0, [2] = 255, [3] = 88, [4] = 255}
elem_ass:new_event()
elem_ass:pos(tx, ty)
elem_ass:an(button_lo.tooltip_an)
elem_ass:append(button_lo.tooltip_style)
ass_append_alpha(elem_ass, tooltipAlpha, 0)
elem_ass:append(button_lo.tooltip)
end
and the following setter to adjust the tooltip based on how close to the window edge it is.
local buttonTooltipStyle = ("{\\blur0\\bord(1)\\1c&HFFFFFF\\3c&H000000\\fs(%d)}"):format(24)
function setButtonTooltip(button_lo, text)
button_lo.button.tooltip = text
button_lo.button.tooltip_style = buttonTooltipStyle
local hw = button_lo.geometry.w/2
local ty = osc_geo.y + padY * direction
local an
local tx
local edgeThreshold = 60
if button_lo.geometry.x - edgeThreshold < osc_geo.x + padX then
an = 1 -- x,y is bottom-left
tx = math.max(osc_geo.x + padX, button_lo.geometry.x - hw)
elseif osc_geo.x + osc_geo.w - padX < button_lo.geometry.x + edgeThreshold then
an = 3 -- x,y is bottom-right
tx = math.min(button_lo.geometry.x + hw, osc_geo.x + osc_geo.w - padX)
else
an = 2 -- x,y is bottom-center
tx = button_lo.geometry.x
end
button_lo.button.tooltip_an = an
button_lo.button.tooltip_geo = { x = tx , y = ty }
end
Right now, the tooltips are very basic. I'll need to work improving them to have a rounded bg and support multiple lines of text since MPV has multiple actions like Left navigating 10s and Shift+Left navigating 1s.
Track Selection
It would be coo to create a merged audio/subtitle button with a popup like Netflix. Might be too complicated to have multiple generated lists of buttons though.
Playlist
Since mpv has seek fwd/back and chapter next/prev buttons, I've moved the playlist next/prev buttons to the right side like Netflix.
Seekbar Thumbnails
This is probably the most unlikely feature to add. I do remember a lua script that would call ffmpeg to generate a cache of thumbnails every 10sec or so. However that would be an ugly approach.
Progress Update

I've managed to iron out the custom button icons. Needed to heavily modify the slider code to support multiple colors for the handle/bg/progress. I've just noticed the cache color is the progress color instead of a gray/white when taking the screenshot.
Since I haven't uploaded a screenshot, here's what the blurred hover effect and tooltip looks like:

https://gist.github.com/Zren/53afba67b4c6cd27eabe47d11a729815
TODO:
- [x] Cache seekbar color should be gray and drawn under handle.
- [x] Smaller text in subtitle selector
- [x] Nicer looking chapter ticks like bomi.
- [ ] Possible make the seek "snap" to the chapter start on hover.
- [x] Change
sub-pos-ywhen osd visible/hidden
Anything else besides those will probably just get modified when I grow bored. The existing icons aren't rounded like tethys but most are fine for now.

I might eventually modify the window controls to be larger, as they're annoying to click when the player is smaller and the osc scales super small.
https://github.com/Zren/mpv-osc-tethys
I just figured out that I can add m 0 0 m 44 44 in front of the path to create a "viewbox" around the icon so that the icon retains the whitespace around it when aligned. This is particularly important when dealing with the volume icons as their width changes. Up till now we couldn't use a center alignment for the volume icon, but instead used center-left to keep the "speaker" from as volume went up/down.
More can be found out in the https://github.com/Zren/mpv-osc-tethys/compare/master...iconrefactor branch.