summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2025-05-19 21:05:32 -0700
committerDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2025-05-19 21:05:32 -0700
commit66f0cc8d069644af4fd8da888664a85784d57339 (patch)
tree933283ba9cb9cfd1458dcd38991d235cfa0d7383
parenteec40d039986119f4e39b2c6e43053da549edc8d (diff)
downloadmpv-iptv-menu-66f0cc8d069644af4fd8da888664a85784d57339.tar.gz
mpv-iptv-menu-66f0cc8d069644af4fd8da888664a85784d57339.tar.xz
add movie posters as an OSD overlay
-rw-r--r--main.lua153
1 files changed, 146 insertions, 7 deletions
diff --git a/main.lua b/main.lua
index 10ccb03..db9f3c4 100644
--- a/main.lua
+++ b/main.lua
@@ -28,6 +28,9 @@ local xc_user = mp.get_opt('iptv_menu.xc_user')
local xc_pass = mp.get_opt('iptv_menu.xc_pass')
local osd = mp.create_osd_overlay('ass-events')
+local osd_width = 0
+local osd_height = 0
+local osd_scale = 1
local osd_lines = math.floor((720 / font_size) + 0.5) - 1
local osd_padding = math.floor((720 - (osd_lines * font_size)) / 2)
local osd_cursor_glyph = '{\\p1\\pbo' .. math.floor(font_size / 5) .. '}' ..
@@ -38,6 +41,7 @@ local osd_bg = mp.create_osd_overlay('ass-events')
osd_bg.z = -1
osd_bg.data = '{\\pos(0,0)}' .. colours.bg ..
'{\\p1}m 0 0 l 7680 0 7680 720 0 720{\\p0}'
+local osd_img
local objects = {}
local epg = {}
@@ -124,6 +128,24 @@ local function write_json_file(fn, data)
f:close()
end
+local function get_image_path(url, dl)
+ local path = 'img/' .. url:gsub('%W', '_')
+
+ local f = utils.file_info(path)
+ if not f then
+ if not dl then
+ return
+ end
+
+ local cmd = 'curl -sSfLo \'' .. path .. '\'' ..
+ ' \'' .. url .. '\''
+ print('exec: ' .. cmd)
+ os.execute(cmd)
+ end
+
+ return path
+end
+
local function add_object(obj)
objects[obj.id] = obj
@@ -370,6 +392,80 @@ local function osd_option_path(opt, info)
return str
end
+local function update_osd_image(path, menu_res)
+ -- images require *real* dimensions and coordinates, unlike other OSD
+ -- functions which scale the given values automatically
+ local padding = osd_scale * osd_padding
+ local start = osd_scale * menu_res.x1
+ local fs = osd_scale * font_size
+
+ -- width is generally computed to 2/3 (standard aspect ratio of movie
+ -- posters) of OSD height. when longer OSD text extends into this area,
+ -- the remaining space is used, with a minimum font-size-derived value
+ -- when there is not enough (or any) space left, which may overlap the
+ -- tail end of text.
+ --
+ -- for consistency, any source images with a different aspect ratio are
+ -- resized, confining them to the area of a "standard" poster.
+ --
+ -- because we have only the total width of the current OSD text, we
+ -- cannot slightly reduce the image width to avoid overlapping some
+ -- longer line at the bottom, as we do not know where the offending
+ -- line is. if it were possible to place images *under* text, maybe
+ -- we'd allow overlap, but mpv currently hard-codes this order.
+ local ratio = 2/3
+ local w = math.floor(math.max(3 * fs * ratio,
+ math.min(osd_width - start - 2*padding,
+ (osd_height - 2*padding) * ratio)))
+ local h = math.floor(w / ratio)
+ local x = math.floor(osd_width - padding - w)
+ local y = math.floor(padding)
+
+ local cmd
+
+ if osd_img and path == osd_img.path and w == osd_img.cmd.w and
+ h == osd_img.cmd.h then
+ if x == osd_img.cmd.x and y == osd_img.cmd.y then
+ return
+ end
+
+ goto disp
+ end
+
+ cmd = 'magick \'' .. path .. '\'' ..
+ ' -background none' ..
+ ' -gravity northwest' ..
+ ' -resize ' .. w .. 'x' .. h ..
+ ' -extent ' .. w .. 'x' .. h ..
+ ' tmp.rgba'
+ print('exec: ' .. cmd)
+ os.execute(cmd)
+
+ ::disp::
+ print('reloading img')
+ osd_img = {
+ path=path,
+ cmd={
+ name='overlay-add',
+ id=0,
+ file='tmp.rgba',
+ w=w,
+ h=h,
+ x=x,
+ y=y,
+ fmt='bgra',
+ offset=0,
+ stride=4*w,
+ },
+ }
+ mp.command_native(osd_img.cmd)
+end
+
+local function remove_osd_image()
+ mp.command_native({name='overlay-remove', id=osd_img.cmd.id})
+ osd_img = nil
+end
+
local function update_osd()
local out = {}
@@ -381,23 +477,42 @@ local function update_osd()
end
local menu = menus[depth]
+
+ local img
+ if menu.img_url then
+ img = get_image_path(menu.img_url, true)
+ end
+
for i = menu.view_top, math.min(
menu.view_top + osd_menu_lines() - 1, #menu.options) do
local opt = menu.options[i]
+
+ local selected = i == menu.cursor and not menu.search_active
local info = {
- selected=(i == menu.cursor and not menu.search_active),
+ selected=selected,
empty=(opt.type == 'group' and not opt.lazy and
#opt.children == 0),
}
out[#out+1] = osd_option_icons(opt, info) ..
osd_option_text(opt, info) ..
osd_option_path(opt, info)
+
+ if selected and opt.stream_icon then
+ img = get_image_path(opt.stream_icon)
+ end
end
-- \q2 disables line wrapping
osd.data = '{\\q2\\fs' .. font_size .. '\\pos(' .. osd_padding ..
',' .. osd_padding .. ')}' .. table.concat(out, '\\N')
- osd:update()
+
+ osd.compute_bounds = not not img
+ local res = osd:update()
+ if img then
+ update_osd_image(img, res)
+ elseif osd_img then
+ remove_osd_image()
+ end
osd_bg:update()
end
@@ -921,15 +1036,16 @@ local function open_option_movie_info(opt)
end
end
- push_menu({
+ local m = {
options=options,
title='Movie Info: ' .. opt.name,
- })
- update_osd()
-
+ }
if info.cover_big then
- mp.commandv('loadfile', info.cover_big)
+ m.img_url = info.cover_big
end
+
+ push_menu(m)
+ update_osd()
end
local function open_option_info()
@@ -953,6 +1069,10 @@ local function search_menu_options_build(options, t, path)
local path = path or {}
for _, v in ipairs(options) do
+ if not v.type then
+ goto continue
+ end
+
if not t[v.type] then
t[v.type] = {}
end
@@ -968,6 +1088,8 @@ local function search_menu_options_build(options, t, path)
search_menu_options_build(
group_menu_options(v), t, path)
end
+
+ ::continue::
end
end
@@ -1196,6 +1318,15 @@ local function toggle_menu()
osd_bg.hidden = osd.hidden
osd_bg:update()
+ if osd_img then
+ if osd.hidden then
+ mp.command_native(
+ {name='overlay-remove', id=osd_img.cmd.id})
+ else
+ mp.command_native(osd_img.cmd)
+ end
+ end
+
if osd.hidden then
unbind_keys()
elseif menus[depth].search_active then
@@ -1205,6 +1336,14 @@ local function toggle_menu()
end
end
+mp.observe_property('osd-dimensions', 'native', function(_, val)
+ osd_width = val.w
+ osd_height = val.h
+ osd_scale = osd_height / 720
+
+ update_osd()
+end)
+
mp.register_event('start-file', function()
playing_id = mp.get_opt('iptv_menu.playing_id')
update_osd()