diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf index dcccd41..1003f9e 100644 --- a/.config/mpv/mpv.conf +++ b/.config/mpv/mpv.conf @@ -39,8 +39,9 @@ prefetch-playlist=yes input-ipc-server=/tmp/mpvsocket hr-seek-framedrop=yes title=${?chapter:${chapter-metadata/by-key/title} | }${media-title} | mpv -osd-msg3=${media-title}${?chapter:\n ${chapter-metadata/by-key/title}}\n${time-pos} / ${playtime-remaining} +#osd-msg3=${media-title}${?chapter:\n ${chapter-metadata/by-key/title}}\n${time-pos} / ${playtime-remaining} osd-font-size=25 +osc=no # YTDL ytdl-format="((bestvideo[vcodec^=av01][height<=?1080][width<=?1920]/bestvideo[vcodec=vp9][height<=?1080][width<=?1920]/bestvideo[height<=?1080][width<=?1920]/bestvideo)+(bestaudio[acodec=opus]/bestaudio[acodec=vorbis]/bestaudio))/best" diff --git a/.config/mpv/script-opts/torque-progressbar/main.conf b/.config/mpv/script-opts/torque-progressbar/main.conf new file mode 100644 index 0000000..dbf77cb --- /dev/null +++ b/.config/mpv/script-opts/torque-progressbar/main.conf @@ -0,0 +1,308 @@ +# Sets the height of the rectangular area at the bottom of the screen that expands +# the progress bar and shows playback time information when the mouse is hovered +# over it. +hover-zone-height=40 + +# Sets the height of the rectangular area at the top of the screen that shows the +# file name and system time when the mouse is hovered over it. +top-hover-zone-height=40 + +# Acts as a multiplier to increase the size of every UI element. Useful for high- +# DPI displays that cause the UI to be rendered too small (happens at least on +# macOS). +display-scale-factor=1 + +# Default style that is applied to all UI elements. A string of ASS override tags. +# Individual elements have their own style settings which override the tags here. +# Changing the font will likely require changing the hover-time margin settings +# and the offscreen-pos settings. +# +# Here are some useful ASS override tags (omit square brackets): +# \fn[Font Name]: sets the font to the named font. +# \fs[number]: sets the font size to the given number. +# \b[1/0]: sets the text bold or not (\b1 is bold, \b0 is regular weight). +# \i[1/0]: sets the text italic or not (same semantics as bold). +# \bord[number]: sets the outline width to the given number (in pixels). +# \shad[number]: sets the shadow size to the given number (pixels). +# \c&H[BBGGRR]&: sets the fill color for the text to the given color (hex pairs in +# the order, blue, green, red). +# \3c&H[BBGGRR]&: sets the outline color of the text to the given color. +# \4c&H[BBGGRR]&: sets the shadow color of the text to the given color. +# \alpha&H[AA]&: sets the line's transparency as a hex pair. 00 is fully opaque +# and FF is fully transparent. Some UI elements are composed of +# multiple layered lines, so adding transparency may not look good. +# For further granularity, \1a&H[AA]& controls the fill opacity, +# \3a&H[AA]& controls the outline opacity, and \4a&H[AA]& controls +# the shadow opacity. +default-style=\fnIBM Plex Mono\b1\bord2\shad0\fs30\c&HFC799E&\3c&H2D2D2D& + +# Controls whether or not the progress bar is drawn at all. If this is disabled, +# it also (naturally) disables the click-to-seek functionality. +enable-bar=yes + +# Causes the bar to not be drawn unless the mouse is hovering over it or a +# request-display call is active. This is somewhat redundant with setting bar- +# height-inactive=0, except that it can allow for very rudimentary context- +# sensitive behavior because it can be toggled at runtime. For example, by using +# the binding `f cycle pause; script-binding progressbar/toggle-inactive-bar`, it +# is possible to have the bar be persistently present only in windowed or +# fullscreen contexts, depending on the default setting. +bar-hide-inactive=no + +# Sets the height of the bar display when the mouse is not in the active zone and +# there is no request-display active. A value of 0 or less will cause bar-hide- +# inactive to be set to true and the bar height to be set to 1. This should result +# in the desired behavior while avoiding annoying debug logging in mpv (libass +# does not like zero-height objects). +bar-height-inactive=3 + +# Sets the height of the bar display when the mouse is in the active zone or +# request-display is active. There is no logic attached to this, so 0 or negative +# values may have unexpected results. +bar-height-active=8 + +# If greater than zero, changes the progress bar style to be a small segment +# rather than a continuous bar and sets its width. +progress-bar-width=0 + +# Affects precision of seeks due to clicks on the progress bar. Should be 'exact' or +# 'keyframes'. Exact is slightly slower, but won't jump around between two +# different times when clicking in the same place. +# +# Actually, this gets passed directly into the `seek` command, so the value can be +# any of the arguments supported by mpv, though the ones above are the only ones +# that really make sense. +seek-precision=exact + +# Causes the progress bar background layer to automatically size itself to the +# tallest of the cache or progress bars. Useful for improving contrast but can +# make the bar take up more screen space. Has no effect if the cache bar height is +# less than the bar height. +bar-background-adaptive=yes + +# Placement of the cache bar. Valid values are 'overlay' and 'underlay'. +# +# 'overlay' causes the cache bar to be drawn on top of the foreground layer of the +# bar, allowing the display of seek ranges that have already been encountered. +# +# 'underlay' draws the cache bar between the foreground and background layers. Any +# demuxer cache ranges that are prior to the current playback point will not be +# shown. This matches the previous behavior. +bar-cache-position=overlay + +# Sets the height of the cache bar display when the mouse is not in the active +# zone and there is no request-display active. Useful in combination with bar- +# cache-position to control whether or not the cache bar is occluded by (or +# occludes) the progress bar. +bar-cache-height-inactive=3 + +# Sets the height of the cache bar display when the mouse is in the active zone or +# request-display is active. Useful in combination with bar-cache- position to +# control whether or not the cache bar is occluded by (or occludes) the progress +# bar. +bar-cache-height-active=8 + +# A string of ASS override tags that get applied to all three layers of the bar: +# progress, cache, and background. You probably don't want to remove \bord0 unless +# your default-style includes it. +bar-default-style=\bord0\shad0 + +# A string of ASS override tags that get applied only to the progress layer of the +# bar. +bar-foreground-style= + +# A string of ASS override tags that get applied only to the cache layer of the +# bar, particularly the part of the cache bar that is behind the current playback +# position. The default sets only the color. +# bar-cache-style=\c&H697374& +bar-cache-style=\c&7A77F2& + +# A string of ASS override tags that get applied only to the cache layer of the +# bar, particularly the part of the cache bar that is after the current playback +# position. The tags specified here are applied after bar-cache-style and override +# them. Leaving this blank will leave the style the same as specified by bar- +# cache-style. The split does not account for a nonzero progress-bar-width and may +# look odd when used in tandem with that setting. +bar-cache-background-style=\c&H697374& + +# A string of ASS override tags that get applied only to the background layer of +# the bar. The default sets only the color. +bar-background-style=\c&H000000& + +# Sets whether or not the elapsed time is displayed at all. +enable-elapsed-time=yes + +# A string of ASS override tags that get applied only to the elapsed time display. +elapsed-style= + +# Controls how far from the left edge of the window the elapsed time display is +# positioned. +elapsed-left-margin=4 + +# Controls how far above the expanded progress bar the elapsed time display is +# positioned. +elapsed-bottom-margin=0 + +# Sets whether or not the remaining time is displayed at all. +enable-remaining-time=yes + +# A string of ASS override tags that get applied only to the remaining time +# display. +remaining-style= + +# Controls how far from the right edge of the window the remaining time display is +# positioned. +remaining-right-margin=4 + +# Controls how far above the expanded progress bar the remaining time display is +# positioned. +remaining-bottom-margin=0 + +# Sets whether or not the calculated time corresponding to the mouse position +# is displayed when the mouse hovers over the progress bar. +enable-hover-time=yes + +# A string of ASS override tags that get applied only to the hover time display. +# Unfortunately, due to the way the hover time display is animated, alpha values +# set here will be overridden. This is subject to change in future versions. +hover-time-style=\fs26 + +# Controls how close to the left edge of the window the hover time display can +# get. If this value is too small, it will end up overlapping the elapsed time +# display. +hover-time-left-margin=120 + +# Controls how close to the right edge of the window the hover time display can +# get. If this value is too small, it will end up overlapping the remaining time +# display. +hover-time-right-margin=130 + +# Controls how far above the expanded progress bar the remaining time display is +# positioned. +hover-time-bottom-margin=0 + +# Sets whether or not the video title is displayed at all. +enable-title=yes + +# A string of ASS override tags that get applied only to the video title display. +title-style= + +# Controls how far from the left edge of the window the video title display is +# positioned. +title-left-margin=4 + +# Controls how far from the top edge of the window the video title display is +# positioned. +title-top-margin=0 + +# Controls whether or not the script logs the video title and playlist position +# to the console every time a new video starts. +title-print-to-cli=yes + +# Sets whether or not the system time is displayed at all. +enable-system-time=yes + +# A string of ASS override tags that get applied only to the system time display. +system-time-style= + +# Sets the format used for the system time display. This must be a strftime- +# compatible format string. +system-time-format=%H:%M + +# Controls how far from the right edge of the window the system time display is +# positioned. +system-time-right-margin=4 + +# Controls how far from the top edge of the window the system time display is +# positioned. +system-time-top-margin=0 + +# Sets whether or not the pause indicator is displayed. The pause indicator is a +# momentary icon that flashes in the middle of the screen, similar to youtube. +pause-indicator=yes + +# A string of ASS override tags that get applied only to the foreground of the +# pause indicator. +pause-indicator-foreground-style=\c&HFC799E& + +# A string of ASS override tags that get applied only to the background of the +# pause indicator. +pause-indicator-background-style=\c&H2D2D2D& + +# Sets whether or not the progress bar is decorated with chapter markers. Due to +# the way the chapter markers are currently implemented, videos with a large +# number of chapters may slow down the script somewhat, but I have yet to run +# into this being a problem. +enable-chapter-markers=yes + +# Controls the width of each chapter marker when the progress bar is inactive. +chapter-marker-width=2 + +# Controls the width of each chapter marker when the progress bar is active. +chapter-marker-width-active=4 + +# Modifies the height of the chapter markers when the progress bar is active. Acts +# as a multiplier on the height of the active progress bar. A value greater than 1 +# will cause the markers to be taller than the expanded progress bar, whereas a +# value less than 1 will cause them to be shorter. +chapter-marker-active-height-fraction=1 + +# A string of ASS override tags that get applied only to chapter markers that have +# not yet been passed. +chapter-marker-before-style=\c&HFC799E& + +# A string of ASS override tags that get applied only to chapter markers that have +# already been passed. +chapter-marker-after-style=\c&H2D2D2D& + +# Sets the amount of time in seconds that the UI stays on the screen after it +# receives a request-display signal. A value of 0 will keep the display on screen +# only as long as the key bound to it is held down. +request-display-duration=0 + +# Controls how often the display is redrawn, in seconds. This does not seem to +# significantly affect the smoothness of animations, and it is subject to the +# accuracy limits imposed by the scheduler mpv uses. Probably not worth changing +# unless you have major performance problems. +redraw-period=0.03 + +# Controls how long the UI animations take. A value of 0 disables all animations +# (which breaks the pause indicator). +animation-duration=0.25 + +# Controls how far off the left side of the window the elapsed time display tries +# to move when it is inactive. If you use a non-default font, this value may need +# to be tweaked. If this value is not far enough off-screen, the elapsed display +# will disappear without animating all the way off-screen. Positive values will +# cause the display to animate the wrong direction. +elapsed-offscreen-pos=-100 + +# Controls how far off the left side of the window the remaining time display +# tries to move when it is inactive. If you use a non-default font, this value may +# need to be tweaked. If this value is not far enough off-screen, the elapsed +# display will disappear without animating all the way off-screen. Positive values +# will cause the display to animate the wrong direction. +remaining-offscreen-pos=-100 + +# Controls how far off the bottom of the window the mouse hover time display tries +# to move when it is inactive. If you use a non-default font, this value may need +# to be tweaked. If this value is not far enough off-screen, the elapsed +# display will disappear without animating all the way off-screen. Positive values +# will cause the display to animate the wrong direction. +hover-time-offscreen-pos=-50 + +# Controls how far off the left side of the window the system time display tries +# to move when it is inactive. If you use a non-default font, this value may need +# to be tweaked. If this value is not far enough off-screen, the elapsed display +# will disappear without animating all the way off-screen. Positive values will +# cause the display to animate the wrong direction. +system-time-offscreen-pos=-100 + +# Controls how far off the left side of the window the video title display tries +# to move when it is inactive. If you use a non-default font, this value may need +# to be tweaked. If this value is not far enough off-screen, the elapsed display +# will disappear without animating all the way off-screen. Positive values will +# cause the display to animate the wrong direction. +title-offscreen-pos=-40 + + diff --git a/.config/mpv/scripts/progress.lua b/.config/mpv/scripts/progress.lua new file mode 100644 index 0000000..d68e9a9 --- /dev/null +++ b/.config/mpv/scripts/progress.lua @@ -0,0 +1,2547 @@ +local msg = require('mp.msg') +local log = { + debug = function(format, ...) + return msg.debug(format:format(...)) + end, + info = function(format, ...) + return msg.info(format:format(...)) + end, + warn = function(format, ...) + return msg.warn(format:format(...)) + end, + dump = function(item, ignore) + if "table" ~= type(item) then + msg.info(tostring(item)) + return + end + local count = 1 + local tablecount = 1 + local result = { + "{ @" .. tostring(tablecount) + } + local seen = { + [item] = tablecount + } + local recurse + recurse = function(item, space) + for key, value in pairs(item) do + if not (key == ignore) then + if "table" == type(value) then + if not (seen[value]) then + tablecount = tablecount + 1 + seen[value] = tablecount + count = count + 1 + result[count] = space .. tostring(key) .. ": { @" .. tostring(tablecount) + recurse(value, space .. " ") + count = count + 1 + result[count] = space .. "}" + else + count = count + 1 + result[count] = space .. tostring(key) .. ": @" .. tostring(seen[value]) + end + else + if "string" == type(value) then + value = ("%q"):format(value) + end + count = count + 1 + result[count] = space .. tostring(key) .. ": " .. tostring(value) + end + end + end + end + recurse(item, " ") + count = count + 1 + result[count] = "}" + return msg.info(table.concat(result, "\n")) + end +} +local options = require('mp.options') +local utils = require('mp.utils') +local script_name = 'torque-progressbar' +mp.get_osd_size = mp.get_osd_size or mp.get_screen_size +local settings = { + _defaults = { } +} +local settingsMeta = { + _reload = function(self) + for key, value in pairs(self._defaults) do + settings[key] = value + end + options.read_options(self, script_name .. '/main') + if self['bar-height-inactive'] <= 0 then + self['bar-hide-inactive'] = true + self['bar-height-inactive'] = 1 + end + end, + _migrate = function(self) + local pathSep = package.config:sub(1, 1) + local onWindows = pathSep == '\\' + local mv + mv = function(oldFile, newFile) + local cmd = { + args = { + 'mv', + oldConfig, + newConfig + } + } + if onWindows then + local oldfile = oldFile:gsub('/', pathSep) + newFile = newFile:gsub('/', pathSep) + cmd = { + args = { + 'cmd', + '/Q', + '/C', + 'move', + '/Y', + oldfile, + newFile + } + } + end + return utils.subprocess(cmd) + end + local mkdir + mkdir = function(directory) + local cmd = { + args = { + 'mkdir', + '-p', + directory + } + } + if onWindows then + directory = directory:gsub('/', pathSep) + cmd = { + args = { + 'cmd', + '/Q', + '/C', + 'mkdir', + directory + } + } + end + return utils.subprocess(cmd) + end + local settingsDirectories = { + 'script-opts', + 'lua-settings' + } + local oldConfigFiles + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #settingsDirectories do + local dir = settingsDirectories[_index_0] + _accum_0[_len_0] = ('%s/%s.conf'):format(dir, script_name) + _len_0 = _len_0 + 1 + end + oldConfigFiles = _accum_0 + end + local newConfigFiles + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #settingsDirectories do + local dir = settingsDirectories[_index_0] + _accum_0[_len_0] = ('%s/%s/main.conf'):format(dir, script_name) + _len_0 = _len_0 + 1 + end + newConfigFiles = _accum_0 + end + local oldConfig = nil + local oldConfigIndex = 1 + local newConfigFile = nil + local newConfig = nil + for idx, file in ipairs(oldConfigFiles) do + log.debug(('checking for old config "%s"'):format(file)) + oldConfig = mp.find_config_file(file) + if oldConfig then + log.debug(('found "%s"'):format(oldConfig)) + oldConfigIndex = idx + break + end + end + if not (oldConfig) then + log.debug('No old config file found. Migration finished.') + return + end + for _index_0 = 1, #newConfigFiles do + local file = newConfigFiles[_index_0] + log.debug(('checking for new config "%s"'):format(file)) + newConfig = mp.find_config_file(file) + if newConfig then + log.debug(('found "%s"'):format(newConfig)) + newConfigFile = file + break + end + end + if oldConfig and not newConfig then + log.debug(('Found "%s". Processing migration.'):format(oldConfig)) + newConfigFile = newConfigFiles[oldConfigIndex] + local baseConfigFolder, _ = utils.split_path(oldConfig) + local configDir = utils.join_path(baseConfigFolder, script_name) + newConfig = utils.join_path(configDir, 'main.conf') + log.info(('Old configuration detected. Attempting to migrate "%s" -> "%s"'):format(oldConfig, newConfig)) + local dirExists = mp.find_config_file(configDir) + if dirExists and not utils.readdir(configDir) then + log.warn(('Configuration migration failed. "%s" exists and does not appear to be a folder'):format(configDir)) + return + else + if not dirExists then + log.debug(('Attempting to create directory "%s"'):format(configDir)) + local res = mkdir(configDir) + if res.error or res.status ~= 0 then + log.warn(('Making directory "%s" failed.'):format(configDir)) + return + end + log.debug('successfully created directory.') + else + log.debug(('Directory "%s" already exists. Continuing.'):format(configDir)) + end + end + log.debug(('Attempting to move "%s" -> "%s"'):format(oldConfig, newConfig)) + local res = mv(oldConfig, newConfig) + if res.error or res.status ~= 0 then + log.warn(('Moving file "%s" -> "%s" failed.'):format(oldConfig, newConfig)) + return + end + if mp.find_config_file(newConfigFile) then + return log.info('Configuration successfully migrated.') + else + return log.warn(('Cannot find "%s". Migration mysteriously failed?'):format(newConfigFile)) + end + end + end, + __newindex = function(self, key, value) + self._defaults[key] = value + return rawset(self, key, value) + end +} +settingsMeta.__index = settingsMeta +setmetatable(settings, settingsMeta) +settings:_migrate() +local helpText = { } +settings['hover-zone-height'] = 40 +helpText['hover-zone-height'] = [[Sets the height of the rectangular area at the bottom of the screen that expands +the progress bar and shows playback time information when the mouse is hovered +over it. +]] +settings['top-hover-zone-height'] = 40 +helpText['top-hover-zone-height'] = [[Sets the height of the rectangular area at the top of the screen that shows the +file name and system time when the mouse is hovered over it. +]] +settings['display-scale-factor'] = 1 +helpText['display-scale-factor'] = [[Acts as a multiplier to increase the size of every UI element. Useful for high- +DPI displays that cause the UI to be rendered too small (happens at least on +macOS). +]] +settings['default-style'] = [[\fnSource Sans Pro\b1\bord2\shad0\fs30\c&HFC799E&\3c&H2D2D2D&]] +helpText['default-style'] = [[Default style that is applied to all UI elements. A string of ASS override tags. +Individual elements have their own style settings which override the tags here. +Changing the font will likely require changing the hover-time margin settings +and the offscreen-pos settings. + +Here are some useful ASS override tags (omit square brackets): +\fn[Font Name]: sets the font to the named font. +\fs[number]: sets the font size to the given number. +\b[1/0]: sets the text bold or not (\b1 is bold, \b0 is regular weight). +\i[1/0]: sets the text italic or not (same semantics as bold). +\bord[number]: sets the outline width to the given number (in pixels). +\shad[number]: sets the shadow size to the given number (pixels). +\c&H[BBGGRR]&: sets the fill color for the text to the given color (hex pairs in + the order, blue, green, red). +\3c&H[BBGGRR]&: sets the outline color of the text to the given color. +\4c&H[BBGGRR]&: sets the shadow color of the text to the given color. +\alpha&H[AA]&: sets the line's transparency as a hex pair. 00 is fully opaque + and FF is fully transparent. Some UI elements are composed of + multiple layered lines, so adding transparency may not look good. + For further granularity, \1a&H[AA]& controls the fill opacity, + \3a&H[AA]& controls the outline opacity, and \4a&H[AA]& controls + the shadow opacity. +]] +settings['enable-bar'] = true +helpText['enable-bar'] = [[Controls whether or not the progress bar is drawn at all. If this is disabled, +it also (naturally) disables the click-to-seek functionality. +]] +settings['bar-hide-inactive'] = false +helpText['bar-hide-inactive'] = [[Causes the bar to not be drawn unless the mouse is hovering over it or a +request-display call is active. This is somewhat redundant with setting bar- +height-inactive=0, except that it can allow for very rudimentary context- +sensitive behavior because it can be toggled at runtime. For example, by using +the binding `f cycle pause; script-binding progressbar/toggle-inactive-bar`, it +is possible to have the bar be persistently present only in windowed or +fullscreen contexts, depending on the default setting. +]] +settings['bar-height-inactive'] = 3 +helpText['bar-height-inactive'] = [[Sets the height of the bar display when the mouse is not in the active zone and +there is no request-display active. A value of 0 or less will cause bar-hide- +inactive to be set to true and the bar height to be set to 1. This should result +in the desired behavior while avoiding annoying debug logging in mpv (libass +does not like zero-height objects). +]] +settings['bar-height-active'] = 8 +helpText['bar-height-active'] = [[Sets the height of the bar display when the mouse is in the active zone or +request-display is active. There is no logic attached to this, so 0 or negative +values may have unexpected results. +]] +settings['progress-bar-width'] = 0 +helpText['progress-bar-width'] = [[If greater than zero, changes the progress bar style to be a small segment +rather than a continuous bar and sets its width. +]] +settings['seek-precision'] = 'exact' +helpText['seek-precision'] = [[Affects precision of seeks due to clicks on the progress bar. Should be 'exact' or +'keyframes'. Exact is slightly slower, but won't jump around between two +different times when clicking in the same place. + +Actually, this gets passed directly into the `seek` command, so the value can be +any of the arguments supported by mpv, though the ones above are the only ones +that really make sense. +]] +settings['bar-background-adaptive'] = true +helpText['bar-background-adaptive'] = [[Causes the progress bar background layer to automatically size itself to the +tallest of the cache or progress bars. Useful for improving contrast but can +make the bar take up more screen space. Has no effect if the cache bar height is +less than the bar height. +]] +settings['bar-cache-position'] = 'overlay' +helpText['bar-cache-position'] = [[Placement of the cache bar. Valid values are 'overlay' and 'underlay'. + +'overlay' causes the cache bar to be drawn on top of the foreground layer of the +bar, allowing the display of seek ranges that have already been encountered. + +'underlay' draws the cache bar between the foreground and background layers. Any +demuxer cache ranges that are prior to the current playback point will not be +shown. This matches the previous behavior. +]] +settings['bar-cache-height-inactive'] = 1.5 +helpText['bar-cache-height-inactive'] = [[Sets the height of the cache bar display when the mouse is not in the active +zone and there is no request-display active. Useful in combination with bar- +cache-position to control whether or not the cache bar is occluded by (or +occludes) the progress bar. +]] +settings['bar-cache-height-active'] = 4 +helpText['bar-cache-height-active'] = [[Sets the height of the cache bar display when the mouse is in the active zone or +request-display is active. Useful in combination with bar-cache- position to +control whether or not the cache bar is occluded by (or occludes) the progress +bar. +]] +settings['bar-default-style'] = [[\bord0\shad0]] +helpText['bar-default-style'] = [[A string of ASS override tags that get applied to all three layers of the bar: +progress, cache, and background. You probably don't want to remove \bord0 unless +your default-style includes it. +]] +settings['bar-foreground-style'] = '' +helpText['bar-foreground-style'] = [[A string of ASS override tags that get applied only to the progress layer of the +bar. +]] +settings['bar-cache-style'] = [[\c&H515151&]] +helpText['bar-cache-style'] = [[A string of ASS override tags that get applied only to the cache layer of the +bar, particularly the part of the cache bar that is behind the current playback +position. The default sets only the color. +]] +settings['bar-cache-background-style'] = [[]] +helpText['bar-cache-background-style'] = [[A string of ASS override tags that get applied only to the cache layer of the +bar, particularly the part of the cache bar that is after the current playback +position. The tags specified here are applied after bar-cache-style and override +them. Leaving this blank will leave the style the same as specified by bar- +cache-style. The split does not account for a nonzero progress-bar-width and may +look odd when used in tandem with that setting. +]] +settings['bar-background-style'] = [[\c&H2D2D2D&]] +helpText['bar-background-style'] = [[A string of ASS override tags that get applied only to the background layer of +the bar. The default sets only the color. +]] +settings['enable-elapsed-time'] = true +helpText['enable-elapsed-time'] = [[Sets whether or not the elapsed time is displayed at all. +]] +settings['elapsed-style'] = '' +helpText['elapsed-style'] = [[A string of ASS override tags that get applied only to the elapsed time display. +]] +settings['elapsed-left-margin'] = 4 +helpText['elapsed-left-margin'] = [[Controls how far from the left edge of the window the elapsed time display is +positioned. +]] +settings['elapsed-bottom-margin'] = 0 +helpText['elapsed-bottom-margin'] = [[Controls how far above the expanded progress bar the elapsed time display is +positioned. +]] +settings['enable-remaining-time'] = true +helpText['enable-remaining-time'] = [[Sets whether or not the remaining time is displayed at all. +]] +settings['remaining-style'] = '' +helpText['remaining-style'] = [[A string of ASS override tags that get applied only to the remaining time +display. +]] +settings['remaining-right-margin'] = 4 +helpText['remaining-right-margin'] = [[Controls how far from the right edge of the window the remaining time display is +positioned. +]] +settings['remaining-bottom-margin'] = 0 +helpText['remaining-bottom-margin'] = [[Controls how far above the expanded progress bar the remaining time display is +positioned. +]] +settings['enable-hover-time'] = true +helpText['enable-hover-time'] = [[Sets whether or not the calculated time corresponding to the mouse position +is displayed when the mouse hovers over the progress bar. +]] +settings['hover-time-style'] = [[\fs26]] +helpText['hover-time-style'] = [[A string of ASS override tags that get applied only to the hover time display. +Unfortunately, due to the way the hover time display is animated, alpha values +set here will be overridden. This is subject to change in future versions. +]] +settings['hover-time-left-margin'] = 120 +helpText['hover-time-left-margin'] = [[Controls how close to the left edge of the window the hover time display can +get. If this value is too small, it will end up overlapping the elapsed time +display. +]] +settings['hover-time-right-margin'] = 130 +helpText['hover-time-right-margin'] = [[Controls how close to the right edge of the window the hover time display can +get. If this value is too small, it will end up overlapping the remaining time +display. +]] +settings['hover-time-bottom-margin'] = 0 +helpText['hover-time-bottom-margin'] = [[Controls how far above the expanded progress bar the remaining time display is +positioned. +]] +settings['enable-title'] = true +helpText['enable-title'] = [[Sets whether or not the video title is displayed at all. +]] +settings['title-style'] = '' +helpText['title-style'] = [[A string of ASS override tags that get applied only to the video title display. +]] +settings['title-left-margin'] = 4 +helpText['title-left-margin'] = [[Controls how far from the left edge of the window the video title display is +positioned. +]] +settings['title-top-margin'] = 0 +helpText['title-top-margin'] = [[Controls how far from the top edge of the window the video title display is +positioned. +]] +settings['title-print-to-cli'] = true +helpText['title-print-to-cli'] = [[Controls whether or not the script logs the video title and playlist position +to the console every time a new video starts. +]] +settings['enable-system-time'] = true +helpText['enable-system-time'] = [[Sets whether or not the system time is displayed at all. +]] +settings['system-time-style'] = '' +helpText['system-time-style'] = [[A string of ASS override tags that get applied only to the system time display. +]] +settings['system-time-format'] = '%H:%M' +helpText['system-time-format'] = [[Sets the format used for the system time display. This must be a strftime- +compatible format string. +]] +settings['system-time-right-margin'] = 4 +helpText['system-time-right-margin'] = [[Controls how far from the right edge of the window the system time display is +positioned. +]] +settings['system-time-top-margin'] = 0 +helpText['system-time-top-margin'] = [[Controls how far from the top edge of the window the system time display is +positioned. +]] +settings['pause-indicator'] = true +helpText['pause-indicator'] = [[Sets whether or not the pause indicator is displayed. The pause indicator is a +momentary icon that flashes in the middle of the screen, similar to youtube. +]] +settings['pause-indicator-foreground-style'] = [[\c&HFC799E&]] +helpText['pause-indicator-foreground-style'] = [[A string of ASS override tags that get applied only to the foreground of the +pause indicator. +]] +settings['pause-indicator-background-style'] = [[\c&H2D2D2D&]] +helpText['pause-indicator-background-style'] = [[A string of ASS override tags that get applied only to the background of the +pause indicator. +]] +settings['enable-chapter-markers'] = true +helpText['enable-chapter-markers'] = [[Sets whether or not the progress bar is decorated with chapter markers. Due to +the way the chapter markers are currently implemented, videos with a large +number of chapters may slow down the script somewhat, but I have yet to run +into this being a problem. +]] +settings['chapter-marker-width'] = 2 +helpText['chapter-marker-width'] = [[Controls the width of each chapter marker when the progress bar is inactive. +]] +settings['chapter-marker-width-active'] = 4 +helpText['chapter-marker-width-active'] = [[Controls the width of each chapter marker when the progress bar is active. +]] +settings['chapter-marker-active-height-fraction'] = 1 +helpText['chapter-marker-active-height-fraction'] = [[Modifies the height of the chapter markers when the progress bar is active. Acts +as a multiplier on the height of the active progress bar. A value greater than 1 +will cause the markers to be taller than the expanded progress bar, whereas a +value less than 1 will cause them to be shorter. +]] +settings['chapter-marker-before-style'] = [[\c&HFC799E&]] +helpText['chapter-marker-before-style'] = [[A string of ASS override tags that get applied only to chapter markers that have +not yet been passed. +]] +settings['chapter-marker-after-style'] = [[\c&H2D2D2D&]] +helpText['chapter-marker-after-style'] = [[A string of ASS override tags that get applied only to chapter markers that have +already been passed. +]] +settings['request-display-duration'] = 1 +helpText['request-display-duration'] = [[Sets the amount of time in seconds that the UI stays on the screen after it +receives a request-display signal. A value of 0 will keep the display on screen +only as long as the key bound to it is held down. +]] +settings['redraw-period'] = 0.03 +helpText['redraw-period'] = [[Controls how often the display is redrawn, in seconds. This does not seem to +significantly affect the smoothness of animations, and it is subject to the +accuracy limits imposed by the scheduler mpv uses. Probably not worth changing +unless you have major performance problems. +]] +settings['animation-duration'] = 0.25 +helpText['animation-duration'] = [[Controls how long the UI animations take. A value of 0 disables all animations +(which breaks the pause indicator). +]] +settings['elapsed-offscreen-pos'] = -100 +helpText['elapsed-offscreen-pos'] = [[Controls how far off the left side of the window the elapsed time display tries +to move when it is inactive. If you use a non-default font, this value may need +to be tweaked. If this value is not far enough off-screen, the elapsed display +will disappear without animating all the way off-screen. Positive values will +cause the display to animate the wrong direction. +]] +settings['remaining-offscreen-pos'] = -100 +helpText['remaining-offscreen-pos'] = [[Controls how far off the left side of the window the remaining time display +tries to move when it is inactive. If you use a non-default font, this value may +need to be tweaked. If this value is not far enough off-screen, the elapsed +display will disappear without animating all the way off-screen. Positive values +will cause the display to animate the wrong direction. +]] +settings['hover-time-offscreen-pos'] = -50 +helpText['hover-time-offscreen-pos'] = [[Controls how far off the bottom of the window the mouse hover time display tries +to move when it is inactive. If you use a non-default font, this value may need +to be tweaked. If this value is not far enough off-screen, the elapsed +display will disappear without animating all the way off-screen. Positive values +will cause the display to animate the wrong direction. +]] +settings['system-time-offscreen-pos'] = -100 +helpText['system-time-offscreen-pos'] = [[Controls how far off the left side of the window the system time display tries +to move when it is inactive. If you use a non-default font, this value may need +to be tweaked. If this value is not far enough off-screen, the elapsed display +will disappear without animating all the way off-screen. Positive values will +cause the display to animate the wrong direction. +]] +settings['title-offscreen-pos'] = -40 +helpText['title-offscreen-pos'] = [[Controls how far off the left side of the window the video title display tries +to move when it is inactive. If you use a non-default font, this value may need +to be tweaked. If this value is not far enough off-screen, the elapsed display +will disappear without animating all the way off-screen. Positive values will +cause the display to animate the wrong direction. +]] +settings:_reload() +local Stack +do + local _class_0 + local removeElementMetadata, reindex + local _base_0 = { + insert = function(self, element, index) + if index then + table.insert(self, index, element) + element[self] = index + else + table.insert(self, element) + element[self] = #self + end + if self.containmentKey then + element[self.containmentKey] = true + end + end, + remove = function(self, element) + if element[self] == nil then + error("Trying to remove an element that doesn't exist in this stack.") + end + table.remove(self, element[self]) + reindex(self, element[self]) + return removeElementMetadata(self, element) + end, + clear = function(self) + local element = table.remove(self) + while element do + removeElementMetadata(self, element) + element = table.remove(self) + end + end, + removeSortedList = function(self, elementList) + if #elementList < 1 then + return + end + for i = 1, #elementList - 1 do + local element = table.remove(elementList) + table.remove(self, element[self]) + removeElementMetadata(self, element) + end + local lastElement = table.remove(elementList) + table.remove(self, lastElement[self]) + reindex(self, lastElement[self]) + return removeElementMetadata(self, lastElement) + end, + removeList = function(self, elementList) + table.sort(elementList, function(a, b) + return a[self] < b[self] + end) + return self:removeSortedList(elementList) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, containmentKey) + self.containmentKey = containmentKey + end, + __base = _base_0, + __name = "Stack" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + removeElementMetadata = function(self, element) + element[self] = nil + if self.containmentKey then + element[self.containmentKey] = false + end + end + reindex = function(self, start) + if start == nil then + start = 1 + end + for i = start, #self do + (self[i])[self] = i + end + end + Stack = _class_0 +end +local Window +do + local _class_0 + local osdScale + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "Window" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + osdScale = settings['display-scale-factor'] + self.__class.w, self.__class.h = 0, 0 + self.update = function(self) + local w, h = mp.get_osd_size() + w, h = math.floor(w / osdScale), math.floor(h / osdScale) + if w ~= self.w or h ~= self.h then + self.w, self.h = w, h + return true + else + return false + end + end + Window = _class_0 +end +local Mouse +do + local _class_0 + local osdScale, scaledPosition + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "Mouse" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + osdScale = settings['display-scale-factor'] + self.__class.x, self.__class.y = -1, -1 + self.__class.inWindow, self.__class.dead = false, true + self.__class.clickX, self.__class.clickY = -1, -1 + self.__class.clickPending = false + scaledPosition = function() + local x, y = mp.get_mouse_pos() + return math.floor(x / osdScale), math.floor(y / osdScale) + end + self.update = function(self) + local oldX, oldY = self.x, self.y + self.x, self.y = scaledPosition() + if self.dead and (oldX ~= self.x or oldY ~= self.y) then + self.dead = false + end + if not self.dead and self.clickPending then + self.clickPending = false + return true + end + return false + end + self.cacheClick = function(self) + if not self.dead then + self.clickX, self.clickY = scaledPosition() + self.clickPending = true + else + self.dead = false + end + end + Mouse = _class_0 +end +mp.add_key_binding("mouse_btn0", "left-click", function() + return Mouse:cacheClick() +end) +mp.observe_property('fullscreen', 'bool', function() + Mouse:update() + Mouse.dead = true +end) +mp.add_forced_key_binding("mouse_leave", "mouse-leave", function() + Mouse.inWindow = false +end) +mp.add_forced_key_binding("mouse_enter", "mouse-enter", function() + Mouse.inWindow = true +end) +local Rect +do + local _class_0 + local _base_0 = { + cacheMaxBounds = function(self) + self.xMax = self.x + self.w + self.yMax = self.y + self.h + end, + setPosition = function(self, x, y) + self.x = x or self.x + self.y = y or self.y + return self:cacheMaxBounds() + end, + setSize = function(self, w, h) + self.w = w or self.w + self.h = h or self.h + return self:cacheMaxBounds() + end, + reset = function(self, x, y, w, h) + self.x = x or self.x + self.y = y or self.y + self.w = w or self.w + self.h = h or self.h + return self:cacheMaxBounds() + end, + move = function(self, x, y) + self.x = self.x + (x or self.x) + self.y = self.y + (y or self.y) + return self:cacheMaxBounds() + end, + stretch = function(self, w, h) + self.w = self.w + (w or self.w) + self.h = self.h + (h or self.h) + return self:cacheMaxBounds() + end, + containsPoint = function(self, x, y) + return (x >= self.x) and (x < self.xMax) and (y >= self.y) and (y < self.yMax) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, x, y, w, h) + if x == nil then + x = -1 + end + if y == nil then + y = -1 + end + if w == nil then + w = -1 + end + if h == nil then + h = -1 + end + self.x, self.y, self.w, self.h = x, y, w, h + return self:cacheMaxBounds() + end, + __base = _base_0, + __name = "Rect" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Rect = _class_0 +end +local ActivityZone +do + local _class_0 + local _parent_0 = Rect + local _base_0 = { + reconfigure = function(self) + self.active = false + end, + addUIElement = function(self, element) + self.elements:insert(element) + return element:activate(self.active) + end, + removeUIElement = function(self, element) + return self.elements:remove(element) + end, + clickHandler = function(self) + if not (self:containsPoint(Mouse.clickX, Mouse.clickY)) then + return + end + for _, element in ipairs(self.elements) do + if element.clickHandler and not element:clickHandler() then + break + end + end + end, + activityCheck = function(self, displayRequested) + if displayRequested == true then + return true + end + if not (Mouse.inWindow) then + return false + end + if Mouse.dead then + return false + end + return self:containsPoint(Mouse.x, Mouse.y) + end, + update = function(self, displayRequested, clickPending) + local nowActive = self:activityCheck(displayRequested) + if self.active ~= nowActive then + self.active = nowActive + for id, element in ipairs(self.elements) do + element:activate(nowActive) + end + end + if clickPending then + self:clickHandler() + end + return nowActive + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, resize, activityCheck) + self.resize, self.activityCheck = resize, activityCheck + _class_0.__parent.__init(self) + self.active = false + self.elements = Stack() + end, + __base = _base_0, + __name = "ActivityZone", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + ActivityZone = _class_0 +end +local AnimationQueue +do + local _class_0 + local animationList, deletionQueue + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "AnimationQueue" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + animationList = Stack('active') + deletionQueue = { } + self.addAnimation = function(animation) + if not (animation.active) then + return animationList:insert(animation) + end + end + self.removeAnimation = function(animation) + if animation.active then + return animationList:remove(animation) + end + end + self.destroyAnimationStack = function() + return animationList:clear() + end + self.animate = function() + if #animationList == 0 then + return + end + local currentTime = mp.get_time() + for _, animation in ipairs(animationList) do + if animation:update(currentTime) then + table.insert(deletionQueue, animation) + end + end + if #deletionQueue > 0 then + return animationList:removeSortedList(deletionQueue) + end + end + self.active = function() + return #animationList > 0 + end + AnimationQueue = _class_0 +end +local EventLoop +do + local _class_0 + local _base_0 = { + reconfigure = function(self) + settings:_reload() + AnimationQueue.destroyAnimationStack() + for _, zone in ipairs(self.activityZones) do + zone:reconfigure() + end + for _, element in ipairs(self.uiElements) do + element:reconfigure() + end + end, + addZone = function(self, zone) + if zone == nil then + return + end + return self.activityZones:insert(zone) + end, + removeZone = function(self, zone) + if zone == nil then + return + end + return self.activityZones:remove(zone) + end, + generateUIFromZones = function(self) + local seenUIElements = { } + self.script = { } + self.uiElements:clear() + AnimationQueue.destroyAnimationStack() + for _, zone in ipairs(self.activityZones) do + for _, uiElement in ipairs(zone.elements) do + if not (seenUIElements[uiElement]) then + self:addUIElement(uiElement) + seenUIElements[uiElement] = true + end + end + end + return self.updateTimer:resume() + end, + addUIElement = function(self, uiElement) + if uiElement == nil then + error('nil UIElement added.') + end + self.uiElements:insert(uiElement) + return table.insert(self.script, '') + end, + removeUIElement = function(self, uiElement) + if uiElement == nil then + error('nil UIElement removed.') + end + table.remove(self.script, uiElement[self.uiElements]) + self.uiElements:remove(uiElement) + self.needsRedraw = true + end, + resize = function(self) + for _, zone in ipairs(self.activityZones) do + zone:resize() + end + for _, uiElement in ipairs(self.uiElements) do + uiElement:resize() + end + end, + redraw = function(self, forceRedraw) + local clickPending = Mouse:update() + if Window:update() then + self:resize() + end + for index, zone in ipairs(self.activityZones) do + zone:update(self.displayRequested, clickPending) + end + AnimationQueue.animate() + for index, uiElement in ipairs(self.uiElements) do + if uiElement:redraw() then + self.script[index] = uiElement:stringify() + self.needsRedraw = true + end + end + if self.needsRedraw then + mp.set_osd_ass(Window.w, Window.h, table.concat(self.script, '\n')) + self.needsRedraw = false + end + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self) + self.script = { } + self.uiElements = Stack() + self.activityZones = Stack() + self.displayRequested = false + self.needsRedraw = false + self.updateTimer = mp.add_periodic_timer(settings['redraw-period'], (function() + local _base_1 = self + local _fn_0 = _base_1.redraw + return function(...) + return _fn_0(_base_1, ...) + end + end)()) + self.updateTimer:stop() + mp.register_event('shutdown', function() + return self.updateTimer:kill() + end) + local displayRequestTimer + local displayDuration = settings['request-display-duration'] + mp.add_key_binding("tab", "request-display", function(event) + if event.event == "repeat" then + return + end + if event.event == "down" or event.event == "press" then + if displayRequestTimer then + displayRequestTimer:kill() + end + self.displayRequested = true + end + if event.event == "up" or event.event == "press" then + if displayDuration == 0 then + self.displayRequested = false + else + displayRequestTimer = mp.add_timeout(displayDuration, function() + self.displayRequested = false + end) + end + end + end, { + complex = true + }) + return mp.add_key_binding('ctrl+r', 'reconfigure', (function() + local _base_1 = self + local _fn_0 = _base_1.reconfigure + return function(...) + return _fn_0(_base_1, ...) + end + end)(), { + repeatable = false + }) + end, + __base = _base_0, + __name = "EventLoop" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + EventLoop = _class_0 +end +local Animation +do + local _class_0 + local _base_0 = { + update = function(self, now) + if self.isReversed then + self.linearProgress = math.max(0, math.min(1, self.linearProgress + (self.lastUpdate - now) * self.durationR)) + if self.linearProgress == 0 then + self.isFinished = true + end + else + self.linearProgress = math.max(0, math.min(1, self.linearProgress + (now - self.lastUpdate) * self.durationR)) + if self.linearProgress == 1 then + self.isFinished = true + end + end + self.lastUpdate = now + local progress = math.pow(self.linearProgress, self.accel) + self.value = (1 - progress) * self.initialValue + progress * self.endValue + self.updateCb(self.value) + if self.isFinished and self.finishedCb then + self:finishedCb() + end + return self.isFinished + end, + interrupt = function(self, reverse) + self.finishedCb = nil + self.lastUpdate = mp.get_time() + self.isReversed = reverse + if not (self.active) then + self.isFinished = false + return AnimationQueue.addAnimation(self) + end + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, initialValue, endValue, duration, updateCb, finishedCb, accel) + if accel == nil then + accel = 1 + end + self.initialValue, self.endValue, self.duration, self.updateCb, self.finishedCb, self.accel = initialValue, endValue, duration, updateCb, finishedCb, accel + self.value = self.initialValue + self.linearProgress = 0 + self.lastUpdate = mp.get_time() + self.durationR = 1 / self.duration + self.isFinished = (self.duration <= 0) + self.active = false + self.isReversed = false + end, + __base = _base_0, + __name = "Animation" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Animation = _class_0 +end +local UIElement +do + local _class_0 + local _base_0 = { + stringify = function(self) + self.needsUpdate = false + if not self.active then + return '' + else + return table.concat(self.line) + end + end, + activate = function(self, activate) + if activate == true then + self.animation:interrupt(false) + self.active = true + else + self.animation:interrupt(true) + self.animation.finishedCb = function() + self.active = false + end + end + end, + reconfigure = function(self) + self.needsUpdate = true + self.animationDuration = settings['animation-duration'] + end, + resize = function(self) + return error('UIElement updateSize called') + end, + redraw = function(self) + return self.needsUpdate + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self) + self.needsUpdate = false + self.active = false + self.animationDuration = settings['animation-duration'] + end, + __base = _base_0, + __name = "UIElement" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + UIElement = _class_0 +end +local BarAccent +do + local _class_0 + local barSize + local _parent_0 = UIElement + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + barSize = settings['bar-height-active'] + end, + resize = function(self) + self.yPos = Window.h - barSize + self.needsUpdate = true + end, + redraw = function(self) + if self.barSize ~= barSize then + self.barSize = barSize + return self:resize() + end + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.yPos = Window.h - barSize + end, + __base = _base_0, + __name = "BarAccent", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + barSize = settings['bar-height-active'] + self.changeBarSize = function(size) + barSize = size + end + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + BarAccent = _class_0 +end +local BarBase +do + local _class_0 + local hideInactive, lineBaseTemplate + local _parent_0 = UIElement + local _base_0 = { + _updateBarVisibility = function(self) + if hideInactive then + self.animationMinHeight = 0 + else + self.animationMinHeight = self.minHeight + end + end, + reconfigure = function(self, prefix) + if prefix == nil then + prefix = 'bar-' + end + _class_0.__parent.__base.reconfigure(self) + self.minHeight = settings[prefix .. 'height-inactive'] * 100 + self.maxHeight = settings[prefix .. 'height-active'] * 100 + hideInactive = settings['bar-hide-inactive'] + self:_updateBarVisibility() + self.line[4] = self.minHeight + self.line[8] = lineBaseTemplate:format(settings['default-style'], settings['bar-default-style'], '%s') + self.animation = Animation(0, 1, self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)()) + end, + stringify = function(self) + self.needsUpdate = false + if hideInactive and not self.active then + return "" + else + return table.concat(self.line) + end + end, + resize = function(self) + self.line[2] = ([[%d,%d]]):format(0, Window.h) + self.line[9] = ([[m 0 0 l %d 0 %d 1 0 1]]):format(Window.w, Window.w) + self.needsUpdate = true + end, + animate = function(self, value) + self.line[4] = ([[%g]]):format((self.maxHeight - self.animationMinHeight) * value + self.animationMinHeight) + self.needsUpdate = true + end, + redraw = function(self) + if self.hideInactive ~= hideInactive then + self.hideInactive = hideInactive + if not (self.active) then + self:animate(0) + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + self.minHeight = settings['bar-height-inactive'] * 100 + self.animationMinHeight = minHeight + self.maxHeight = settings['bar-height-active'] * 100 + self.line = { + [[{\pos(]], + 0, + [[)\fscy]], + minHeight, + [[\fscx]], + 0.001, + [[]], + lineBaseTemplate, + 0 + } + _class_0.__parent.__init(self) + table.insert(self.__class.instantiatedBars, self) + return self:reconfigure() + end, + __base = _base_0, + __name = "BarBase", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + hideInactive = settings['bar-hide-inactive'] + self.instantiatedBars = { } + self.toggleInactiveVisibility = function(self) + hideInactive = not hideInactive + local _list_0 = self.instantiatedBars + for _index_0 = 1, #_list_0 do + local bar = _list_0[_index_0] + bar:_updateBarVisibility() + end + end + lineBaseTemplate = [[\an1%s%s%s\p1}]] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + BarBase = _class_0 +end +local ProgressBar +do + local _class_0 + local seekString + local _parent_0 = BarBase + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + seekString = ('absolute-percent+%s'):format(settings['seek-precision']) + self.barShift = settings['progress-bar-width'] / 2.0 + self:resize() + self.line[7] = [[]] + self.line[8] = self.line[8]:format(settings['bar-foreground-style']) + end, + clickHandler = function(self) + return mp.commandv("seek", Mouse.clickX * 100 / Window.w, seekString) + end, + resize = function(self) + _class_0.__parent.__base.resize(self) + if self.barShift > 0 then + self.line[2] = ('%g,%g'):format(self.barShift, Window.h) + end + end, + redraw = function(self) + _class_0.__parent.__base.redraw(self) + if self.hideInactive and not self.active then + return self.needsUpdate + end + local position = mp.get_property_number('percent-pos', 0) + if position ~= self.lastPosition or self.needsUpdate then + self.line[6] = position + if self.barShift > 0 then + local followingEdge = Window.w * position * 1e-2 - self.barShift + self.line[7] = ([[\clip(m %g 0 l %g 0 %g %g %g %g)]]):format(followingEdge, Window.w, Window.w, Window.h, followingEdge, Window.h) + end + self.lastPosition = position + self.needsUpdate = true + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.lastPosition = 0 + end, + __base = _base_0, + __name = "ProgressBar", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + seekString = ('absolute-percent+%s'):format(settings['seek-precision']) + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + ProgressBar = _class_0 +end +local ProgressBarCache +do + local _class_0 + local timestamp + local _parent_0 = BarBase + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self, 'bar-cache-') + self.line[6] = 100 + self.line[8] = self.line[8]:format(settings['bar-cache-style']) .. 'm 0 0' + self.line[10] = ([[{\p0%s\p1}]]):format(settings['bar-cache-background-style']) + self.line[11] = [[]] + self.fileDuration = mp.get_property_number('duration', nil) + end, + resize = function(self) + _class_0.__parent.__base.resize(self) + if self.fileDuration then + self.coordinateRemap = Window.w / self.fileDuration + end + self.line[9] = [[]] + end, + redraw = function(self) + _class_0.__parent.__base.redraw(self) + if self.hideInactive and not self.active then + return self.needsUpdate + end + if self.fileDuration and (self.fileDuration > 0) then + local barDrawing = { + past = { }, + future = { } + } + local ranges + ranges = mp.get_property_native('demuxer-cache-state', { })['seekable-ranges'] + if ranges and (#ranges > 0) then + local position = mp.get_property_number('percent-pos', 0) + local cacheKeyAggregator = { + Window.w, + position + } + for _index_0 = 1, #ranges do + local _des_0 = ranges[_index_0] + local rangeStart, rangeEnd + rangeStart, rangeEnd = _des_0.start, _des_0["end"] + table.insert(cacheKeyAggregator, rangeStart) + table.insert(cacheKeyAggregator, rangeEnd) + end + local cacheKey = table.concat(cacheKeyAggregator, '_') + if cacheKey == self.cacheKey then + return self.needsUpdate + end + local progressPosition = mp.get_property_number('percent-pos', 0) * Window.w * 0.01 + for _index_0 = 1, #ranges do + local _des_0 = ranges[_index_0] + local rangeStart, rangeEnd + rangeStart, rangeEnd = _des_0.start, _des_0["end"] + rangeStart = rangeStart * self.coordinateRemap + rangeEnd = rangeEnd * self.coordinateRemap + if rangeEnd < progressPosition then + local rect = ('m %g 0 l %g 1 %g 1 %g 0'):format(rangeStart, rangeStart, rangeEnd, rangeEnd) + table.insert(barDrawing.past, rect) + elseif rangeStart > progressPosition then + rangeStart = rangeStart - progressPosition + rangeEnd = rangeEnd - progressPosition + local rect = ('m %g 0 l %g 1 %g 1 %g 0'):format(rangeStart, rangeStart, rangeEnd, rangeEnd) + table.insert(barDrawing.future, rect) + else + rangeEnd = rangeEnd - progressPosition + local rectPast = ('m %g 0 l %g 1 %g 1 %g 0'):format(rangeStart, rangeStart, progressPosition, progressPosition) + local rectFuture = ('m %g 0 l %g 1 %g 1 %g 0'):format(0, 0, rangeEnd, rangeEnd) + table.insert(barDrawing.past, rectPast) + table.insert(barDrawing.future, rectFuture) + end + end + self.line[9] = table.concat(barDrawing.past, ' ') .. ('m %g 0'):format(progressPosition) + self.line[11] = table.concat(barDrawing.future, ' ') + self.cacheKey = cacheKey + self.needsUpdate = true + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.cacheKey = nil + self.coordinateRemap = 0 + return mp.observe_property('duration', 'number', function(name, value) + if value and (value > 0) then + self.fileDuration = value + self.coordinateRemap = Window.w / value + end + end) + end, + __base = _base_0, + __name = "ProgressBarCache", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + timestamp = os.time() + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + ProgressBarCache = _class_0 +end +local ProgressBarBackground +do + local _class_0 + local _parent_0 = BarBase + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + if settings['bar-background-adaptive'] then + local _list_0 = self.__class.instantiatedBars + for _index_0 = 1, #_list_0 do + local bar = _list_0[_index_0] + self.minHeight = math.max(self.minHeight, bar.minHeight) + self.maxHeight = math.max(self.maxHeight, bar.maxHeight) + end + self:_updateBarVisibility() + end + self.line[6] = 100 + self.line[8] = self.line[8]:format(settings['bar-background-style']) + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "ProgressBarBackground", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + ProgressBarBackground = _class_0 +end +local ChapterMarker +do + local _class_0 + local beforeStyle, afterStyle + local _base_0 = { + stringify = function(self) + return table.concat(self.line) + end, + resize = function(self) + self.line[2] = ('%d,%d'):format(math.floor(self.position * Window.w), Window.h) + end, + animate = function(self, width, height) + self.line[4] = ('%g'):format(width) + self.line[6] = ('%g'):format(height) + end, + redraw = function(self, position, update) + if update == nil then + update = false + end + if not self.passed and (position > self.position) then + self.line[7] = afterStyle + self.passed = true + update = true + elseif self.passed and (position < self.position) then + self.line[7] = beforeStyle + self.passed = false + update = true + end + return update + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, position, minWidth, minHeight) + self.position = position + self.line = { + [[{\an2\bord0\p1\pos(]], + ([[%g,%g]]):format(self.position * Window.w, Window.h), + [[)\fscx]], + minWidth, + [[\fscy]], + minHeight, + beforeStyle, + '}m 0 0 l 1 0 1 1 0 1\n' + } + self.passed = false + end, + __base = _base_0, + __name = "ChapterMarker" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + beforeStyle = settings['chapter-marker-before-style'] + afterStyle = settings['chapter-marker-after-style'] + self.reconfigure = function(self) + beforeStyle = settings['chapter-marker-before-style'] + afterStyle = settings['chapter-marker-after-style'] + end + ChapterMarker = _class_0 +end +local Chapters +do + local _class_0 + local minWidth, maxWidth, maxHeight, maxHeightFrac + local _parent_0 = BarBase + local _base_0 = { + createMarkers = function(self) + self.line = { } + self.markers = { } + local totalTime = mp.get_property_number('duration', 0.01) + local chapters = mp.get_property_native('chapter-list', { }) + local markerHeight = self.active and maxHeight * maxHeightFrac or BarBase.instantiatedBars[1].animationMinHeight + local markerWidth = self.active and maxWidth or minWidth + for _index_0 = 1, #chapters do + local chapter = chapters[_index_0] + local marker = ChapterMarker(chapter.time / totalTime, markerWidth, markerHeight) + table.insert(self.markers, marker) + table.insert(self.line, marker:stringify()) + end + self.needsUpdate = true + end, + reconfigure = function(self) + UIElement.reconfigure(self) + minWidth = settings['chapter-marker-width'] * 100 + maxWidth = settings['chapter-marker-width-active'] * 100 + maxHeight = settings['bar-height-active'] * 100 + maxHeightFrac = settings['chapter-marker-active-height-fraction'] + ChapterMarker:reconfigure() + self:createMarkers() + self.animation = Animation(0, 1, self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)()) + end, + resize = function(self) + for i, marker in ipairs(self.markers) do + marker:resize() + self.line[i] = marker:stringify() + end + self.needsUpdate = true + end, + animate = function(self, value) + local width = (maxWidth - minWidth) * value + minWidth + local height = (maxHeight * maxHeightFrac - BarBase.instantiatedBars[1].animationMinHeight) * value + BarBase.instantiatedBars[1].animationMinHeight + for i, marker in ipairs(self.markers) do + marker:animate(width, height) + self.line[i] = marker:stringify() + end + self.needsUpdate = true + end, + redraw = function(self) + _class_0.__parent.__base.redraw(self) + local currentPosition = mp.get_property_number('percent-pos', 0) * 0.01 + local update = false + for i, marker in ipairs(self.markers) do + if marker:redraw(currentPosition) then + self.line[i] = marker:stringify() + update = true + end + end + return self.needsUpdate or update + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.line = { } + self.markers = { } + self.animation = Animation(0, 1, self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)()) + end, + __base = _base_0, + __name = "Chapters", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + minWidth = settings['chapter-marker-width'] * 100 + maxWidth = settings['chapter-marker-width-active'] * 100 + maxHeight = settings['bar-height-active'] * 100 + maxHeightFrac = settings['chapter-marker-active-height-fraction'] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Chapters = _class_0 +end +local TimeElapsed +do + local _class_0 + local bottomMargin + local _parent_0 = BarAccent + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + bottomMargin = settings['elapsed-bottom-margin'] + local offscreenPos = settings['elapsed-offscreen-pos'] + self.line[2] = ('%g,%g'):format(self.position, self.yPos - bottomMargin) + self.line[3] = ([[)\an1%s%s}]]):format(settings['default-style'], settings['elapsed-style']) + self.animation = Animation(offscreenPos, settings['elapsed-left-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + resize = function(self) + _class_0.__parent.__base.resize(self) + self.line[2] = ('%g,%g'):format(self.position, self.yPos - bottomMargin) + end, + animate = function(self, value) + self.position = value + self.line[2] = ('%g,%g'):format(value, self.yPos - bottomMargin) + self.needsUpdate = true + end, + redraw = function(self) + if self.active then + _class_0.__parent.__base.redraw(self) + local timeElapsed = math.floor(mp.get_property_number('time-pos', 0)) + if timeElapsed ~= self.lastTime then + local update = true + self.line[4] = ('%d:%02d:%02d'):format(math.floor(timeElapsed / 3600), math.floor((timeElapsed / 60) % 60), math.floor(timeElapsed % 60)) + self.lastTime = timeElapsed + self.needsUpdate = true + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + local offscreenPos = settings['elapsed-offscreen-pos'] + self.line = { + [[{\pos(]], + ([[%g,0]]):format(offscreenPos), + ([[)\an1%s%s}]]):format(settings['default-style'], settings['elapsed-style']), + [[????]] + } + self.lastTime = -1 + self.position = offscreenPos + self.animation = Animation(offscreenPos, settings['elapsed-left-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + __base = _base_0, + __name = "TimeElapsed", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + bottomMargin = settings['elapsed-bottom-margin'] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + TimeElapsed = _class_0 +end +local TimeRemaining +do + local _class_0 + local bottomMargin + local _parent_0 = BarAccent + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + bottomMargin = settings['remaining-bottom-margin'] + local offscreenPos = settings['remaining-offscreen-pos'] + self.line[2] = ('%g,%g'):format(self.position, self.yPos - bottomMargin) + self.line[3] = ([[)\an3%s%s}]]):format(settings['default-style'], settings['remaining-style']) + self.animation = Animation(offscreenPos, settings['remaining-right-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + resize = function(self) + _class_0.__parent.__base.resize(self) + self.position = Window.w - self.animation.value + self.line[2] = ('%g,%g'):format(self.position, self.yPos - bottomMargin) + end, + animate = function(self, value) + self.position = Window.w - value + self.line[2] = ('%g,%g'):format(self.position, self.yPos - bottomMargin) + self.needsUpdate = true + end, + redraw = function(self) + if self.active then + _class_0.__parent.__base.redraw(self) + local timeRemaining = math.floor(mp.get_property_number('playtime-remaining', 0)) + if timeRemaining ~= self.lastTime then + local update = true + self.line[4] = ('–%d:%02d:%02d'):format(math.floor(timeRemaining / 3600), math.floor((timeRemaining / 60) % 60), math.floor(timeRemaining % 60)) + self.lastTime = timeRemaining + self.needsUpdate = true + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + local offscreenPos = settings['remaining-offscreen-pos'] + self.line = { + [[{\pos(]], + ([[%g,0]]):format(offscreenPos), + ([[)\an3%s%s}]]):format(settings['default-style'], settings['remaining-style']), + [[????]] + } + self.lastTime = -1 + self.position = offscreenPos + self.animation = Animation(offscreenPos, settings['remaining-right-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + __base = _base_0, + __name = "TimeRemaining", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + bottomMargin = settings['remaining-bottom-margin'] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + TimeRemaining = _class_0 +end +local HoverTime +do + local _class_0 + local rightMargin, leftMargin, bottomMargin, offScreenPos + local _parent_0 = BarAccent + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + rightMargin = settings['hover-time-right-margin'] + leftMargin = settings['hover-time-left-margin'] + bottomMargin = settings['hover-time-bottom-margin'] + offScreenPos = settings['hover-time-offscreen-pos'] + self.line[2] = ('%g,%g'):format(math.min(Window.w - rightMargin, math.max(leftMargin, Mouse.x)), self.position) + self.line[1] = ([[{%s%s\pos(]]):format(settings['default-style'], settings['hover-time-style']) + self.animation = Animation(offScreenPos, bottomMargin, self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + resize = function(self) + _class_0.__parent.__base.resize(self) + self.line[2] = ("%g,%g"):format(math.min(Window.w - rightMargin, math.max(leftMargin, Mouse.x)), self.yPos - self.animation.value) + end, + animate = function(self, value) + self.position = self.yPos - value + self.line[2] = ("%g,%g"):format(math.min(Window.w - rightMargin, math.max(leftMargin, Mouse.x)), self.position) + self.needsUpdate = true + end, + redraw = function(self) + if self.active then + _class_0.__parent.__base.redraw(self) + if Mouse.x ~= self.lastX then + self.line[2] = ("%g,%g"):format(math.min(Window.w - rightMargin, math.max(leftMargin, Mouse.x)), self.position) + self.lastX = Mouse.x + local hoverTime = mp.get_property_number('duration', 0) * Mouse.x / Window.w + if hoverTime ~= self.lastTime then + self.line[4] = ([[%d:%02d:%02d]]):format(math.floor(hoverTime / 3600), math.floor((hoverTime / 60) % 60), math.floor(hoverTime % 60)) + self.lastTime = hoverTime + end + self.needsUpdate = true + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.line = { + ([[{%s%s\pos(]]):format(settings['default-style'], settings['hover-time-style']), + [[-100,0]], + [[)\an2}]], + [[????]] + } + self.lastTime = 0 + self.lastX = -1 + self.position = offScreenPos + self.animation = Animation(offScreenPos, bottomMargin, self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + __base = _base_0, + __name = "HoverTime", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + rightMargin = settings['hover-time-right-margin'] + leftMargin = settings['hover-time-left-margin'] + bottomMargin = settings['hover-time-bottom-margin'] + offScreenPos = settings['hover-time-offscreen-pos'] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + HoverTime = _class_0 +end +local PauseIndicator +do + local _class_0 + local _base_0 = { + stringify = function(self) + return table.concat(self.line) + end, + resize = function(self) + local w, h = 0.5 * Window.w, 0.5 * Window.h + self.line[5] = ([[%g,%g]]):format(w, h) + self.line[12] = ([[%g,%g]]):format(w, h) + end, + redraw = function() + return true + end, + animate = function(self, value) + local scale = value * 50 + 100 + local scaleStr = ([[{\fscx%g\fscy%g]]):format(scale, scale) + local alphaStr = ('%02X'):format(value * value * 255) + self.line[1] = scaleStr + self.line[8] = scaleStr + self.line[3] = alphaStr + self.line[10] = alphaStr + end, + destroy = function(self, animation) + return self.eventLoop:removeUIElement(self) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, eventLoop, paused) + self.eventLoop = eventLoop + local w, h = 0.5 * Window.w, 0.5 * Window.h + self.line = { + [[{\fscx0\fscy0]], + [[\alpha&H]], + 0, + [[&\pos(]], + ([[%g,%g]]):format(w, h), + ([[)\an5\bord0%s\p1}]]):format(settings['pause-indicator-background-style']), + 0, + [[{\fscx0\fscy0]], + [[\alpha&H]], + 0, + [[&\pos(]], + ([[%g,%g]]):format(w, h), + ([[)\an5\bord0%s\p1}]]):format(settings['pause-indicator-foreground-style']), + 0 + } + if paused then + self.line[7] = 'm 75 37.5 b 75 58.21 58.21 75 37.5 75 16.79 75 0 58.21 0 37.5 0 16.79 16.79 0 37.5 0 58.21 0 75 16.79 75 37.5 m 23 20 l 23 55 33 55 33 20 m 42 20 l 42 55 52 55 52 20\n' + self.line[14] = 'm 0 0 m 75 75 m 23 20 l 23 55 33 55 33 20 m 42 20 l 42 55 52 55 52 20' + else + self.line[7] = 'm 75 37.5 b 75 58.21 58.21 75 37.5 75 16.79 75 0 58.21 0 37.5 0 16.79 16.79 0 37.5 0 58.21 0 75 16.79 75 37.5 m 25.8333 17.18 l 25.8333 57.6 60.8333 37.39\n' + self.line[14] = 'm 0 0 m 75 75 m 25.8333 17.18 l 25.8333 57.6 60.8333 37.39' + end + AnimationQueue.addAnimation(Animation(0, 1, settings['animation-duration'], (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), (function() + local _base_1 = self + local _fn_0 = _base_1.destroy + return function(...) + return _fn_0(_base_1, ...) + end + end)())) + return self.eventLoop:addUIElement(self) + end, + __base = _base_0, + __name = "PauseIndicator" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + PauseIndicator = _class_0 +end +local Title +do + local _class_0 + local _parent_0 = UIElement + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + local offscreenPos = settings['title-offscreen-pos'] + self.line[2] = ('%g,%g'):format(settings['title-left-margin'], self.animation.value) + self.line[3] = ([[)\an7%s%s}]]):format(settings['default-style'], settings['title-style']) + self.animation = Animation(offscreenPos, settings['title-top-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + resize = function(self) end, + animate = function(self, value) + self.line[2] = ('%g,%g'):format(settings['title-left-margin'], value) + self.needsUpdate = true + end, + _forceUpdatePlaylistInfo = function(self) + self.playlistInfo = { + ['media-title'] = mp.get_property('media-title', '????'), + ['playlist-pos-1'] = mp.get_property_number('playlist-pos-1', 1), + ['playlist-count'] = mp.get_property_number('playlist-count', 1) + } + end, + generateTitleString = function(self, quote) + if quote == nil then + quote = false + end + local title, position, total + do + local _obj_0 = self.playlistInfo + title, position, total = _obj_0['media-title'], _obj_0['playlist-pos-1'], _obj_0['playlist-count'] + end + local prefix = (total > 1) and ('%d/%d - '):format(position, total) or '' + if quote then + return prefix .. ('%q'):format(title) + else + return prefix .. title + end + end, + updatePlaylistInfo = function(self, changedProp, newValue) + if newValue then + self.playlistInfo[changedProp] = newValue + self.line[4] = self:generateTitleString() + self.needsUpdate = true + end + end, + print = function(self) + if settings['title-print-to-cli'] then + return log.warn("Playing: %s", self:generateTitleString(true)) + end + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + local offscreenPos = settings['title-offscreen-pos'] + self.line = { + [[{\pos(]], + ([[%g,%g]]):format(settings['title-left-margin'], offscreenPos), + ([[)\an7%s%s}]]):format(settings['default-style'], settings['title-style']), + [[????]] + } + self.position = offscreenPos + self.animation = Animation(offscreenPos, settings['title-top-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + self:_forceUpdatePlaylistInfo() + local updatePlaylistInfo + do + local _base_1 = self + local _fn_0 = _base_1.updatePlaylistInfo + updatePlaylistInfo = function(...) + return _fn_0(_base_1, ...) + end + end + mp.observe_property('media-title', 'string', updatePlaylistInfo) + mp.observe_property('playlist-pos-1', 'number', updatePlaylistInfo) + return mp.observe_property('playlist-count', 'number', updatePlaylistInfo) + end, + __base = _base_0, + __name = "Title", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Title = _class_0 +end +local SystemTime +do + local _class_0 + local offscreenPosition, topMargin, timeFormat + local _parent_0 = UIElement + local _base_0 = { + reconfigure = function(self) + _class_0.__parent.__base.reconfigure(self) + offscreenPosition = settings['system-time-offscreen-pos'] + topMargin = settings['system-time-top-margin'] + timeFormat = settings['system-time-format'] + self.line[2] = ('%g,%g'):format(self.position, topMargin) + self.line[3] = ([[)\an9%s%s}]]):format(settings['default-style'], settings['system-time-style']) + self.animation = Animation(offscreenPosition, settings['system-time-right-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + resize = function(self) + self.position = Window.w - self.animation.value + self.line[2] = ('%g,%g'):format(self.position, topMargin) + end, + animate = function(self, value) + self.position = Window.w - value + self.line[2] = ('%g,%g'):format(self.position, topMargin) + self.needsUpdate = true + end, + redraw = function(self) + if self.active then + local systemTime = os.time() + if systemTime ~= self.lastTime then + local update = true + self.line[4] = os.date(timeFormat, systemTime) + self.lastTime = systemTime + self.needsUpdate = true + end + end + return self.needsUpdate + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self) + _class_0.__parent.__init(self) + self.line = { + [[{\pos(]], + [[-100,0]], + ([[)\an9%s%s}]]):format(settings['default-style'], settings['system-time-style']), + [[????]] + } + self.lastTime = -1 + self.position = offscreenPosition + self.animation = Animation(offscreenPosition, settings['system-time-right-margin'], self.animationDuration, (function() + local _base_1 = self + local _fn_0 = _base_1.animate + return function(...) + return _fn_0(_base_1, ...) + end + end)(), nil, 0.5) + end, + __base = _base_0, + __name = "SystemTime", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + offscreenPosition = settings['system-time-offscreen-pos'] + topMargin = settings['system-time-top-margin'] + timeFormat = settings['system-time-format'] + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + SystemTime = _class_0 +end +local eventLoop = EventLoop() +local activeHeight = settings['hover-zone-height'] +local ignoreRequestDisplay +ignoreRequestDisplay = function(self) + if not (Mouse.inWindow) then + return false + end + if Mouse.dead then + return false + end + return self:containsPoint(Mouse.x, Mouse.y) +end +local bottomZone = ActivityZone(function(self) + return self:reset(0, Window.h - activeHeight, Window.w, activeHeight) +end) +local hoverTimeZone = ActivityZone(function(self) + return self:reset(0, Window.h - activeHeight, Window.w, activeHeight) +end, ignoreRequestDisplay) +local topZone = ActivityZone(function(self) + return self:reset(0, 0, Window.w, activeHeight) +end, ignoreRequestDisplay) +local chapters, progressBar, barCache, barBackground, elapsedTime, remainingTime, hoverTime +if settings['enable-bar'] then + progressBar = ProgressBar() + barCache = ProgressBarCache() + barBackground = ProgressBarBackground() + bottomZone:addUIElement(barBackground) + if settings['bar-cache-position'] == 'overlay' then + bottomZone:addUIElement(progressBar) + bottomZone:addUIElement(barCache) + else + bottomZone:addUIElement(barCache) + bottomZone:addUIElement(progressBar) + end + mp.add_key_binding("c", "toggle-inactive-bar", function() + return BarBase:toggleInactiveVisibility() + end) +end +if settings['enable-chapter-markers'] then + chapters = Chapters() + bottomZone:addUIElement(chapters) +end +if settings['enable-elapsed-time'] then + elapsedTime = TimeElapsed() + bottomZone:addUIElement(elapsedTime) +end +if settings['enable-remaining-time'] then + remainingTime = TimeRemaining() + bottomZone:addUIElement(remainingTime) +end +if settings['enable-hover-time'] then + hoverTime = HoverTime() + hoverTimeZone:addUIElement(hoverTime) +end +local title = nil +if settings['enable-title'] then + title = Title() + bottomZone:addUIElement(title) + topZone:addUIElement(title) +end +if settings['enable-system-time'] then + local systemTime = SystemTime() + bottomZone:addUIElement(systemTime) + topZone:addUIElement(systemTime) +end +eventLoop:addZone(hoverTimeZone) +eventLoop:addZone(bottomZone) +eventLoop:addZone(topZone) +local notFrameStepping = false +if settings['pause-indicator'] then + local PauseIndicatorWrapper + PauseIndicatorWrapper = function(event, paused) + if notFrameStepping then + return PauseIndicator(eventLoop, paused) + elseif paused then + notFrameStepping = true + end + end + mp.add_key_binding('.', 'step-forward', function() + notFrameStepping = false + return mp.commandv('frame_step') + end, { + repeatable = true + }) + mp.add_key_binding(',', 'step-backward', function() + notFrameStepping = false + return mp.commandv('frame_back_step') + end, { + repeatable = true + }) + mp.observe_property('pause', 'bool', PauseIndicatorWrapper) +end +local streamMode = false +local initDraw +initDraw = function() + if chapters then + chapters:createMarkers() + end + if title then + title:_forceUpdatePlaylistInfo() + title:print() + end + notFrameStepping = true + local duration = mp.get_property('duration') + if not (streamMode or duration) then + BarAccent.changeBarSize(0) + if progressBar then + bottomZone:removeUIElement(progressBar) + bottomZone:removeUIElement(barCache) + bottomZone:removeUIElement(barBackground) + end + if chapters then + bottomZone:removeUIElement(chapters) + end + if hoverTime then + hoverTimeZone:removeUIElement(hoverTime) + end + if remainingTime then + bottomZone:removeUIElement(remainingTime) + end + streamMode = true + elseif streamMode and duration then + BarAccent.changeBarSize(settings['bar-height-active']) + if progressBar then + bottomZone:addUIElement(barBackground) + bottomZone:addUIElement(barCache) + bottomZone:addUIElement(progressBar) + end + if chapters then + bottomZone:addUIElement(chapters) + end + if hoverTime then + hoverTimeZone:addUIElement(hoverTime) + end + if remainingTime then + bottomZone:addUIElement(remainingTime) + end + streamMode = false + end + mp.command('script-message-to osc disable-osc') + eventLoop:generateUIFromZones() + eventLoop:resize() + return eventLoop:redraw() +end +return mp.register_event('file-loaded', initDraw) + +