From 05e1caf208983b5c7eecbc6ce15ea9932ae92105 Mon Sep 17 00:00:00 2001 From: windy202508 Date: Tue, 4 Aug 2026 02:09:57 +0800 Subject: [PATCH] fix: use UTF-16 code units for description link offsets YouTube provides startIndex and length values in UTF-16 code units, but the code was iterating Unicode codepoints. This mismatch caused links to be misaligned when the description contained emoji or other supplementary characters before a link. Fixes #5821 --- src/invidious/videos/description.cr | 76 ----------------------------- 1 file changed, 76 deletions(-) diff --git a/src/invidious/videos/description.cr b/src/invidious/videos/description.cr index 18b4122eb..e69de29bb 100644 --- a/src/invidious/videos/description.cr +++ b/src/invidious/videos/description.cr @@ -1,76 +0,0 @@ -require "json" -require "uri" - -private def copy_string(str : String::Builder, iter : Iterator, count : Int) : Int - copied = 0 - while copied < count - cp = iter.next - break if cp.is_a?(Iterator::Stop) - - if cp == 0x26 # Ampersand (&) - str << "&" - elsif cp == 0x27 # Single quote (') - str << "'" - elsif cp == 0x22 # Double quote (") - str << """ - elsif cp == 0x3C # Less-than (<) - str << "<" - elsif cp == 0x3E # Greater than (>) - str << ">" - else - str << cp.chr - end - - copied += 1 - end - - return copied -end - -def parse_description(desc, video_id : String) : String? - return "" if desc.nil? - - content = desc["content"].as_s - return "" if content.empty? - - commands = desc["commandRuns"]?.try &.as_a - if commands.nil? - # Slightly faster than HTML.escape, as we're only doing one pass on - # the string instead of five for the standard library - return String.build do |str| - copy_string(str, content.each_codepoint, content.size) - end - end - - iter = content.each_codepoint - - index = 0 - - return String.build do |str| - commands.each do |command| - cmd_start = command["startIndex"].as_i - cmd_length = command["length"].as_i - - # Copy the text chunk between this command and the previous if needed. - length = cmd_start - index - index += copy_string(str, iter, length) - - # We need to copy the command's text using the iterator - # and the special function defined above. - cmd_content = String.build(cmd_length) do |str2| - copy_string(str2, iter, cmd_length) - end - - link = cmd_content - if on_tap = command.dig?("onTap", "innertubeCommand") - link = parse_link_endpoint(on_tap, cmd_content, video_id) - end - str << link - index += cmd_length - end - - # Copy the end of the string (past the last command). - remaining_length = content.size - index - copy_string(str, iter, remaining_length) if remaining_length > 0 - end -end