feat: add time_precision
option
Number that determines sub second fraction precision to display in timeline timestamps. Default is `0`. closes #127
This commit is contained in:
@@ -103,6 +103,8 @@ color_background_text=ffffff
|
|||||||
font_bold=no
|
font_bold=no
|
||||||
# show total time instead of time remaining
|
# show total time instead of time remaining
|
||||||
total_time=no
|
total_time=no
|
||||||
|
# display sub second fraction in timestamps up to this precision
|
||||||
|
time_precision=0
|
||||||
# hide UI when mpv autohides the cursor
|
# hide UI when mpv autohides the cursor
|
||||||
autohide=no
|
autohide=no
|
||||||
# can be: none, flash, static, manual (controlled by flash-pause-indicator and decide-pause-indicator commands)
|
# can be: none, flash, static, manual (controlled by flash-pause-indicator and decide-pause-indicator commands)
|
||||||
|
87
uosc.lua
87
uosc.lua
@@ -91,6 +91,7 @@ local options = {
|
|||||||
color_background = '000000',
|
color_background = '000000',
|
||||||
color_background_text = 'ffffff',
|
color_background_text = 'ffffff',
|
||||||
total_time = false,
|
total_time = false,
|
||||||
|
time_precision = 0,
|
||||||
font_bold = false,
|
font_bold = false,
|
||||||
autohide = false,
|
autohide = false,
|
||||||
pause_indicator = 'flash',
|
pause_indicator = 'flash',
|
||||||
@@ -130,8 +131,10 @@ local state = {
|
|||||||
end)(),
|
end)(),
|
||||||
cwd = mp.get_property('working-directory'),
|
cwd = mp.get_property('working-directory'),
|
||||||
media_title = '',
|
media_title = '',
|
||||||
duration = nil,
|
time = nil, -- current media playback time
|
||||||
position = nil,
|
duration = nil, -- current media duration
|
||||||
|
time_human = nil, -- current playback time in human format
|
||||||
|
duration_or_remaining_time_human = nil, -- depends on options.total_time
|
||||||
pause = mp.get_property_native('pause'),
|
pause = mp.get_property_native('pause'),
|
||||||
chapters = nil,
|
chapters = nil,
|
||||||
chapter_ranges = nil,
|
chapter_ranges = nil,
|
||||||
@@ -468,6 +471,17 @@ function ass_escape(str)
|
|||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param seconds number
|
||||||
|
---@return string
|
||||||
|
function format_time(seconds)
|
||||||
|
local human = mp.format_time(seconds)
|
||||||
|
if options.time_precision > 0 then
|
||||||
|
local formatted = string.format('%.'..options.time_precision..'f', math.abs(seconds) % 1)
|
||||||
|
human = human..'.'..string.sub(formatted, 3)
|
||||||
|
end
|
||||||
|
return human
|
||||||
|
end
|
||||||
|
|
||||||
function opacity_to_alpha(opacity)
|
function opacity_to_alpha(opacity)
|
||||||
return 255 - math.ceil(255 * opacity)
|
return 255 - math.ceil(255 * opacity)
|
||||||
end
|
end
|
||||||
@@ -1415,10 +1429,25 @@ function update_proximities()
|
|||||||
for _, element in ipairs(mouse_enter_elements) do element:trigger('mouse_enter') end
|
for _, element in ipairs(mouse_enter_elements) do element:trigger('mouse_enter') end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function update_human_times()
|
||||||
|
if state.time then
|
||||||
|
state.time_human = format_time(state.time)
|
||||||
|
if state.duration then
|
||||||
|
state.duration_or_remaining_time_human = format_time(
|
||||||
|
options.total_time and state.duration or state.time - state.duration
|
||||||
|
)
|
||||||
|
else
|
||||||
|
state.duration_or_remaining_time_human = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
state.time_human = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- ELEMENT RENDERERS
|
-- ELEMENT RENDERERS
|
||||||
|
|
||||||
function render_timeline(this)
|
function render_timeline(this)
|
||||||
if this.size_max == 0 or state.duration == nil or state.duration == 0 or state.position == nil then return end
|
if this.size_max == 0 or state.duration == nil or state.duration == 0 or state.time == nil then return end
|
||||||
|
|
||||||
local size_min = this:get_effective_size_min()
|
local size_min = this:get_effective_size_min()
|
||||||
local size = this:get_effective_size()
|
local size = this:get_effective_size()
|
||||||
@@ -1433,7 +1462,7 @@ function render_timeline(this)
|
|||||||
local text_opacity = math.max(math.min(size - hide_text_below, hide_text_ramp), 0) / hide_text_ramp
|
local text_opacity = math.max(math.min(size - hide_text_below, hide_text_ramp), 0) / hide_text_ramp
|
||||||
|
|
||||||
local spacing = math.max(math.floor((this.size_max - this.font_size) / 2.5), 4)
|
local spacing = math.max(math.floor((this.size_max - this.font_size) / 2.5), 4)
|
||||||
local progress = state.position / state.duration
|
local progress = state.time / state.duration
|
||||||
local is_line = options.timeline_style == 'line'
|
local is_line = options.timeline_style == 'line'
|
||||||
|
|
||||||
-- Background bar coordinates
|
-- Background bar coordinates
|
||||||
@@ -1649,7 +1678,7 @@ function render_timeline(this)
|
|||||||
local function render_time()
|
local function render_time()
|
||||||
if text_opacity > 0 then
|
if text_opacity > 0 then
|
||||||
-- Elapsed time
|
-- Elapsed time
|
||||||
if state.elapsed_seconds then
|
if state.time_human then
|
||||||
local elapsed_x = bax + spacing
|
local elapsed_x = bax + spacing
|
||||||
local elapsed_y = fay + (size / 2)
|
local elapsed_y = fay + (size / 2)
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
@@ -1657,23 +1686,17 @@ function render_timeline(this)
|
|||||||
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
||||||
ass:pos(elapsed_x, elapsed_y)
|
ass:pos(elapsed_x, elapsed_y)
|
||||||
ass:an(4)
|
ass:an(4)
|
||||||
ass:append(state.elapsed_time)
|
ass:append(state.time_human)
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
ass:append('{\\blur0\\bord0\\shad1\\1c&H'..options.color_background_text..'\\4c&H'..options.color_background..'\\fn'..config.font..'\\fs'..this.font_size..bold_tag..'\\iclip('..foreground_coordinates..')')
|
ass:append('{\\blur0\\bord0\\shad1\\1c&H'..options.color_background_text..'\\4c&H'..options.color_background..'\\fn'..config.font..'\\fs'..this.font_size..bold_tag..'\\iclip('..foreground_coordinates..')')
|
||||||
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
||||||
ass:pos(elapsed_x, elapsed_y)
|
ass:pos(elapsed_x, elapsed_y)
|
||||||
ass:an(4)
|
ass:an(4)
|
||||||
ass:append(state.elapsed_time)
|
ass:append(state.time_human)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- End time
|
-- End time
|
||||||
local end_time
|
if state.duration_or_remaining_time_human then
|
||||||
if options.total_time then
|
|
||||||
end_time = this.total_time
|
|
||||||
else
|
|
||||||
end_time = state.remaining_time and '-'..state.remaining_time
|
|
||||||
end
|
|
||||||
if end_time then
|
|
||||||
local end_x = bbx - spacing
|
local end_x = bbx - spacing
|
||||||
local end_y = fay + (size / 2)
|
local end_y = fay + (size / 2)
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
@@ -1681,13 +1704,13 @@ function render_timeline(this)
|
|||||||
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
||||||
ass:pos(end_x, end_y)
|
ass:pos(end_x, end_y)
|
||||||
ass:an(6)
|
ass:an(6)
|
||||||
ass:append(end_time)
|
ass:append(state.duration_or_remaining_time_human)
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
ass:append('{\\blur0\\bord0\\shad1\\1c&H'..options.color_background_text..'\\4c&H'..options.color_background..'\\fn'..config.font..'\\fs'..this.font_size..bold_tag..'\\iclip('..foreground_coordinates..')')
|
ass:append('{\\blur0\\bord0\\shad1\\1c&H'..options.color_background_text..'\\4c&H'..options.color_background..'\\fn'..config.font..'\\fs'..this.font_size..bold_tag..'\\iclip('..foreground_coordinates..')')
|
||||||
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1), text_opacity))
|
||||||
ass:pos(end_x, end_y)
|
ass:pos(end_x, end_y)
|
||||||
ass:an(6)
|
ass:an(6)
|
||||||
ass:append(end_time)
|
ass:append(state.duration_or_remaining_time_human)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1725,7 +1748,7 @@ function render_timeline(this)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local time_formatted = mp.format_time(hovered_seconds)
|
local time_formatted = format_time(hovered_seconds)
|
||||||
local margin_time = text_width_estimate(time_formatted, this.font_size) / 2
|
local margin_time = text_width_estimate(time_formatted, this.font_size) / 2
|
||||||
local margin_title = chapter_title_width * this.font_size * options.font_height_to_letter_width_ratio / 2
|
local margin_title = chapter_title_width * this.font_size * options.font_height_to_letter_width_ratio / 2
|
||||||
ass:new_event()
|
ass:new_event()
|
||||||
@@ -2387,7 +2410,6 @@ elements:add('timeline', Element.new({
|
|||||||
size_max = 0, size_min = 0, -- set in `on_display_change` handler based on `state.fullormaxed`
|
size_max = 0, size_min = 0, -- set in `on_display_change` handler based on `state.fullormaxed`
|
||||||
size_min_override = options.timeline_start_hidden and 0 or nil, -- used for toggle-progress command
|
size_min_override = options.timeline_start_hidden and 0 or nil, -- used for toggle-progress command
|
||||||
font_size = 0, -- calculated in on_display_change
|
font_size = 0, -- calculated in on_display_change
|
||||||
total_time = nil, -- set in op_prop_duration listener
|
|
||||||
top_border = options.timeline_border,
|
top_border = options.timeline_border,
|
||||||
get_effective_proximity = function(this)
|
get_effective_proximity = function(this)
|
||||||
if this.pressed or is_element_persistent('timeline') then return 1 end
|
if this.pressed or is_element_persistent('timeline') then return 1 end
|
||||||
@@ -2423,9 +2445,6 @@ elements:add('timeline', Element.new({
|
|||||||
on_prop_border = function(this) this:update_dimensions() end,
|
on_prop_border = function(this) this:update_dimensions() end,
|
||||||
on_prop_fullormaxed = function(this) this:update_dimensions() end,
|
on_prop_fullormaxed = function(this) this:update_dimensions() end,
|
||||||
on_display_change = function(this) this:update_dimensions() end,
|
on_display_change = function(this) this:update_dimensions() end,
|
||||||
on_prop_duration = function(this, value)
|
|
||||||
this.total_time = value and mp.format_time(value) or nil
|
|
||||||
end,
|
|
||||||
set_from_cursor = function(this)
|
set_from_cursor = function(this)
|
||||||
-- padding serves the purpose of matching cursor to timeline_style=line exactly
|
-- padding serves the purpose of matching cursor to timeline_style=line exactly
|
||||||
local padding = (options.timeline_style == 'line' and this:get_effective_line_width() or 0) / 2
|
local padding = (options.timeline_style == 'line' and this:get_effective_line_width() or 0) / 2
|
||||||
@@ -3361,6 +3380,16 @@ end
|
|||||||
|
|
||||||
-- HOOKS
|
-- HOOKS
|
||||||
mp.register_event('file-loaded', parse_chapters)
|
mp.register_event('file-loaded', parse_chapters)
|
||||||
|
mp.observe_property('playback-time', 'number', function(name, val)
|
||||||
|
state.time = val
|
||||||
|
update_human_times()
|
||||||
|
request_render()
|
||||||
|
end)
|
||||||
|
mp.observe_property('duration', 'number', function(name, val)
|
||||||
|
state.duration = val
|
||||||
|
update_human_times()
|
||||||
|
request_render()
|
||||||
|
end)
|
||||||
mp.observe_property('track-list', 'native', function(name, value)
|
mp.observe_property('track-list', 'native', function(name, value)
|
||||||
-- checks if the file is audio only (mp3, etc)
|
-- checks if the file is audio only (mp3, etc)
|
||||||
local has_audio = false
|
local has_audio = false
|
||||||
@@ -3384,7 +3413,6 @@ mp.observe_property('chapter-list', 'native', parse_chapters)
|
|||||||
mp.observe_property('border', 'bool', create_state_setter('border'))
|
mp.observe_property('border', 'bool', create_state_setter('border'))
|
||||||
mp.observe_property('ab-loop-a', 'number', create_state_setter('ab_loop_a'))
|
mp.observe_property('ab-loop-a', 'number', create_state_setter('ab_loop_a'))
|
||||||
mp.observe_property('ab-loop-b', 'number', create_state_setter('ab_loop_b'))
|
mp.observe_property('ab-loop-b', 'number', create_state_setter('ab_loop_b'))
|
||||||
mp.observe_property('duration', 'number', create_state_setter('duration'))
|
|
||||||
mp.observe_property('media-title', 'string', create_state_setter('media_title'))
|
mp.observe_property('media-title', 'string', create_state_setter('media_title'))
|
||||||
mp.observe_property('playlist-pos-1', 'number', create_state_setter('playlist_pos'))
|
mp.observe_property('playlist-pos-1', 'number', create_state_setter('playlist_pos'))
|
||||||
mp.observe_property('playlist-count', 'number', create_state_setter('playlist_count'))
|
mp.observe_property('playlist-count', 'number', create_state_setter('playlist_count'))
|
||||||
@@ -3408,21 +3436,6 @@ mp.observe_property('pause', 'bool', create_state_setter('pause'))
|
|||||||
mp.observe_property('volume', 'number', create_state_setter('volume'))
|
mp.observe_property('volume', 'number', create_state_setter('volume'))
|
||||||
mp.observe_property('volume-max', 'number', create_state_setter('volume_max'))
|
mp.observe_property('volume-max', 'number', create_state_setter('volume_max'))
|
||||||
mp.observe_property('mute', 'bool', create_state_setter('mute'))
|
mp.observe_property('mute', 'bool', create_state_setter('mute'))
|
||||||
mp.observe_property('playback-time', 'number', function(name, val)
|
|
||||||
-- Ignore the initial call with nil value
|
|
||||||
if val == nil then return end
|
|
||||||
|
|
||||||
state.position = val
|
|
||||||
state.elapsed_seconds = val
|
|
||||||
state.elapsed_time = state.elapsed_seconds and mp.format_time(state.elapsed_seconds) or nil
|
|
||||||
|
|
||||||
request_render()
|
|
||||||
end)
|
|
||||||
mp.observe_property('playtime-remaining', 'number', function(name, val)
|
|
||||||
state.remaining_seconds = mp.get_property_native('playtime-remaining')
|
|
||||||
state.remaining_time = state.remaining_seconds and mp.format_time(state.remaining_seconds) or nil
|
|
||||||
request_render()
|
|
||||||
end)
|
|
||||||
mp.observe_property('osd-dimensions', 'native', function(name, val)
|
mp.observe_property('osd-dimensions', 'native', function(name, val)
|
||||||
update_display_dimensions()
|
update_display_dimensions()
|
||||||
request_render()
|
request_render()
|
||||||
|
Reference in New Issue
Block a user