From 437f42250e381ab7652e07b4a413bb5d152356e1 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Mon, 7 Nov 2022 03:49:00 +0100 Subject: Watched marker --- src/invidious/views/components/item.ecr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 0e959ff2..e53fa075 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -99,7 +99,7 @@ <% else %> <% if !env.get("preferences").as(Preferences).thin_mode %> -
+
"> <% if env.get? "show_watched" %>
" method="post"> -- cgit v1.2.3 From 7b573817734dfd48fc6d1fbdc9a0a99f379f0ed1 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Mon, 7 Nov 2022 19:03:23 +0000 Subject: Added watch indicator --- assets/css/default.css | 13 +++++++++++++ assets/js/watched_widget.js | 27 +++++++++++++++++++++++++++ docker-compose.yml | 4 ++-- src/invidious/views/components/item.ecr | 7 ++++++- src/invidious/views/feeds/subscriptions.ecr | 3 ++- 5 files changed, 50 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/assets/css/default.css b/assets/css/default.css index ab2b79e6..30a562e2 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -135,6 +135,9 @@ div.thumbnail { position: relative; box-sizing: border-box; } +div.thumbnail.thumbnail-watched { + background-color: rgba(255,255,255,.4); +} img.thumbnail { position: absolute; @@ -143,6 +146,16 @@ img.thumbnail { left: 0; top: 0; object-fit: cover; + z-index: -1; +} + +div.watched-indicator { + position: absolute; + left: 0; + bottom: 0; + height: 4px; + width: 100%; + background: red; } .length { diff --git a/assets/js/watched_widget.js b/assets/js/watched_widget.js index f1ac9cb4..10b33c1a 100644 --- a/assets/js/watched_widget.js +++ b/assets/js/watched_widget.js @@ -32,3 +32,30 @@ function mark_unwatched(target) { } }); } + + +var save_player_pos_key = 'save_player_pos'; + +function get_all_video_times() { + return helpers.storage.get(save_player_pos_key) || {}; +} + +var watchedIndicators = document.getElementsByClassName('watched-indicator'); +for (var i = 0; i < watchedIndicators.length; i++) { + var indicator = watchedIndicators[i]; + + var watched_part = get_all_video_times()[indicator.getAttribute('data-id')]; + var total = parseInt(indicator.getAttribute('data-length'), 10); + + var percentage = Math.round((watched_part / total) * 100); + + + if (percentage < 5) { + percentage = 5; + } + if (percentage > 90) { + percentage = 100; + } + + indicator.style.width = percentage + '%'; +} diff --git a/docker-compose.yml b/docker-compose.yml index eb83b020..48ee6a4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: dockerfile: docker/Dockerfile restart: unless-stopped ports: - - "127.0.0.1:3000:3000" + - "3003:3000" environment: # Please read the following file for a comprehensive list of all available # configuration options and their associated syntax: @@ -23,7 +23,7 @@ services: dbname: invidious user: kemal password: kemal - host: invidious-db + host: invidious-invidious-db-1 port: 5432 check_tables: true # external_port: diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index e53fa075..d63dca14 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -99,7 +99,8 @@ <% else %> <% if !env.get("preferences").as(Preferences).thin_mode %> -
"> + <% item_watched = env.get("user") && env.get("user").as(User).watched && env.get("user").as(User).watched.index(item.id) != nil %> +
"> <% if env.get? "show_watched" %> " method="post"> @@ -124,6 +125,10 @@ <% elsif item.length_seconds != 0 %>

<%= recode_length_seconds(item.length_seconds) %>

<% end %> + + <% if item_watched %> +
+ <% end %>
<% end %>

<%= HTML.escape(item.title) %>

