Skip to content

Commit

Permalink
Alternative approach
Browse files Browse the repository at this point in the history
  • Loading branch information
christoph-heinrich committed Aug 15, 2022
1 parent 7671e00 commit e7a94b6
Showing 1 changed file with 124 additions and 30 deletions.
154 changes: 124 additions & 30 deletions uosc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,110 @@ function text_width_estimate(text, font_size)
return text_width * options.font_height_to_letter_width_ratio
end

function utf8_iter(string)
local byte_start = 1
local byte_count = 1

return function()
if #string < byte_start then return nil end

local char_byte = string.byte(string, byte_start)

byte_count = 1;
if char_byte < 192 then byte_count = 1
elseif char_byte < 224 then byte_count = 2
elseif char_byte < 240 then byte_count = 3
elseif char_byte < 248 then byte_count = 4
elseif char_byte < 252 then byte_count = 5
elseif char_byte < 254 then byte_count = 6
end

local start = byte_start
byte_start = byte_start + byte_count

return start, byte_count, (byte_count > 2 and 2 or 1)
end
end

function wrap_text(text, line_width_requested)
local line_width = 0
local wrap_at_chars = {' ', ' ', '-', ''}
local remove_when_wrap = {' ', ' '}
local lines = {}
local line_start = 1
local before_end = nil
local before_width = 0
local before_line_start = 0
local before_removed_width = 0
local max_width = 0
for char_start, count, char_width in utf8_iter(text) do
local char_end = char_start + count - 1
local char = text.sub(text, char_start, char_end)
local can_wrap = false
for _, c in ipairs(wrap_at_chars) do
if char == c then
can_wrap = true
break
end
end
line_width = line_width + char_width
if can_wrap or (char_end == #text) then
local remove = false
for _, c in ipairs(remove_when_wrap) do
if char == c then
remove = true
break
end
end
local line_width_after_remove = line_width - (remove and char_width or 0)
if line_width_after_remove < line_width_requested then
before_end = remove and char_start - 1 or char_end
before_width = line_width_after_remove
before_line_start = char_end + 1
before_removed_width = remove and char_width or 0
else
if (line_width_requested - before_width) <
(line_width_after_remove - line_width_requested) then
lines[#lines+1] = text.sub(text, line_start, before_end)
line_start = before_line_start
line_width = line_width - before_width - before_removed_width
if before_removed_width > max_width then before_removed_width = line_width end
else
lines[#lines+1] = text.sub(text, line_start, remove and char_start - 1 or char_end)
line_start = char_end + 1
line_width = remove and line_width - char_width or line_width
if line_width > max_width then max_width = line_width end
line_width = 0
end
before_end = line_start
before_width = 0
end
end
end
if #text >= line_start then
lines[#lines+1] = string.sub(text, line_start)
if line_width > max_width then max_width = line_width end
end
return table.concat(lines, '\n'), max_width
end

-- Escape a string for verbatim display on the OSD
function ass_escape(str)
-- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if
-- it isn't followed by a recognised character, so add a zero-width
-- non-breaking space
str = str:gsub('\\', '\\\239\187\191')
str = str:gsub('{', '\\{')
str = str:gsub('}', '\\}')
-- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
-- consecutive newlines
str = str:gsub('\n', '\239\187\191\\N')
-- Turn leading spaces into hard spaces to prevent ASS from stripping them
str = str:gsub('\\N ', '\\N\\h')
str = str:gsub('^ ', '\\h')
return str
end

function opacity_to_alpha(opacity)
return 255 - math.ceil(255 * opacity)
end
Expand Down Expand Up @@ -1665,7 +1769,9 @@ function render_timeline(this)

if state.chapters ~= nil then
for i, chapter in ipairs(state.chapters) do
draw_chapter(chapter.time)
if not chapter._uosc_used_as_range_point then
draw_chapter(chapter.time)
end
end
end

Expand Down Expand Up @@ -1727,41 +1833,27 @@ function render_timeline(this)
-- Hovered time and chapter
local hovered_seconds = state.duration * (cursor.x / display.width)
local chapter_title = ''
local chapter_time = 0
if state.chapter_ranges then
for _,chapter_range in pairs(state.chapter_ranges) do
-- sould be in chronological order from here
for j = #chapter_range.ranges, 1, -1 do
local range = chapter_range.ranges[j]
for _, chapter in ipairs({range['end'], range['start']}) do
if hovered_seconds >= chapter.time and chapter.time > chapter_time then
chapter_title = chapter.title
chapter_time = chapter.time
goto HOVER_CHAPTER_CONTINUE
end
end
end
::HOVER_CHAPTER_CONTINUE::
end
end
local chapter_title_width = 0
if (state.chapters and options.chapters ~= 'none') then
for i = #state.chapters, 1, -1 do
local chapter = state.chapters[i]
if hovered_seconds >= chapter.time and chapter.time > chapter_time then
chapter_title = chapter.title
if hovered_seconds >= chapter.time then
chapter_title = chapter.title_wrapped
chapter_title_width = chapter.title_wrapped_width
break
end
end
end
local time_formatted = mp.format_time(hovered_seconds)
local text_len = math.max(time_formatted:len(), chapter_title:len())
local box_half_width_estimate = text_width_estimate(text_len, this.font_size) / 2
local text_width = math.max(chapter_title_width, time_formatted:len())
local margin = text_width_estimate(text_width / 2, this.font_size)
ass:new_event()
ass:append('{\\blur0\\bord1\\shad0\\1c&H'..options.color_background_text..'\\3c&H'..options.color_background..'\\fn'..config.font..'\\fs'..this.font_size..bold_tag..'')
ass:append(ass_opacity(math.min(options.timeline_opacity + 0.1, 1)))
ass:pos(math.min(math.max(cursor.x, box_half_width_estimate), display.width - box_half_width_estimate), fay)
ass:pos(math.min(math.max(cursor.x, margin), display.width - margin), fay)
ass:an(2)
ass:append(chapter_title .. '\\N')
ass:append(chapter_title)
ass:append('\\N')
ass:append(time_formatted)

-- Cursor line
Expand Down Expand Up @@ -2867,7 +2959,7 @@ for _, definition in ipairs(split(options.chapter_ranges, ' *,+ *')) do
if is_end then
if current_range == nil and uses_bof and not bof_used then
bof_used = true
start_range({time = 0, title = ''})
start_range({time = 0})
end
if current_range ~= nil then
end_range(chapter)
Expand All @@ -2888,7 +2980,7 @@ for _, definition in ipairs(split(options.chapter_ranges, ' *,+ *')) do

-- If there is an unfinished range and range type accepts eof, use it
if current_range ~= nil and uses_eof then
end_range({time = state.duration or infinity, title = ''})
end_range({time = state.duration or infinity})
end
end

Expand All @@ -2911,10 +3003,12 @@ function parse_chapters()
chapter_range.serialize(chapters)
end

-- Filter out chapters that were used as ranges
state.chapters = itable_remove(chapters, function(chapter)
return chapter._uosc_used_as_range_point == true
end)
for _, chapter in ipairs(chapters) do
chapter.title_wrapped, chapter.title_wrapped_width = wrap_text(chapter.title, 25)
chapter.title_wrapped = ass_escape(chapter.title_wrapped)
end

state.chapters = chapters

request_render()
end
Expand Down

0 comments on commit e7a94b6

Please sign in to comment.