summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/invidious/channels/about.cr20
-rw-r--r--src/invidious/comments.cr46
-rw-r--r--src/invidious/config.cr5
-rw-r--r--src/invidious/helpers/i18n.cr1
-rw-r--r--src/invidious/routes/watch.cr19
-rw-r--r--src/invidious/views/watch.ecr4
6 files changed, 75 insertions, 20 deletions
diff --git a/src/invidious/channels/about.cr b/src/invidious/channels/about.cr
index d48fd1fb..da71e9a8 100644
--- a/src/invidious/channels/about.cr
+++ b/src/invidious/channels/about.cr
@@ -6,6 +6,7 @@ record AboutChannel,
author_url : String,
author_thumbnail : String,
banner : String?,
+ description : String,
description_html : String,
total_views : Int64,
sub_count : Int32,
@@ -52,8 +53,7 @@ def get_about_info(ucid, locale) : AboutChannel
banners = initdata["header"]["interactiveTabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]?
banner = banners.try &.[-1]?.try &.["url"].as_s?
- description = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"]["simpleText"].as_s
- description_html = HTML.escape(description)
+ description_node = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"]
is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool
allowed_regions = initdata["microformat"]["microformatDataRenderer"]["availableCountries"].as_a.map(&.as_s)
@@ -75,13 +75,24 @@ def get_about_info(ucid, locale) : AboutChannel
author_verified_badge = initdata["header"].dig?("c4TabbedHeaderRenderer", "badges", 0, "metadataBadgeRenderer", "tooltip")
author_verified = (author_verified_badge && author_verified_badge == "Verified")
- description = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?.try &.as_s? || ""
- description_html = HTML.escape(description)
+ description_node = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?
is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool
allowed_regions = initdata["microformat"]["microformatDataRenderer"]["availableCountries"].as_a.map(&.as_s)
end
+ description = !description_node.nil? ? description_node.as_s : ""
+ description_html = HTML.escape(description)
+ if !description_node.nil?
+ if description_node.as_h?.nil?
+ description_node = text_to_parsed_content(description_node.as_s)
+ end
+ description_html = parse_content(description_node)
+ if description_html == "" && description != ""
+ description_html = HTML.escape(description)
+ end
+ end
+
total_views = 0_i64
joined = Time.unix(0)
@@ -125,6 +136,7 @@ def get_about_info(ucid, locale) : AboutChannel
author_url: author_url,
author_thumbnail: author_thumbnail,
banner: banner,
+ description: description,
description_html: description_html,
total_views: total_views,
sub_count: sub_count,
diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr
index f50b5907..15a15224 100644
--- a/src/invidious/comments.cr
+++ b/src/invidious/comments.cr
@@ -560,6 +560,48 @@ def fill_links(html, scheme, host)
return html.to_xml(options: XML::SaveOptions::NO_DECL)
end
+def text_to_parsed_content(text : String) : JSON::Any
+ nodes = [] of JSON::Any
+ # For each line convert line to array of nodes
+ text.split('\n').each do |line|
+ # In first case line is just a simple node before
+ # check patterns inside line
+ # { 'text': line }
+ currentNodes = [] of JSON::Any
+ initialNode = {"text" => line}
+ currentNodes << (JSON.parse(initialNode.to_json))
+
+ # For each match with url pattern, get last node and preserve
+ # last node before create new node with url information
+ # { 'text': match, 'navigationEndpoint': { 'urlEndpoint' : 'url': match } }
+ line.scan(/https?:\/\/[^ ]*/).each do |urlMatch|
+ # Retrieve last node and update node without match
+ lastNode = currentNodes[currentNodes.size - 1].as_h
+ splittedLastNode = lastNode["text"].as_s.split(urlMatch[0])
+ lastNode["text"] = JSON.parse(splittedLastNode[0].to_json)
+ currentNodes[currentNodes.size - 1] = JSON.parse(lastNode.to_json)
+ # Create new node with match and navigation infos
+ currentNode = {"text" => urlMatch[0], "navigationEndpoint" => {"urlEndpoint" => {"url" => urlMatch[0]}}}
+ currentNodes << (JSON.parse(currentNode.to_json))
+ # If text remain after match create new simple node with text after match
+ afterNode = {"text" => splittedLastNode.size > 0 ? splittedLastNode[1] : ""}
+ currentNodes << (JSON.parse(afterNode.to_json))
+ end
+
+ # After processing of matches inside line
+ # Add \n at end of last node for preserve carriage return
+ lastNode = currentNodes[currentNodes.size - 1].as_h
+ lastNode["text"] = JSON.parse("#{currentNodes[currentNodes.size - 1]["text"]}\n".to_json)
+ currentNodes[currentNodes.size - 1] = JSON.parse(lastNode.to_json)
+
+ # Finally add final nodes to nodes returned
+ currentNodes.each do |node|
+ nodes << (node)
+ end
+ end
+ return JSON.parse({"runs" => nodes}.to_json)
+end
+
def parse_content(content : JSON::Any, video_id : String? = "") : String
content["simpleText"]?.try &.as_s.rchop('\ufeff').try { |b| HTML.escape(b) }.to_s ||
content["runs"]?.try &.as_a.try { |r| content_to_comment_html(r, video_id).try &.to_s.gsub("\n", "<br>") } || ""
@@ -567,6 +609,10 @@ end
def content_to_comment_html(content, video_id : String? = "")
html_array = content.map do |run|
+ # Sometimes, there is an empty element.
+ # See: https://github.com/iv-org/invidious/issues/3096
+ next if run.as_h.empty?
+
text = HTML.escape(run["text"].as_s)
if run["navigationEndpoint"]?
diff --git a/src/invidious/config.cr b/src/invidious/config.cr
index 93c4c0f7..a077c7fd 100644
--- a/src/invidious/config.cr
+++ b/src/invidious/config.cr
@@ -161,16 +161,13 @@ class Config
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
if ENV.has_key?({{env_id}})
- # puts %(Config.{{ivar.id}} : Loading from env var {{env_id}})
env_value = ENV.fetch({{env_id}})
success = false
# Use YAML converter if specified
{% ann = ivar.annotation(::YAML::Field) %}
{% if ann && ann[:converter] %}
- puts %(Config.{{ivar.id}} : Parsing "#{env_value}" as {{ivar.type}} with {{ann[:converter]}} converter)
config.{{ivar.id}} = {{ann[:converter]}}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{env_id}})).nodes[0])
- puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}})
success = true
# Use regular YAML parser otherwise
@@ -181,9 +178,7 @@ class Config
{{ivar_types}}.each do |ivar_type|
if !success
begin
- # puts %(Config.{{ivar.id}} : Trying to parse "#{env_value}" as #{ivar_type})
config.{{ivar.id}} = ivar_type.from_yaml(env_value)
- puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}} (#{ivar_type}))
success = true
rescue
# nop
diff --git a/src/invidious/helpers/i18n.cr b/src/invidious/helpers/i18n.cr
index 9d3c4e8b..fd86594c 100644
--- a/src/invidious/helpers/i18n.cr
+++ b/src/invidious/helpers/i18n.cr
@@ -10,6 +10,7 @@ LOCALES_LIST = {
"en-US" => "English", # English
"eo" => "Esperanto", # Esperanto
"es" => "Español", # Spanish
+ "et" => "Eesti keel", # Estonian
"fa" => "فارسی", # Persian
"fi" => "Suomi", # Finnish
"fr" => "Français", # French
diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr
index 867ffa6a..7280de4f 100644
--- a/src/invidious/routes/watch.cr
+++ b/src/invidious/routes/watch.cr
@@ -306,27 +306,28 @@ module Invidious::Routes::Watch
download_widget = JSON.parse(selection)
extension = download_widget["ext"].as_s
- filename = "#{video_id}-#{title}.#{extension}"
+ filename = "#{title}-#{video_id}.#{extension}"
- # Pass form parameters as URL parameters for the handlers of both
- # /latest_version and /api/v1/captions. This avoids an un-necessary
- # redirect and duplicated (and hazardous) sanity checks.
- env.params.query["id"] = video_id
- env.params.query["title"] = filename
-
- # Delete the useless ones
+ # Delete the now useless URL parameters
env.params.body.delete("id")
env.params.body.delete("title")
env.params.body.delete("download_widget")
+ # Pass form parameters as URL parameters for the handlers of both
+ # /latest_version and /api/v1/captions. This avoids an un-necessary
+ # redirect and duplicated (and hazardous) sanity checks.
if label = download_widget["label"]?
# URL params specific to /api/v1/captions/:id
- env.params.query["label"] = URI.encode_www_form(label.as_s, space_to_plus: false)
+ env.params.url["id"] = video_id
+ env.params.query["title"] = filename
+ env.params.query["label"] = URI.decode_www_form(label.as_s)
return Invidious::Routes::API::V1::Videos.captions(env)
elsif itag = download_widget["itag"]?.try &.as_i
# URL params specific to /latest_version
+ env.params.query["id"] = video_id
env.params.query["itag"] = itag.to_s
+ env.params.query["title"] = filename
env.params.query["local"] = "true"
return Invidious::Routes::VideoPlayback.latest_version(env)
diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr
index 861b2048..d1fdcce2 100644
--- a/src/invidious/views/watch.ecr
+++ b/src/invidious/views/watch.ecr
@@ -173,7 +173,7 @@ we're going to need to do it here in order to allow for translations.
<p id="views"><i class="icon ion-ios-eye"></i> <%= number_with_separator(video.views) %></p>
<p id="likes"><i class="icon ion-ios-thumbs-up"></i> <%= number_with_separator(video.likes) %></p>
- <p id="dislikes"><i class="icon ion-ios-thumbs-down"></i> <%= number_with_separator(video.dislikes) %></p>
+ <p id="dislikes"></p>
<p id="genre"><%= translate(locale, "Genre: ") %>
<% if !video.genre_url %>
<%= video.genre %>
@@ -186,7 +186,7 @@ we're going to need to do it here in order to allow for translations.
<% end %>
<p id="family_friendly"><%= translate(locale, "Family friendly? ") %><%= translate_bool(locale, video.is_family_friendly) %></p>
<p id="wilson"><%= translate(locale, "Wilson score: ") %><%= video.wilson_score %></p>
- <p id="rating"><%= translate(locale, "Rating: ") %><%= video.average_rating %> / 5</p>
+ <p id="rating"></p>
<p id="engagement"><%= translate(locale, "Engagement: ") %><%= video.engagement %>%</p>
<% if video.allowed_regions.size != REGIONS.size %>
<p id="allowed_regions">