Skip to content

Commit

Permalink
Merge branch 'iv-org:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
MrLetsplay2003 authored Aug 24, 2024
2 parents cc7ec86 + c5fdd9e commit 49098fe
Show file tree
Hide file tree
Showing 23 changed files with 633 additions and 250 deletions.
19 changes: 18 additions & 1 deletion assets/css/default.css
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,14 @@ div.thumbnail > .bottom-right-overlay {
display: inline;
}

.searchbar .pure-form fieldset { padding: 0; }
.searchbar .pure-form {
display: flex;
}

.searchbar .pure-form fieldset {
padding: 0;
flex: 1;
}

.searchbar input[type="search"] {
width: 100%;
Expand Down Expand Up @@ -310,6 +317,16 @@ input[type="search"]::-webkit-search-cancel-button {
background-size: 14px;
}

.searchbar #searchbutton {
border: none;
background: none;
margin-top: 0;
}

.searchbar #searchbutton:hover {
color: rgb(0, 182, 240);
}

.user-field {
display: flex;
flex-direction: row;
Expand Down
166 changes: 89 additions & 77 deletions src/invidious/channels/about.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ record AboutChannel,
allowed_regions : Array(String),
tabs : Array(String),
tags : Array(String),
verified : Bool
verified : Bool,
is_age_gated : Bool

def get_about_info(ucid, locale) : AboutChannel
begin
Expand Down Expand Up @@ -45,45 +46,101 @@ def get_about_info(ucid, locale) : AboutChannel
end

tags = [] of String
tab_names = [] of String
total_views = 0_i64
joined = Time.unix(0)

if auto_generated
author = initdata["header"]["interactiveTabbedHeaderRenderer"]["title"]["simpleText"].as_s
author_url = initdata["microformat"]["microformatDataRenderer"]["urlCanonical"].as_s
author_thumbnail = initdata["header"]["interactiveTabbedHeaderRenderer"]["boxArt"]["thumbnails"][0]["url"].as_s
if age_gate_renderer = initdata.dig?("contents", "twoColumnBrowseResultsRenderer", "tabs", 0, "tabRenderer", "content", "sectionListRenderer", "contents", 0, "channelAgeGateRenderer")
description_node = nil
author = age_gate_renderer["channelTitle"].as_s
ucid = initdata.dig("responseContext", "serviceTrackingParams", 0, "params", 0, "value").as_s
author_url = "https://www.youtube.com/channel/#{ucid}"
author_thumbnail = age_gate_renderer.dig("avatar", "thumbnails", 0, "url").as_s
banner = nil
is_family_friendly = false
is_age_gated = true
tab_names = ["videos", "shorts", "streams"]
auto_generated = false
else
if auto_generated
author = initdata["header"]["interactiveTabbedHeaderRenderer"]["title"]["simpleText"].as_s
author_url = initdata["microformat"]["microformatDataRenderer"]["urlCanonical"].as_s
author_thumbnail = initdata["header"]["interactiveTabbedHeaderRenderer"]["boxArt"]["thumbnails"][0]["url"].as_s

# Raises a KeyError on failure.
banners = initdata["header"]["interactiveTabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]?
banner = banners.try &.[-1]?.try &.["url"].as_s?

description_base_node = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"]
# some channels have the description in a simpleText
# ex: https://www.youtube.com/channel/UCQvWX73GQygcwXOTSf_VDVg/
description_node = description_base_node.dig?("simpleText") || description_base_node

tags = initdata.dig?("header", "interactiveTabbedHeaderRenderer", "badges")
.try &.as_a.map(&.["metadataBadgeRenderer"]["label"].as_s) || [] of String
else
author = initdata["metadata"]["channelMetadataRenderer"]["title"].as_s
author_url = initdata["metadata"]["channelMetadataRenderer"]["channelUrl"].as_s
author_thumbnail = initdata["metadata"]["channelMetadataRenderer"]["avatar"]["thumbnails"][0]["url"].as_s
author_verified = has_verified_badge?(initdata.dig?("header", "c4TabbedHeaderRenderer", "badges"))

# Raises a KeyError on failure.
banners = initdata["header"]["interactiveTabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]?
banner = banners.try &.[-1]?.try &.["url"].as_s?
ucid = initdata["metadata"]["channelMetadataRenderer"]["externalId"].as_s

description_base_node = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"]
# some channels have the description in a simpleText
# ex: https://www.youtube.com/channel/UCQvWX73GQygcwXOTSf_VDVg/
description_node = description_base_node.dig?("simpleText") || description_base_node
# Raises a KeyError on failure.
banners = initdata["header"]["c4TabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]?
banners ||= initdata.dig?("header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "banner", "imageBannerViewModel", "image", "sources")
banner = banners.try &.[-1]?.try &.["url"].as_s?

tags = initdata.dig?("header", "interactiveTabbedHeaderRenderer", "badges")
.try &.as_a.map(&.["metadataBadgeRenderer"]["label"].as_s) || [] of String
else
author = initdata["metadata"]["channelMetadataRenderer"]["title"].as_s
author_url = initdata["metadata"]["channelMetadataRenderer"]["channelUrl"].as_s
author_thumbnail = initdata["metadata"]["channelMetadataRenderer"]["avatar"]["thumbnails"][0]["url"].as_s
author_verified = has_verified_badge?(initdata.dig?("header", "c4TabbedHeaderRenderer", "badges"))
# if banner.includes? "channels/c4/default_banner"
# banner = nil
# end

ucid = initdata["metadata"]["channelMetadataRenderer"]["externalId"].as_s
description_node = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?
tags = initdata.dig?("microformat", "microformatDataRenderer", "tags").try &.as_a.map(&.as_s) || [] of String
end

# Raises a KeyError on failure.
banners = initdata["header"]["c4TabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]?
banners ||= initdata.dig?("header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "banner", "imageBannerViewModel", "image", "sources")
banner = banners.try &.[-1]?.try &.["url"].as_s?
is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool
if tabs_json = initdata["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]?
# Get the name of the tabs available on this channel
tab_names = tabs_json.as_a.compact_map do |entry|
name = entry.dig?("tabRenderer", "title").try &.as_s.downcase

# if banner.includes? "channels/c4/default_banner"
# banner = nil
# end
# This is a small fix to not add extra code on the HTML side
# I.e, the URL for the "live" tab is .../streams, so use "streams"
# everywhere for the sake of simplicity
(name == "live") ? "streams" : name
end

description_node = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?
tags = initdata.dig?("microformat", "microformatDataRenderer", "tags").try &.as_a.map(&.as_s) || [] of String
end
# Get the currently active tab ("About")
about_tab = extract_selected_tab(tabs_json)

# Try to find the about metadata section
channel_about_meta = about_tab.dig?(
"content",
"sectionListRenderer", "contents", 0,
"itemSectionRenderer", "contents", 0,
"channelAboutFullMetadataRenderer"
)

is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool
if !channel_about_meta.nil?
total_views = channel_about_meta.dig?("viewCountText", "simpleText").try &.as_s.gsub(/\D/, "").to_i64? || 0_i64

# The joined text is split to several sub strings. The reduce joins those strings before parsing the date.
joined = extract_text(channel_about_meta["joinedDateText"]?)
.try { |text| Time.parse(text, "Joined %b %-d, %Y", Time::Location.local) } || Time.unix(0)

# Normal Auto-generated channels
# https://support.google.com/youtube/answer/2579942
# For auto-generated channels, channel_about_meta only has
# ["description"]["simpleText"] and ["primaryLinks"][0]["title"]["simpleText"]
auto_generated = (
(channel_about_meta["primaryLinks"]?.try &.size) == 1 && \
extract_text(channel_about_meta.dig?("primaryLinks", 0, "title")) == "Auto-generated by YouTube" ||
channel_about_meta.dig?("links", 0, "channelExternalLinkViewModel", "title", "content").try &.as_s == "Auto-generated by YouTube"
)
end
end
end

allowed_regions = initdata
.dig?("microformat", "microformatDataRenderer", "availableCountries")
Expand All @@ -102,52 +159,6 @@ def get_about_info(ucid, locale) : AboutChannel
end
end

total_views = 0_i64
joined = Time.unix(0)

tab_names = [] of String

if tabs_json = initdata["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]?
# Get the name of the tabs available on this channel
tab_names = tabs_json.as_a.compact_map do |entry|
name = entry.dig?("tabRenderer", "title").try &.as_s.downcase

# This is a small fix to not add extra code on the HTML side
# I.e, the URL for the "live" tab is .../streams, so use "streams"
# everywhere for the sake of simplicity
(name == "live") ? "streams" : name
end

# Get the currently active tab ("About")
about_tab = extract_selected_tab(tabs_json)

# Try to find the about metadata section
channel_about_meta = about_tab.dig?(
"content",
"sectionListRenderer", "contents", 0,
"itemSectionRenderer", "contents", 0,
"channelAboutFullMetadataRenderer"
)

if !channel_about_meta.nil?
total_views = channel_about_meta.dig?("viewCountText", "simpleText").try &.as_s.gsub(/\D/, "").to_i64? || 0_i64

# The joined text is split to several sub strings. The reduce joins those strings before parsing the date.
joined = extract_text(channel_about_meta["joinedDateText"]?)
.try { |text| Time.parse(text, "Joined %b %-d, %Y", Time::Location.local) } || Time.unix(0)

# Normal Auto-generated channels
# https://support.google.com/youtube/answer/2579942
# For auto-generated channels, channel_about_meta only has
# ["description"]["simpleText"] and ["primaryLinks"][0]["title"]["simpleText"]
auto_generated = (
(channel_about_meta["primaryLinks"]?.try &.size) == 1 && \
extract_text(channel_about_meta.dig?("primaryLinks", 0, "title")) == "Auto-generated by YouTube" ||
channel_about_meta.dig?("links", 0, "channelExternalLinkViewModel", "title", "content").try &.as_s == "Auto-generated by YouTube"
)
end
end

sub_count = 0

if (metadata_rows = initdata.dig?("header", "pageHeaderRenderer", "content", "pageHeaderViewModel", "metadata", "contentMetadataViewModel", "metadataRows").try &.as_a)
Expand Down Expand Up @@ -177,6 +188,7 @@ def get_about_info(ucid, locale) : AboutChannel
tabs: tab_names,
tags: tags,
verified: author_verified || false,
is_age_gated: is_age_gated || false,
)
end

Expand Down
1 change: 1 addition & 0 deletions src/invidious/database/playlists.cr
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ module Invidious::Database::Playlists
request = <<-SQL
SELECT id,title FROM playlists
WHERE author = $1 AND id LIKE 'IV%'
ORDER BY title
SQL

PG_DB.query_all(request, email, as: {String, String})
Expand Down
4 changes: 2 additions & 2 deletions src/invidious/helpers/serialized_yt_data.cr
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct SearchVideo
json.field "lengthSeconds", self.length_seconds
json.field "liveNow", self.live_now
json.field "premium", self.premium
json.field "isUpcoming", self.is_upcoming
json.field "isUpcoming", self.upcoming?

if self.premiere_timestamp
json.field "premiereTimestamp", self.premiere_timestamp.try &.to_unix
Expand All @@ -109,7 +109,7 @@ struct SearchVideo
to_json(nil, json)
end

def is_upcoming
def upcoming?
premiere_timestamp ? true : false
end
end
Expand Down
4 changes: 1 addition & 3 deletions src/invidious/helpers/signatures.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ class Invidious::DecryptFunction
end

def check_update
now = Time.utc

# If we have updated in the last 5 minutes, do nothing
return if (now - @last_update) > 5.minutes
return if (Time.utc - @last_update) < 5.minutes

# Get the amount of time elapsed since when the player was updated, in the
# event where multiple invidious processes are run in parallel.
Expand Down
32 changes: 19 additions & 13 deletions src/invidious/jsonify/api_v1/video_json.cr
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ module Invidious::JSONify::APIv1
json.field "isListed", video.is_listed
json.field "liveNow", video.live_now
json.field "isPostLiveDvr", video.post_live_dvr
json.field "isUpcoming", video.is_upcoming
json.field "isUpcoming", video.upcoming?

if video.premiere_timestamp
json.field "premiereTimestamp", video.premiere_timestamp.try &.to_unix
Expand Down Expand Up @@ -109,7 +109,7 @@ module Invidious::JSONify::APIv1
# On livestreams, it's not present, so always fall back to the
# current unix timestamp (up to mS precision) for compatibility.
last_modified = fmt["lastModified"]?
last_modified ||= "#{Time.utc.to_unix_ms.to_s}000"
last_modified ||= "#{Time.utc.to_unix_ms}000"
json.field "lmt", last_modified

json.field "projectionType", fmt["projectionType"]
Expand Down Expand Up @@ -162,7 +162,13 @@ module Invidious::JSONify::APIv1
json.array do
video.fmt_stream.each do |fmt|
json.object do
json.field "url", fmt["url"]
if proxy
json.field "url", Invidious::HttpServer::Utils.proxy_video_url(
fmt["url"].to_s, absolute: true
)
else
json.field "url", fmt["url"]
end
json.field "itag", fmt["itag"].as_i.to_s
json.field "type", fmt["mimeType"]
json.field "quality", fmt["quality"]
Expand Down Expand Up @@ -271,17 +277,17 @@ module Invidious::JSONify::APIv1

def storyboards(json, id, storyboards)
json.array do
storyboards.each do |storyboard|
storyboards.each do |sb|
json.object do
json.field "url", "/api/v1/storyboards/#{id}?width=#{storyboard[:width]}&height=#{storyboard[:height]}"
json.field "templateUrl", storyboard[:url]
json.field "width", storyboard[:width]
json.field "height", storyboard[:height]
json.field "count", storyboard[:count]
json.field "interval", storyboard[:interval]
json.field "storyboardWidth", storyboard[:storyboard_width]
json.field "storyboardHeight", storyboard[:storyboard_height]
json.field "storyboardCount", storyboard[:storyboard_count]
json.field "url", "/api/v1/storyboards/#{id}?width=#{sb.width}&height=#{sb.height}"
json.field "templateUrl", sb.url.to_s
json.field "width", sb.width
json.field "height", sb.height
json.field "count", sb.count
json.field "interval", sb.interval
json.field "storyboardWidth", sb.columns
json.field "storyboardHeight", sb.rows
json.field "storyboardCount", sb.images_count
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions src/invidious/playlists.cr
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ struct PlaylistVideo
XML.build { |xml| to_xml(xml) }
end

def to_json(locale : String?, json : JSON::Builder)
to_json(json)
end

def to_json(json : JSON::Builder, index : Int32? = nil)
json.object do
json.field "type", "video"

json.field "title", self.title
json.field "videoId", self.id

Expand All @@ -67,6 +73,7 @@ struct PlaylistVideo
end

json.field "lengthSeconds", self.length_seconds
json.field "liveNow", self.live_now
end
end

Expand Down
Loading

0 comments on commit 49098fe

Please sign in to comment.