From f6e671fae1dc9821e4f38e05f94cd0a04bc2e429 Mon Sep 17 00:00:00 2001 From: zy26thu-hash <310195780+zy26thu-hash@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:54:54 +0800 Subject: [PATCH] Link hashtags in video titles --- spec/invidious/helpers_spec.cr | 12 ++++++++++++ src/invidious/helpers/utils.cr | 10 ++++++++++ src/invidious/views/watch.ecr | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/spec/invidious/helpers_spec.cr b/spec/invidious/helpers_spec.cr index 9fbb6d6fe..107e5aef7 100644 --- a/spec/invidious/helpers_spec.cr +++ b/spec/invidious/helpers_spec.cr @@ -3,6 +3,18 @@ require "../spec_helper" CONFIG = Config.from_yaml(File.open("config/config.example.yml")) Spectator.describe "Helper" do + describe "#parse_video_title" do + it "links hashtags in video titles" do + expect(parse_video_title("Video title #music")) + .to eq(%(Video title #music)) + end + + it "escapes video titles before linking hashtags" do + expect(parse_video_title(%(#music))) + .to eq(%(<b>#music</b>)) + end + end + describe "#produce_channel_search_continuation" do it "correctly produces token for searching a specific channel" do expect(produce_channel_search_continuation("UCXuqSBlHAE6Xw-yeJA0Tunw", "", 100)).to eq("4qmFsgJqEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaIEVnWnpaV0Z5WTJnd0FUZ0JZQUY2QkVkS2IxaTRBUUE9WgCaAilicm93c2UtZmVlZFVDWHVxU0JsSEFFNlh3LXllSkEwVHVud3NlYXJjaA%3D%3D") diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index 7a262f849..7769cb5cf 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -20,6 +20,16 @@ def elapsed_text(elapsed) "#{(millis * 1000).round(2)}µs" end +def parse_video_title(title : String) : String + HTML.escape(title).gsub(/(^|[[:space:]])#([A-Za-z0-9_]+)/) do |match| + prefix = match.starts_with?("#") ? "" : match[0].to_s + hashtag = match[prefix.size + 1..] + href = URI.encode_path("/hashtag/#{hashtag}") + + %(#{prefix}##{hashtag}) + end +end + def decode_length_seconds(string) length_seconds = string.gsub(/[^0-9:]/, "") return 0_i32 if length_seconds.empty? diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 796c0c914..ee393e7de 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -1,5 +1,6 @@ <% ucid = video.ucid %> <% title = HTML.escape(video.title) %> +<% title_html = parse_video_title(video.title) %> <% author = HTML.escape(video.author) %> @@ -77,7 +78,7 @@ we're going to need to do it here in order to allow for translations.

- <%= title %> + <%= title_html %> <% if params.listen %> " id="link-iv-listen" data-base-url="/watch?<%= env.params.query %>&listen=0" href="/watch?<%= env.params.query %>&listen=0">