diff --git a/assets/css/default.css b/assets/css/default.css index 80bf6a20..9788e9f7 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -490,8 +490,9 @@ hr { } /* Description Expansion Styling*/ -#descexpansionbutton { - display: none +#descexpansionbutton, +#music-desc-expansion { + display: none; } #descexpansionbutton ~ div { @@ -509,7 +510,8 @@ hr { margin-top: 20px; } -label[for="descexpansionbutton"]:hover { +label[for="descexpansionbutton"]:hover, +label[for="music-desc-expansion"]:hover { cursor: pointer; } @@ -521,14 +523,38 @@ h4, h5, p, #descriptionWrapper, -#description-box { - unicode-bidi: plaintext; - text-align: start; +#description-box, +#music-description-box { + unicode-bidi: plaintext; + text-align: start; } #descriptionWrapper { - max-width: 600px; - white-space: pre-wrap; + max-width: 600px; + white-space: pre-wrap; +} + +#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; +} + +/* 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 12955665..a5c16fd7 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 in this video": "Music in this video", + "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 d626c7d1..436ac82d 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -247,6 +247,12 @@ struct Video info["reason"]?.try &.as_s end + 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) + } + end + # Macros defining getters/setters for various types of data private macro getset_string(name) 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 5c323975..cf43f1be 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -311,6 +311,33 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any end end + # Music section + + music_list = [] of VideoMusic + 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.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_list << VideoMusic.new(album.to_s, artist.to_s, music_license.to_s) + end + # Author infos author = video_details["author"]?.try &.as_s @@ -361,6 +388,8 @@ 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" => 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 a6f2e524..666eb3b0 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -235,6 +235,28 @@ we're going to need to do it here in order to allow for translations.
+ <% if !video.music.empty? %> + + + +
+ <% video.music.each do |music| %> +
+

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

+

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

+

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

+
+ <% end %> +
+
+ + <% end %>
<% if nojs %> <%= comment_html %>