diff --git a/scraper/src/youtube2zim/playlists/scraper.py b/scraper/src/youtube2zim/playlists/scraper.py index 0f5a1dda..c3301bd6 100644 --- a/scraper/src/youtube2zim/playlists/scraper.py +++ b/scraper/src/youtube2zim/playlists/scraper.py @@ -91,7 +91,6 @@ def run(self): ( playlists, main_channel_id, - uploads_playlist_id, user_long_uploads_playlist_id, user_short_uploads_playlist_id, user_lives_playlist_id, @@ -109,10 +108,6 @@ def run(self): shutil.rmtree(self.build_dir, ignore_errors=True) for playlist in playlists: - if playlist.playlist_id == uploads_playlist_id: - logger.info(f"Skipping playlist {playlist.playlist_id} (uploads one)") - continue - logger.info(f"Executing youtube2zim for playlist {playlist.playlist_id}") success, process = self.run_playlist_zim(playlist) if success: diff --git a/scraper/src/youtube2zim/schemas.py b/scraper/src/youtube2zim/schemas.py index 89696659..edba89c0 100644 --- a/scraper/src/youtube2zim/schemas.py +++ b/scraper/src/youtube2zim/schemas.py @@ -105,7 +105,7 @@ class Channel(CamelModel): profile_path: str | None = None banner_path: str | None = None joined_date: str - main_playlist: str | None = None + first_playlist: str | None = None user_long_uploads_playlist: str | None = None user_short_uploads_playlist: str | None = None user_lives_playlist: str | None = None diff --git a/scraper/src/youtube2zim/scraper.py b/scraper/src/youtube2zim/scraper.py index 7307772b..3a036971 100644 --- a/scraper/src/youtube2zim/scraper.py +++ b/scraper/src/youtube2zim/scraper.py @@ -170,7 +170,6 @@ def __init__( # process-related self.playlists = [] - self.uploads_playlist_id = None self.user_long_uploads_playlist_id = None self.user_short_uploads_playlist_id = None self.user_lives_playlist_id = None @@ -232,30 +231,6 @@ def banner_path(self): def is_single_channel(self): return len({pl.creator_id for pl in self.playlists}) == 1 - @property - def sorted_playlists(self): - """sorted list of playlists (by title) but with Uploads one at first if any""" - if len(self.playlists) <= 1: - return self.playlists - - sorted_playlists = sorted(self.playlists, key=lambda x: x.title) - index = 0 - # make sure our Uploads, special playlist is first - if self.uploads_playlist_id: - try: - index = [ - index - for index, p in enumerate(sorted_playlists) - if p.playlist_id == self.uploads_playlist_id - ][-1] - except Exception: - index = 0 - return ( - [sorted_playlists[index]] - + sorted_playlists[0:index] - + sorted_playlists[index + 1 :] - ) - def run(self): """execute the scraper step by step""" @@ -555,7 +530,6 @@ def extract_playlists(self): ( self.playlists, self.main_channel_id, - self.uploads_playlist_id, self.user_long_uploads_playlist_id, self.user_short_uploads_playlist_id, self.user_lives_playlist_id, @@ -1158,10 +1132,9 @@ def get_playlist_slug(playlist) -> str: ) # write playlists JSON files - playlist_list = [] - home_playlist_list = [] + playlist_list: list[PlaylistPreview] = [] + home_playlist_list: list[Playlist] = [] - main_playlist_slug = None user_long_uploads_playlist_slug = None user_short_uploads_playlist_slug = None user_lives_playlist_slug = None @@ -1178,18 +1151,6 @@ def get_playlist_slug(playlist) -> str: if len(self.playlists) == 0: raise Exception("No playlist succeeded to download") - main_playlist_slug = get_playlist_slug( - self.playlists[0] - ) # set first playlist as main playlist - - # Initialize placeholders for special playlists - special_playlists: dict[str, dict[str, PlaylistPreview | Playlist]] = { - "user_long_uploads_playlist": {}, - "user_short_uploads_playlist": {}, - "user_lives_playlist": {}, - } - main_playlist = None - for playlist in self.playlists: playlist_slug = get_playlist_slug(playlist) playlist_path = f"playlists/{playlist_slug}.json" @@ -1214,59 +1175,15 @@ def get_playlist_slug(playlist) -> str: # modify playlist object for preview on homepage playlist_obj.videos = playlist_obj.videos[:12] + home_playlist_list.append(playlist_obj) if playlist.playlist_id == self.user_long_uploads_playlist_id: user_long_uploads_playlist_slug = playlist_slug - special_playlists["user_long_uploads_playlist"] = { - "preview": generate_playlist_preview_object(playlist), - "full": playlist_obj, - } - elif playlist.playlist_id == self.user_short_uploads_playlist_id: user_short_uploads_playlist_slug = playlist_slug - special_playlists["user_short_uploads_playlist"] = { - "preview": generate_playlist_preview_object(playlist), - "full": playlist_obj, - } - elif playlist.playlist_id == self.user_lives_playlist_id: user_lives_playlist_slug = playlist_slug - special_playlists["user_lives_playlist"] = { - "preview": generate_playlist_preview_object(playlist), - "full": playlist_obj, - } - - elif playlist.playlist_id == self.uploads_playlist_id: - main_playlist = playlist - main_playlist_slug = ( - playlist_slug # set uploads playlist as main playlist - ) - # insert uploads playlist at the beginning of the list - home_playlist_list.insert(0, playlist_obj) else: playlist_list.append(generate_playlist_preview_object(playlist)) - home_playlist_list.append(playlist_obj) - - # Check if only one special playlist exists - special_playlist_count = sum( - 1 for k in special_playlists if special_playlists[k] - ) - - if special_playlist_count == 1: - if main_playlist is not None: - self.playlists.remove(main_playlist) - for key in special_playlists: - if special_playlists[key]: - main_playlist_slug = special_playlists[key]["preview"].slug - home_playlist_list[0] = special_playlists[key]["full"] - else: - # Insert special playlists in the desired order - for key in [ - "user_lives_playlist", - "user_short_uploads_playlist", - "user_long_uploads_playlist", - ]: - if special_playlists[key]: - home_playlist_list.insert(1, special_playlists[key]["full"]) # write playlists.json file self.zim_file.add_item_for( @@ -1303,7 +1220,7 @@ def get_playlist_slug(playlist) -> str: channel_description=channel_data["snippet"]["description"], profile_path="profile.jpg", banner_path="banner.jpg", - main_playlist=main_playlist_slug, + first_playlist=playlist_list[0].id, user_long_uploads_playlist=user_long_uploads_playlist_slug, user_short_uploads_playlist=user_short_uploads_playlist_slug, user_lives_playlist=user_lives_playlist_slug, diff --git a/scraper/src/youtube2zim/youtube.py b/scraper/src/youtube2zim/youtube.py index 33294143..9f7ede30 100644 --- a/scraper/src/youtube2zim/youtube.py +++ b/scraper/src/youtube2zim/youtube.py @@ -343,8 +343,9 @@ def skip_outofrange_videos(date_range, item): def extract_playlists_details_from(youtube_id: str): """prepare a list of Playlist from user request""" - uploads_playlist_id = None - main_channel_id = None + main_channel_id = user_long_uploads_playlist_id = user_short_uploads_playlist_id = ( + user_lives_playlist_id + ) = None if "," not in youtube_id: try: # first try to consider passed ID is a channel ID (or username or handle) @@ -369,21 +370,21 @@ def extract_playlists_details_from(youtube_id: str): ) user_lives_playlist_id = user_lives_json["id"] if user_lives_json else None - # Add special playlists if they exists - playlist_ids += filter( - None, - [ - user_long_uploads_playlist_id, - user_short_uploads_playlist_id, - user_lives_playlist_id, - ], + # Add special playlists if they exists, in proper order + playlist_ids = ( + list( + filter( + None, + [ + user_long_uploads_playlist_id, + user_short_uploads_playlist_id, + user_lives_playlist_id, + ], + ) + ) + + playlist_ids ) - # we always include uploads playlist (contains everything) - playlist_ids += [ - channel_json["contentDetails"]["relatedPlaylists"]["uploads"] - ] - uploads_playlist_id = playlist_ids[-1] is_playlist = False except ChannelNotFoundError: # channel not found, then ID should be a playlist @@ -402,7 +403,6 @@ def extract_playlists_details_from(youtube_id: str): # dict.fromkeys maintains the order of playlist_ids while removing duplicates [Playlist.from_id(playlist_id) for playlist_id in dict.fromkeys(playlist_ids)], main_channel_id, - uploads_playlist_id, user_long_uploads_playlist_id, user_short_uploads_playlist_id, user_lives_playlist_id, diff --git a/scraper/tests-integration/integration.py b/scraper/tests-integration/integration.py index 8241a565..d48be851 100644 --- a/scraper/tests-integration/integration.py +++ b/scraper/tests-integration/integration.py @@ -47,7 +47,7 @@ def test_zim_channel_json(): assert channel_json["id"] == "UC8elThf5TGMpQfQc_VE917Q" assert channel_json["channelName"] == "openZIM_testing" - assert channel_json["mainPlaylist"] == "uploads_from_openzim_testing-917Q" + assert channel_json["firstPlaylist"] == "uploads_from_openzim_testing-917Q" def test_zim_videos(): diff --git a/zimui/cypress/fixtures/channel/channel.json b/zimui/cypress/fixtures/channel/channel.json index 19696e8b..eba49a46 100644 --- a/zimui/cypress/fixtures/channel/channel.json +++ b/zimui/cypress/fixtures/channel/channel.json @@ -7,5 +7,5 @@ "profilePath": "profile.jpg", "bannerPath": "banner.jpg", "joinedDate": "2024-06-04T13:30:16.232286Z", - "mainPlaylist": "uploads_from_openzim_testing-917Q" + "firstPlaylist": "uploads_from_openzim_testing-917Q" } diff --git a/zimui/src/components/channel/tabs/ChannelHomeGridTab.vue b/zimui/src/components/channel/tabs/ChannelHomeGridTab.vue index 87421603..11e4ca55 100644 --- a/zimui/src/components/channel/tabs/ChannelHomeGridTab.vue +++ b/zimui/src/components/channel/tabs/ChannelHomeGridTab.vue @@ -15,7 +15,7 @@ const isLoading = ref(true) // Watch for changes in the main playlist watch( - () => main.channel?.mainPlaylist, + () => main.channel?.firstPlaylist, () => { fetchData() } @@ -23,9 +23,9 @@ watch( // Fetch the videos for the main playlist const fetchData = async function () { - if (main.channel?.mainPlaylist) { + if (main.channel?.firstPlaylist) { try { - const resp = await main.fetchPlaylist(main.channel?.mainPlaylist) + const resp = await main.fetchPlaylist(main.channel?.firstPlaylist) if (resp) { playlist.value = resp videos.value = resp.videos @@ -54,6 +54,6 @@ onMounted(() => { :count-text="playlist?.videos.length === 1 ? 'video' : 'videos'" icon="mdi-video-outline" /> - + diff --git a/zimui/src/components/channel/tabs/ChannelHomeListTab.vue b/zimui/src/components/channel/tabs/ChannelHomeListTab.vue index b6078cf0..423cd580 100644 --- a/zimui/src/components/channel/tabs/ChannelHomeListTab.vue +++ b/zimui/src/components/channel/tabs/ChannelHomeListTab.vue @@ -12,7 +12,7 @@ const isLoading = ref(true) // Watch for changes in the main playlist watch( - () => main.channel?.mainPlaylist, + () => main.channel?.id, () => { fetchData() } @@ -20,7 +20,7 @@ watch( // Fetch the videos for the main playlist const fetchData = async function () { - if (main.channel?.mainPlaylist) { + if (main.channel?.id) { try { const resp = await main.fetchHomePlaylists() if (resp) { diff --git a/zimui/src/components/channel/tabs/GenericTab.vue b/zimui/src/components/channel/tabs/GenericTab.vue index 4317d476..26ba5c14 100755 --- a/zimui/src/components/channel/tabs/GenericTab.vue +++ b/zimui/src/components/channel/tabs/GenericTab.vue @@ -67,10 +67,6 @@ onMounted(() => { :count-text="playlist?.videos.length === 1 ? 'video' : 'videos'" icon="mdi-video-outline" /> - + diff --git a/zimui/src/components/channel/tabs/PlaylistsTab.vue b/zimui/src/components/channel/tabs/PlaylistsTab.vue index a06c7039..a97a602a 100644 --- a/zimui/src/components/channel/tabs/PlaylistsTab.vue +++ b/zimui/src/components/channel/tabs/PlaylistsTab.vue @@ -13,7 +13,7 @@ const isLoading = ref(true) // Watch for changes in the main playlist watch( - () => main.channel?.mainPlaylist, + () => main.channel?.id, () => { fetchData() } @@ -21,7 +21,7 @@ watch( // Fetch the playlists for the playlist tab const fetchData = async function () { - if (main.channel?.mainPlaylist) { + if (main.channel?.id) { try { const resp = await main.fetchPlaylists() if (resp) { diff --git a/zimui/src/types/Channel.ts b/zimui/src/types/Channel.ts index 967d9e3d..f243a077 100644 --- a/zimui/src/types/Channel.ts +++ b/zimui/src/types/Channel.ts @@ -7,10 +7,10 @@ export interface Channel { profilePath?: string bannerPath?: string joinedDate: string - mainPlaylist?: string - userLongUploadsPlaylist?:string - userShortUploadsPlaylist?:string - userLivesPlaylist?:string + firstPlaylist?: string + userLongUploadsPlaylist?: string + userShortUploadsPlaylist?: string + userLivesPlaylist?: string playlistCount: number }