diff --git a/src/invidious/views/feeds/subscriptions.ecr b/src/invidious/views/feeds/subscriptions.ecr index 8d56ad14..add1eefc 100644 --- a/src/invidious/views/feeds/subscriptions.ecr +++ b/src/invidious/views/feeds/subscriptions.ecr @@ -50,7 +50,6 @@ }.to_pretty_json %> -
<% videos.each do |item| %> @@ -58,6 +57,8 @@ <% end %>
+ +
<% if page > 1 %> -- cgit v1.2.3 From f604c1c68bbba81310ca2fd0a7283482840e0a26 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Tue, 8 Nov 2022 23:15:42 +0100 Subject: Fixed thumbnails with darkreader, Added watched indicator in more locations --- assets/css/default.css | 16 +++++++++++----- assets/js/watched_widget.js | 4 +--- src/invidious/views/components/item.ecr | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/assets/css/default.css b/assets/css/default.css index 30a562e2..890bd524 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -135,9 +135,7 @@ div.thumbnail { position: relative; box-sizing: border-box; } -div.thumbnail.thumbnail-watched { - background-color: rgba(255,255,255,.4); -} + img.thumbnail { position: absolute; @@ -146,7 +144,15 @@ img.thumbnail { left: 0; top: 0; object-fit: cover; - z-index: -1; +} + +div.watched-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255,255,255,.4); } div.watched-indicator { @@ -155,7 +161,7 @@ div.watched-indicator { bottom: 0; height: 4px; width: 100%; - background: red; + background-color: red; } .length { diff --git a/assets/js/watched_widget.js b/assets/js/watched_widget.js index 10b33c1a..ffcdaad8 100644 --- a/assets/js/watched_widget.js +++ b/assets/js/watched_widget.js @@ -41,15 +41,13 @@ function get_all_video_times() { } var watchedIndicators = document.getElementsByClassName('watched-indicator'); +console.log('indicators', watchedIndicators.length); for (var i = 0; i < watchedIndicators.length; i++) { var indicator = watchedIndicators[i]; - var watched_part = get_all_video_times()[indicator.getAttribute('data-id')]; var total = parseInt(indicator.getAttribute('data-length'), 10); - var percentage = Math.round((watched_part / total) * 100); - if (percentage < 5) { percentage = 5; } diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index d63dca14..47d077cf 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -1,3 +1,5 @@ +<% item_watched = !item.is_a?(SearchChannel) && !item.is_a?(SearchPlaylist) && !item.is_a?(InvidiousPlaylist) && !item.is_a?(Category) && env.get("user") && env.get("user").as(User).watched && env.get("user").as(User).watched.index(item.id) != nil %> +
<% case item when %> @@ -40,6 +42,11 @@ <% if item.length_seconds != 0 %>

<%= recode_length_seconds(item.length_seconds) %>

<% end %> + + <% if item_watched %> +
+
+ <% end %>
<% end %>

<%= HTML.escape(item.title) %>

@@ -67,6 +74,11 @@ <% elsif item.length_seconds != 0 %>

<%= recode_length_seconds(item.length_seconds) %>

<% end %> + + <% if item_watched %> +
+
+ <% end %>
<% end %>

<%= HTML.escape(item.title) %>

@@ -99,8 +111,7 @@ <% else %>
<% if !env.get("preferences").as(Preferences).thin_mode %> - <% item_watched = env.get("user") && env.get("user").as(User).watched && env.get("user").as(User).watched.index(item.id) != nil %> -
"> +
<% if env.get? "show_watched" %> " method="post"> @@ -127,6 +138,7 @@ <% end %> <% if item_watched %> +
<% end %>
-- cgit v1.2.3 From c95ee10d6915bd1bb42e8e81f85848f1ad7b6240 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Tue, 8 Nov 2022 23:18:24 +0100 Subject: Added parital watch indicator on more locations --- src/invidious/views/add_playlist_items.ecr | 2 ++ src/invidious/views/channel.ecr | 2 ++ src/invidious/views/edit_playlist.ecr | 2 ++ src/invidious/views/feeds/playlists.ecr | 2 ++ src/invidious/views/feeds/popular.ecr | 2 ++ src/invidious/views/feeds/trending.ecr | 2 ++ src/invidious/views/hashtag.ecr | 2 ++ src/invidious/views/playlist.ecr | 2 ++ src/invidious/views/playlists.ecr | 2 ++ src/invidious/views/search.ecr | 2 ++ 10 files changed, 20 insertions(+) (limited to 'src') diff --git a/src/invidious/views/add_playlist_items.ecr b/src/invidious/views/add_playlist_items.ecr index 22870317..70575de3 100644 --- a/src/invidious/views/add_playlist_items.ecr +++ b/src/invidious/views/add_playlist_items.ecr @@ -39,6 +39,8 @@ <% end %>
+ + <% if query %> <%- query_encoded = URI.encode_www_form(query.text, space_to_plus: true) -%>
diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr index dea86abe..1295423e 100644 --- a/src/invidious/views/channel.ecr +++ b/src/invidious/views/channel.ecr @@ -110,6 +110,8 @@ <% end %>
+ +
<% if page > 1 %> diff --git a/src/invidious/views/edit_playlist.ecr b/src/invidious/views/edit_playlist.ecr index 89819ef0..100764c7 100644 --- a/src/invidious/views/edit_playlist.ecr +++ b/src/invidious/views/edit_playlist.ecr @@ -62,6 +62,8 @@ <% end %>
+ +
<% if page > 1 %> diff --git a/src/invidious/views/feeds/playlists.ecr b/src/invidious/views/feeds/playlists.ecr index a59344c4..f9064762 100644 --- a/src/invidious/views/feeds/playlists.ecr +++ b/src/invidious/views/feeds/playlists.ecr @@ -32,3 +32,5 @@ <%= rendered "components/item" %> <% end %>
+ + diff --git a/src/invidious/views/feeds/popular.ecr b/src/invidious/views/feeds/popular.ecr index e77f35b9..919002cd 100644 --- a/src/invidious/views/feeds/popular.ecr +++ b/src/invidious/views/feeds/popular.ecr @@ -16,3 +16,5 @@ <%= rendered "components/item" %> <% end %>
+ + diff --git a/src/invidious/views/feeds/trending.ecr b/src/invidious/views/feeds/trending.ecr index a35c4ee3..76218165 100644 --- a/src/invidious/views/feeds/trending.ecr +++ b/src/invidious/views/feeds/trending.ecr @@ -45,3 +45,5 @@ <%= rendered "components/item" %> <% end %>
+ + diff --git a/src/invidious/views/hashtag.ecr b/src/invidious/views/hashtag.ecr index 0ecfe832..6064af74 100644 --- a/src/invidious/views/hashtag.ecr +++ b/src/invidious/views/hashtag.ecr @@ -24,6 +24,8 @@ <%- end -%>
+ +
<%- if page > 1 -%> diff --git a/src/invidious/views/playlist.ecr b/src/invidious/views/playlist.ecr index df3112db..1df047ba 100644 --- a/src/invidious/views/playlist.ecr +++ b/src/invidious/views/playlist.ecr @@ -106,6 +106,8 @@ <% end %>
+ +
<% if page > 1 %> diff --git a/src/invidious/views/playlists.ecr b/src/invidious/views/playlists.ecr index c8718e7b..6ce8b033 100644 --- a/src/invidious/views/playlists.ecr +++ b/src/invidious/views/playlists.ecr @@ -96,6 +96,8 @@ <% end %>
+ +
diff --git a/src/invidious/views/search.ecr b/src/invidious/views/search.ecr index 254449a1..c4960d08 100644 --- a/src/invidious/views/search.ecr +++ b/src/invidious/views/search.ecr @@ -37,6 +37,8 @@
<%- end -%> + +
<%- if query.page > 1 -%> -- cgit v1.2.3 From 8df1c3bb57154dda021add8d11da9e7f4ae88bf1 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 10:17:47 -0500 Subject: Add support for timedtext captions --- src/invidious/routes/api/v1/videos.cr | 92 +++++++++++++++++++---------------- src/invidious/videos/caption.cr | 56 ++++++++++++++++++++- 2 files changed, 106 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index a6b2eb4e..918fb421 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -90,47 +90,52 @@ module Invidious::Routes::API::V1::Videos # as well as some other markup that makes it cumbersome, so we try to fix that here if caption.name.includes? "auto-generated" caption_xml = YT_POOL.client &.get(url).body - caption_xml = XML.parse(caption_xml) - webvtt = String.build do |str| - str << <<-END_VTT - WEBVTT - Kind: captions - Language: #{tlang || caption.language_code} - - - END_VTT - - caption_nodes = caption_xml.xpath_nodes("//transcript/text") - caption_nodes.each_with_index do |node, i| - start_time = node["start"].to_f.seconds - duration = node["dur"]?.try &.to_f.seconds - duration ||= start_time - - if caption_nodes.size > i + 1 - end_time = caption_nodes[i + 1]["start"].to_f.seconds - else - end_time = start_time + duration - end - - start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" - end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" - - text = HTML.unescape(node.content) - text = text.gsub(//, "") - text = text.gsub(/<\/font>/, "") - if md = text.match(/(?.*) : (?.*)/) - text = "#{md["text"]}" - end - - str << <<-END_CUE - #{start_time} --> #{end_time} - #{text} - - - END_CUE - end - end + if caption_xml.starts_with?(" i + 1 + end_time = caption_nodes[i + 1]["start"].to_f.seconds + else + end_time = start_time + duration + end + + start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" + end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" + + text = HTML.unescape(node.content) + text = text.gsub(//, "") + text = text.gsub(/<\/font>/, "") + if md = text.match(/(?.*) : (?.*)/) + text = "#{md["text"]}" + end + + str << <<-END_CUE + #{start_time} --> #{end_time} + #{text} + + + END_CUE + end + end + end else # Some captions have "align:[start/end]" and "position:[num]%" # attributes. Those are causing issues with VideoJS, which is unable @@ -138,7 +143,12 @@ module Invidious::Routes::API::V1::Videos # # See: https://github.com/iv-org/invidious/issues/2391 webvtt = YT_POOL.client &.get("#{url}&format=vtt").body - .gsub(/([0-9:.]{12} --> [0-9:.]{12}).+/, "\\1") + if webvtt.starts_with?(" [0-9:.]{12}).+/, "\\1") + end end if title = env.params.query["title"]? diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 4642c1a7..941b9646 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -30,7 +30,60 @@ module Invidious::Videos return captions_list end - + + def timedtext_to_vtt(timedtext : String, tlang = nil) : String + #In the future, we could just directly work with the url. This is more of a POC + cues = [] of XML::Node + tree = XML.parse(timedtext) + tree = tree.children.first() + + tree.children.each do |item| + if item.name == "body" + item.children.each do |cue| + if cue.name == "p" + cues << cue + end + end + break + end + end + result = String.build do |result| + result << <<-END_VTT + WEBVTT + Kind: captions + Language: #{tlang || @language_code} + + + END_VTT + cues.each_with_index do |node,i| + start_time = node["t"].to_f.milliseconds + + duration = node["d"]?.try &.to_f.milliseconds + + duration ||= start_time + + if cues.size > i + 1 + end_time = cues[i + 1]["t"].to_f.milliseconds + else + end_time = start_time + duration + end + + start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" + + end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" + text = String.build do |text| + node.children.each do |s| + text << s.content + end + end + result << start_time + " --> " + end_time + "\n" + result << text + "\n" + result << "\n" + end + end + return result + end + # List of all caption languages available on Youtube. LANGUAGES = { "", @@ -164,5 +217,6 @@ module Invidious::Videos "Yoruba", "Zulu", } + end end -- cgit v1.2.3 From b49ed65a07d1e80eb5430b40dac47e7a2477cd39 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 10:21:16 -0500 Subject: Linting --- src/invidious/videos/caption.cr | 97 ++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 941b9646..4049c5d0 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -30,60 +30,60 @@ module Invidious::Videos return captions_list end - - def timedtext_to_vtt(timedtext : String, tlang = nil) : String - #In the future, we could just directly work with the url. This is more of a POC - cues = [] of XML::Node - tree = XML.parse(timedtext) - tree = tree.children.first() - - tree.children.each do |item| - if item.name == "body" - item.children.each do |cue| - if cue.name == "p" - cues << cue - end - end - break - end - end - result = String.build do |result| - result << <<-END_VTT + + def timedtext_to_vtt(timedtext : String, tlang = nil) : String + # In the future, we could just directly work with the url. This is more of a POC + cues = [] of XML::Node + tree = XML.parse(timedtext) + tree = tree.children.first + + tree.children.each do |item| + if item.name == "body" + item.children.each do |cue| + if cue.name == "p" + cues << cue + end + end + break + end + end + result = String.build do |result| + result << <<-END_VTT WEBVTT Kind: captions Language: #{tlang || @language_code} END_VTT - cues.each_with_index do |node,i| - start_time = node["t"].to_f.milliseconds - - duration = node["d"]?.try &.to_f.milliseconds - - duration ||= start_time - - if cues.size > i + 1 - end_time = cues[i + 1]["t"].to_f.milliseconds - else - end_time = start_time + duration - end - - start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" - - end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" - text = String.build do |text| - node.children.each do |s| - text << s.content - end - end - result << start_time + " --> " + end_time + "\n" - result << text + "\n" - result << "\n" - end - end - return result - end - + cues.each_with_index do |node, i| + start_time = node["t"].to_f.milliseconds + + duration = node["d"]?.try &.to_f.milliseconds + + duration ||= start_time + + if cues.size > i + 1 + end_time = cues[i + 1]["t"].to_f.milliseconds + else + end_time = start_time + duration + end + + start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" + + end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" + text = String.build do |text| + node.children.each do |s| + text << s.content + end + end + result << start_time + " --> " + end_time + "\n" + result << text + "\n" + result << "\n" + end + end + return result + end + # List of all caption languages available on Youtube. LANGUAGES = { "", @@ -217,6 +217,5 @@ module Invidious::Videos "Yoruba", "Zulu", } - end end -- cgit v1.2.3 From 45b8f6d0cd89541d93a479ec20f43ee5c029abf8 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 10:25:05 -0500 Subject: More linting --- src/invidious/routes/api/v1/videos.cr | 74 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index 918fb421..eb371241 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -92,50 +92,50 @@ module Invidious::Routes::API::V1::Videos caption_xml = YT_POOL.client &.get(url).body if caption_xml.starts_with?(" i + 1 - end_time = caption_nodes[i + 1]["start"].to_f.seconds - else - end_time = start_time + duration - end - - start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" - end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" - - text = HTML.unescape(node.content) - text = text.gsub(//, "") - text = text.gsub(/<\/font>/, "") - if md = text.match(/(?.*) : (?.*)/) - text = "#{md["text"]}" - end - - str << <<-END_CUE + + caption_nodes = caption_xml.xpath_nodes("//transcript/text") + caption_nodes.each_with_index do |node, i| + start_time = node["start"].to_f.seconds + duration = node["dur"]?.try &.to_f.seconds + duration ||= start_time + + if caption_nodes.size > i + 1 + end_time = caption_nodes[i + 1]["start"].to_f.seconds + else + end_time = start_time + duration + end + + start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" + end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" + + text = HTML.unescape(node.content) + text = text.gsub(//, "") + text = text.gsub(/<\/font>/, "") + if md = text.match(/(?.*) : (?.*)/) + text = "#{md["text"]}" + end + + str << <<-END_CUE #{start_time} --> #{end_time} #{text} END_CUE - end - end - end + end + end + end else # Some captions have "align:[start/end]" and "position:[num]%" # attributes. Those are causing issues with VideoJS, which is unable @@ -144,11 +144,11 @@ module Invidious::Routes::API::V1::Videos # See: https://github.com/iv-org/invidious/issues/2391 webvtt = YT_POOL.client &.get("#{url}&format=vtt").body if webvtt.starts_with?(" [0-9:.]{12}).+/, "\\1") - end + webvtt = YT_POOL.client &.get("#{url}&format=vtt").body + .gsub(/([0-9:.]{12} --> [0-9:.]{12}).+/, "\\1") + end end if title = env.params.query["title"]? @@ -371,4 +371,4 @@ module Invidious::Routes::API::V1::Videos end end end -end +end \ No newline at end of file -- cgit v1.2.3 From 9d83e2da4e5c1dffc994dc8acd3f2a74280ffcc4 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 10:29:17 -0500 Subject: Add newline --- src/invidious/routes/api/v1/videos.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index eb371241..51344508 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -371,4 +371,4 @@ module Invidious::Routes::API::V1::Videos end end end -end \ No newline at end of file +end -- cgit v1.2.3 From 76758baab83b303e43a41a11bad37058c696905a Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 13:10:26 -0500 Subject: Removed unneccesary String::Builder and removed cues that was just a blank line --- src/invidious/videos/caption.cr | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 4049c5d0..83a4c82f 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -41,7 +41,9 @@ module Invidious::Videos if item.name == "body" item.children.each do |cue| if cue.name == "p" - cues << cue + if !(cue.children.size == 1 && cue.children[0].content == "\n") + cues << cue + end end end break @@ -71,13 +73,13 @@ module Invidious::Videos start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" - text = String.build do |text| - node.children.each do |s| - text << s.content - end - end + result << start_time + " --> " + end_time + "\n" - result << text + "\n" + + node.children.each do |s| + result << s.content + end + result << "\n" result << "\n" end end -- cgit v1.2.3 From 85dd3533bb4f9bc8e007d3b5de158f56db1445ce Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Tue, 3 Jan 2023 20:18:10 -0500 Subject: Fix for the ArithmeticOverflow Problem --- src/invidious/helpers/utils.cr | 2 +- src/invidious/yt_backend/extractors.cr | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index ed0cca38..59d8953a 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -162,7 +162,7 @@ def number_with_separator(number) end def short_text_to_number(short_text : String) : Int64 - matches = /(?\d+(\.\d+)?)\s?(?[mMkKbB])?/.match(short_text) + matches = /(?\d+(\.\d+)?)\s?(?[mMkKbB]|())?/.match(short_text) number = matches.try &.["number"].to_f || 0.0 case matches.try &.["suffix"].downcase diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index edc722cf..326d2d62 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -169,7 +169,12 @@ private module Parsers # When public subscriber count is disabled, the subscriberCountText isn't sent by InnerTube. # Always simpleText # TODO change default value to nil + subscriber_count = item_contents.dig?("subscriberCountText", "simpleText") + if !subscriber_count || !subscriber_count.as_s.includes? " subscriber" + subscriber_count = item_contents.dig?("videoCountText", "simpleText") + end + subscriber_count = subscriber_count .try { |s| short_text_to_number(s.as_s.split(" ")[0]).to_i32 } || 0 # Auto-generated channels doesn't have videoCountText -- cgit v1.2.3 From 0d3610f63d726ac038861d3aede8d7339c552d74 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Wed, 4 Jan 2023 18:12:15 -0500 Subject: Change regex used in short_text_to_number --- src/invidious/helpers/utils.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index 59d8953a..72fdb187 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -162,7 +162,7 @@ def number_with_separator(number) end def short_text_to_number(short_text : String) : Int64 - matches = /(?\d+(\.\d+)?)\s?(?[mMkKbB]|())?/.match(short_text) + matches = /(?\d+(\.\d+)?)\s?(?[mMkKbB]?)/.match(short_text) number = matches.try &.["number"].to_f || 0.0 case matches.try &.["suffix"].downcase -- cgit v1.2.3 From 8d08cfe30f550431015a7ecc8845b9c2968e27be Mon Sep 17 00:00:00 2001 From: DUO Labs Date: Thu, 5 Jan 2023 20:42:11 -0500 Subject: Add comments to src/invidious/yt_backend/extractors.cr Co-authored-by: Samantaz Fox --- src/invidious/yt_backend/extractors.cr | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index 326d2d62..cd52c73b 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -171,6 +171,11 @@ private module Parsers # TODO change default value to nil subscriber_count = item_contents.dig?("subscriberCountText", "simpleText") + + # Since youtube added channel handles, `VideoCountText` holds the number of + # subscribers and `subscriberCountText` holds the handle, except when the + # channel doesn't have a handle (e.g: some topic music channels). + # See https://github.com/iv-org/invidious/issues/3394#issuecomment-1321261688 if !subscriber_count || !subscriber_count.as_s.includes? " subscriber" subscriber_count = item_contents.dig?("videoCountText", "simpleText") end -- cgit v1.2.3 From 32471382c48289bafd0234d5e339fdfefb328da0 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Sun, 8 Jan 2023 16:18:35 -0500 Subject: Different cosmetic fixes --- src/invidious/routes/api/v1/videos.cr | 6 +++--- src/invidious/videos/caption.cr | 34 +++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index 51344508..54602112 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -128,11 +128,11 @@ module Invidious::Routes::API::V1::Videos end str << <<-END_CUE - #{start_time} --> #{end_time} - #{text} + #{start_time} --> #{end_time} + #{text} - END_CUE + END_CUE end end end diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 83a4c82f..377f30d6 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -40,8 +40,7 @@ module Invidious::Videos tree.children.each do |item| if item.name == "body" item.children.each do |cue| - if cue.name == "p" - if !(cue.children.size == 1 && cue.children[0].content == "\n") + if cue.name == "p" && !(cue.children.size == 1 && cue.children[0].content == "\n") cues << cue end end @@ -51,12 +50,15 @@ module Invidious::Videos end result = String.build do |result| result << <<-END_VTT - WEBVTT - Kind: captions - Language: #{tlang || @language_code} - - - END_VTT + WEBVTT + Kind: captions + Language: #{tlang || @language_code} + + + END_VTT + + result << "\n\n" + cues.each_with_index do |node, i| start_time = node["t"].to_f.milliseconds @@ -70,11 +72,21 @@ module Invidious::Videos end_time = start_time + duration end - start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}" + # start_time + result << start_time.hours.to_s.rjust(2, '0') + result << ':' << start_time.minutes.to_s.rjust(2, '0') + result << ':' << start_time.seconds.to_s.rjust(2, '0') + result << '.' << start_time.milliseconds.to_s.rjust(3, '0') - end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}" + result << " --> " - result << start_time + " --> " + end_time + "\n" + # end_time + result << end_time.hours.to_s.rjust(2, '0') + result << ':' << end_time.minutes.to_s.rjust(2, '0') + result << ':' << end_time.seconds.to_s.rjust(2, '0') + result << '.' << end_time.milliseconds.to_s.rjust(3, '0') + + result << "\n" node.children.each do |s| result << s.content -- cgit v1.2.3 From 4fc1b8ae86ab3d32955e72c957514799e5e121dc Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Sun, 8 Jan 2023 16:20:23 -0500 Subject: Remove superfluous 'end' --- src/invidious/videos/caption.cr | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 377f30d6..95b9d643 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -42,7 +42,6 @@ module Invidious::Videos item.children.each do |cue| if cue.name == "p" && !(cue.children.size == 1 && cue.children[0].content == "\n") cues << cue - end end end break -- cgit v1.2.3 From 456e91426aeeafe889e2ea8887cfc3aa3f92fcd3 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Sun, 8 Jan 2023 16:44:44 -0500 Subject: Formatting --- src/invidious/videos/caption.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 95b9d643..03bc3fd0 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -41,7 +41,7 @@ module Invidious::Videos if item.name == "body" item.children.each do |cue| if cue.name == "p" && !(cue.children.size == 1 && cue.children[0].content == "\n") - cues << cue + cues << cue end end break @@ -56,8 +56,8 @@ module Invidious::Videos END_VTT - result << "\n\n" - + result << "\n\n" + cues.each_with_index do |node, i| start_time = node["t"].to_f.milliseconds -- cgit v1.2.3 From 4b2d9420247ab83b2690a331c727e0227b5b7a19 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Wed, 11 Jan 2023 15:58:07 -0500 Subject: Convert tabs to spaces --- src/invidious/routes/api/v1/videos.cr | 22 +++++++++++----------- src/invidious/videos/caption.cr | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index 54602112..b10a30ea 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -98,12 +98,12 @@ module Invidious::Routes::API::V1::Videos webvtt = String.build do |str| str << <<-END_VTT - WEBVTT - Kind: captions - Language: #{tlang || caption.language_code} - - - END_VTT + WEBVTT + Kind: captions + Language: #{tlang || caption.language_code} + + + END_VTT caption_nodes = caption_xml.xpath_nodes("//transcript/text") caption_nodes.each_with_index do |node, i| @@ -128,11 +128,11 @@ module Invidious::Routes::API::V1::Videos end str << <<-END_CUE - #{start_time} --> #{end_time} - #{text} - - - END_CUE + #{start_time} --> #{end_time} + #{text} + + + END_CUE end end end diff --git a/src/invidious/videos/caption.cr b/src/invidious/videos/caption.cr index 03bc3fd0..13f81a31 100644 --- a/src/invidious/videos/caption.cr +++ b/src/invidious/videos/caption.cr @@ -49,12 +49,12 @@ module Invidious::Videos end result = String.build do |result| result << <<-END_VTT - WEBVTT - Kind: captions - Language: #{tlang || @language_code} + WEBVTT + Kind: captions + Language: #{tlang || @language_code} - END_VTT + END_VTT result << "\n\n" -- cgit v1.2.3 From 1fb0a495925a60b2d4839b98440e220b7f95d10e Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Fri, 13 Jan 2023 12:05:01 -0500 Subject: Make DASH absolute urls when local --- src/invidious/routes/api/manifest.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/api/manifest.cr b/src/invidious/routes/api/manifest.cr index ae65f10d..f5d8e5de 100644 --- a/src/invidious/routes/api/manifest.cr +++ b/src/invidious/routes/api/manifest.cr @@ -42,7 +42,7 @@ module Invidious::Routes::API::Manifest if local adaptive_fmts.each do |fmt| - fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) + fmt["url"] = JSON::Any.new("#{HOST_URL}#{URI.parse(fmt["url"].as_s).request_target}") end end -- cgit v1.2.3 From 01acb9bfbfda00c4fdcb8de87c33174d694de530 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Fri, 13 Jan 2023 19:04:37 -0500 Subject: Login redirect to referer on logged-in user --- src/invidious/helpers/utils.cr | 2 +- src/invidious/routes/login.cr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index ed0cca38..4448508c 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -259,7 +259,7 @@ def get_referer(env, fallback = "/", unroll = true) end referer = referer.request_target - referer = "/" + referer.gsub(/[^\/?@&%=\-_.0-9a-zA-Z]/, "").lstrip("/\\") + referer = "/" + referer.gsub(/[^\/?@&%=\-_.:,0-9a-zA-Z]/, "").lstrip("/\\") if referer == env.request.path referer = fallback diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr index 99fc13a2..6454131a 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -6,14 +6,14 @@ module Invidious::Routes::Login user = env.get? "user" - return env.redirect "/feed/subscriptions" if user + referer = get_referer(env, "/feed/subscriptions") + + return env.redirect referer if user if !CONFIG.login_enabled return error_template(400, "Login has been disabled by administrator.") end - referer = get_referer(env, "/feed/subscriptions") - email = nil password = nil captcha = nil -- cgit v1.2.3 From 1b5fbfc13efa9eace904d24dc89b7fdf72c1ce52 Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Sat, 14 Jan 2023 09:38:55 +0100 Subject: Video: Add support for the music section --- locales/en-US.json | 3 +++ src/invidious/videos.cr | 3 +++ src/invidious/videos/parser.cr | 22 ++++++++++++++++++++++ src/invidious/views/watch.ecr | 9 +++++++++ 4 files changed, 37 insertions(+) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index 12955665..bc6a3275 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -188,6 +188,9 @@ "Engagement: ": "Engagement: ", "Whitelisted regions: ": "Whitelisted regions: ", "Blacklisted regions: ": "Blacklisted regions: ", + "Music artist: ": "Music artist: ", + "Music album: ": "Music album: ", + "Music licenses: ": "Music licenses: ", "Shared `x`": "Shared `x`", "Premieres in `x`": "Premieres in `x`", "Premieres `x`": "Premieres `x`", diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index d626c7d1..be4854fe 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -314,6 +314,9 @@ struct Video getset_string genre getset_string genreUcid getset_string license + getset_string music_artist + getset_string music_album + getset_string music_licenses getset_string shortDescription getset_string subCountText getset_string title diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 5df49286..4540dd13 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -309,6 +309,24 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any end end + # Music section + + music_desc = player_response.dig?("engagementPanels", 1, "engagementPanelSectionListRenderer", "content", "structuredDescriptionContentRenderer", "items", 2, "videoDescriptionMusicSectionRenderer", "carouselLockups", 0, "carouselLockupRenderer", "infoRows").try &.as_a + artist = nil + album = nil + music_licenses = nil + + music_desc.try &.each do |desc| + desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) + if desc_title == "ARTIST" + artist = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) + elsif desc_title == "ALBUM" + album = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) + elsif desc_title == "LICENSES" + music_licenses = extract_text(desc.dig?("infoRowRenderer", "expandedMetadata")) + end + end + # Author infos author = video_details["author"]?.try &.as_s @@ -359,6 +377,10 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any "genre" => JSON::Any.new(genre.try &.as_s || ""), "genreUcid" => JSON::Any.new(genre_ucid.try &.as_s || ""), "license" => JSON::Any.new(license.try &.as_s || ""), + # Music section + "music_artist" => JSON::Any.new(artist || ""), + "music_album" => JSON::Any.new(album || ""), + "music_licenses" => JSON::Any.new(music_licenses || ""), # Author infos "author" => JSON::Any.new(author || ""), "ucid" => JSON::Any.new(ucid || ""), diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index a6f2e524..beab1bb2 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -196,6 +196,15 @@ we're going to need to do it here in order to allow for translations. <% end %>

<% end %> + <% if !video.music_artist.empty? %> +

<%= translate(locale, "Music artist: ") %><%= video.music_artist %>

+ <% end %> + <% if !video.music_album.empty? %> +

<%= translate(locale, "Music album: ") %><%= video.music_album %>

+ <% end %> + <% if !video.music_licenses.empty? %> +

<%= translate(locale, "Music licenses: ") %><%= video.music_licenses %>

+ <% end %>
-- cgit v1.2.3 From 4ee483282e072473b618df1ce9a96668c2905cf5 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sat, 14 Jan 2023 20:00:46 +0100 Subject: Video proxy: always include the 'range' header --- src/invidious/routes/video_playback.cr | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr index 560f9c19..a0216cce 100644 --- a/src/invidious/routes/video_playback.cr +++ b/src/invidious/routes/video_playback.cr @@ -35,6 +35,13 @@ module Invidious::Routes::VideoPlayback end end + # See: https://github.com/iv-org/invidious/issues/3302 + range_header = env.request.headers["Range"]? + if range_header.nil? + range_for_head = query_params["range"]? || "0-640" + headers["Range"] = "bytes=#{range_for_head}" + end + client = make_client(URI.parse(host), region) response = HTTP::Client::Response.new(500) error = "" @@ -70,6 +77,9 @@ module Invidious::Routes::VideoPlayback end end + # Remove the Range header added previously. + headers.delete("Range") if range_header.nil? + if response.status_code >= 400 env.response.content_type = "text/plain" haltf env, response.status_code -- cgit v1.2.3 From d6087fac472711376762cfb2c5f7672f84f6d4fe Mon Sep 17 00:00:00 2001 From: Émilien Devos Date: Sun, 15 Jan 2023 12:07:58 +0000 Subject: Don't continue when LOGIN_REQUIRED and no videoDetails --- src/invidious/videos/parser.cr | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 5df49286..5c323975 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -66,8 +66,10 @@ def extract_video_info(video_id : String, proxy_region : String? = nil) reason ||= subreason.try &.[]("runs").as_a.map(&.[]("text")).join("") reason ||= player_response.dig("playabilityStatus", "reason").as_s - # Stop here if video is not a scheduled livestream - if !{"LIVE_STREAM_OFFLINE", "LOGIN_REQUIRED"}.any?(playability_status) + # Stop here if video is not a scheduled livestream or + # for LOGIN_REQUIRED when videoDetails element is not found because retrying won't help + if !{"LIVE_STREAM_OFFLINE", "LOGIN_REQUIRED"}.any?(playability_status) || + playability_status == "LOGIN_REQUIRED" && !player_response.dig?("videoDetails") return { "version" => JSON::Any.new(Video::SCHEMA_VERSION.to_i64), "reason" => JSON::Any.new(reason), -- cgit v1.2.3 From 1af846e58c3df98a589fe8fdda3e45f2745e69bc Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 15 Jan 2023 17:04:04 +0100 Subject: API: make /api/v1/videos respect the 'local' parameter --- src/invidious.cr | 1 + src/invidious/http_server/utils.cr | 20 ++++++++++++++++++++ src/invidious/jsonify/api_v1/video_json.cr | 11 +++++++++-- src/invidious/routes/api/v1/videos.cr | 5 ++++- src/invidious/routes/video_playback.cr | 10 ++-------- 5 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 src/invidious/http_server/utils.cr (limited to 'src') diff --git a/src/invidious.cr b/src/invidious.cr index 5064f0b8..d4f8e0fb 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -34,6 +34,7 @@ require "protodec/utils" require "./invidious/database/*" require "./invidious/database/migrations/*" +require "./invidious/http_server/*" require "./invidious/helpers/*" require "./invidious/yt_backend/*" require "./invidious/frontend/*" diff --git a/src/invidious/http_server/utils.cr b/src/invidious/http_server/utils.cr new file mode 100644 index 00000000..e3f1fa0f --- /dev/null +++ b/src/invidious/http_server/utils.cr @@ -0,0 +1,20 @@ +module Invidious::HttpServer + module Utils + extend self + + def proxy_video_url(raw_url : String, *, region : String? = nil, absolute : Bool = false) + url = URI.parse(raw_url) + + # Add some URL parameters + params = url.query_params + params["host"] = url.host.not_nil! # Should never be nil, in theory + params["region"] = region if !region.nil? + + if absolute + return "#{HOST_URL}#{url.request_target}?#{params}" + else + return "#{url.request_target}?#{params}" + end + end + end +end diff --git a/src/invidious/jsonify/api_v1/video_json.cr b/src/invidious/jsonify/api_v1/video_json.cr index 642789aa..a2b1a35c 100644 --- a/src/invidious/jsonify/api_v1/video_json.cr +++ b/src/invidious/jsonify/api_v1/video_json.cr @@ -3,7 +3,7 @@ require "json" module Invidious::JSONify::APIv1 extend self - def video(video : Video, json : JSON::Builder, *, locale : String?) + def video(video : Video, json : JSON::Builder, *, locale : String?, proxy : Bool = false) json.object do json.field "type", video.video_type @@ -89,7 +89,14 @@ module Invidious::JSONify::APIv1 # Not available on MPEG-4 Timed Text (`text/mp4`) streams (livestreams only) json.field "bitrate", fmt["bitrate"].as_i.to_s if fmt["bitrate"]? - 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 "clen", fmt["contentLength"]? || "-1" diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index a6b2eb4e..79f7bd3f 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -6,6 +6,7 @@ module Invidious::Routes::API::V1::Videos id = env.params.url["id"] region = env.params.query["region"]? + proxy = {"1", "true"}.any? &.== env.params.query["local"]? begin video = get_video(id, region: region) @@ -15,7 +16,9 @@ module Invidious::Routes::API::V1::Videos return error_json(500, ex) end - video.to_json(locale, nil) + return JSON.build do |json| + Invidious::JSONify::APIv1.video(video, json, locale: locale, proxy: proxy) + end end def self.captions(env) diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr index 560f9c19..04b13630 100644 --- a/src/invidious/routes/video_playback.cr +++ b/src/invidious/routes/video_playback.cr @@ -91,14 +91,8 @@ module Invidious::Routes::VideoPlayback env.response.headers["Access-Control-Allow-Origin"] = "*" if location = resp.headers["Location"]? - location = URI.parse(location) - location = "#{location.request_target}&host=#{location.host}" - - if region - location += "®ion=#{region}" - end - - return env.redirect location + url = Invidious::HttpServer::Utils.proxy_video_url(location, region: region) + return env.redirect url end IO.copy(resp.body_io, env.response) -- cgit v1.2.3 From fe5b81f2c3caf37e10fd3284a49146e7aefb1530 Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Mon, 16 Jan 2023 13:58:05 +0100 Subject: Add support for multiple songs --- assets/css/default.css | 35 +++++++++++++++++++++++++---------- locales/en-US.json | 5 ++--- src/invidious/videos.cr | 12 +++++++++--- src/invidious/videos/music.cr | 12 ++++++++++++ src/invidious/videos/parser.cr | 35 +++++++++++++++++++---------------- src/invidious/views/watch.ecr | 42 +++++++++++++++++++++++++++++++----------- 6 files changed, 98 insertions(+), 43 deletions(-) create mode 100644 src/invidious/videos/music.cr (limited to 'src') diff --git a/assets/css/default.css b/assets/css/default.css index 80bf6a20..4ec6f720 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -490,26 +490,31 @@ hr { } /* Description Expansion Styling*/ -#descexpansionbutton { +#descexpansionbutton, +#musicdescexpansionbutton { display: none } -#descexpansionbutton ~ div { +#descexpansionbutton ~ div, +#musicdescexpansionbutton ~ div { overflow: hidden; height: 8.3em; } -#descexpansionbutton:checked ~ div { +#descexpansionbutton:checked ~ div, +#musicdescexpansionbutton:checked ~ div { overflow: unset; height: 100%; } -#descexpansionbutton ~ label { +#descexpansionbutton ~ label, +#musicdescexpansionbutton ~ label { order: 1; margin-top: 20px; } -label[for="descexpansionbutton"]:hover { +label[for="descexpansionbutton"]:hover, +label[for="musicdescexpansionbutton"]:hover { cursor: pointer; } @@ -521,14 +526,24 @@ h4, h5, p, #descriptionWrapper, -#description-box { - unicode-bidi: plaintext; - text-align: start; +#description-box, +#music-description-box, +#musicDescriptionWrapper { + unicode-bidi: plaintext; + text-align: start; } #descriptionWrapper { - max-width: 600px; - white-space: pre-wrap; + max-width: 600px; + white-space: pre-wrap; +} + +#musicDescriptionWrapper { + max-width: 600px; +} + +#music-description-title { + margin-bottom: 0px; } /* Center the "invidious" logo on the search page */ diff --git a/locales/en-US.json b/locales/en-US.json index bc6a3275..20f1a46d 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -188,9 +188,8 @@ "Engagement: ": "Engagement: ", "Whitelisted regions: ": "Whitelisted regions: ", "Blacklisted regions: ": "Blacklisted regions: ", - "Music artist: ": "Music artist: ", - "Music album: ": "Music album: ", - "Music licenses: ": "Music licenses: ", + "Artist: ": "Artist: ", + "Album: ": "Album: ", "Shared `x`": "Shared `x`", "Premieres in `x`": "Premieres in `x`", "Premieres `x`": "Premieres `x`", diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index be4854fe..aa3ef1a8 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -247,6 +247,15 @@ struct Video info["reason"]?.try &.as_s end + def music : Array(VideoMusic) + music_list = Array(VideoMusic).new + + info["music"].as_a.each do |music_json| + music_list << VideoMusic.new(music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) + end + return music_list + end + # Macros defining getters/setters for various types of data private macro getset_string(name) @@ -314,9 +323,6 @@ struct Video getset_string genre getset_string genreUcid getset_string license - getset_string music_artist - getset_string music_album - getset_string music_licenses getset_string shortDescription getset_string subCountText getset_string title diff --git a/src/invidious/videos/music.cr b/src/invidious/videos/music.cr new file mode 100644 index 00000000..402ae46f --- /dev/null +++ b/src/invidious/videos/music.cr @@ -0,0 +1,12 @@ +require "json" + +struct VideoMusic + include JSON::Serializable + + property album : String + property artist : String + property license : String + + def initialize(@album : String, @artist : String, @license : String) + end +end diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 4540dd13..69b04cb6 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -311,20 +311,25 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any # Music section - music_desc = player_response.dig?("engagementPanels", 1, "engagementPanelSectionListRenderer", "content", "structuredDescriptionContentRenderer", "items", 2, "videoDescriptionMusicSectionRenderer", "carouselLockups", 0, "carouselLockupRenderer", "infoRows").try &.as_a - artist = nil - album = nil - music_licenses = nil - - music_desc.try &.each do |desc| - desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) - if desc_title == "ARTIST" - artist = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) - elsif desc_title == "ALBUM" - album = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) - elsif desc_title == "LICENSES" - music_licenses = extract_text(desc.dig?("infoRowRenderer", "expandedMetadata")) + music_list = [] of VideoMusic + music_desclist = player_response.dig?("engagementPanels", 1, "engagementPanelSectionListRenderer", "content", "structuredDescriptionContentRenderer", "items", 2, "videoDescriptionMusicSectionRenderer", "carouselLockups").try &.as_a + music_desclist.try &.each do |music_desc| + artist = nil + album = nil + music_license = nil + + music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.try &.each do |desc| + desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) + if desc_title == "ARTIST" + artist = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) + elsif desc_title == "ALBUM" + album = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) + elsif desc_title == "LICENSES" + music_license = extract_text(desc.dig?("infoRowRenderer", "expandedMetadata")) + end end + music = VideoMusic.new(album.to_s, artist.to_s, music_license.to_s) + music_list << music end # Author infos @@ -378,9 +383,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any "genreUcid" => JSON::Any.new(genre_ucid.try &.as_s || ""), "license" => JSON::Any.new(license.try &.as_s || ""), # Music section - "music_artist" => JSON::Any.new(artist || ""), - "music_album" => JSON::Any.new(album || ""), - "music_licenses" => JSON::Any.new(music_licenses || ""), + "music" => JSON.parse(music_list.to_json), # Author infos "author" => JSON::Any.new(author || ""), "ucid" => JSON::Any.new(ucid || ""), diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index beab1bb2..207dae18 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -34,11 +34,13 @@ we're going to need to do it here in order to allow for translations. --> @@ -196,15 +198,6 @@ we're going to need to do it here in order to allow for translations. <% end %>

<% end %> - <% if !video.music_artist.empty? %> -

<%= translate(locale, "Music artist: ") %><%= video.music_artist %>

- <% end %> - <% if !video.music_album.empty? %> -

<%= translate(locale, "Music album: ") %><%= video.music_album %>

- <% end %> - <% if !video.music_licenses.empty? %> -

<%= translate(locale, "Music licenses: ") %><%= video.music_licenses %>

- <% end %>
@@ -244,6 +237,33 @@ we're going to need to do it here in order to allow for translations.
+ <% if !video.music.empty? %> +

<%= translate(locale, "Music") %>

+
+
+ + <% end %>
<% if nojs %> <%= comment_html %> -- cgit v1.2.3 From 910809f1eb185328fa94b5d8baff9ba7756ade48 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 16 Jan 2023 08:33:34 -0500 Subject: Handle case with included manifest --- src/invidious/routes/api/manifest.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/api/manifest.cr b/src/invidious/routes/api/manifest.cr index f5d8e5de..662d1002 100644 --- a/src/invidious/routes/api/manifest.cr +++ b/src/invidious/routes/api/manifest.cr @@ -29,7 +29,7 @@ module Invidious::Routes::API::Manifest if local uri = URI.parse(url) - url = "#{uri.request_target}host/#{uri.host}/" + url = "#{HOST_URL}#{uri.request_target}host/#{uri.host}/" end "#{url}" -- cgit v1.2.3 From 8dcc98b3b9d8e189a4c92ab0cbed7e3635341b5d Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Mon, 16 Jan 2023 18:37:52 -0500 Subject: If videCountText lists the number of subscribers, then don't use it in get_video_count --- src/invidious/yt_backend/extractors.cr | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index cd52c73b..d32f5646 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -652,8 +652,13 @@ module HelperExtractors # # Returns a 0 when it's unable to do so def self.get_video_count(container : JSON::Any) : Int32 + puts container if box = container["videoCountText"]? - return extract_text(box).try &.gsub(/\D/, "").to_i || 0 + if (extracted_text = extract_text(box)) && !extracted_text.includes? " subscriber" + return extracted_text.gsub(/\D/, "").to_i + else + return 0 + end elsif box = container["videoCount"]? return box.as_s.to_i else -- cgit v1.2.3 From 86333cd4344267f09ca34a179558dc71fb8b6fb4 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Mon, 16 Jan 2023 18:43:58 -0500 Subject: Formatting --- src/invidious/yt_backend/extractors.cr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index d32f5646..fbb02824 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -652,13 +652,13 @@ module HelperExtractors # # Returns a 0 when it's unable to do so def self.get_video_count(container : JSON::Any) : Int32 - puts container + puts container if box = container["videoCountText"]? - if (extracted_text = extract_text(box)) && !extracted_text.includes? " subscriber" - return extracted_text.gsub(/\D/, "").to_i - else - return 0 - end + if (extracted_text = extract_text(box)) && !extracted_text.includes? " subscriber" + return extracted_text.gsub(/\D/, "").to_i + else + return 0 + end elsif box = container["videoCount"]? return box.as_s.to_i else -- cgit v1.2.3 From 67ace4fd9dd1a62ab004b05dc0403cc71ef5e206 Mon Sep 17 00:00:00 2001 From: DUO Labs Date: Mon, 16 Jan 2023 18:50:38 -0500 Subject: Some indention changes Co-authored-by: Samantaz Fox --- src/invidious/routes/api/v1/videos.cr | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index b10a30ea..4ef877e5 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -98,12 +98,12 @@ module Invidious::Routes::API::V1::Videos webvtt = String.build do |str| str << <<-END_VTT - WEBVTT - Kind: captions - Language: #{tlang || caption.language_code} - - - END_VTT + WEBVTT + Kind: captions + Language: #{tlang || caption.language_code} + + + END_VTT caption_nodes = caption_xml.xpath_nodes("//transcript/text") caption_nodes.each_with_index do |node, i| @@ -128,11 +128,11 @@ module Invidious::Routes::API::V1::Videos end str << <<-END_CUE - #{start_time} --> #{end_time} - #{text} - - - END_CUE + #{start_time} --> #{end_time} + #{text} + + + END_CUE end end end -- cgit v1.2.3 From ff66cec9209f464ffc269a7d189199a22b5486c0 Mon Sep 17 00:00:00 2001 From: DUOLabs333 Date: Mon, 16 Jan 2023 18:52:17 -0500 Subject: Remove debug print --- src/invidious/yt_backend/extractors.cr | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index fbb02824..1f7726fb 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -652,7 +652,6 @@ module HelperExtractors # # Returns a 0 when it's unable to do so def self.get_video_count(container : JSON::Any) : Int32 - puts container if box = container["videoCountText"]? if (extracted_text = extract_text(box)) && !extracted_text.includes? " subscriber" return extracted_text.gsub(/\D/, "").to_i -- cgit v1.2.3 From f6a4d04070203111c294520301ef6e439e110ade Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Wed, 18 Jan 2023 15:58:59 -0500 Subject: Redirect auth token to login --- src/invidious/routes/account.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/account.cr b/src/invidious/routes/account.cr index 9bb73136..e6a70ed2 100644 --- a/src/invidious/routes/account.cr +++ b/src/invidious/routes/account.cr @@ -203,7 +203,7 @@ module Invidious::Routes::Account referer = get_referer(env) if !user - return env.redirect referer + return env.redirect "/login?referer=#{URI.encode_path_segment(env.request.resource)}" end user = user.as(User) -- cgit v1.2.3 From cf93c94fc43bdb19160555747409b0a59b0c5f6b Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sat, 21 Jan 2023 15:23:15 +0100 Subject: Formatting fix for Crystal nightly Changes added by https://github.com/crystal-lang/crystal/pull/12951 --- src/invidious/helpers/json_filter.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/invidious/helpers/json_filter.cr b/src/invidious/helpers/json_filter.cr index b8e8f96d..3f4080ba 100644 --- a/src/invidious/helpers/json_filter.cr +++ b/src/invidious/helpers/json_filter.cr @@ -20,7 +20,7 @@ module JSONFilter /^\(|\(\(|\/\(/ end - def self.parse_fields(fields_text : String) : Nil + def self.parse_fields(fields_text : String, &) : Nil if fields_text.empty? raise FieldsParser::ParseError.new "Fields is empty" end @@ -42,7 +42,7 @@ module JSONFilter parse_nest_groups(fields_text) { |nest_list| yield nest_list } end - def self.parse_single_nests(fields_text : String) : Nil + def self.parse_single_nests(fields_text : String, &) : Nil single_nests = remove_nest_groups(fields_text) if !single_nests.empty? @@ -60,7 +60,7 @@ module JSONFilter end end - def self.parse_nest_groups(fields_text : String) : Nil + def self.parse_nest_groups(fields_text : String, &) : Nil nest_stack = [] of NamedTuple(group_name: String, closing_bracket_index: Int64) bracket_pairs = get_bracket_pairs(fields_text, true) -- cgit v1.2.3 From 7fd205179b5707a2774d83866f5a35b2bd8cfe16 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Sat, 21 Jan 2023 23:24:22 +0100 Subject: Added suggestions --- src/invidious/views/components/item.ecr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 47d077cf..fa12374f 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -1,4 +1,4 @@ -<% item_watched = !item.is_a?(SearchChannel) && !item.is_a?(SearchPlaylist) && !item.is_a?(InvidiousPlaylist) && !item.is_a?(Category) && env.get("user") && env.get("user").as(User).watched && env.get("user").as(User).watched.index(item.id) != nil %> +<% item_watched = !item.is_a?(SearchChannel | SearchPlaylist | InvidiousPlaylist | Category) && env.get?("user").try &.as(User).watched.index(item.id) != nil %>
@@ -42,7 +42,7 @@ <% if item.length_seconds != 0 %>

<%= recode_length_seconds(item.length_seconds) %>

<% end %> - + <% if item_watched %>
@@ -74,7 +74,7 @@ <% elsif item.length_seconds != 0 %>

<%= recode_length_seconds(item.length_seconds) %>

<% end %> - + <% if item_watched %>
-- cgit v1.2.3 From caf9520c865133eb669025f9cd64607546e09a89 Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Sun, 22 Jan 2023 00:12:04 +0100 Subject: Major improvements --- assets/css/default.css | 41 ++++++++++++++++++++++++++--------------- locales/en-US.json | 1 + src/invidious/videos.cr | 9 +++------ src/invidious/videos/parser.cr | 14 +++++++++----- src/invidious/views/watch.ecr | 39 ++++++++++++++++----------------------- 5 files changed, 55 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/assets/css/default.css b/assets/css/default.css index 4ec6f720..9788e9f7 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -491,30 +491,27 @@ hr { /* Description Expansion Styling*/ #descexpansionbutton, -#musicdescexpansionbutton { - display: none +#music-desc-expansion { + display: none; } -#descexpansionbutton ~ div, -#musicdescexpansionbutton ~ div { +#descexpansionbutton ~ div { overflow: hidden; height: 8.3em; } -#descexpansionbutton:checked ~ div, -#musicdescexpansionbutton:checked ~ div { +#descexpansionbutton:checked ~ div { overflow: unset; height: 100%; } -#descexpansionbutton ~ label, -#musicdescexpansionbutton ~ label { +#descexpansionbutton ~ label { order: 1; margin-top: 20px; } label[for="descexpansionbutton"]:hover, -label[for="musicdescexpansionbutton"]:hover { +label[for="music-desc-expansion"]:hover { cursor: pointer; } @@ -527,8 +524,7 @@ h5, p, #descriptionWrapper, #description-box, -#music-description-box, -#musicDescriptionWrapper { +#music-description-box { unicode-bidi: plaintext; text-align: start; } @@ -538,12 +534,27 @@ p, white-space: pre-wrap; } -#musicDescriptionWrapper { - max-width: 600px; +#music-description-box { + display: none; +} + +#music-desc-expansion:checked ~ #music-description-box { + display: block; +} + +#music-desc-expansion ~ label > h3 > .ion-ios-arrow-up, +#music-desc-expansion:checked ~ label > h3 > .ion-ios-arrow-down { + display: none; +} + +#music-desc-expansion:checked ~ label > h3 > .ion-ios-arrow-up, +#music-desc-expansion ~ label > h3 > .ion-ios-arrow-down { + display: inline; } -#music-description-title { - margin-bottom: 0px; +/* Select all the music items except the first one */ +.music-item + .music-item { + border-top: 1px solid #ffffff; } /* Center the "invidious" logo on the search page */ diff --git a/locales/en-US.json b/locales/en-US.json index 20f1a46d..a5c16fd7 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -188,6 +188,7 @@ "Engagement: ": "Engagement: ", "Whitelisted regions: ": "Whitelisted regions: ", "Blacklisted regions: ": "Blacklisted regions: ", + "Music in this video": "Music in this video", "Artist: ": "Artist: ", "Album: ": "Album: ", "Shared `x`": "Shared `x`", diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index aa3ef1a8..436ac82d 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -248,12 +248,9 @@ struct Video end def music : Array(VideoMusic) - music_list = Array(VideoMusic).new - - info["music"].as_a.each do |music_json| - music_list << VideoMusic.new(music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) - end - return music_list + info["music"].as_a.map { |music_json| + VideoMusic.new(music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) + } end # Macros defining getters/setters for various types of data diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 69b04cb6..0abac32f 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -312,13 +312,18 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any # Music section music_list = [] of VideoMusic - music_desclist = player_response.dig?("engagementPanels", 1, "engagementPanelSectionListRenderer", "content", "structuredDescriptionContentRenderer", "items", 2, "videoDescriptionMusicSectionRenderer", "carouselLockups").try &.as_a - music_desclist.try &.each do |music_desc| + music_desclist = player_response.dig?( + "engagementPanels", 1, "engagementPanelSectionListRenderer", + "content", "structuredDescriptionContentRenderer", "items", 2, + "videoDescriptionMusicSectionRenderer", "carouselLockups" + ) + + music_desclist.try &.as_a.each do |music_desc| artist = nil album = nil music_license = nil - music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.try &.each do |desc| + music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.each do |desc| desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) if desc_title == "ARTIST" artist = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) @@ -328,8 +333,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any music_license = extract_text(desc.dig?("infoRowRenderer", "expandedMetadata")) end end - music = VideoMusic.new(album.to_s, artist.to_s, music_license.to_s) - music_list << music + music_list << VideoMusic.new(album.to_s, artist.to_s, music_license.to_s) end # Author infos diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 207dae18..666eb3b0 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -34,13 +34,11 @@ we're going to need to do it here in order to allow for translations. --> @@ -238,27 +236,22 @@ we're going to need to do it here in order to allow for translations.
<% if !video.music.empty? %> -

<%= translate(locale, "Music") %>

+ + +
- <% if video.music.size == 1 %> -
-

<%= translate(locale, "Artist: ") %><%= video.music[0].artist %>

-

<%= translate(locale, "Album: ") %><%= video.music[0].album %>

-

<%= translate(locale, "License: ") %><%= video.music[0].license %>

-
- <% else %> - -
- <% video.music.each do |music| %> -

<%= translate(locale, "Artist: ") %><%= music.artist %>

-

<%= translate(locale, "Album: ") %><%= music.album %>

-

<%= translate(locale, "License: ") %><%= music.license %>

-
- <% end %> + <% video.music.each do |music| %> +
+

<%= translate(locale, "Artist: ") %><%= music.artist %>

+

<%= translate(locale, "Album: ") %><%= music.album %>

+

<%= translate(locale, "License: ") %><%= music.license %>

- <% end %>

-- cgit v1.2.3 From c2957dbce4a76b9a85fde9224b8c18edcb5821ba Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 24 Jan 2023 23:21:09 -0500 Subject: fix displaying author name #1612 --- src/invidious/channels/community.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 8e300288..76dff555 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -69,7 +69,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) next if !post content_html = post["contentText"]?.try { |t| parse_content(t) } || "" - author = post["authorText"]?.try &.["simpleText"]? || "" + author = post["authorText"]["runs"]?.try &.[0]?.try &.["text"]? || "" json.object do json.field "author", author -- cgit v1.2.3 From 13bf4e9e00030161165edf45b5e7d6e2ab1b3e30 Mon Sep 17 00:00:00 2001 From: Macic Date: Thu, 26 Jan 2023 01:19:12 +0100 Subject: Support handles --- src/invidious/routing.cr | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 491022a5..157e6de7 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -132,6 +132,8 @@ module Invidious::Routing get "/c/:user#{path}", Routes::Channels, :brand_redirect # /user/linustechtips | Not always the same as /c/ get "/user/:user#{path}", Routes::Channels, :brand_redirect + # /@LinusTechTips | Handle + get "/@:user#{path}", Routes::Channels, :brand_redirect # /attribution_link?a=anything&u=/channel/UCZYTClx2T1of7BRZ86-8fow get "/attribution_link#{path}", Routes::Channels, :brand_redirect # /profile?user=linustechtips -- cgit v1.2.3 From 785fe5267480db83173e54423051bc528c545b0c Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Sun, 29 Jan 2023 10:28:42 -0500 Subject: API: Parse multiimage community posts --- src/invidious/channels/community.cr | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 76dff555..13af2d8b 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -189,6 +189,32 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) # when .has_key?("pollRenderer") # attachment = attachment["pollRenderer"] # json.field "type", "poll" + when .has_key?("postMultiImageRenderer") + attachment = attachment["postMultiImageRenderer"] + json.field "type", "multiImage" + json.field "images" do + json.array do + attachment["images"].as_a.each do |image| + json.array do + thumbnail = image["backstageImageRenderer"]["image"]["thumbnails"][0].as_h + width = thumbnail["width"].as_i + height = thumbnail["height"].as_i + aspect_ratio = (width.to_f / height.to_f) + url = thumbnail["url"].as_s.gsub(/=w\d+-h\d+(-p)?(-nd)?(-df)?(-rwa)?/, "=s640") + + qualities = {320, 560, 640, 1280, 2000} + + qualities.each do |quality| + json.object do + json.field "url", url.gsub(/=s\d+/, "=s#{quality}") + json.field "width", quality + json.field "height", (quality / aspect_ratio).ceil.to_i + end + end + end + end + end + end else json.field "type", "unknown" json.field "error", "Unrecognized attachment type." -- cgit v1.2.3 From e7a9aeff9538903d22363d2abcee28c62dc10895 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 30 Jan 2023 10:49:23 -0500 Subject: Add username to auth token callback --- src/invidious/routes/account.cr | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/invidious/routes/account.cr b/src/invidious/routes/account.cr index 9bb73136..d01aee56 100644 --- a/src/invidious/routes/account.cr +++ b/src/invidious/routes/account.cr @@ -262,6 +262,7 @@ module Invidious::Routes::Account end query["token"] = access_token + query["username"] = user.email url.query = query.to_s env.redirect url.to_s -- cgit v1.2.3 From bf5175d1e979005f6d04c9d7639c9db4aa08fb7b Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Thu, 2 Feb 2023 11:52:31 -0500 Subject: Feat: Add api endpoint to resolve youtube urls --- src/invidious/routes/api/v1/misc.cr | 27 +++++++++++++++++++++++++++ src/invidious/routing.cr | 1 + 2 files changed, 28 insertions(+) (limited to 'src') diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr index 43d360e6..9679b530 100644 --- a/src/invidious/routes/api/v1/misc.cr +++ b/src/invidious/routes/api/v1/misc.cr @@ -150,4 +150,31 @@ module Invidious::Routes::API::V1::Misc response end + + # resolve channel and clip urls, return the UCID + def self.resolve_url(env) + env.response.content_type = "application/json" + url = env.params.query["url"]? + + return error_json(400, "Missing URL to resolve") if !url + + begin + resolved_url = YoutubeAPI.resolve_url(url.as(String)) + endpoint = resolved_url["endpoint"] + if resolved_ucid = endpoint.dig?("watchEndpoint", "videoId") + elsif resolved_ucid = endpoint.dig?("browseEndpoint", "browseId") + elsif pageType = endpoint.dig?("commandMetadata", "webCommandMetadata", "webPageType").try &.as_s || "" + if pageType == "WEB_PAGE_TYPE_UNKNOWN" + return error_json(400, "Unknown url") + end + end + rescue ex + return error_json(500, ex) + end + JSON.build do |json| + json.object do + json.field "ucid", resolved_ucid.try &.as_s || "" + end + end + end end diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 157e6de7..fb9851a3 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -281,6 +281,7 @@ module Invidious::Routing get "/api/v1/playlists/:plid", {{namespace}}::Misc, :get_playlist get "/api/v1/auth/playlists/:plid", {{namespace}}::Misc, :get_playlist get "/api/v1/mixes/:rdid", {{namespace}}::Misc, :mixes + get "/api/v1/resolveurl", {{namespace}}::Misc, :resolve_url {% end %} end end -- cgit v1.2.3 From c162c7ff3f27498bd374b674bf7ca9b0c0790cc8 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Thu, 2 Feb 2023 18:20:14 -0500 Subject: add pageType --- src/invidious/routes/api/v1/misc.cr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr index 9679b530..e499f4d6 100644 --- a/src/invidious/routes/api/v1/misc.cr +++ b/src/invidious/routes/api/v1/misc.cr @@ -161,12 +161,11 @@ module Invidious::Routes::API::V1::Misc begin resolved_url = YoutubeAPI.resolve_url(url.as(String)) endpoint = resolved_url["endpoint"] + pageType = endpoint.dig?("commandMetadata", "webCommandMetadata", "webPageType").try &.as_s || "" if resolved_ucid = endpoint.dig?("watchEndpoint", "videoId") elsif resolved_ucid = endpoint.dig?("browseEndpoint", "browseId") - elsif pageType = endpoint.dig?("commandMetadata", "webCommandMetadata", "webPageType").try &.as_s || "" - if pageType == "WEB_PAGE_TYPE_UNKNOWN" - return error_json(400, "Unknown url") - end + elsif pageType == "WEB_PAGE_TYPE_UNKNOWN" + return error_json(400, "Unknown url") end rescue ex return error_json(500, ex) @@ -174,6 +173,7 @@ module Invidious::Routes::API::V1::Misc JSON.build do |json| json.object do json.field "ucid", resolved_ucid.try &.as_s || "" + json.field "pageType", pageType end end end -- cgit v1.2.3 From b2589c74bedb73a1ab6e0afe1a921b97f80c4b8e Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Thu, 2 Feb 2023 19:14:02 -0500 Subject: Add API for import/export --- src/invidious/routes/api/v1/authenticated.cr | 49 ++++++++++++++++++++++++++++ src/invidious/routing.cr | 3 ++ 2 files changed, 52 insertions(+) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 421355bb..c6042e40 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -31,6 +31,55 @@ module Invidious::Routes::API::V1::Authenticated env.response.status_code = 204 end + def self.export_invidious(env) + env.response.content_type = "application/json" + user = env.get("user").as(User) + + playlists = Invidious::Database::Playlists.select_like_iv(user.email) + + return JSON.build do |json| + json.object do + json.field "subscriptions", user.subscriptions + json.field "watch_history", user.watched + json.field "preferences", user.preferences + json.field "playlists" do + json.array do + playlists.each do |playlist| + json.object do + json.field "title", playlist.title + json.field "description", html_to_content(playlist.description_html) + json.field "privacy", playlist.privacy.to_s + json.field "videos" do + json.array do + Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: 500).each do |video_id| + json.string video_id + end + end + end + end + end + end + end + end + end + end + + def self.import_invidious(env) + user = env.get("user").as(User) + + begin + if body = env.request.body + body = env.request.body.not_nil!.gets_to_end + else + body = "{}" + end + Invidious::User::Import.from_invidious(user, body) + rescue + end + + env.response.status_code = 204 + end + def self.feed(env) env.response.content_type = "application/json" diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 157e6de7..d5766b90 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -254,6 +254,9 @@ module Invidious::Routing get "/api/v1/auth/preferences", {{namespace}}::Authenticated, :get_preferences post "/api/v1/auth/preferences", {{namespace}}::Authenticated, :set_preferences + get "/api/v1/auth/export/invidious", {{namespace}}::Authenticated, :export_invidious + post "/api/v1/auth/import/invidious", {{namespace}}::Authenticated, :import_invidious + get "/api/v1/auth/feed", {{namespace}}::Authenticated, :feed get "/api/v1/auth/subscriptions", {{namespace}}::Authenticated, :get_subscriptions -- cgit v1.2.3 From 2606decd21a84ac3cba914f327f60a8403398ed9 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Sun, 5 Feb 2023 15:00:11 -0500 Subject: Refactor export function --- src/invidious/routes/api/v1/authenticated.cr | 28 +--------------------- src/invidious/routes/subscriptions.cr | 26 +-------------------- src/invidious/user/exports.cr | 35 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 52 deletions(-) create mode 100644 src/invidious/user/exports.cr (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index c6042e40..6b935312 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -35,33 +35,7 @@ module Invidious::Routes::API::V1::Authenticated env.response.content_type = "application/json" user = env.get("user").as(User) - playlists = Invidious::Database::Playlists.select_like_iv(user.email) - - return JSON.build do |json| - json.object do - json.field "subscriptions", user.subscriptions - json.field "watch_history", user.watched - json.field "preferences", user.preferences - json.field "playlists" do - json.array do - playlists.each do |playlist| - json.object do - json.field "title", playlist.title - json.field "description", html_to_content(playlist.description_html) - json.field "privacy", playlist.privacy.to_s - json.field "videos" do - json.array do - Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: 500).each do |video_id| - json.string video_id - end - end - end - end - end - end - end - end - end + return Invidious::User::Export.to_invidious(user) end def self.import_invidious(env) diff --git a/src/invidious/routes/subscriptions.cr b/src/invidious/routes/subscriptions.cr index 7b1fa876..3090e026 100644 --- a/src/invidious/routes/subscriptions.cr +++ b/src/invidious/routes/subscriptions.cr @@ -106,31 +106,7 @@ module Invidious::Routes::Subscriptions env.response.headers["content-disposition"] = "attachment" playlists = Invidious::Database::Playlists.select_like_iv(user.email) - return JSON.build do |json| - json.object do - json.field "subscriptions", user.subscriptions - json.field "watch_history", user.watched - json.field "preferences", user.preferences - json.field "playlists" do - json.array do - playlists.each do |playlist| - json.object do - json.field "title", playlist.title - json.field "description", html_to_content(playlist.description_html) - json.field "privacy", playlist.privacy.to_s - json.field "videos" do - json.array do - Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: 500).each do |video_id| - json.string video_id - end - end - end - end - end - end - end - end - end + return Invidious::User::Export.to_invidious(user) else env.response.content_type = "application/xml" env.response.headers["content-disposition"] = "attachment" diff --git a/src/invidious/user/exports.cr b/src/invidious/user/exports.cr new file mode 100644 index 00000000..32be0ca2 --- /dev/null +++ b/src/invidious/user/exports.cr @@ -0,0 +1,35 @@ +struct Invidious::User + module Export + extend self + + def to_invidious(user : User) + playlists = Invidious::Database::Playlists.select_like_iv(user.email) + + return JSON.build do |json| + json.object do + json.field "subscriptions", user.subscriptions + json.field "watch_history", user.watched + json.field "preferences", user.preferences + json.field "playlists" do + json.array do + playlists.each do |playlist| + json.object do + json.field "title", playlist.title + json.field "description", html_to_content(playlist.description_html) + json.field "privacy", playlist.privacy.to_s + json.field "videos" do + json.array do + Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: 500).each do |video_id| + json.string video_id + end + end + end + end + end + end + end + end + end + end + end # module +end -- cgit v1.2.3 From 47a5b98e2554b32946864bc3320478d0dcc1daf8 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Sun, 5 Feb 2023 15:43:58 -0500 Subject: Remove unused db call --- src/invidious/routes/subscriptions.cr | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/subscriptions.cr b/src/invidious/routes/subscriptions.cr index 3090e026..0704c05e 100644 --- a/src/invidious/routes/subscriptions.cr +++ b/src/invidious/routes/subscriptions.cr @@ -104,7 +104,6 @@ module Invidious::Routes::Subscriptions if format == "json" env.response.content_type = "application/json" env.response.headers["content-disposition"] = "attachment" - playlists = Invidious::Database::Playlists.select_like_iv(user.email) return Invidious::User::Export.to_invidious(user) else -- cgit v1.2.3 From c37d8e36645d23afedff2729b8ad504cc5ba0655 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Sun, 5 Feb 2023 15:49:56 -0500 Subject: Use CONFIG.playlist_length_limit when exporting playlists --- src/invidious/user/exports.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/user/exports.cr b/src/invidious/user/exports.cr index 32be0ca2..b52503c9 100644 --- a/src/invidious/user/exports.cr +++ b/src/invidious/user/exports.cr @@ -19,7 +19,7 @@ struct Invidious::User json.field "privacy", playlist.privacy.to_s json.field "videos" do json.array do - Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: 500).each do |video_id| + Invidious::Database::PlaylistVideos.select_ids(playlist.id, playlist.index, limit: CONFIG.playlist_length_limit).each do |video_id| json.string video_id end end -- cgit v1.2.3 From 28424d0e881c8595bbc5797b9ef46e98103fe6d6 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Feb 2023 09:23:26 -0500 Subject: Ignore casing for trending type in api --- src/invidious/trending.cr | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/invidious/trending.cr b/src/invidious/trending.cr index 1f957081..d164c37f 100644 --- a/src/invidious/trending.cr +++ b/src/invidious/trending.cr @@ -4,11 +4,14 @@ def fetch_trending(trending_type, region, locale) plid = nil - if trending_type == "Music" + trending_type ||= "default" + trending_type = trending_type.downcase + + if trending_type == "music" params = "4gINGgt5dG1hX2NoYXJ0cw%3D%3D" - elsif trending_type == "Gaming" + elsif trending_type == "gaming" params = "4gIcGhpnYW1pbmdfY29ycHVzX21vc3RfcG9wdWxhcg%3D%3D" - elsif trending_type == "Movies" + elsif trending_type == "movies" params = "4gIKGgh0cmFpbGVycw%3D%3D" else # Default params = "" -- cgit v1.2.3 From 97825be10c4acf98962c9e65d63305cc77c21021 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Feb 2023 21:52:53 -0500 Subject: add missing authorVerified to api --- src/invidious/helpers/serialized_yt_data.cr | 1 + src/invidious/routes/api/v1/channels.cr | 2 ++ 2 files changed, 3 insertions(+) (limited to 'src') diff --git a/src/invidious/helpers/serialized_yt_data.cr b/src/invidious/helpers/serialized_yt_data.cr index 635f0984..c1874780 100644 --- a/src/invidious/helpers/serialized_yt_data.cr +++ b/src/invidious/helpers/serialized_yt_data.cr @@ -74,6 +74,7 @@ struct SearchVideo json.field "author", self.author json.field "authorId", self.ucid json.field "authorUrl", "/channel/#{self.ucid}" + json.field "authorVerified", self.author_verified json.field "videoThumbnails" do Invidious::JSONify::APIv1.thumbnails(json, self.id) diff --git a/src/invidious/routes/api/v1/channels.cr b/src/invidious/routes/api/v1/channels.cr index ca2b2734..bcb4db2c 100644 --- a/src/invidious/routes/api/v1/channels.cr +++ b/src/invidious/routes/api/v1/channels.cr @@ -89,6 +89,8 @@ module Invidious::Routes::API::V1::Channels json.field "descriptionHtml", channel.description_html json.field "allowedRegions", channel.allowed_regions + json.field "tabs", channel.tabs + json.field "authorVerified", channel.verified json.field "latestVideos" do json.array do -- cgit v1.2.3 From b893bdac0d6b76a61e2cd972b29e44cf5b9c88f0 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Feb 2023 22:02:35 -0500 Subject: parse isPinned, add support for strikethrough --- src/invidious/comments.cr | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index d691ca36..357a461c 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -181,6 +181,8 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b json.field "content", html_to_content(content_html) json.field "contentHtml", content_html + json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) + json.field "published", published.to_unix json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) @@ -670,6 +672,7 @@ def content_to_comment_html(content, video_id : String? = "") end text = "#{text}" if run["bold"]? + text = "#{text}" if run["strikethrough"]? text = "#{text}" if run["italics"]? text -- cgit v1.2.3 From d57d278f32e94d2bec75ffbc3c7bf28e6cb7638d Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Thu, 9 Feb 2023 15:00:23 -0500 Subject: Make itag optional under /latest_version --- src/invidious/routes/video_playback.cr | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr index 1e932d11..f24c0ded 100644 --- a/src/invidious/routes/video_playback.cr +++ b/src/invidious/routes/video_playback.cr @@ -256,7 +256,7 @@ module Invidious::Routes::VideoPlayback return error_template(400, "Invalid video ID") end - if itag.nil? || itag <= 0 || itag >= 1000 + if !itag.nil? && (itag <= 0 || itag >= 1000) return error_template(400, "Invalid itag") end @@ -277,7 +277,11 @@ module Invidious::Routes::VideoPlayback return error_template(500, ex) end - fmt = video.fmt_stream.find(nil) { |f| f["itag"].as_i == itag } || video.adaptive_fmts.find(nil) { |f| f["itag"].as_i == itag } + if itag.nil? + fmt = video.fmt_stream[-1] + else + fmt = video.fmt_stream.find(nil) { |f| f["itag"].as_i == itag } || video.adaptive_fmts.find(nil) { |f| f["itag"].as_i == itag } + end url = fmt.try &.["url"]?.try &.as_s if !url -- cgit v1.2.3 From e0c70d34cc3f937149d5c36c76aed8d8b57b4de5 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Thu, 9 Feb 2023 17:13:21 -0500 Subject: Make sure pinnedCommentBadge isn't equal to false Co-authored-by: Samantaz Fox --- src/invidious/comments.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 357a461c..41b0efa8 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -181,7 +181,7 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b json.field "content", html_to_content(content_html) json.field "contentHtml", content_html - json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) + json.field "isPinned", (node_comment["pinnedCommentBadge"]?.try(&.as_bool) == true) json.field "published", published.to_unix json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) -- cgit v1.2.3 From 838cbeffcc7c8f85c83f6ab3e97362f803bd766c Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Sat, 11 Feb 2023 08:41:26 -0500 Subject: Use case statement for trending_type Co-Authored-By: Samantaz Fox --- src/invidious/trending.cr | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/invidious/trending.cr b/src/invidious/trending.cr index d164c37f..134eb437 100644 --- a/src/invidious/trending.cr +++ b/src/invidious/trending.cr @@ -4,14 +4,12 @@ def fetch_trending(trending_type, region, locale) plid = nil - trending_type ||= "default" - trending_type = trending_type.downcase - - if trending_type == "music" + case trending_type.try &.downcase + when "music" params = "4gINGgt5dG1hX2NoYXJ0cw%3D%3D" - elsif trending_type == "gaming" + when "gaming" params = "4gIcGhpnYW1pbmdfY29ycHVzX21vc3RfcG9wdWxhcg%3D%3D" - elsif trending_type == "movies" + when "movies" params = "4gIKGgh0cmFpbGVycw%3D%3D" else # Default params = "" -- cgit v1.2.3 From 87342e4efd4258f52d2b34f0e5af0fcf7ca09f90 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 12 Feb 2023 17:57:07 +0100 Subject: Comments: Revert "isPinned" to a nil check "pinnedCommentBadge" is not a boolean, but a complex structure. This commit fixes a wrong assumption I had during the rewiew of https://github.com/iv-org/invidious/pull/3626 --- src/invidious/comments.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 41b0efa8..357a461c 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -181,7 +181,7 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b json.field "content", html_to_content(content_html) json.field "contentHtml", content_html - json.field "isPinned", (node_comment["pinnedCommentBadge"]?.try(&.as_bool) == true) + json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) json.field "published", published.to_unix json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) -- cgit v1.2.3 From 8384fa94c2de8c4bf561f4fe5964ce802f22a545 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:48:37 -0500 Subject: Community: Parse polls --- src/invidious/channels/community.cr | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 13af2d8b..a0e79c22 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -185,10 +185,40 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) end end end - # TODO - # when .has_key?("pollRenderer") - # attachment = attachment["pollRenderer"] - # json.field "type", "poll" + when .has_key?("pollRenderer") + attachment = attachment["pollRenderer"] + json.field "type", "poll" + json.field "totalVotes", attachment["totalVotes"]["simpleText"].as_s + json.field "choices" do + json.array do + attachment["choices"].as_a.each do |choice| + json.object do + json.field "text", choice["text"]["runs"][0]["text"].as_s + # A choice can have an image associated with it. + # Ex post: https://www.youtube.com/post/UgkxD4XavXUD4NQiddJXXdohbwOwcVqrH9Re + if choice["image"]? + thumbnail = choice["image"]["thumbnails"][0].as_h + width = thumbnail["width"].as_i + height = thumbnail["height"].as_i + aspect_ratio = (width.to_f / height.to_f) + url = thumbnail["url"].as_s.gsub(/=w\d+-h\d+(-p)?(-nd)?(-df)?(-rwa)?/, "=s640") + qualities = {320, 560, 640, 1280, 2000} + json.field "image" do + json.array do + qualities.each do |quality| + json.object do + json.field "url", url.gsub(/=s\d+/, "=s#{quality}") + json.field "width", quality + json.field "height", (quality / aspect_ratio).ceil.to_i + end + end + end + end + end + end + end + end + end when .has_key?("postMultiImageRenderer") attachment = attachment["postMultiImageRenderer"] json.field "type", "multiImage" -- cgit v1.2.3 From aecbafbc7beb5c007031c02cfba9f419c58d4545 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 14 Feb 2023 22:52:59 -0500 Subject: Community: parse replyCount --- src/invidious/channels/community.cr | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index a0e79c22..9f9f3fde 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -108,6 +108,8 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) like_count = post["actionButtons"]["commentActionButtonsRenderer"]["likeButton"]["toggleButtonRenderer"]["accessibilityData"]["accessibilityData"]["label"] .try &.as_s.gsub(/\D/, "").to_i? || 0 + reply_count = short_text_to_number(post.dig?("actionButtons", "commentActionButtonsRenderer", "replyButton", "buttonRenderer", "text", "simpleText").try &.as_s || "0") + json.field "content", html_to_content(content_html) json.field "contentHtml", content_html @@ -115,6 +117,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) json.field "likeCount", like_count + json.field "replyCount", reply_count json.field "commentId", post["postId"]? || post["commentId"]? || "" json.field "authorIsChannelOwner", post["authorEndpoint"]["browseEndpoint"]["browseId"] == ucid -- cgit v1.2.3 From 4731480821247a542ff05a8faedefcef55c009d9 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 14 Feb 2023 23:03:25 -0500 Subject: parse votes as number Co-Authored-By: syeopite <70992037+syeopite@users.noreply.github.com> --- src/invidious/channels/community.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 9f9f3fde..87659c47 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -191,7 +191,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) when .has_key?("pollRenderer") attachment = attachment["pollRenderer"] json.field "type", "poll" - json.field "totalVotes", attachment["totalVotes"]["simpleText"].as_s + json.field "totalVotes", short_text_to_number(attachment["totalVotes"]["simpleText"].as_s.split(" ")[0]) json.field "choices" do json.array do attachment["choices"].as_a.each do |choice| -- cgit v1.2.3 From d03a62641f20a8dfd15fc9fe50373a5e75ee3d6e Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Wed, 15 Feb 2023 00:20:45 -0500 Subject: Add support for custom emojis in comments --- src/invidious/comments.cr | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 357a461c..5749248e 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -182,7 +182,11 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b json.field "contentHtml", content_html json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) - + json.field "isMember", (node_comment["sponsorCommentBadge"]? != nil) + if node_comment["sponsorCommentBadge"]? + # Member icon thumbnails always have one object and there's only ever the url property in it + json.field "memberIconUrl", node_comment["sponsorCommentBadge"]["sponsorCommentBadgeRenderer"]["customBadge"]["thumbnails"][0]["url"].to_s + end json.field "published", published.to_unix json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) @@ -674,6 +678,14 @@ def content_to_comment_html(content, video_id : String? = "") text = "#{text}" if run["bold"]? text = "#{text}" if run["strikethrough"]? text = "#{text}" if run["italics"]? + if emojiImage = run.dig?("emoji", "image") + emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text + emojiThumb = emojiImage["thumbnails"][0] + emojiUrl = "/ggpht#{URI.parse(emojiThumb["url"].as_s).request_target}" + emojiWidth = emojiThumb["width"] + emojiHeight = emojiThumb["height"] + text = "\"#{emojiAlt}\"" + end text end -- cgit v1.2.3 From 76ad4e802603f82fe45d522a9c268e972d428a75 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Thu, 16 Feb 2023 14:12:56 -0500 Subject: show member icon, hide deleted emojis, fix non-custom emojis --- locales/en-US.json | 1 + src/invidious/comments.cr | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index a5c16fd7..5bbf6db6 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -405,6 +405,7 @@ "YouTube comment permalink": "YouTube comment permalink", "permalink": "permalink", "`x` marked it with a ❤": "`x` marked it with a ❤", + "Member": "Member", "Audio mode": "Audio mode", "Video mode": "Video mode", "Playlists": "Playlists", diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 5749248e..f1942ceb 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -328,11 +328,21 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) end author_name = HTML.escape(child["author"].as_s) + member_icon = "" if child["verified"]?.try &.as_bool && child["authorIsChannelOwner"]?.try &.as_bool author_name += " " elsif child["verified"]?.try &.as_bool author_name += " " end + if child["isMember"]?.try &.as_bool + member_icon = "\"\"" + end html << <<-END_HTML
@@ -343,6 +353,7 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) #{author_name} + #{member_icon}

#{child["contentHtml"]}

END_HTML @@ -678,13 +689,17 @@ def content_to_comment_html(content, video_id : String? = "") text = "#{text}" if run["bold"]? text = "#{text}" if run["strikethrough"]? text = "#{text}" if run["italics"]? - if emojiImage = run.dig?("emoji", "image") - emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text - emojiThumb = emojiImage["thumbnails"][0] - emojiUrl = "/ggpht#{URI.parse(emojiThumb["url"].as_s).request_target}" - emojiWidth = emojiThumb["width"] - emojiHeight = emojiThumb["height"] - text = "\"#{emojiAlt}\"" + if run["emoji"]? + if run["emoji"]["isCustomEmoji"]?.try &.as_bool + if emojiImage = run.dig?("emoji", "image") + emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text + emojiThumb = emojiImage["thumbnails"][0] + text = "\"#{emojiAlt}\"" + else + # Hide deleted channel emoji + text = "" + end + end end text -- cgit v1.2.3 From bc5d81fe60b324459ac428f4269316bd4cfdc3a1 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Sun, 19 Feb 2023 12:46:46 -0500 Subject: use string builder to create images change member to sponsor --- locales/en-US.json | 2 +- src/invidious/comments.cr | 36 ++++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index 5bbf6db6..bd2b9d44 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -405,7 +405,7 @@ "YouTube comment permalink": "YouTube comment permalink", "permalink": "permalink", "`x` marked it with a ❤": "`x` marked it with a ❤", - "Member": "Member", + "Channel Sponsor": "Channel Sponsor", "Audio mode": "Audio mode", "Video mode": "Video mode", "Playlists": "Playlists", diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index f1942ceb..b866b6ef 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -182,10 +182,10 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b json.field "contentHtml", content_html json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) - json.field "isMember", (node_comment["sponsorCommentBadge"]? != nil) + json.field "isSponsor", (node_comment["sponsorCommentBadge"]? != nil) if node_comment["sponsorCommentBadge"]? - # Member icon thumbnails always have one object and there's only ever the url property in it - json.field "memberIconUrl", node_comment["sponsorCommentBadge"]["sponsorCommentBadgeRenderer"]["customBadge"]["thumbnails"][0]["url"].to_s + # Sponsor icon thumbnails always have one object and there's only ever the url property in it + json.field "sponsorIconUrl", node_comment.dig("sponsorCommentBadge", "sponsorCommentBadgeRenderer", "customBadge", "thumbnails", 0, "url").to_s end json.field "published", published.to_unix json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) @@ -328,20 +328,19 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) end author_name = HTML.escape(child["author"].as_s) - member_icon = "" + sponsor_icon = "" if child["verified"]?.try &.as_bool && child["authorIsChannelOwner"]?.try &.as_bool author_name += " " elsif child["verified"]?.try &.as_bool author_name += " " end - if child["isMember"]?.try &.as_bool - member_icon = "\"\"" + if child["isSponsor"].as_bool + sponsor_icon = String.build do |str| + str << %() + end end html << <<-END_HTML
@@ -353,7 +352,7 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) #{author_name} - #{member_icon} + #{sponsor_icon}

#{child["contentHtml"]}

END_HTML @@ -689,12 +688,21 @@ def content_to_comment_html(content, video_id : String? = "") text = "#{text}" if run["bold"]? text = "#{text}" if run["strikethrough"]? text = "#{text}" if run["italics"]? + + # check for custom emojis if run["emoji"]? if run["emoji"]["isCustomEmoji"]?.try &.as_bool if emojiImage = run.dig?("emoji", "image") emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text emojiThumb = emojiImage["thumbnails"][0] - text = "\"#{emojiAlt}\"" + text = String.build do |str| + str << %() << emojiAlt << ') + end else # Hide deleted channel emoji text = "" -- cgit v1.2.3 From bde21d527f1fae4a84b964f1b297d7b246526ba0 Mon Sep 17 00:00:00 2001 From: Wes van der Vleuten <16665772+WesVleuten@users.noreply.github.com> Date: Sun, 19 Feb 2023 20:41:18 +0100 Subject: Fixed console error --- assets/js/watched_indicator.js | 24 ++++++++++++++++++++++++ assets/js/watched_widget.js | 24 ------------------------ src/invidious/views/add_playlist_items.ecr | 2 +- src/invidious/views/channel.ecr | 2 +- src/invidious/views/edit_playlist.ecr | 2 +- src/invidious/views/feeds/playlists.ecr | 2 +- src/invidious/views/feeds/popular.ecr | 2 +- src/invidious/views/feeds/subscriptions.ecr | 3 ++- src/invidious/views/feeds/trending.ecr | 2 +- src/invidious/views/hashtag.ecr | 2 +- src/invidious/views/playlist.ecr | 2 +- src/invidious/views/search.ecr | 2 +- 12 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 assets/js/watched_indicator.js (limited to 'src') diff --git a/assets/js/watched_indicator.js b/assets/js/watched_indicator.js new file mode 100644 index 00000000..e971cd80 --- /dev/null +++ b/assets/js/watched_indicator.js @@ -0,0 +1,24 @@ +'use strict'; +var save_player_pos_key = 'save_player_pos'; + +function get_all_video_times() { + return helpers.storage.get(save_player_pos_key) || {}; +} + +document.querySelectorAll('.watched-indicator').forEach(function (indicator) { + var watched_part = get_all_video_times()[indicator.dataset.id]; + var total = parseInt(indicator.dataset.length, 10); + if (watched_part === undefined) { + watched_part = total; + } + var percentage = Math.round((watched_part / total) * 100); + + if (percentage < 5) { + percentage = 5; + } + if (percentage > 90) { + percentage = 100; + } + + indicator.style.width = percentage + '%'; +}); diff --git a/assets/js/watched_widget.js b/assets/js/watched_widget.js index 02537111..f1ac9cb4 100644 --- a/assets/js/watched_widget.js +++ b/assets/js/watched_widget.js @@ -32,27 +32,3 @@ function mark_unwatched(target) { } }); } - -var save_player_pos_key = 'save_player_pos'; - -function get_all_video_times() { - return helpers.storage.get(save_player_pos_key) || {}; -} - -document.querySelectorAll('.watched-indicator').forEach(function (indicator) { - var watched_part = get_all_video_times()[indicator.dataset.id]; - var total = parseInt(indicator.dataset.length, 10); - if (watched_part === undefined) { - watched_part = total; - } - var percentage = Math.round((watched_part / total) * 100); - - if (percentage < 5) { - percentage = 5; - } - if (percentage > 90) { - percentage = 100; - } - - indicator.style.width = percentage + '%'; -}); diff --git a/src/invidious/views/add_playlist_items.ecr b/src/invidious/views/add_playlist_items.ecr index 70575de3..bcba74cf 100644 --- a/src/invidious/views/add_playlist_items.ecr +++ b/src/invidious/views/add_playlist_items.ecr @@ -39,7 +39,7 @@ <% end %>
- + <% if query %> <%- query_encoded = URI.encode_www_form(query.text, space_to_plus: true) -%> diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr index 931dd407..6e62a471 100644 --- a/src/invidious/views/channel.ecr +++ b/src/invidious/views/channel.ecr @@ -49,7 +49,7 @@ <% end %>
- +
diff --git a/src/invidious/views/edit_playlist.ecr b/src/invidious/views/edit_playlist.ecr index 100764c7..548104c8 100644 --- a/src/invidious/views/edit_playlist.ecr +++ b/src/invidious/views/edit_playlist.ecr @@ -62,7 +62,7 @@ <% end %>
- +
diff --git a/src/invidious/views/feeds/playlists.ecr b/src/invidious/views/feeds/playlists.ecr index f9064762..e52a7707 100644 --- a/src/invidious/views/feeds/playlists.ecr +++ b/src/invidious/views/feeds/playlists.ecr @@ -33,4 +33,4 @@ <% end %>
- + diff --git a/src/invidious/views/feeds/popular.ecr b/src/invidious/views/feeds/popular.ecr index 919002cd..5fbe539c 100644 --- a/src/invidious/views/feeds/popular.ecr +++ b/src/invidious/views/feeds/popular.ecr @@ -17,4 +17,4 @@ <% end %>
- + diff --git a/src/invidious/views/feeds/subscriptions.ecr b/src/invidious/views/feeds/subscriptions.ecr index d4e93240..9c69c5b0 100644 --- a/src/invidious/views/feeds/subscriptions.ecr +++ b/src/invidious/views/feeds/subscriptions.ecr @@ -54,6 +54,7 @@ }.to_pretty_json %> +
<% videos.each do |item| %> @@ -61,7 +62,7 @@ <% end %>
- +
diff --git a/src/invidious/views/feeds/trending.ecr b/src/invidious/views/feeds/trending.ecr index 76218165..7dc416c6 100644 --- a/src/invidious/views/feeds/trending.ecr +++ b/src/invidious/views/feeds/trending.ecr @@ -46,4 +46,4 @@ <% end %>
- + diff --git a/src/invidious/views/hashtag.ecr b/src/invidious/views/hashtag.ecr index 6064af74..3351c21c 100644 --- a/src/invidious/views/hashtag.ecr +++ b/src/invidious/views/hashtag.ecr @@ -24,7 +24,7 @@ <%- end -%>
- +
diff --git a/src/invidious/views/playlist.ecr b/src/invidious/views/playlist.ecr index 1df047ba..a04acf4c 100644 --- a/src/invidious/views/playlist.ecr +++ b/src/invidious/views/playlist.ecr @@ -106,7 +106,7 @@ <% end %>
- +
diff --git a/src/invidious/views/search.ecr b/src/invidious/views/search.ecr index c4960d08..a7469e36 100644 --- a/src/invidious/views/search.ecr +++ b/src/invidious/views/search.ecr @@ -37,7 +37,7 @@
<%- end -%> - +
-- cgit v1.2.3 From b5eb6016bbc455921ce3d8ec24589d706f8a5fb1 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Sun, 19 Feb 2023 14:51:39 -0500 Subject: add spaces at end of attribute --- src/invidious/comments.cr | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index b866b6ef..6c323bc1 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -336,10 +336,10 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) end if child["isSponsor"].as_bool sponsor_icon = String.build do |str| - str << %() + str << %() end end html << <<-END_HTML @@ -696,12 +696,12 @@ def content_to_comment_html(content, video_id : String? = "") emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text emojiThumb = emojiImage["thumbnails"][0] text = String.build do |str| - str << %() << emojiAlt << ') + str << %() << emojiAlt << ) end else # Hide deleted channel emoji -- cgit v1.2.3 From 7b124eec640ca601d2cafc366867e1d6cd283577 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 20 Feb 2023 16:27:16 -0500 Subject: Add History API --- src/invidious/routes/api/v1/authenticated.cr | 50 ++++++++++++++++++++++++++++ src/invidious/routing.cr | 5 +++ 2 files changed, 55 insertions(+) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 6b935312..e670a87c 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -54,6 +54,56 @@ module Invidious::Routes::API::V1::Authenticated env.response.status_code = 204 end + def self.get_history(env) + env.response.content_type = "application/json" + user = env.get("user").as(User) + + page = env.params.query["page"]?.try &.to_i? + page ||= 1 + + max_results = env.params.query["max_results"]?.try &.to_i?.try &.clamp(0, MAX_ITEMS_PER_PAGE) + max_results ||= user.preferences.max_results + max_results ||= CONFIG.default_user_preferences.max_results + + if user.watched[(page - 1) * max_results]? + watched = user.watched.reverse[(page - 1) * max_results, max_results] + end + watched ||= [] of String + + return watched.to_json + end + + def self.mark_watched(env) + user = env.get("user").as(User) + + id = env.params.url["id"]?.try &.as(String) + if !id + return error_json(400, "Invalid video id.") + end + + Invidious::Database::Users.mark_watched(user, id) + env.response.status_code = 204 + end + + def self.mark_unwatched(env) + user = env.get("user").as(User) + + id = env.params.url["id"]?.try &.as(String) + if !id + return error_json(400, "Invalid video id.") + end + + Invidious::Database::Users.mark_unwatched(user, id) + env.response.status_code = 204 + end + + def self.clear_history(env) + user = env.get("user").as(User) + + Invidious::Database::Users.clear_watch_history(user) + env.response.status_code = 204 + end + def self.feed(env) env.response.content_type = "application/json" diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index dca2f117..9e2ade3d 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -257,6 +257,11 @@ module Invidious::Routing get "/api/v1/auth/export/invidious", {{namespace}}::Authenticated, :export_invidious post "/api/v1/auth/import/invidious", {{namespace}}::Authenticated, :import_invidious + get "/api/v1/auth/history", {{namespace}}::Authenticated, :get_history + post "/api/v1/auth/history/:id", {{namespace}}::Authenticated, :mark_watched + delete "/api/v1/auth/history/:id", {{namespace}}::Authenticated, :mark_unwatched + delete "/api/v1/auth/history", {{namespace}}::Authenticated, :clear_history + get "/api/v1/auth/feed", {{namespace}}::Authenticated, :feed get "/api/v1/auth/subscriptions", {{namespace}}::Authenticated, :get_subscriptions -- cgit v1.2.3 From 15e9510ab212ac1f8b6bc2a5a3e83ebc4ba1fe90 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Mon, 20 Feb 2023 16:43:36 -0500 Subject: Check preferences before marking video as watched --- src/invidious/routes/api/v1/authenticated.cr | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index e670a87c..dc86bb3c 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -76,6 +76,10 @@ module Invidious::Routes::API::V1::Authenticated def self.mark_watched(env) user = env.get("user").as(User) + if !user.preferences.watch_history + return error_json(409, "Watch history is disabled in preferences.") + end + id = env.params.url["id"]?.try &.as(String) if !id return error_json(400, "Invalid video id.") -- cgit v1.2.3 From 6ee51f460a27618d5926e9caf230a7ada2823e70 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 21 Feb 2023 15:24:25 -0500 Subject: encode username on callback --- src/invidious/routes/account.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/account.cr b/src/invidious/routes/account.cr index d01aee56..284d5b06 100644 --- a/src/invidious/routes/account.cr +++ b/src/invidious/routes/account.cr @@ -262,7 +262,7 @@ module Invidious::Routes::Account end query["token"] = access_token - query["username"] = user.email + query["username"] = URI.encode_path_segment(user.email) url.query = query.to_s env.redirect url.to_s -- cgit v1.2.3 From 8eca5b270ed10b6233371f5495cf059bc353dcb1 Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Sat, 14 Jan 2023 01:49:58 +0100 Subject: Video: Fix 0 views, and empty license field --- locales/en-US.json | 1 + src/invidious/videos/parser.cr | 2 +- src/invidious/views/watch.ecr | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index a5c16fd7..fbcc1341 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -183,6 +183,7 @@ "Show annotations": "Show annotations", "Genre: ": "Genre: ", "License: ": "License: ", + "Standard YouTube license": "Standard YouTube license", "Family friendly? ": "Family friendly? ", "Wilson score: ": "Wilson score: ", "Engagement: ": "Engagement: ", diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index cf43f1be..04ee7303 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -186,7 +186,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any # then from videoDetails, as the latter is "0" for livestreams (we want # to get the amount of viewers watching). views_txt = video_primary_renderer - .try &.dig?("viewCount", "videoViewCountRenderer", "viewCount", "runs", 0, "text") + .try &.dig?("viewCount", "videoViewCountRenderer", "viewCount", "simpleText") views_txt ||= video_details["viewCount"]? views = views_txt.try &.as_s.gsub(/\D/, "").to_i64? diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 666eb3b0..c23a9552 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -181,7 +181,11 @@ we're going to need to do it here in order to allow for translations. <% end %>

