Files
uosc/uosc.lua

727 lines
24 KiB
Lua

--[[
uosc 1.0.5 | https://github.com/darsain/uosc
Minimalistic proximity based UI for MPV player.
uosc replaces the default osc UI, so that has to be disabled first.
Place these options into your `mpv.conf` file:
```
osc=no # required so that the 2 UIs don't fight each other
border=no # if you disable window border, uosc will draw
# its own proximity based window controls
```
Options go in `script-opts/uosc.conf`. Defaults:
```
# display window title (filename) in no-border mode
title=no
# seekbar size in pixels, 0 to disable
seekbar_size=40
# same as ^ but when in fullscreen
seekbar_size_fullscreen=40
# seekbar chapters style: dots, lines, lines-top, lines-bottom
seekbar_chapters=
# progressbar size in pixels, 0 to disable
progressbar_size=4
# same as ^ but when in fullscreen
progressbar_size_fullscreen=4
# progressbar chapters style: lines, lines-top, lines-bottom
progressbar_chapters=
# proximity below which opacity equals 1
min_proximity=40
# proximity above which opacity equals 0
max_proximity=120
# max opacity of progress and seek bars
bar_opacity=0.8
# chapters indicator opacity
chapters_opacity=0.2
# BBGGRR - BLUE GREEN RED hex code
bar_color_foreground=FFFFFF
# BBGGRR - BLUE GREEN RED hex code
bar_color_background=000000
```
Available keybindings (place into `input.conf`):
```
Key script-binding uosc/toggleprogressbar
```
]]
if mp.get_property('osc') == 'yes' then
mp.msg.info("Disabled because original osc is enabled!")
return
end
local assdraw = require 'mp.assdraw'
local opt = require 'mp.options'
local osd = mp.create_osd_overlay("ass-events")
local options = {
title = false, -- display window title (filename) in no-border mode
seekbar_size = 40, -- seekbar size in pixels, 0 to disable
seekbar_size_fullscreen = 40, -- same as ^ but when in fullscreen
seekbar_chapters = "", -- seekbar chapters style: dots, lines, lines-top, lines-bottom
progressbar_size = 4, -- progressbar size in pixels, 0 to disable
progressbar_size_fullscreen = 4, -- same as ^ but when in fullscreen
progressbar_chapters = "", -- progressbar chapters style: lines, lines-top, lines-bottom
min_proximity = 40, -- proximity below which opacity equals 1
max_proximity = 120, -- proximity above which opacity equals 0
bar_opacity = 0.8, -- max opacity of progress and seek bars
chapter_opacity = 0.2, -- chapters indicator opacity
bar_color_foreground = "FFFFFF", -- BBGGRR - BLUE GREEN RED hex code
bar_color_background = "000000", -- BBGGRR - BLUE GREEN RED hex code
}
opt.read_options(options, "uosc")
local config = {
render_delay = 0.03, -- sets rendering frequency
font = mp.get_property("options/osd-font"),
window_controls = {
button_width = 46,
height = 40,
icon_opacity = 0.8,
background_opacity = 0.8,
}
}
local state = {
filename = "",
border = mp.get_property_native("border"),
duration = nil,
position = nil,
paused = false,
fullscreen = mp.get_property_native("fullscreen"),
maximized = mp.get_property_native("window-maximized"),
render_timer = nil,
render_last_time = 0,
mouse_bindings_enabled = false
}
local display = {
width = 1280,
height = 720,
aspect = 1.77778,
}
local cursor = {
hidden = true, -- true when autohidden or outside of the player window
x = nil,
y = nil,
}
local infinity = 1e309
local elements = {
progressbar = {
enabled = true, -- flag set manually through runtime keybinds
size = 0, -- consolidation of `progressbar_size` and `progressbar_size_fullscreen` options
on_display_resize = function(element)
if state.fullscreen or state.maximized then
element.size = options.progressbar_size_fullscreen
else
element.size = options.progressbar_size
end
end,
render = function(ass) render_progressbar(ass) end,
},
seekbar = {
interactive = true, -- listen for mouse events and don't disable window dragging
size = 0, -- consolidation of `seekbar_size` and `seekbar_size_fullscreen` options
ax = 0, ay = 0, bx = 0, by = 0, -- calculated by on_display_resize
proximity = infinity, opacity = 0, -- calculated on mouse movement
on_mouse_move = function(element) update_element_cursor_proximity(element) end,
on_display_resize = function(element)
if state.fullscreen or state.maximized then
element.size = options.seekbar_size_fullscreen
else
element.size = options.seekbar_size
end
element.interactive = element.size > 0
element.ax = 0
element.ay = display.height - element.size
element.bx = display.width
element.by = display.height
end,
on_mbtn_left_down = function()
mp.commandv("seek", ((cursor.x / display.width) * 100), "absolute-percent+exact")
end,
render = function(ass) render_seekbar(ass) end,
},
window_controls = {
ax = 0, ay = 0, bx = 0, by = 0, -- calculated by on_display_resize
proximity = infinity, opacity = 0, -- calculated on mouse movement
on_mouse_move = function(element) update_element_cursor_proximity(element) end,
on_display_resize = function(element)
local ax = display.width - (config.window_controls.button_width * 3)
element.ax = options.title and 0 or ax
element.ay = 0
element.bx = display.width
element.by = config.window_controls.height
end,
render = function(ass) render_window_controls(ass) end,
},
window_controls_minimize = {
interactive = true, -- listen for mouse events and don't disable window dragging
ax = 0, ay = 0, bx = 0, by = 0, -- calculated by on_display_resize
proximity = infinity, opacity = 0, -- calculated on mouse movement
on_mouse_move = function(element) update_element_cursor_proximity(element) end,
on_display_resize = function(element)
element.ax = display.width - (config.window_controls.button_width * 3)
element.ay = 0
element.bx = element.ax + config.window_controls.button_width
element.by = config.window_controls.height
end,
on_mbtn_left_down = function() mp.commandv("cycle", "window-minimized") end
},
window_controls_maximize = {
interactive = true, -- listen for mouse events and don't disable window dragging
ax = 0, ay = 0, bx = 0, by = 0, -- calculated by on_display_resize
proximity = infinity, opacity = 0, -- calculated on mouse movement
on_mouse_move = function(element) update_element_cursor_proximity(element) end,
on_display_resize = function(element)
element.ax = display.width - (config.window_controls.button_width * 2)
element.ay = 0
element.bx = element.ax + config.window_controls.button_width
element.by = config.window_controls.height
end,
on_mbtn_left_down = function() mp.commandv("cycle", "window-maximized") end
},
window_controls_close = {
interactive = true, -- listen for mouse events and don't disable window dragging
ax = 0, ay = 0, bx = 0, by = 0, -- calculated by on_display_resize
proximity = infinity, opacity = 0, -- calculated on mouse movement
on_mouse_move = function(element) update_element_cursor_proximity(element) end,
on_display_resize = function(element)
element.ax = display.width - config.window_controls.button_width
element.ay = 0
element.bx = element.ax + config.window_controls.button_width
element.by = config.window_controls.height
end,
on_mbtn_left_down = function() mp.commandv("quit") end
}
}
-- HELPER FUNCTIONS
function get_point_to_rectangle_proximity(point, rect)
local dx = math.max(rect.ax - point.x, 0, point.x - rect.bx + 1)
local dy = math.max(rect.ay - point.y, 0, point.y - rect.by + 1)
return math.sqrt(dx*dx + dy*dy);
end
function to_alpha(opacity, fraction)
fraction = fraction ~= nil and fraction or 1
return 255 - math.ceil(255 * opacity * fraction)
end
function ass_append_opacity(ass, opacity, fraction)
if type(opacity) == "number" then
ass:append(string.format("{\\alpha&H%X&}", to_alpha(opacity, fraction)))
else
ass:append(string.format(
"{\\1a&H%X&\\2a&H%X&\\3a&H%X&\\4a&H%X&}",
to_alpha(opacity[1] or 0, fraction),
to_alpha(opacity[2] or 0, fraction),
to_alpha(opacity[3] or 0, fraction),
to_alpha(opacity[4] or 0, fraction)
))
end
end
-- STATE UPDATES
function update_display_dimensions()
local o = mp.get_property_native("osd-dimensions")
display.width = o.w
display.height = o.h
display.aspect = o.aspect
-- Tell elements to update their area rectangles
for _, element in pairs(elements) do
if element.on_display_resize ~= nil then
element.on_display_resize(element)
end
end
end
function update_cursor_position()
local x, y = mp.get_mouse_pos()
cursor.x = x
cursor.y = y
update_proximities()
end
function update_element_cursor_proximity(element)
if cursor.hidden then
element.proximity = infinity
element.opacity = 0
else
local range = options.max_proximity - options.min_proximity
element.proximity = get_point_to_rectangle_proximity(cursor, element)
element.opacity = 1 - math.min(math.max(element.proximity - options.min_proximity, 0), range) / range
end
end
function update_proximities()
local should_enable_mouse_bindings = false
-- Calculates proximities and opacities for defined elements
for _, element in pairs(elements) do
-- Only update proximity and opacity for elements that care about it
if element.proximity ~= nil and element.on_mouse_move ~= nil then
element.on_mouse_move(element)
should_enable_mouse_bindings = should_enable_mouse_bindings or (element.interactive and element.proximity == 0)
end
end
-- Disable cursor input interception when cursor is not over any controls
if not state.mouse_bindings_enabled and should_enable_mouse_bindings then
state.mouse_bindings_enabled = true
mp.enable_key_bindings("mouse_buttons")
elseif state.mouse_bindings_enabled and not should_enable_mouse_bindings then
state.mouse_bindings_enabled = false
mp.disable_key_bindings("mouse_buttons")
end
end
function draw_chapters(ass, style, chapter_y, size, foreground_cutoff, master_opacity)
if state.chapters ~= nil then
local half_size = size / 2
local bezier_stretch = size * 0.67
for i, chapter in ipairs(state.chapters) do
local chapter_x = display.width * (chapter.time / state.duration)
ass:new_event()
if chapter_x > foreground_cutoff then
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_foreground.."}")
else
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_background.."}")
end
ass_append_opacity(ass, options.chapter_opacity, master_opacity)
ass:pos(0, 0)
ass:draw_start()
if style == "dots" then
ass:move_to(chapter_x - half_size, chapter_y)
ass:bezier_curve(
chapter_x - half_size, chapter_y - bezier_stretch,
chapter_x + half_size, chapter_y - bezier_stretch,
chapter_x + half_size, chapter_y
)
ass:bezier_curve(
chapter_x + half_size, chapter_y + bezier_stretch,
chapter_x - half_size, chapter_y + bezier_stretch,
chapter_x - half_size, chapter_y
)
elseif style == "lines" then
ass:rect_cw(chapter_x, chapter_y, chapter_x + 1, chapter_y + size)
end
ass:draw_stop()
end
end
end
-- ELEMENT RENDERERS
function render_progressbar(ass)
local bar = elements.progressbar
if not bar.enabled
or bar.size == 0
or state.duration == nil
or state.position == nil then
return
end
local progress = state.position / state.duration
local master_opacity = elements.seekbar.size > 0
and (1 - math.min(elements.seekbar.opacity / 0.4, 1))
or 1
if master_opacity == 0 then
return
end
local ax = 0
local ay = display.height - bar.size
local bx = display.width * progress
local by = display.height
-- Background
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_background.."\\iclip("..ax..","..ay..","..bx..","..by..")}")
ass_append_opacity(ass, math.max(options.bar_opacity - 0.1, 0), master_opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(ax, ay - 1, display.width, by)
ass:draw_stop()
-- Progress
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_foreground.."}")
ass_append_opacity(ass, options.bar_opacity, master_opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(ax, ay, bx, by)
ass:draw_stop()
-- Chapters
if options.progressbar_chapters == "lines" then
draw_chapters(ass, "lines", ay, bar.size, bx, bar.opacity)
elseif options.progressbar_chapters == "lines-top" then
draw_chapters(ass, "lines", ay, bar.size / 2, bx, bar.opacity)
elseif options.progressbar_chapters == "lines-bottom" then
draw_chapters(ass, "lines", ay + bar.size - (bar.size / 2), bar.size / 2, bx, bar.opacity)
end
end
function render_seekbar(ass)
local bar = elements.seekbar
if cursor.hidden
or bar.size == 0
or bar.opacity == 0
or state.duration == nil
or state.position == nil then
return
end
local progress = state.position / state.duration
local spacing = math.ceil(bar.size * 0.27)
local fontsize = math.floor(bar.size - (spacing * 2))
local ax = 0
local ay = display.height - bar.size
local bx = display.width * progress
local by = display.height
local elapsed_bar_coordinates = ax..","..ay..","..bx..","..by
-- Background
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_background.."\\iclip("..elapsed_bar_coordinates..")}")
ass_append_opacity(ass, math.max(options.bar_opacity - 0.1, 0), bar.opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(0, ay - 1, display.width, by)
ass:draw_stop()
-- Progress
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H"..options.bar_color_foreground.."}")
ass_append_opacity(ass, options.bar_opacity, bar.opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(ax, ay, bx, by)
ass:draw_stop()
-- Chapters
if options.seekbar_chapters == "dots" then
draw_chapters(ass, "dots", ay + 6, 6, bx, bar.opacity)
elseif options.seekbar_chapters == "lines" then
draw_chapters(ass, "lines", ay, bar.size, bx, bar.opacity)
elseif options.seekbar_chapters == "lines-top" then
draw_chapters(ass, "lines", ay, bar.size / 4, bx, bar.opacity)
elseif options.seekbar_chapters == "lines-bottom" then
draw_chapters(ass, "lines", ay + bar.size - (bar.size / 4), bar.size / 4, bx, bar.opacity)
end
-- Elapsed time
local elapsed_seconds = mp.get_property_native("time-pos")
ass:new_event()
ass:append("{\\blur0\\bord0\\shad0\\1c&H"..options.bar_color_background.."\\fn"..config.font.."\\fs"..fontsize.."\\clip("..elapsed_bar_coordinates..")")
ass_append_opacity(ass, math.min(options.bar_opacity + 0.1, 1), bar.opacity)
ass:pos(spacing, ay + (bar.size / 2))
ass:an(4)
ass:append(mp.format_time(elapsed_seconds))
ass:new_event()
ass:append("{\\blur0\\bord0\\shad1\\1c&H"..options.bar_color_foreground.."\\4c&H"..options.bar_color_background.."\\fn"..config.font.."\\fs"..fontsize.."\\iclip("..elapsed_bar_coordinates..")")
ass_append_opacity(ass, math.min(options.bar_opacity + 0.1, 1), bar.opacity)
ass:pos(spacing, ay + (bar.size / 2))
ass:an(4)
ass:append(mp.format_time(elapsed_seconds))
-- Remaining time
local remaining_seconds = mp.get_property_native("playtime-remaining")
ass:new_event()
ass:append("{\\blur0\\bord0\\shad0\\1c&H"..options.bar_color_background.."\\fn"..config.font.."\\fs"..fontsize.."\\clip("..elapsed_bar_coordinates..")")
ass_append_opacity(ass, math.min(options.bar_opacity + 0.1, 1), bar.opacity)
ass:pos(display.width - spacing, ay + (bar.size / 2))
ass:an(6)
ass:append("-"..mp.format_time(remaining_seconds))
ass:new_event()
ass:append("{\\blur0\\bord0\\shad1\\1c&H"..options.bar_color_foreground.."\\4c&H"..options.bar_color_background.."\\fn"..config.font.."\\fs"..fontsize.."\\iclip("..elapsed_bar_coordinates..")")
ass_append_opacity(ass, math.min(options.bar_opacity + 0.1, 1), bar.opacity)
ass:pos(display.width - spacing, ay + (bar.size / 2))
ass:an(6)
ass:append("-"..mp.format_time(remaining_seconds))
if bar.proximity == 0 then
-- Hovered time
local hovered_seconds = mp.get_property_native("duration") * (cursor.x / display.width)
local box_half_width_guesstimate = (fontsize * 4.2) / 2
ass:new_event()
ass:append("{\\blur0\\bord0\\shad1\\1c&H"..options.bar_color_foreground.."\\4c&H"..options.bar_color_background.."\\fn"..config.font.."\\fs"..fontsize.."")
ass_append_opacity(ass, math.min(options.bar_opacity + 0.1, 1))
ass:pos(math.min(math.max(cursor.x, box_half_width_guesstimate), display.width - box_half_width_guesstimate), ay)
ass:an(2)
ass:append(mp.format_time(hovered_seconds))
-- Cursor line
ass:new_event()
ass:append("{\\blur0\\bord0\\xshad-1\\yshad0\\1c&H"..options.bar_color_foreground.."\\4c&H"..options.bar_color_background.."}")
ass_append_opacity(ass, 0.2)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(cursor.x, ay, cursor.x + 1, by)
ass:draw_stop()
end
end
function render_window_controls(ass)
if cursor.hidden
or state.border
or state.duration == nil
or state.position == nil then
return
end
local master_opacity = elements.window_controls.opacity
if master_opacity == 0 then return end
-- Close button
local close = elements.window_controls_close
if close.proximity == 0 then
-- Background on hover
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H2311e8}")
ass_append_opacity(ass, config.window_controls.background_opacity, master_opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(close.ax, close.ay, close.bx, close.by)
ass:draw_stop()
end
ass:new_event()
ass:append("{\\blur0\\bord1\\shad1\\3c&HFFFFFF\\4c&H000000}")
ass_append_opacity(ass, config.window_controls.icon_opacity, master_opacity)
ass:pos(close.ax + (config.window_controls.button_width / 2), (config.window_controls.height / 2))
ass:draw_start()
ass:move_to(-5, 5)
ass:line_to(5, -5)
ass:move_to(-5, -5)
ass:line_to(5, 5)
ass:draw_stop()
-- Maximize button
local maximize = elements.window_controls_maximize
if maximize.proximity == 0 then
-- Background on hover
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H222222}")
ass_append_opacity(ass, config.window_controls.background_opacity, master_opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(maximize.ax, maximize.ay, maximize.bx, maximize.by)
ass:draw_stop()
end
ass:new_event()
ass:append("{\\blur0\\bord2\\shad0\\1c\\3c&H000000}")
ass_append_opacity(ass, {[3] = config.window_controls.icon_opacity}, master_opacity)
ass:pos(maximize.ax + (config.window_controls.button_width / 2), (config.window_controls.height / 2))
ass:draw_start()
ass:rect_cw(-4, -4, 6, 6)
ass:draw_stop()
ass:new_event()
ass:append("{\\blur0\\bord2\\shad0\\1c\\3c&HFFFFFF}")
ass_append_opacity(ass, {[3] = config.window_controls.icon_opacity}, master_opacity)
ass:pos(maximize.ax + (config.window_controls.button_width / 2), (config.window_controls.height / 2))
ass:draw_start()
ass:rect_cw(-5, -5, 5, 5)
ass:draw_stop()
-- Minimize button
local minimize = elements.window_controls_minimize
if minimize.proximity == 0 then
-- Background on hover
ass:new_event()
ass:append("{\\blur0\\bord0\\1c&H222222}")
ass_append_opacity(ass, config.window_controls.background_opacity, master_opacity)
ass:pos(0, 0)
ass:draw_start()
ass:rect_cw(minimize.ax, minimize.ay, minimize.bx, minimize.by)
ass:draw_stop()
end
ass:new_event()
ass:append("{\\blur0\\bord1\\shad1\\3c&HFFFFFF\\4c&H000000}")
ass_append_opacity(ass, config.window_controls.icon_opacity, master_opacity)
ass:append("{\\1a&HFF&}")
ass:pos(minimize.ax + (config.window_controls.button_width / 2), (config.window_controls.height / 2))
ass:draw_start()
ass:move_to(-5, 0)
ass:line_to(5, 0)
ass:draw_stop()
-- Window title
if options.title then
local spacing = math.ceil(config.window_controls.height * 0.25)
local fontsize = math.floor(config.window_controls.height - (spacing * 2))
local clip_coordinates = "0,0,"..(minimize.ax - 10)..","..config.window_controls.height
ass:new_event()
ass:append("{\\q2\\blur0\\bord0\\shad1\\1c&HFFFFFF\\4c&H000000\\fn"..config.font.."\\fs"..fontsize.."\\clip("..clip_coordinates..")")
ass_append_opacity(ass, 1, master_opacity)
ass:pos(0 + spacing, config.window_controls.height / 2)
ass:an(4)
ass:append(state.filename)
end
end
-- MAIN RENDERING
-- Request that render() is called.
-- The render is then either executed immediately, or rate-limited if it was
-- called a small time ago.
function request_render()
if state.render_timer == nil then
state.render_timer = mp.add_timeout(0, render)
end
if not state.render_timer:is_enabled() then
local now = mp.get_time()
local timeout = config.render_delay - (now - state.render_last_time)
if timeout < 0 then
timeout = 0
end
state.render_timer.timeout = timeout
state.render_timer:resume()
end
end
function render()
state.render_last_time = mp.get_time()
-- Actual rendering
local ass = assdraw.ass_new()
ass.scale = 1
for _, element in pairs(elements) do
if element.render ~= nil then
element.render(ass)
end
end
-- submit
if osd.res_x == display.width and osd.res_y == display.height and osd.data == ass.text then
return
end
osd.res_x = display.width
osd.res_y = display.height
osd.data = ass.text
osd.z = 2000
osd:update()
end
-- EVENT HANDLERS
function dispatch_event_to_element_below_mouse_button(name, value)
for _, element in pairs(elements) do
if element.proximity == 0 then
local handler = element["on_"..name]
if handler ~= nil and element.proximity == 0 then
handler(value)
break
end
end
end
end
function handle_file_load()
state.duration = mp.get_property_number("duration", nil)
state.filename = mp.get_property_native("filename", "")
end
function handle_event(source, what)
if source == "mbtn_left" then
if what == "down" or what == "press" then
dispatch_event_to_element_below_mouse_button("mbtn_left_down")
elseif what == "up" then
dispatch_event_to_element_below_mouse_button("mbtn_left_up")
end
elseif source == "mbtn_right" then
if what == "down" or what == "press" then
dispatch_event_to_element_below_mouse_button("mbtn_right_down")
elseif what == "up" then
dispatch_event_to_element_below_mouse_button("mbtn_right_up")
end
elseif source == "mouse_leave" then
cursor.hidden = true
update_proximities()
end
request_render()
end
function handle_mouse_move()
cursor.hidden = false
update_cursor_position()
request_render()
end
function handle_toggle_progress()
elements.progressbar.enabled = not elements.progressbar.enabled
end
function event_handler(source, what)
return function() handle_event(source, what) end
end
function state_setter(name)
return function(_, value) state[name] = value end
end
-- HOOKS
mp.register_event("file-loaded", handle_file_load)
mp.observe_property("chapter-list", "native", state_setter("chapters"))
mp.observe_property("fullscreen", "bool", state_setter("fullscreen"))
mp.observe_property("border", "bool", state_setter("border"))
mp.observe_property("window-maximized", "bool", state_setter("maximized"))
mp.observe_property("idle-active", "bool", state_setter("idle"))
mp.observe_property("pause", "bool", state_setter("paused"))
mp.observe_property("playback-time", "number", function(name, val)
state.position = val
request_render()
end)
mp.observe_property("osd-dimensions", "native", function(name, val)
update_display_dimensions()
request_render()
end)
-- CONTROLS
-- mouse movement bindings
mp.set_key_bindings({
{"mouse_move", handle_mouse_move},
{"mouse_leave", event_handler("mouse_leave", nil)},
}, "mouse_movement", "force")
mp.enable_key_bindings("mouse_movement", "allow-vo-dragging+allow-hide-cursor")
-- mouse button bindings
mp.set_key_bindings({
{"mbtn_left", event_handler("mbtn_left", "up"), event_handler("mbtn_left", "down")},
{"mbtn_right", event_handler("mbtn_right", "up"), event_handler("mbtn_right", "down")},
{"mbtn_left_dbl", "ignore"},
{"mbtn_right_dbl", "ignore"},
}, "mouse_buttons", "force")
-- User defined keybindings
mp.add_key_binding(nil, 'toggleprogressbar', handle_toggle_progress)