diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/invidious/channels/about.cr | 20 | ||||
| -rw-r--r-- | src/invidious/comments.cr | 46 | ||||
| -rw-r--r-- | src/invidious/config.cr | 5 | ||||
| -rw-r--r-- | src/invidious/helpers/i18n.cr | 1 | ||||
| -rw-r--r-- | src/invidious/routes/watch.cr | 19 | ||||
| -rw-r--r-- | src/invidious/views/watch.ecr | 4 |
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"> |