<% if video.license %> -

<%= translate(locale, "License: ") %><%= video.license %>

+ <% if video.license == "" %> +

<%= translate(locale, "License: ") %><%= translate(locale, "Standard YouTube license") %>

+ <% else %> +

<%= translate(locale, "License: ") %><%= video.license %>

+ <% end %> <% end %>

<%= translate(locale, "Family friendly? ") %><%= translate_bool(locale, video.is_family_friendly) %>

-- cgit v1.2.3 From 4ac263f1dfdc18e5de584d4fb8bbfd74141e2716 Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Sun, 15 Jan 2023 16:26:51 +0100 Subject: Replace == with empty? --- src/invidious/views/watch.ecr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index c23a9552..1fc79495 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -181,7 +181,7 @@ we're going to need to do it here in order to allow for translations. <% end %>

<% if video.license %> - <% if video.license == "" %> + <% if video.license.empty? %>

<%= translate(locale, "License: ") %><%= translate(locale, "Standard YouTube license") %>

<% else %>

<%= translate(locale, "License: ") %><%= video.license %>

-- cgit v1.2.3 From 27bf4d02a185e6750cdecdc4f1c169b0723dbbf5 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Wed, 1 Mar 2023 22:08:19 -0500 Subject: PR nursing --- src/invidious/routes/api/v1/authenticated.cr | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index dc86bb3c..a20d23d0 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -58,15 +58,16 @@ module Invidious::Routes::API::V1::Authenticated env.response.content_type = "application/json" user = env.get("user").as(User) - page = env.params.query["page"]?.try &.to_i? + page = env.params.query["page"]?.try &.to_i?.try &.clamp(0, Int32::MAX) page ||= 1 max_results = env.params.query["max_results"]?.try &.to_i?.try &.clamp(0, MAX_ITEMS_PER_PAGE) max_results ||= user.preferences.max_results max_results ||= CONFIG.default_user_preferences.max_results - if user.watched[(page - 1) * max_results]? - watched = user.watched.reverse[(page - 1) * max_results, max_results] + start_index = (page - 1) * max_results + if user.watched[start_index]? + watched = user.watched.reverse[start_index, max_results] end watched ||= [] of String -- cgit v1.2.3 From 4a1471346237f44481b4de823e87d393739e12c1 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Wed, 1 Mar 2023 23:39:07 -0500 Subject: use dig, create private image quality constant Co-Authored-By: Samantaz Fox --- src/invidious/channels/community.cr | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 87659c47..da8be6ea 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -1,3 +1,5 @@ +private IMAGE_QUALITIES = {320, 560, 640, 1280, 2000} + # TODO: Add "sort_by" def fetch_channel_community(ucid, continuation, locale, format, thin_mode) response = YT_POOL.client &.get("/channel/#{ucid}/community?gl=US&hl=en") @@ -75,10 +77,9 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) json.field "author", author json.field "authorThumbnails" do json.array do - qualities = {32, 48, 76, 100, 176, 512} author_thumbnail = post["authorThumbnail"]["thumbnails"].as_a[0]["url"].as_s - qualities.each do |quality| + IMAGE_QUALITIES.each do |quality| json.object do json.field "url", author_thumbnail.gsub(/s\d+-/, "s#{quality}-") json.field "width", quality @@ -177,9 +178,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) aspect_ratio = (width.to_f / height.to_f) url = thumbnail["url"].as_s.gsub(/=w\d+-h\d+(-p)?(-nd)?(-df)?(-rwa)?/, "=s640") - qualities = {320, 560, 640, 1280, 2000} - - qualities.each do |quality| + IMAGE_QUALITIES.each do |quality| json.object do json.field "url", url.gsub(/=s\d+/, "=s#{quality}") json.field "width", quality @@ -196,7 +195,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) json.array do attachment["choices"].as_a.each do |choice| json.object do - json.field "text", choice["text"]["runs"][0]["text"].as_s + json.field "text", choice.dig("text", "runs", 0, "text").as_s # A choice can have an image associated with it. # Ex post: https://www.youtube.com/post/UgkxD4XavXUD4NQiddJXXdohbwOwcVqrH9Re if choice["image"]? @@ -205,10 +204,9 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) height = thumbnail["height"].as_i aspect_ratio = (width.to_f / height.to_f) url = thumbnail["url"].as_s.gsub(/=w\d+-h\d+(-p)?(-nd)?(-df)?(-rwa)?/, "=s640") - qualities = {320, 560, 640, 1280, 2000} json.field "image" do json.array do - qualities.each do |quality| + IMAGE_QUALITIES.each do |quality| json.object do json.field "url", url.gsub(/=s\d+/, "=s#{quality}") json.field "width", quality @@ -235,9 +233,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) aspect_ratio = (width.to_f / height.to_f) url = thumbnail["url"].as_s.gsub(/=w\d+-h\d+(-p)?(-nd)?(-df)?(-rwa)?/, "=s640") - qualities = {320, 560, 640, 1280, 2000} - - qualities.each do |quality| + IMAGE_QUALITIES.each do |quality| json.object do json.field "url", url.gsub(/=s\d+/, "=s#{quality}") json.field "width", quality -- cgit v1.2.3 From 60b7c8015c9ae77664d0b0680a81cfcc979d5a03 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Thu, 2 Mar 2023 07:29:44 -0500 Subject: add channel emoji css class --- assets/css/default.css | 4 ++++ src/invidious/comments.cr | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/assets/css/default.css b/assets/css/default.css index 9788e9f7..5ec79a43 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -565,3 +565,7 @@ p, /* Wider settings name to less word wrap */ .pure-form-aligned .pure-control-group label { width: 19em; } + +.channel-emoji { + margin: 0 2px; +} diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 6c323bc1..56622dec 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -701,7 +701,7 @@ def content_to_comment_html(content, video_id : String? = "") str << %(title=") << emojiAlt << "\" " str << %(width=") << emojiThumb["width"] << "\" " str << %(height=") << emojiThumb["height"] << "\" " - str << %(style="margin-right:2px;margin-left:2px;"/>) + str << %(class="channel-emoji"/>) end else # Hide deleted channel emoji -- cgit v1.2.3 From 8c0efb3ea9e409796ae860128b16d8aac860c5c6 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Thu, 2 Mar 2023 14:45:26 -0500 Subject: validate video id --- src/invidious/routes/api/v1/authenticated.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index a20d23d0..75dad6df 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -94,7 +94,7 @@ module Invidious::Routes::API::V1::Authenticated user = env.get("user").as(User) id = env.params.url["id"]?.try &.as(String) - if !id + if !id.match(/[a-zA-Z0-9_-]{11}/) return error_json(400, "Invalid video id.") end -- cgit v1.2.3 From 38f6d08be6559915262cd246b7a82988700250a5 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Thu, 2 Mar 2023 14:47:14 -0500 Subject: Validate id, avoid db call if not needed --- src/invidious/routes/api/v1/authenticated.cr | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 75dad6df..e8e7c524 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -82,7 +82,7 @@ module Invidious::Routes::API::V1::Authenticated end id = env.params.url["id"]?.try &.as(String) - if !id + if !id.match(/[a-zA-Z0-9_-]{11}/) return error_json(400, "Invalid video id.") end @@ -93,6 +93,10 @@ module Invidious::Routes::API::V1::Authenticated def self.mark_unwatched(env) user = env.get("user").as(User) + if !user.preferences.watch_history + return error_json(409, "Watch history is disabled in preferences.") + end + id = env.params.url["id"]?.try &.as(String) if !id.match(/[a-zA-Z0-9_-]{11}/) return error_json(400, "Invalid video id.") -- cgit v1.2.3 From a5cc66e060578f801371fe3f4b53bcb3d61b3ef9 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Thu, 2 Mar 2023 16:11:50 -0500 Subject: Fix id check --- src/invidious/routes/api/v1/authenticated.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index e8e7c524..a024736c 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -81,7 +81,7 @@ module Invidious::Routes::API::V1::Authenticated return error_json(409, "Watch history is disabled in preferences.") end - id = env.params.url["id"]?.try &.as(String) + id = env.params.url["id"] if !id.match(/[a-zA-Z0-9_-]{11}/) return error_json(400, "Invalid video id.") end @@ -97,7 +97,7 @@ module Invidious::Routes::API::V1::Authenticated return error_json(409, "Watch history is disabled in preferences.") end - id = env.params.url["id"]?.try &.as(String) + id = env.params.url["id"] if !id.match(/[a-zA-Z0-9_-]{11}/) return error_json(400, "Invalid video id.") end -- cgit v1.2.3 From d8e23d34b63b8f4f34da5c6b4bddf6eb46a3a828 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:38:09 -0500 Subject: add song title for music tracks --- locales/en-US.json | 1 + src/invidious/jsonify/api_v1/video_json.cr | 15 +++++++++++++++ src/invidious/videos.cr | 2 +- src/invidious/videos/music.cr | 3 ++- src/invidious/videos/parser.cr | 5 ++++- src/invidious/views/watch.ecr | 7 ++++--- 6 files changed, 27 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index 86b83a23..65a81ab7 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -190,6 +190,7 @@ "Blacklisted regions: ": "Blacklisted regions: ", "Music in this video": "Music in this video", "Artist: ": "Artist: ", + "Song: ": "Song: ", "Album: ": "Album: ", "Shared `x`": "Shared `x`", "Premieres in `x`": "Premieres in `x`", diff --git a/src/invidious/jsonify/api_v1/video_json.cr b/src/invidious/jsonify/api_v1/video_json.cr index a2b1a35c..fe4b5223 100644 --- a/src/invidious/jsonify/api_v1/video_json.cr +++ b/src/invidious/jsonify/api_v1/video_json.cr @@ -197,6 +197,21 @@ module Invidious::JSONify::APIv1 end end + if !video.music.empty? + json.field "musicTracks" do + json.array do + video.music.each do |music| + json.object do + json.field "song", music.song + json.field "artist", music.artist + json.field "album", music.album + json.field "license", music.license + end + end + end + end + end + json.field "recommendedVideos" do json.array do video.related_videos.each do |rv| diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index 436ac82d..86f5ada4 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -249,7 +249,7 @@ struct Video def music : Array(VideoMusic) info["music"].as_a.map { |music_json| - VideoMusic.new(music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) + VideoMusic.new(music_json["song"].as_s, music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) } end diff --git a/src/invidious/videos/music.cr b/src/invidious/videos/music.cr index 402ae46f..08d88a3e 100644 --- a/src/invidious/videos/music.cr +++ b/src/invidious/videos/music.cr @@ -3,10 +3,11 @@ require "json" struct VideoMusic include JSON::Serializable + property song : String property album : String property artist : String property license : String - def initialize(@album : String, @artist : String, @license : String) + def initialize(@song : String, @album : String, @artist : String, @license : String) end end diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index cf43f1be..1a8c25e4 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -322,6 +322,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any music_desclist.try &.as_a.each do |music_desc| artist = nil + song = nil album = nil music_license = nil @@ -329,13 +330,15 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) if desc_title == "ARTIST" artist = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) + elsif desc_title == "SONG" + song = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) elsif desc_title == "ALBUM" album = extract_text(desc.dig?("infoRowRenderer", "defaultMetadata")) elsif desc_title == "LICENSES" music_license = extract_text(desc.dig?("infoRowRenderer", "expandedMetadata")) end end - music_list << VideoMusic.new(album.to_s, artist.to_s, music_license.to_s) + music_list << VideoMusic.new(song.to_s, album.to_s, artist.to_s, music_license.to_s) end # Author infos diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 666eb3b0..01b30f7a 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -248,9 +248,10 @@ we're going to need to do it here in order to allow for translations.
<% video.music.each do |music| %>
-

