--[[ A simple script that shows a pause indicator, on pause https://github.com/Samillion/ModernZ/tree/main/extras/pause-indicator-lite --]] local options = { -- indicator icon type indicator_icon = "pause", -- indicator icon type. "pause", "play" indicator_stay = true, -- keep indicator visibile during pause indicator_timeout = 0.6, -- timeout (seconds) if indicator doesn't stay -- keybind keybind_allow = true, -- allow keybind to toggle pause keybind_set = "mbtn_left", -- the used keybind to toggle pause keybind_mode = "onpause", -- mode to activate keybind. "onpause", "always" keybind_eof_disable = true, -- disable keybind on eof (end of file) -- icon colors & opacity icon_color = "#FFFFFF", -- icon fill color icon_border_color = "#111111", -- icon border color icon_border_width = 1.5, -- icon border width icon_opacity = 40, -- icon opacity (0-100) -- pause icon rectangles_width = 30, -- width of rectangles rectangles_height = 80, -- height of rectangles rectangles_spacing = 20, -- spacing between the two rectangles -- play icon triangle_width = 80, -- width of triangle triangle_height = 80, -- height of triangle -- best with pause icon flash_play_icon = true, -- flash play icon on unpause flash_icon_timeout = 0.3, -- timeout (seconds) for flash icon -- icon style used in ModernZ osc fluent_icons = false, -- requires fonts/fluent-system-icons.ttf fluent_icon_size = 80, -- fluent icon size -- mute options mute_indicator = false, -- show a mute indicator (requires fluent font) mute_indicator_pos = "middle_right", -- position of mute indicator. top_left, top_right, top_center -- also: middle_*, bottom_* same as top_* (ie: bottom_right) } local msg = require "mp.msg" require 'mp.options'.read_options(options, "pause_indicator_lite") -- convert color from hex (adjusted from mpv/osc.lua) local function convert_color(color) if color:find("^#%x%x%x%x%x%x$") == nil then msg.warn("'" .. color .. "' is not a valid color, using default '#FFFFFF'") return "FFFFFF" -- color fallback end return color:sub(6,7) .. color:sub(4,5) .. color:sub(2,3) end -- convert percentage opacity (0-100) to ASS alpha values local function convert_opacity(value) value = math.max(0, math.min(100, value)) return string.format("%02X", (255 - (value * 2.55))) end -- colors and opaicty local icon_color = convert_color(options.icon_color) local icon_border_color = convert_color(options.icon_border_color) local icon_opacity = convert_opacity(options.icon_opacity) local icon_font = "fluent-system-icons" -- pause icon local function draw_rectangles() if options.fluent_icons then local pause_icon = "\238\163\140" return string.format([[{\\rDefault\\an5\\alpha&H%s\\bord%s\\1c&H%s&\\3c&H%s&\\fs%s\\fn%s}%s]], icon_opacity, options.icon_border_width, icon_color, icon_border_color, options.fluent_icon_size, icon_font, pause_icon) else return string.format([[{\\rDefault\\p1\\an5\\alpha&H%s\\bord%s\\1c&H%s&\\3c&H%s&}m 0 0 l %d 0 l %d %d l 0 %d m %d 0 l %d 0 l %d %d l %d %d{\\p0}]], icon_opacity, options.icon_border_width, icon_color, icon_border_color, options.rectangles_width, options.rectangles_width, options.rectangles_height, options.rectangles_height, options.rectangles_width + options.rectangles_spacing, options.rectangles_width * 2 + options.rectangles_spacing, options.rectangles_width * 2 + options.rectangles_spacing, options.rectangles_height, options.rectangles_width + options.rectangles_spacing, options.rectangles_height) end end -- play icon local function draw_triangle() if options.fluent_icons then local play_icon = "\238\166\143" return string.format([[{\\rDefault\\an5\\alpha&H%s\\bord%s\\1c&H%s&\\3c&H%s&\\fs%s\\fn%s}%s]], icon_opacity, options.icon_border_width, icon_color, icon_border_color, options.fluent_icon_size, icon_font, play_icon) else return string.format([[{\\rDefault\\p1\\an5\\alpha&H%s\\bord%s\\1c&H%s&\\3c&H%s&}m 0 0 l %d %d l 0 %d{\\p0}]], icon_opacity, options.icon_border_width, icon_color, icon_border_color, options.triangle_width, options.triangle_height / 2, options.triangle_height) end end -- mute icon local function draw_mute() if not options.fluent_icons then return end local mute_icon = "\238\173\138" local mute_pos_list = { ["top_left"] = 7, ["top_center"] = 8, ["top_right"] = 9, ["middle_left"] = 4, ["middle_center"] = 5, ["middle_right"] = 6, ["bottom_left"] = 1, ["bottom_center"] = 2, ["bottom_right"] = 3, } local mute_pos = mute_pos_list[options.mute_indicator_pos:lower()] or 6 return string.format([[{\\rDefault\\an%s\\alpha&H%s\\bord%s\\1c&H%s&\\3c&H%s&\\fs%s\\fn%s}%s]], mute_pos, icon_opacity, options.icon_border_width, icon_color, icon_border_color, options.fluent_icon_size, icon_font, mute_icon) end -- initiate overlay local indicator = mp.create_osd_overlay("ass-events") local flash = mp.create_osd_overlay("ass-events") local mute = mp.create_osd_overlay("ass-events") -- keep track of pause toggle and end of file local toggled, eof -- draw and update indicator local function update_indicator() local _, _, display_aspect = mp.get_osd_size() if display_aspect == 0 or (indicator.visible and not toggled) then return end indicator.data = options.indicator_icon == "play" and draw_triangle() or draw_rectangles() indicator:update() if not options.indicator_stay then mp.add_timeout(options.indicator_timeout, function() indicator:remove() end) end end -- flash play icon local function flash_icon() if not options.flash_play_icon then return flash:remove() end flash.data = draw_triangle() flash:update() mp.add_timeout(options.flash_icon_timeout, function() flash:remove() end) end -- draw mute icon local function mute_icon() mute.data = draw_mute() mute:update() end -- check if file is video local function is_video() local t = mp.get_property_native("current-tracks/video") return t and not (t.image or t.albumart) and true or false end -- remove overlays local function shutdown() if flash then flash:remove() end if indicator then indicator:remove() end mp.unobserve_property("pause") end -- end of file keybind check if options.keybind_eof_disable then mp.observe_property("eof-reached", "bool", function(_, val) eof = val end) end -- observe when pause state changes mp.observe_property("pause", "bool", function(_, paused) if not is_video() then return shutdown() end if paused then update_indicator() toggled = true if options.flash_play_icon then flash:remove() end else indicator:remove() if toggled then flash_icon() toggled = false end end -- keybind setup (if options allow it) if options.keybind_allow == true then mp.set_key_bindings({ {options.keybind_set, function() mp.commandv("cycle", "pause") end} }, "pause-indicator", "force") if options.keybind_mode == "always" or (options.keybind_mode == "onpause" and paused) then if not eof then mp.enable_key_bindings("pause-indicator") end else mp.disable_key_bindings("pause-indicator") end end end) -- update pause indicator position if window size changes mp.observe_property("osd-dimensions", "native", function() if indicator and indicator.visible then update_indicator() end end) if options.mute_indicator and options.fluent_icons then mp.observe_property("mute", "bool", function(_, val) if val and not mute.visible then mute_icon() else mute:remove() end end) else mute:remove() end