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 _mathmin = math.min
local _mathmax = math.max
local clamp
clamp = function(value, min, max)
  return _mathmin(max, _mathmax(value, min))
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'] = 0
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'] = 0
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['default-style'] = [[\fnSource Sans Pro\b1\bord2\shad0\fs30\c&H0000FF&\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'] = 4
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'] = 0.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-thumbnail'] = true
helpText['enable-thumbnail'] = [[Sets whether or not thumbnails are displayed at all. Note: thumbnail display
requires use of the thumbfast script (See: https://github.com/po5/thumbfast).
]]
settings['thumbnail-left-margin'] = 10
helpText['thumbnail-left-margin'] = [[Controls how close to the left edge of the window the thumbnail display can
get.
]]
settings['thumbnail-right-margin'] = 10
helpText['thumbnail-right-margin'] = [[Controls how close to the right edge of the window the thumbnail display can
get.
]]
settings['thumbnail-bottom-margin'] = 40
helpText['thumbnail-bottom-margin'] = [[Controls how far above the expanded progress bar the thumbnail 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 _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
  self.__class.osdScale = mp.get_property_number("display-hidpi-scale", 1)
  self.__class.w, self.__class.h = 0, 0
  self.__class._rawW, self.__class._rawH = 0, 0
  self.update = function(self)
    local w, h = mp.get_osd_size()
    local osdScale = mp.get_property_number("display-hidpi-scale", 1)
    self._rawW, self._rawH = w, h
    w, h = math.floor(w / osdScale), math.floor(h / osdScale)
    if w ~= self.w or h ~= self.h or osdScale ~= self.osdScale then
      self.w, self.h, self.osdScale = w, h, osdScale
      return true
    else
      return false
    end
  end
  Window = _class_0
end
local Mouse
do
  local _class_0
  local 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
  self.__class.x, self.__class.y = -1, -1
  self.__class._rawX, self.__class._rawY = -1, -1
  self.__class.inWindow, self.__class.dead = false, true
  self.__class.clickX, self.__class.clickY = -1, -1
  self.__class.clickPending = false
  scaledPosition = function(self)
    local x, y = mp.get_mouse_pos()
    self._rawX, self._rawY = x, y
    return math.floor(x / Window.osdScale), math.floor(y / Window.osdScale)
  end
  self.update = function(self)
    local oldX, oldY = self.x, self.y
    self.x, self.y = scaledPosition(self)
    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)
      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.canvas.res_x = Window.w
        self.canvas.res_y = Window.h
        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
        self.canvas.data = table.concat(self.script, '\n')
        self.canvas:update()
        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.canvas = mp.create_osd_overlay("ass-events")
      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 = clamp(self.linearProgress + (self.lastUpdate - now) * self.durationR, 0, 1)
        if self.linearProgress == 0 then
          self.isFinished = true
        end
      else
        self.linearProgress = clamp(self.linearProgress + (now - self.lastUpdate) * self.durationR, 0, 1)
        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
        if self.animation then
          self.animation:interrupt(false)
        end
        self.active = true
      else
        if self.animation then
          self.animation:interrupt(true)
          self.animation.finishedCb = function()
            self.active = false
          end
        else
          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[9] = ''
      self.line[10] = '\n'
      for idx = 1, 9 do
        self.line[idx + 10] = self.line[idx]
      end
      self.line[8] = self.line[8]:format(settings['bar-cache-style'])
      self.line[18] = self.line[18]:format(settings['bar-cache-background-style'])
      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[12] = self.line[2]
      return self:clobber()
    end,
    animate = function(self, value)
      _class_0.__parent.__base.animate(self, value)
      self.line[14] = self.line[4]
    end,
    clobber = function(self)
      self.line[9] = ""
      self.line[19] = ""
    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
              local rect = ('m %g 0 l %g 1 %g 1 %g 0'):format(rangeStart, rangeStart, rangeEnd, rangeEnd)
              table.insert(barDrawing.future, rect)
            else
              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(progressPosition, progressPosition, rangeEnd, rangeEnd)
              table.insert(barDrawing.past, rectPast)
              table.insert(barDrawing.future, rectFuture)
            end
          end
          self.line[9] = table.concat(barDrawing.past, ' ')
          self.line[19] = table.concat(barDrawing.future, ' ')
          self.cacheKey = cacheKey
          self.needsUpdate = true
        else
          self:clobber()
        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(clamp(Mouse.x, leftMargin, Window.w - rightMargin), 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(clamp(Mouse.x, leftMargin, Window.w - rightMargin), self.yPos - self.animation.value)
    end,
    animate = function(self, value)
      self.position = self.yPos - value
      self.line[2] = ("%g,%g"):format(clamp(Mouse.x, leftMargin, Window.w - rightMargin), self.position)
      self.needsUpdate = true
    end,
    _setXPosition = function(self, x)
      self.line[2] = ("%g,%g"):format(clamp(x, leftMargin, Window.w - rightMargin), self.position)
      self.needsUpdate = true
    end,
    _setUnknownDuration = function(self)
      self.line[4] = "????"
      self.needsUpdate = true
    end,
    _setTime = function(self, hoverTime)
      self.line[4] = ([[%d:%02d:%02d]]):format(math.floor(hoverTime / 3600), math.floor((hoverTime / 60) % 60), math.floor(hoverTime % 60))
      self.needsUpdate = true
    end,
    redraw = function(self)
      if self.active then
        _class_0.__parent.__base.redraw(self)
        local duration = mp.get_property_number('duration', 0)
        local hoverTime = duration * Mouse.x / Window.w
        if Mouse.x ~= self.lastX then
          self.lastX = Mouse.x
          self:_setXPosition(Mouse.x)
        end
        if duration ~= self.lastDuration or hoverTime ~= self.lastTime then
          self.lastDuration = duration
          self.lastTime = hoverTime
          if duration == 0 then
            self:_setUnknownDuration()
          else
            self:_setTime(hoverTime)
          end
        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.lastDuration = 0
      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 Thumbnail
do
  local _class_0
  local rightMargin, leftMargin, bottomMargin
  local _parent_0 = BarAccent
  local _base_0 = {
    updateInfo = function(self, thumbfastInfo)
      self.thumbfast = thumbfastInfo
      self.lastX = -1
      self.needsUpdate = true
    end,
    reconfigure = function(self)
      _class_0.__parent.__base.reconfigure(self)
      rightMargin = settings['thumbnail-right-margin']
      leftMargin = settings['thumbnail-left-margin']
      bottomMargin = settings['thumbnail-bottom-margin']
    end,
    activate = function(self, activate)
      _class_0.__parent.__base.activate(self, activate)
      if not activate then
        mp.commandv('script-message-to', 'thumbfast', 'clear')
        self.needsUpdate = true
      end
    end,
    redraw = function(self)
      if self.active then
        _class_0.__parent.__base.redraw(self)
        if Mouse.x ~= self.lastX and not self.thumbfast.disabled then
          self.lastX = Mouse.x
          local hoverTime = mp.get_property_number('duration', 0) * Mouse.x / Window.w
          mp.commandv('script-message-to', 'thumbfast', 'thumb', hoverTime, clamp(Mouse._rawX - self.thumbfast.width / 2, leftMargin, Window._rawW - self.thumbfast.width - rightMargin), Window._rawH - bottomMargin * Window.osdScale - self.thumbfast.height)
        end
        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, thumbfastInfo)
      _class_0.__parent.__init(self)
      self.line = { }
      self.lastX = -1
      return self:updateInfo(thumbfastInfo)
    end,
    __base = _base_0,
    __name = "Thumbnail",
    __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['thumbnail-right-margin']
  leftMargin = settings['thumbnail-left-margin']
  bottomMargin = settings['thumbnail-bottom-margin']
  if _parent_0.__inherited then
    _parent_0.__inherited(_parent_0, _class_0)
  end
  Thumbnail = _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)
      }
      self.needsUpdate = true
    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, thumbnail
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
if settings['enable-thumbnail'] then
  mp.register_script_message('thumbfast-info', function(json)
    local data = utils.parse_json(json)
    if type(data) ~= 'table' or not data.width or not data.height then
      return log.warn('thumbfast did not respond with proper thumbnail information. Thumbnails are disabled.')
    else
      if thumbnail then
        return thumbnail:updateInfo(data)
      else
        thumbnail = Thumbnail(data)
        hoverTimeZone:addUIElement(thumbnail)
        return eventLoop:generateUIFromZones()
      end
    end
  end)
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)