<%= translate(locale, "Artist: ") %><%= music.artist %>

-

<%= translate(locale, "Album: ") %><%= music.album %>

-

<%= translate(locale, "License: ") %><%= music.license %>

+

<%= translate(locale, "Song: ") %><%= music.song %>

+

<%= translate(locale, "Artist: ") %><%= music.artist %>

+

<%= translate(locale, "Album: ") %><%= music.album %>

+

<%= translate(locale, "License: ") %><%= music.license %>

<% end %>
-- cgit v1.2.3 From 742c951bc9fdc6eb1e5687104e67500fb778e0ea Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Mar 2023 13:06:15 -0500 Subject: support videos with multiple songs --- src/invidious/videos/parser.cr | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 1a8c25e4..722c90e8 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -322,10 +322,17 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any music_desclist.try &.as_a.each do |music_desc| artist = nil - song = nil album = nil music_license = nil + # used when multiple songs + song = music_desc.dig?("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title", "simpleText") + + # used when multiple songs and the song has a link + if !song + song = music_desc.dig("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title", "runs", 0, "text") + end + music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.each do |desc| desc_title = extract_text(desc.dig?("infoRowRenderer", "title")) if desc_title == "ARTIST" -- cgit v1.2.3 From 0b17f68ebacdb54e74116cf3364c8229e896eff0 Mon Sep 17 00:00:00 2001 From: Brahim Hadriche Date: Tue, 7 Mar 2023 13:50:02 -0500 Subject: Fix input validation --- src/invidious/routes/api/v1/authenticated.cr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index a024736c..ce2ee812 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -82,7 +82,7 @@ module Invidious::Routes::API::V1::Authenticated end id = env.params.url["id"] - if !id.match(/[a-zA-Z0-9_-]{11}/) + if !id.match(/^[a-zA-Z0-9_-]{11}$/) return error_json(400, "Invalid video id.") end @@ -98,7 +98,7 @@ module Invidious::Routes::API::V1::Authenticated end id = env.params.url["id"] - if !id.match(/[a-zA-Z0-9_-]{11}/) + if !id.match(/^[a-zA-Z0-9_-]{11}$/) return error_json(400, "Invalid video id.") end -- cgit v1.2.3 From e3081ef1a93973fe10ba8508ad31d257d641350e Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Mar 2023 14:23:08 -0500 Subject: Apply style change suggestions Co-authored-by: Samantaz Fox --- src/invidious/videos.cr | 7 ++++++- src/invidious/videos/parser.cr | 10 ++++------ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index 86f5ada4..0038a97a 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -249,7 +249,12 @@ struct Video def music : Array(VideoMusic) info["music"].as_a.map { |music_json| - VideoMusic.new(music_json["song"].as_s, music_json["album"].as_s, music_json["artist"].as_s, music_json["license"].as_s) + VideoMusic.new( + music_json["song"].as_s, + music_json["album"].as_s, + music_json["artist"].as_s, + music_json["license"].as_s + ) } end diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 722c90e8..7cfc7ea7 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -325,12 +325,10 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any album = nil music_license = nil - # used when multiple songs - song = music_desc.dig?("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title", "simpleText") - - # used when multiple songs and the song has a link - if !song - song = music_desc.dig("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title", "runs", 0, "text") + # Used when the video has multiple songs + if song_title = music_desc.dig?("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title") + # "simpleText" for plain text / "runs" when song has a link + song = song_title["simpleText"]? || song_title.dig("runs", 0, "text") end music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.each do |desc| -- cgit v1.2.3 From a781cf37347e97c469eb098e95c9a80482aac1b9 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:59:51 -0500 Subject: readd try as bool for isSponsor key --- src/invidious/comments.cr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr index 56622dec..b15d63d4 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -334,7 +334,8 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false) elsif child["verified"]?.try &.as_bool author_name += " " end - if child["isSponsor"].as_bool + + if child["isSponsor"]?.try &.as_bool sponsor_icon = String.build do |str| str << %( Date: Sun, 12 Mar 2023 18:36:03 -0400 Subject: Update src/invidious/routes/video_playback.cr Co-authored-by: Samantaz Fox --- src/invidious/routes/video_playback.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr index f24c0ded..9641e01a 100644 --- a/src/invidious/routes/video_playback.cr +++ b/src/invidious/routes/video_playback.cr @@ -278,7 +278,7 @@ module Invidious::Routes::VideoPlayback end if itag.nil? - fmt = video.fmt_stream[-1] + fmt = video.fmt_stream[-1]? else fmt = video.fmt_stream.find(nil) { |f| f["itag"].as_i == itag } || video.adaptive_fmts.find(nil) { |f| f["itag"].as_i == itag } end -- cgit v1.2.3 From ffcc837c2adcb4faac104c08c32060a475730e2b Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Sun, 12 Mar 2023 18:50:01 -0400 Subject: remove music license --- src/invidious/views/watch.ecr | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 01b30f7a..ce92a546 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -251,7 +251,6 @@ we're going to need to do it here in order to allow for translations.

