diff --git a/src/invidious.cr b/src/invidious.cr index 80ae4395f..1a02741b1 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -3405,31 +3405,10 @@ get "/api/v1/trending" do |env| videos = JSON.build do |json| json.array do trending.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) + video.to_json(locale, config, Kemal.config, json) end - - json.field "lengthSeconds", video.length_seconds - json.field "viewCount", video.views - - json.field "author", video.author - json.field "authorId", video.ucid - json.field "authorUrl", "/channel/#{video.ucid}" - - json.field "published", video.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale)) - json.field "description", video.description - json.field "descriptionHtml", video.description_html - json.field "liveNow", video.live_now - json.field "paid", video.paid - json.field "premium", video.premium end end - end - end videos end @@ -3459,9 +3438,12 @@ get "/api/v1/top" do |env| next error_message end - videos = JSON.build do |json| + JSON.build do |json| json.array do top_videos.each do |video| + # Top videos have much more information than provided below (adaptiveFormats, etc) + # but can be very out of date, so we only provide a subset here + json.object do json.field "title", video.title json.field "videoId", video.id @@ -3487,8 +3469,6 @@ get "/api/v1/top" do |env| end end end - - videos end get "/api/v1/channels/:ucid" do |env| @@ -3577,6 +3557,7 @@ get "/api/v1/channels/:ucid" do |env| end channel_info = JSON.build do |json| + # TODO: Refactor into `to_json` for InvidiousChannel json.object do json.field "author", author json.field "authorId", ucid @@ -3634,35 +3615,7 @@ get "/api/v1/channels/:ucid" do |env| json.field "latestVideos" do json.array do videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - - if auto_generated - json.field "author", video.author - json.field "authorId", video.ucid - json.field "authorUrl", "/channel/#{video.ucid}" - else - json.field "author", author - json.field "authorId", ucid - json.field "authorUrl", "/channel/#{ucid}" - end - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) - end - - json.field "description", video.description - json.field "descriptionHtml", video.description_html - - json.field "viewCount", video.views - json.field "published", video.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale)) - json.field "lengthSeconds", video.length_seconds - json.field "liveNow", video.live_now - json.field "paid", video.paid - json.field "premium", video.premium - end + video.to_json(locale, config, Kemal.config, json) end end end @@ -3727,45 +3680,15 @@ end next error_message end - result = JSON.build do |json| + JSON.build do |json| json.array do videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - - if auto_generated - json.field "author", video.author - json.field "authorId", video.ucid - json.field "authorUrl", "/channel/#{video.ucid}" - else - json.field "author", author - json.field "authorId", ucid - json.field "authorUrl", "/channel/#{ucid}" + video.to_json(locale, config, Kemal.config, json) end - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) end - - json.field "description", video.description - json.field "descriptionHtml", video.description_html - - json.field "viewCount", video.views - json.field "published", video.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale)) - json.field "lengthSeconds", video.length_seconds - json.field "liveNow", video.live_now - json.field "paid", video.paid - json.field "premium", video.premium end end end - end - - result - end -end {"/api/v1/channels/:ucid/latest", "/api/v1/channels/latest/:ucid"}.each do |route| get route do |env| @@ -3786,33 +3709,12 @@ end JSON.build do |json| json.array do videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - - json.field "authorId", ucid - json.field "authorUrl", "/channel/#{ucid}" - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) + video.to_json(locale, config, Kemal.config, json) end - - json.field "description", video.description - json.field "descriptionHtml", video.description_html - - json.field "viewCount", video.views - json.field "published", video.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale)) - json.field "lengthSeconds", video.length_seconds - json.field "liveNow", video.live_now - json.field "paid", video.paid - json.field "premium", video.premium end end end end - end -end {"/api/v1/channels/:ucid/playlists", "/api/v1/channels/playlists/:ucid"}.each do |route| get route do |env| @@ -3841,32 +3743,8 @@ end json.field "playlists" do json.array do items.each do |item| - json.object do - if item.is_a?(SearchPlaylist) - json.field "title", item.title - json.field "playlistId", item.id - - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "videoCount", item.video_count - json.field "videos" do - json.array do - item.videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - json.field "lengthSeconds", video.length_seconds - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) - end - end - end - end - end - end + if item.is_a?(SearchPlaylist) + item.to_json(locale, config, Kemal.config, json) end end end @@ -3894,90 +3772,13 @@ get "/api/v1/channels/search/:ucid" do |env| page ||= 1 count, search_results = channel_search(query, page, ucid) - response = JSON.build do |json| + JSON.build do |json| json.array do search_results.each do |item| - json.object do - case item - when SearchVideo - json.field "type", "video" - json.field "title", item.title - json.field "videoId", item.id - - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "videoThumbnails" do - generate_thumbnails(json, item.id, config, Kemal.config) - end - - json.field "description", item.description - json.field "descriptionHtml", item.description_html - - json.field "viewCount", item.views - json.field "published", item.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(item.published, locale)) - json.field "lengthSeconds", item.length_seconds - json.field "liveNow", item.live_now - json.field "paid", item.paid - json.field "premium", item.premium - when SearchPlaylist - json.field "type", "playlist" - json.field "title", item.title - json.field "playlistId", item.id - - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "videoCount", item.video_count - json.field "videos" do - json.array do - item.videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - json.field "lengthSeconds", video.length_seconds - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) - end - end - end - end - end - when SearchChannel - json.field "type", "channel" - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "authorThumbnails" do - json.array do - qualities = {32, 48, 76, 100, 176, 512} - - qualities.each do |quality| - json.object do - json.field "url", item.author_thumbnail.gsub("=s176-", "=s#{quality}-") - json.field "width", quality - json.field "height", quality - end - end - end - end - - json.field "subCount", item.subscriber_count - json.field "videoCount", item.video_count - json.field "description", item.description - json.field "descriptionHtml", item.description_html - end - end + item.to_json(locale, config, Kemal.config, json) end end end - - response end get "/api/v1/search" do |env| @@ -4019,90 +3820,13 @@ get "/api/v1/search" do |env| end count, search_results = search(query, page, search_params, proxies, region).as(Tuple) - response = JSON.build do |json| + JSON.build do |json| json.array do search_results.each do |item| - json.object do - case item - when SearchVideo - json.field "type", "video" - json.field "title", item.title - json.field "videoId", item.id - - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "videoThumbnails" do - generate_thumbnails(json, item.id, config, Kemal.config) - end - - json.field "description", item.description - json.field "descriptionHtml", item.description_html - - json.field "viewCount", item.views - json.field "published", item.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(item.published, locale)) - json.field "lengthSeconds", item.length_seconds - json.field "liveNow", item.live_now - json.field "paid", item.paid - json.field "premium", item.premium - when SearchPlaylist - json.field "type", "playlist" - json.field "title", item.title - json.field "playlistId", item.id - - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "videoCount", item.video_count - json.field "videos" do - json.array do - item.videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - json.field "lengthSeconds", video.length_seconds - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) - end - end - end - end - end - when SearchChannel - json.field "type", "channel" - json.field "author", item.author - json.field "authorId", item.ucid - json.field "authorUrl", "/channel/#{item.ucid}" - - json.field "authorThumbnails" do - json.array do - qualities = {32, 48, 76, 100, 176, 512} - - qualities.each do |quality| - json.object do - json.field "url", item.author_thumbnail.gsub("=s176-", "=s#{quality}-") - json.field "width", quality - json.field "height", quality - end - end - end - end - - json.field "subCount", item.subscriber_count - json.field "videoCount", item.video_count - json.field "description", item.description - json.field "descriptionHtml", item.description_html - end - end + item.to_json(locale, config, Kemal.config, json) end end end - - response end get "/api/v1/playlists/:plid" do |env| @@ -4170,26 +3894,12 @@ get "/api/v1/playlists/:plid" do |env| json.field "videos" do json.array do videos.each do |video| - json.object do - json.field "title", video.title - json.field "videoId", video.id - - json.field "author", video.author - json.field "authorId", video.ucid - json.field "authorUrl", "/channel/#{video.ucid}" - - json.field "videoThumbnails" do - generate_thumbnails(json, video.id, config, Kemal.config) - end - - json.field "index", video.index - json.field "lengthSeconds", video.length_seconds + video.to_json(locale, config, Kemal.config, json) end end end end end - end if format == "html" response = JSON.parse(response) diff --git a/src/invidious/channels.cr b/src/invidious/channels.cr index b7b6f5534..0582eb2fd 100644 --- a/src/invidious/channels.cr +++ b/src/invidious/channels.cr @@ -135,9 +135,7 @@ def get_batch_channels(channels, db, refresh = false, pull_all_videos = true, ma end def get_channel(id, db, refresh = true, pull_all_videos = true) - if db.query_one?("SELECT EXISTS (SELECT true FROM channels WHERE id = $1)", id, as: Bool) - channel = db.query_one("SELECT * FROM channels WHERE id = $1", id, as: InvidiousChannel) - + if channel = db.query_one?("SELECT * FROM channels WHERE id = $1", id, as: InvidiousChannel) if refresh && Time.utc - channel.updated > 10.minutes channel = fetch_channel(id, db, pull_all_videos: pull_all_videos) channel_array = channel.to_a diff --git a/src/invidious/mixes.cr b/src/invidious/mixes.cr index 47c480d7f..8664f83da 100644 --- a/src/invidious/mixes.cr +++ b/src/invidious/mixes.cr @@ -6,7 +6,7 @@ struct MixVideo ucid: String, length_seconds: Int32, index: Int32, - mixes: Array(String), + rdid: String, }) end @@ -70,7 +70,7 @@ def fetch_mix(rdid, video_id, cookies = nil, locale = nil) ucid, length_seconds, index, - [rdid] + rdid ) end diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr index 6eb0fd39e..54b7af0ae 100644 --- a/src/invidious/playlists.cr +++ b/src/invidious/playlists.cr @@ -1,4 +1,32 @@ struct PlaylistVideo + def to_json(locale, config, kemal_config, json : JSON::Builder) + json.object do + json.field "title", self.title + json.field "videoId", self.id + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "videoThumbnails" do + generate_thumbnails(json, self.id, config, kemal_config) + end + + json.field "index", self.index + json.field "lengthSeconds", self.length_seconds + end + end + + def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil) + if json + to_json(locale, config, kemal_config, json) + else + JSON.build do |json| + to_json(locale, config, kemal_config, json) + end + end + end + db_mapping({ title: String, id: String, diff --git a/src/invidious/search.cr b/src/invidious/search.cr index 12aa81b99..49aa422ac 100644 --- a/src/invidious/search.cr +++ b/src/invidious/search.cr @@ -50,6 +50,43 @@ struct SearchVideo end end + def to_json(locale, config, kemal_config, json : JSON::Builder) + json.object do + json.field "type", "video" + json.field "title", self.title + json.field "videoId", self.id + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "videoThumbnails" do + generate_thumbnails(json, self.id, config, kemal_config) + end + + json.field "description", self.description + json.field "descriptionHtml", self.description_html + + json.field "viewCount", self.views + json.field "published", self.published.to_unix + json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale)) + json.field "lengthSeconds", self.length_seconds + json.field "liveNow", self.live_now + json.field "paid", self.paid + json.field "premium", self.premium + end + end + + def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil) + if json + to_json(locale, config, kemal_config, json) + else + JSON.build do |json| + to_json(locale, config, kemal_config, json) + end + end + end + db_mapping({ title: String, id: String, @@ -76,6 +113,45 @@ struct SearchPlaylistVideo end struct SearchPlaylist + def to_json(locale, config, kemal_config, json : JSON::Builder) + json.object do + json.field "type", "playlist" + json.field "title", self.title + json.field "playlistId", self.id + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "videoCount", self.video_count + json.field "videos" do + json.array do + self.videos.each do |video| + json.object do + json.field "title", video.title + json.field "videoId", video.id + json.field "lengthSeconds", video.length_seconds + + json.field "videoThumbnails" do + generate_thumbnails(json, video.id, config, Kemal.config) + end + end + end + end + end + end + end + + def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil) + if json + to_json(locale, config, kemal_config, json) + else + JSON.build do |json| + to_json(locale, config, kemal_config, json) + end + end + end + db_mapping({ title: String, id: String, @@ -88,6 +164,44 @@ struct SearchPlaylist end struct SearchChannel + def to_json(locale, config, kemal_config, json : JSON::Builder) + json.object do + json.field "type", "channel" + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "authorThumbnails" do + json.array do + qualities = {32, 48, 76, 100, 176, 512} + + qualities.each do |quality| + json.object do + json.field "url", self.author_thumbnail.gsub("=s176-", "=s#{quality}-") + json.field "width", quality + json.field "height", quality + end + end + end + end + + json.field "subCount", self.subscriber_count + json.field "videoCount", self.video_count + json.field "description", self.description + json.field "descriptionHtml", self.description_html + end + end + + def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil) + if json + to_json(locale, config, kemal_config, json) + else + JSON.build do |json| + to_json(locale, config, kemal_config, json) + end + end + end + db_mapping({ author: String, ucid: String, diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index 78a52db3a..854c059c3 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -273,184 +273,182 @@ struct Video end end - def to_json(locale, config, kemal_config, decrypt_function) - JSON.build do |json| - json.object do - json.field "type", "video" + def to_json(locale, config, kemal_config, decrypt_function, json : JSON::Builder) + json.object do + json.field "type", "video" - json.field "title", self.title - json.field "videoId", self.id - json.field "videoThumbnails" do - generate_thumbnails(json, self.id, config, kemal_config) - end - json.field "storyboards" do - generate_storyboards(json, self.id, self.storyboards, config, kemal_config) - end + json.field "title", self.title + json.field "videoId", self.id + json.field "videoThumbnails" do + generate_thumbnails(json, self.id, config, kemal_config) + end + json.field "storyboards" do + generate_storyboards(json, self.id, self.storyboards, config, kemal_config) + end - description_html, description = html_to_content(self.description) + description_html, description = html_to_content(self.description) - json.field "description", description - json.field "descriptionHtml", description_html - json.field "published", self.published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale)) - json.field "keywords", self.keywords + json.field "description", description + json.field "descriptionHtml", description_html + json.field "published", self.published.to_unix + json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale)) + json.field "keywords", self.keywords - json.field "viewCount", self.views - json.field "likeCount", self.likes - json.field "dislikeCount", self.dislikes + json.field "viewCount", self.views + json.field "likeCount", self.likes + json.field "dislikeCount", self.dislikes - json.field "paid", self.paid - json.field "premium", self.premium - json.field "isFamilyFriendly", self.is_family_friendly - json.field "allowedRegions", self.allowed_regions - json.field "genre", self.genre - json.field "genreUrl", self.genre_url + json.field "paid", self.paid + json.field "premium", self.premium + json.field "isFamilyFriendly", self.is_family_friendly + json.field "allowedRegions", self.allowed_regions + json.field "genre", self.genre + json.field "genreUrl", self.genre_url - json.field "author", self.author - json.field "authorId", self.ucid - json.field "authorUrl", "/channel/#{self.ucid}" + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" - json.field "authorThumbnails" do - json.array do - qualities = {32, 48, 76, 100, 176, 512} + json.field "authorThumbnails" do + json.array do + qualities = {32, 48, 76, 100, 176, 512} - qualities.each do |quality| - json.object do - json.field "url", self.author_thumbnail.gsub("=s48-", "=s#{quality}-") - json.field "width", quality - json.field "height", quality - end + qualities.each do |quality| + json.object do + json.field "url", self.author_thumbnail.gsub("=s48-", "=s#{quality}-") + json.field "width", quality + json.field "height", quality end end end + end - json.field "subCountText", self.sub_count_text + json.field "subCountText", self.sub_count_text - json.field "lengthSeconds", self.info["length_seconds"].to_i - json.field "allowRatings", self.allow_ratings - json.field "rating", self.info["avg_rating"].to_f32 - json.field "isListed", self.is_listed - json.field "liveNow", self.live_now - json.field "isUpcoming", self.is_upcoming + json.field "lengthSeconds", self.info["length_seconds"].to_i + json.field "allowRatings", self.allow_ratings + json.field "rating", self.info["avg_rating"].to_f32 + json.field "isListed", self.is_listed + json.field "liveNow", self.live_now + json.field "isUpcoming", self.is_upcoming - if self.premiere_timestamp - json.field "premiereTimestamp", self.premiere_timestamp.not_nil!.to_unix - end + if self.premiere_timestamp + json.field "premiereTimestamp", self.premiere_timestamp.not_nil!.to_unix + end - if self.player_response["streamingData"]?.try &.["hlsManifestUrl"]? - host_url = make_host_url(config, kemal_config) + if self.player_response["streamingData"]?.try &.["hlsManifestUrl"]? + host_url = make_host_url(config, kemal_config) - hlsvp = self.player_response["streamingData"]["hlsManifestUrl"].as_s - hlsvp = hlsvp.gsub("https://manifest.googlevideo.com", host_url) + hlsvp = self.player_response["streamingData"]["hlsManifestUrl"].as_s + hlsvp = hlsvp.gsub("https://manifest.googlevideo.com", host_url) - json.field "hlsUrl", hlsvp - end + json.field "hlsUrl", hlsvp + end - json.field "dashUrl", "#{make_host_url(config, kemal_config)}/api/manifest/dash/id/#{id}" + json.field "dashUrl", "#{make_host_url(config, kemal_config)}/api/manifest/dash/id/#{id}" - json.field "adaptiveFormats" do - json.array do - self.adaptive_fmts(decrypt_function).each do |fmt| - json.object do - json.field "index", fmt["index"] - json.field "bitrate", fmt["bitrate"] - json.field "init", fmt["init"] - json.field "url", fmt["url"] - json.field "itag", fmt["itag"] - json.field "type", fmt["type"] - json.field "clen", fmt["clen"] - json.field "lmt", fmt["lmt"] - json.field "projectionType", fmt["projection_type"] + json.field "adaptiveFormats" do + json.array do + self.adaptive_fmts(decrypt_function).each do |fmt| + json.object do + json.field "index", fmt["index"] + json.field "bitrate", fmt["bitrate"] + json.field "init", fmt["init"] + json.field "url", fmt["url"] + json.field "itag", fmt["itag"] + json.field "type", fmt["type"] + json.field "clen", fmt["clen"] + json.field "lmt", fmt["lmt"] + json.field "projectionType", fmt["projection_type"] - fmt_info = itag_to_metadata?(fmt["itag"]) - if fmt_info - fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30 - json.field "fps", fps - json.field "container", fmt_info["ext"] - json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"] + fmt_info = itag_to_metadata?(fmt["itag"]) + if fmt_info + fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30 + json.field "fps", fps + json.field "container", fmt_info["ext"] + json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"] - if fmt_info["height"]? - json.field "resolution", "#{fmt_info["height"]}p" + if fmt_info["height"]? + json.field "resolution", "#{fmt_info["height"]}p" - quality_label = "#{fmt_info["height"]}p" - if fps > 30 - quality_label += "60" - end - json.field "qualityLabel", quality_label + quality_label = "#{fmt_info["height"]}p" + if fps > 30 + quality_label += "60" + end + json.field "qualityLabel", quality_label - if fmt_info["width"]? - json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}" - end + if fmt_info["width"]? + json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}" end end end end end end + end - json.field "formatStreams" do - json.array do - self.fmt_stream(decrypt_function).each do |fmt| - json.object do - json.field "url", fmt["url"] - json.field "itag", fmt["itag"] - json.field "type", fmt["type"] - json.field "quality", fmt["quality"] + json.field "formatStreams" do + json.array do + self.fmt_stream(decrypt_function).each do |fmt| + json.object do + json.field "url", fmt["url"] + json.field "itag", fmt["itag"] + json.field "type", fmt["type"] + json.field "quality", fmt["quality"] - fmt_info = itag_to_metadata?(fmt["itag"]) - if fmt_info - fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30 - json.field "fps", fps - json.field "container", fmt_info["ext"] - json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"] + fmt_info = itag_to_metadata?(fmt["itag"]) + if fmt_info + fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30 + json.field "fps", fps + json.field "container", fmt_info["ext"] + json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"] - if fmt_info["height"]? - json.field "resolution", "#{fmt_info["height"]}p" + if fmt_info["height"]? + json.field "resolution", "#{fmt_info["height"]}p" - quality_label = "#{fmt_info["height"]}p" - if fps > 30 - quality_label += "60" - end - json.field "qualityLabel", quality_label + quality_label = "#{fmt_info["height"]}p" + if fps > 30 + quality_label += "60" + end + json.field "qualityLabel", quality_label - if fmt_info["width"]? - json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}" - end + if fmt_info["width"]? + json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}" end end end end end end + end - json.field "captions" do - json.array do - self.captions.each do |caption| + json.field "captions" do + json.array do + self.captions.each do |caption| + json.object do + json.field "label", caption.name.simpleText + json.field "languageCode", caption.languageCode + json.field "url", "/api/v1/captions/#{id}?label=#{URI.escape(caption.name.simpleText)}" + end + end + end + end + + json.field "recommendedVideos" do + json.array do + self.info["rvs"]?.try &.split(",").each do |rv| + rv = HTTP::Params.parse(rv) + + if rv["id"]? json.object do - json.field "label", caption.name.simpleText - json.field "languageCode", caption.languageCode - json.field "url", "/api/v1/captions/#{id}?label=#{URI.escape(caption.name.simpleText)}" - end - end - end - end - - json.field "recommendedVideos" do - json.array do - self.info["rvs"]?.try &.split(",").each do |rv| - rv = HTTP::Params.parse(rv) - - if rv["id"]? - json.object do - json.field "videoId", rv["id"] - json.field "title", rv["title"] - json.field "videoThumbnails" do - generate_thumbnails(json, rv["id"], config, kemal_config) - end - json.field "author", rv["author"] - json.field "lengthSeconds", rv["length_seconds"].to_i - json.field "viewCountText", rv["short_view_count_text"] + json.field "videoId", rv["id"] + json.field "title", rv["title"] + json.field "videoThumbnails" do + generate_thumbnails(json, rv["id"], config, kemal_config) end + json.field "author", rv["author"] + json.field "lengthSeconds", rv["length_seconds"].to_i + json.field "viewCountText", rv["short_view_count_text"] end end end @@ -459,6 +457,16 @@ struct Video end end + def to_json(locale, config, kemal_config, decrypt_function, json : JSON::Builder | Nil = nil) + if json + to_json(locale, config, kemal_config, decrypt_function, json) + else + JSON.build do |json| + to_json(locale, config, kemal_config, decrypt_function, json) + end + end + end + def allow_ratings allow_ratings = player_response["videoDetails"]?.try &.["allowRatings"]?.try &.as_bool @@ -848,9 +856,7 @@ class VideoRedirect < Exception end def get_video(id, db, proxies = {} of String => Array({ip: String, port: Int32}), refresh = true, region = nil, force_refresh = false) - if db.query_one?("SELECT EXISTS (SELECT true FROM videos WHERE id = $1)", id, as: Bool) && !region - video = db.query_one("SELECT * FROM videos WHERE id = $1", id, as: Video) - + if (video = db.query_one?("SELECT * FROM videos WHERE id = $1", id, as: Video)) && !region # If record was last updated over 10 minutes ago, or video has since premiered, # refresh (expire param in response lasts for 6 hours) if (refresh && diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 780174243..28e700581 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -35,7 +35,7 @@

<% when MixVideo %> - + <% if !env.get("preferences").as(Preferences).thin_mode %>