Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local API: Extract playlists on the auto-generated "Music" channel #5250

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/renderer/helpers/api/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,24 @@ export function parseLocalListPlaylist(playlist, channelId = undefined, channelN
}
}

/**
* @param {import('youtubei.js').YTNodes.CompactStation} compactStation
* @param {string} channelId
* @param {string} channelName
*/
export function parseLocalCompactStation(compactStation, channelId, channelName) {
return {
type: 'playlist',
dataSource: 'local',
title: compactStation.title.text,
thumbnail: compactStation.thumbnail[1].url,
channelName,
channelId,
playlistId: compactStation.endpoint.payload.playlistId,
videoCount: extractNumberFromString(compactStation.video_count.text)
}
}

/**
* @param {YT.Search} response
*/
Expand Down
23 changes: 20 additions & 3 deletions src/renderer/views/Channel/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
parseLocalChannelShorts,
parseLocalChannelVideos,
parseLocalCommunityPosts,
parseLocalCompactStation,
parseLocalListPlaylist,
parseLocalListVideo,
parseLocalSubscriberCount
Expand Down Expand Up @@ -666,9 +667,25 @@ export default defineComponent({
this.getChannelReleasesLocal()
}

if (!this.hideChannelPlaylists && channel.has_playlists) {
tabs.push('playlists')
this.getChannelPlaylistsLocal()
if (!this.hideChannelPlaylists) {
if (channel.has_playlists) {
tabs.push('playlists')
this.getChannelPlaylistsLocal()
} else if (channelId === 'UC-9-kyTW8ZkZNDHQJ6FgpwQ') {
// Special handling for "The Music Channel" (https://youtube.com/music)
tabs.push('playlists')
const playlists = channel.playlists.map(playlist => parseLocalListPlaylist(playlist))

const compactStations = channel.memo.get('CompactStation')
if (compactStations) {
for (const compactStation of compactStations) {
playlists.push(parseLocalCompactStation(compactStation, channelId, channelName))
}
}

this.showPlaylistSortBy = false
this.latestPlaylists = playlists
}
}

if (!this.hideChannelCommunity && channel.has_community) {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/views/Playlist/Playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ export default defineComponent({
this.playlistDescription = result.info.description ?? ''
this.firstVideoId = result.items[0].id
this.playlistThumbnail = result.info.thumbnails[0].url
this.viewCount = extractNumberFromString(result.info.views)
this.viewCount = result.info.views.toLowerCase() === 'no views' ? 0 : extractNumberFromString(result.info.views)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): We have a few places in the code where we use extractNumberFromString and it ends up getting used as NaN. I get from an "API" level why NaN is an appropriate return value, but it is this behavior that ultimately results in us displaying NaN throughout the app. I'd recommend returning 0 instead of NaN from that function in both the not-string case and NaN parseInt case just to cover the swathe of edge cases more easily.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you are correct that in many places we don't handle NaN and just display it to the user, in other places we actually rely on it, so we know when to hide UI elements for example.

So we either need to create a separate wrapper function the converts the NaN to zero in the places where that is desired or add an extra parameter to control when the fallback should be zero.

this.videoCount = extractNumberFromString(result.info.total_items)
this.lastUpdated = result.info.last_updated ?? ''
this.channelName = channelName ?? ''
Expand Down