feat: make hashtags in video titles clickable (#442)

Adds parse_hashtags_in_text() to utils.cr that wraps #hashtag patterns
in anchor links pointing to /hashtag/:tag. Applied to video titles on:
- Watch page (watch.ecr) - main title and related video titles
- Search/feed items (item.ecr) - all video result titles

The function uses a regex to find #word patterns and converts them to
<a href="/hashtag/TAG">#TAG</a> links, preserving the original text
appearance while making hashtags navigable to their search pages.
This commit is contained in:
Alex DevTech 2026-07-30 18:06:12 -07:00
parent 9d1291a0b8
commit b7697e97c3
3 changed files with 14 additions and 4 deletions

View File

@ -404,3 +404,13 @@ def invidious_companion_encrypt(data)
encrypted_data = encrypt_ecb_without_salt("#{timestamp}|#{data}", CONFIG.invidious_companion_key)
return Base64.urlsafe_encode(encrypted_data)
end
# Parses hashtags (#tag) in a text string and wraps them in clickable links.
# The input text should already be HTML-escaped. The hashtag text is kept as-is
# (including the # symbol) within the link, while the URL uses the encoded tag name.
def parse_hashtags_in_text(text : String) : String
text.gsub(/#([\w-]+)/) do |_match|
hashtag = $1
%(<a href="/hashtag/#{URI.encode_www_form(hashtag, space_to_plus: false)}">##{hashtag}</a>)
end
end

View File

@ -78,7 +78,7 @@
</div>
<div class="video-card-row">
<a href="<%= link_url %>"><p dir="auto"><%= HTML.escape(item.title) %></p></a>
<a href="<%= link_url %>"><p dir="auto"><%= parse_hashtags_in_text(HTML.escape(item.title)) %></p></a>
</div>
<div class="video-card-row flexible">
@ -176,7 +176,7 @@
</div>
<div class="video-card-row">
<a href="<%= link_url %>"><p dir="auto"><%= HTML.escape(item.title) %></p></a>
<a href="<%= link_url %>"><p dir="auto"><%= parse_hashtags_in_text(HTML.escape(item.title)) %></p></a>
</div>
<div class="video-card-row flexible">

View File

@ -1,5 +1,5 @@
<% ucid = video.ucid %>
<% title = HTML.escape(video.title) %>
<% title = parse_hashtags_in_text(HTML.escape(video.title)) %>
<% author = HTML.escape(video.author) %>
@ -341,7 +341,7 @@ we're going to need to do it here in order to allow for translations.
</div>
<div class="video-card-row">
<a href="/watch?v=<%= rv["id"] %>&listen=<%= params.listen %>"><p dir="auto"><%= HTML.escape(rv["title"]) %></p></a>
<a href="/watch?v=<%= rv["id"] %>&listen=<%= params.listen %>"><p dir="auto"><%= parse_hashtags_in_text(HTML.escape(rv["title"])) %></p></a>
</div>
<h5 class="pure-g">