<%= translate(locale, "Song: ") %><%= music.song %>

<%= translate(locale, "Artist: ") %><%= music.artist %>

<%= translate(locale, "Album: ") %><%= music.album %>

-

<%= translate(locale, "License: ") %><%= music.license %>

<% end %>
-- cgit v1.2.3 From b66a5c40a97de2816f43b7b6c816f20252eb4cbc Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Wed, 15 Mar 2023 22:37:07 +0100 Subject: Community: Restore thumbnail qualities array --- src/invidious/channels/community.cr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index da8be6ea..ce34ff82 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -77,9 +77,10 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode) json.field "author", author json.field "authorThumbnails" do json.array do + qualities = {32, 48, 76, 100, 176, 512} author_thumbnail = post["authorThumbnail"]["thumbnails"].as_a[0]["url"].as_s - IMAGE_QUALITIES.each do |quality| + qualities.each do |quality| json.object do json.field "url", author_thumbnail.gsub(/s\d+-/, "s#{quality}-") json.field "width", quality -- cgit v1.2.3 From 4ae158ef6dcb89c2cd0eec646a42f11ebc207fba Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 19 Mar 2023 22:44:59 +0100 Subject: Videos: Add back support for views on livestreams --- src/invidious/videos/parser.cr | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 04ee7303..efc4b2e5 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -185,10 +185,12 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any # We have to try to extract viewCount from videoPrimaryInfoRenderer first, # then from videoDetails, as the latter is "0" for livestreams (we want # to get the amount of viewers watching). - views_txt = video_primary_renderer - .try &.dig?("viewCount", "videoViewCountRenderer", "viewCount", "simpleText") - views_txt ||= video_details["viewCount"]? - views = views_txt.try &.as_s.gsub(/\D/, "").to_i64? + views_txt = extract_text( + video_primary_renderer + .try &.dig?("viewCount", "videoViewCountRenderer", "viewCount") + ) + views_txt ||= video_details["viewCount"]?.try &.as_s || "" + views = views_txt.gsub(/\D/, "").to_i64? length_txt = (microformat["lengthSeconds"]? || video_details["lengthSeconds"]) .try &.as_s.to_i64 -- cgit v1.2.3 From 3492485789ae3758f551916b406ed75b3c028021 Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Tue, 21 Mar 2023 21:24:37 -0400 Subject: Fix channel search --- src/invidious/yt_backend/extractors.cr | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index b14ad7b9..090944fc 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -18,6 +18,7 @@ private ITEM_PARSERS = { Parsers::CategoryRendererParser, Parsers::RichItemRendererParser, Parsers::ReelItemRendererParser, + Parsers::ItemSectionRendererParser, Parsers::ContinuationItemRendererParser, } @@ -377,6 +378,30 @@ private module Parsers end end + # Parses an InnerTube itemSectionRenderer into a SearchVideo. + # Returns nil when the given object isn't a ItemSectionRenderer + # + # A itemSectionRenderer seems to be a simple wrapper for a videoRenderer, used + # by the result page for channel searches. It is located inside a continuationItems + # container.It is very similar to RichItemRendererParser + # + module ItemSectionRendererParser + def self.process(item : JSON::Any, author_fallback : AuthorFallback) + if item_contents = item.dig?("itemSectionRenderer", "contents", 0) + return self.parse(item_contents, author_fallback) + end + end + + private def self.parse(item_contents, author_fallback) + child = VideoRendererParser.process(item_contents, author_fallback) + return child + end + + def self.parser_name + return {{@type.name}} + end + end + # Parses an InnerTube richItemRenderer into a SearchVideo. # Returns nil when the given object isn't a RichItemRenderer # -- cgit v1.2.3 From f840addd930945141a6d4fdf7e7eb8376411d82d Mon Sep 17 00:00:00 2001 From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com> Date: Mon, 27 Mar 2023 22:10:28 -0400 Subject: Fix error when song title is missing from the track --- src/invidious/videos/parser.cr | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 608ae99d..13ee5f65 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -330,7 +330,10 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any # Used when the video has multiple songs if song_title = music_desc.dig?("carouselLockupRenderer", "videoLockup", "compactVideoRenderer", "title") # "simpleText" for plain text / "runs" when song has a link - song = song_title["simpleText"]? || song_title.dig("runs", 0, "text") + song = song_title["simpleText"]? || song_title.dig?("runs", 0, "text") + + # some videos can have empty tracks. See: https://www.youtube.com/watch?v=eBGIQ7ZuuiU + next if !song end music_desc.dig?("carouselLockupRenderer", "infoRows").try &.as_a.each do |desc| -- cgit v1.2.3 From 0fe1b1ec19d8bf108765842dc84252fc3b394a9b Mon Sep 17 00:00:00 2001 From: Jarek Baran Date: Thu, 30 Mar 2023 12:52:03 +0200 Subject: download_widget: Add missing translation key --- locales/en-US.json | 1 + locales/pl.json | 1 + src/invidious/frontend/watch_page.cr | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/locales/en-US.json b/locales/en-US.json index a3c195ff..05811f27 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -402,6 +402,7 @@ "Movies": "Movies", "Download": "Download", "Download as: ": "Download as: ", + "Download is disabled": "Download is disabled", "%A %B %-d, %Y": "%A %B %-d, %Y", "(edited)": "(edited)", "YouTube comment permalink": "YouTube comment permalink", diff --git a/locales/pl.json b/locales/pl.json index 3ca78e43..3c713e70 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -317,6 +317,7 @@ "Movies": "Filmy", "Download": "Pobierz", "Download as: ": "Pobierz jako: ", + "Download is disabled": "Pobieranie jest wyłączone", "%A %B %-d, %Y": "%A, %-d %B %Y", "(edited)": "(edytowany)", "YouTube comment permalink": "Odnośnik bezpośredni do komentarza na YouTube", diff --git a/src/invidious/frontend/watch_page.cr b/src/invidious/frontend/watch_page.cr index a9b00860..e3214469 100644 --- a/src/invidious/frontend/watch_page.cr +++ b/src/invidious/frontend/watch_page.cr @@ -20,7 +20,7 @@ module Invidious::Frontend::WatchPage def download_widget(locale : String, video : Video, video_assets : VideoAssets) : String if CONFIG.disabled?("downloads") - return "

