mirror of
https://github.com/iv-org/invidious.git
synced 2026-09-07 09:33:04 -05:00
fix: use UTF-16 offsets for description links
This commit is contained in:
parent
ad4b1c69ce
commit
ed68874dc6
56
spec/invidious/videos/description_spec.cr
Normal file
56
spec/invidious/videos/description_spec.cr
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
require "../../spec_helper"
|
||||||
|
require "../../../src/invidious/videos/description"
|
||||||
|
|
||||||
|
Spectator.describe "Video description parser" do
|
||||||
|
describe "#parse_description" do
|
||||||
|
it "uses UTF-16 offsets when an emoji precedes a command" do
|
||||||
|
description = JSON.parse(<<-JSON)
|
||||||
|
{
|
||||||
|
"content": "🚀 Visit example now",
|
||||||
|
"commandRuns": [{
|
||||||
|
"startIndex": 3,
|
||||||
|
"length": 5,
|
||||||
|
"onTap": {
|
||||||
|
"innertubeCommand": {
|
||||||
|
"urlEndpoint": {"url": "https://example.com"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
JSON
|
||||||
|
|
||||||
|
expect(parse_description(description, "video-id")).to eq(
|
||||||
|
%(🚀 <a href="https://example.com">Visit</a> example now)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses UTF-16 lengths when an emoji is inside a command" do
|
||||||
|
description = JSON.parse(<<-JSON)
|
||||||
|
{
|
||||||
|
"content": "Open 😀 docs",
|
||||||
|
"commandRuns": [{
|
||||||
|
"startIndex": 0,
|
||||||
|
"length": 7,
|
||||||
|
"onTap": {
|
||||||
|
"innertubeCommand": {
|
||||||
|
"urlEndpoint": {"url": "https://example.com"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
JSON
|
||||||
|
|
||||||
|
expect(parse_description(description, "video-id")).to eq(
|
||||||
|
%(<a href="https://example.com">Open 😀</a> docs)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "escapes complete descriptions without command runs" do
|
||||||
|
description = JSON.parse(%({"content":"🚀 <safe> & complete"}))
|
||||||
|
|
||||||
|
expect(parse_description(description, "video-id")).to eq(
|
||||||
|
%(🚀 <safe> & complete)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,9 +1,9 @@
|
|||||||
require "json"
|
require "json"
|
||||||
require "uri"
|
require "uri"
|
||||||
|
|
||||||
private def copy_string(str : String::Builder, iter : Iterator, count : Int) : Int
|
private def copy_string(str : String::Builder, iter : Iterator, count : Int? = nil) : Int
|
||||||
copied = 0
|
copied = 0
|
||||||
while copied < count
|
while count.nil? || copied < count
|
||||||
cp = iter.next
|
cp = iter.next
|
||||||
break if cp.is_a?(Iterator::Stop)
|
break if cp.is_a?(Iterator::Stop)
|
||||||
|
|
||||||
@ -21,7 +21,9 @@ private def copy_string(str : String::Builder, iter : Iterator, count : Int) : I
|
|||||||
str << cp.chr
|
str << cp.chr
|
||||||
end
|
end
|
||||||
|
|
||||||
copied += 1
|
# YouTube expresses command offsets in UTF-16 code units. Astral
|
||||||
|
# codepoints therefore count as two units instead of one.
|
||||||
|
copied += cp > 0xFFFF ? 2 : 1
|
||||||
end
|
end
|
||||||
|
|
||||||
return copied
|
return copied
|
||||||
@ -38,7 +40,7 @@ def parse_description(desc, video_id : String) : String?
|
|||||||
# Slightly faster than HTML.escape, as we're only doing one pass on
|
# Slightly faster than HTML.escape, as we're only doing one pass on
|
||||||
# the string instead of five for the standard library
|
# the string instead of five for the standard library
|
||||||
return String.build do |str|
|
return String.build do |str|
|
||||||
copy_string(str, content.each_codepoint, content.size)
|
copy_string(str, content.each_codepoint)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -70,7 +72,6 @@ def parse_description(desc, video_id : String) : String?
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Copy the end of the string (past the last command).
|
# Copy the end of the string (past the last command).
|
||||||
remaining_length = content.size - index
|
copy_string(str, iter)
|
||||||
copy_string(str, iter, remaining_length) if remaining_length > 0
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user