From 9274eb229b35d7347429d9f3766be51fc2ebc9c9 Mon Sep 17 00:00:00 2001 From: Fijxu Date: Fri, 13 Nov 2026 15:14:49 -0300 Subject: [PATCH] fix: correctly parse premiere_timestamp on channel videos (#6140) Closes: https://github.com/iv-org/invidious/issues/6135 --- src/invidious/helpers/utils.cr | 14 ++++++++++++++ src/invidious/yt_backend/extractors.cr | 9 +++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index 1cb052922..8c90683e3 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -94,6 +94,20 @@ def decode_date(string : String) return Time.utc(string.to_i, 1, 1) end + # Try to parse "Premieres 6/29/27, 9:00 PM" + # For some reason, the Innertube response contains a '\u202F' + # character in the separation between the time and the period + # so the raw string returned by Innertube is something like this: + # "Premieres 6/29/27, 9:00\u202FPM". Instead of using a space character + # it uses the '\u202F' character. + # + # Raw: "Premieres 6/29/27, 9:00 PM" + begin + string2 = string.lchop("Premieres ").gsub('\u202F', " ") + return Time.parse(string2, "%m/%d/%y, %l:%M %p", Time::Location.local) + rescue + end + # Try to parse as format Jul 10, 2000 begin return Time.parse(string, "%b %-d, %Y", Time::Location.local) diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index 1fc2bb9fd..485bb5d87 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -712,6 +712,7 @@ private module Parsers title = metadata.dig("title", "content").as_s published = nil view_count_text = nil + premiere_timestamp = nil # Contains the views of the video and the published time of the video. if (metadata_rows = metadata.dig("metadata", "contentMetadataViewModel", "metadataRows").try &.as_a) metadata_rows.each do |row| @@ -732,8 +733,12 @@ private module Parsers published = metadata_parts.try &.find { |item| item["icon"]?.nil? && item.dig?("text", "content").try &.as_s.includes?("ago") } .try { |item| decode_date(item.dig("text", "content").as_s) } end + if premiere_timestamp.nil? + premiere_timestamp = metadata_parts.try &.find { |item| item["icon"]?.nil? && item.dig?("text", "content").try &.as_s.includes?("Premieres") } + .try { |item| decode_date(item.dig("text", "content").as_s) } + end - break if !view_count_text.nil? && !published.nil? + break if !view_count_text.nil? && !published.nil? && !premiere_timestamp.nil? end end @@ -752,7 +757,7 @@ private module Parsers views: view_count, description_html: "", length_seconds: length_seconds || 0, - premiere_timestamp: Time.unix(0), + premiere_timestamp: premiere_timestamp, author_verified: false, author_thumbnail: nil, badges: VideoBadges::None,