#{translate(locale, "Download is disabled.")}

" + return "

#{translate(locale, "Download is disabled")}

" end return String.build(4000) do |str| -- cgit v1.2.3 From e0600f455393ffcf0edd2f0c4b644fac7dba209f Mon Sep 17 00:00:00 2001 From: Emilien Devos Date: Fri, 31 Mar 2023 22:08:09 +0200 Subject: quick fix for channel videos page --- src/invidious/channels/videos.cr | 4 +++- src/invidious/yt_backend/extractors.cr | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/invidious/channels/videos.cr b/src/invidious/channels/videos.cr index befec03d..3d53f2ab 100644 --- a/src/invidious/channels/videos.cr +++ b/src/invidious/channels/videos.cr @@ -30,7 +30,9 @@ def produce_channel_videos_continuation(ucid, page = 1, auto_generated = nil, so "15:embedded" => { "1:embedded" => { "1:string" => object_inner_2_encoded, - "2:string" => "00000000-0000-0000-0000-000000000000", + }, + "2:embedded" => { + "1:string" => "00000000-0000-0000-0000-000000000000", }, "3:varint" => sort_by_numerical, }, diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index b14ad7b9..978e380d 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -773,6 +773,7 @@ end def extract_items(initial_data : InitialData, &block) if unpackaged_data = initial_data["contents"]?.try &.as_h elsif unpackaged_data = initial_data["response"]?.try &.as_h + elsif unpackaged_data = initial_data.dig?("onResponseReceivedActions", 1).try &.as_h elsif unpackaged_data = initial_data.dig?("onResponseReceivedActions", 0).try &.as_h else unpackaged_data = initial_data -- cgit v1.2.3