11# 16.03.25
22
33import os
4+ import time
45from urllib .parse import urlparse , parse_qs
56from typing import Tuple
67
@@ -59,18 +60,17 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
5960 mp4_name = f"{ map_episode_title (scrape_serie .series_name , index_season_selected , index_episode_selected , obj_episode .get ('name' ))} .{ extension_output } "
6061 mp4_path = os_manager .get_sanitize_path (os .path .join (site_constants .SERIES_FOLDER , scrape_serie .series_name , f"S{ index_season_selected } " ))
6162
62- # Get playback session
63+ # Get media ID and main_guid for complete subtitles
6364 url_id = obj_episode .get ('url' ).split ('/' )[- 1 ]
64- playback_result = get_playback_session ( client , url_id )
65+ main_guid = obj_episode . get ( 'main_guid' )
6566
66- # Check if access was denied (403)
67- if playback_result is None :
68- console .print ("[red]✗ Access denied: This episode requires a premium subscription" )
69- return None , False
67+ # Get playback session
68+ mpd_url , mpd_headers , mpd_list_sub , token , audio_locale = get_playback_session (client , url_id , main_guid )
7069
71- mpd_url , mpd_headers , mpd_list_sub , token , _ = playback_result
70+ # Parse playback token from URL
7271 parsed_url = urlparse (mpd_url )
7372 query_params = parse_qs (parsed_url .query )
73+ playback_guid = query_params .get ('playbackGuid' , [token ])[0 ] if query_params .get ('playbackGuid' ) else token
7474
7575 # Download the episode
7676 dash_process = DASH_Downloader (
@@ -85,7 +85,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
8585 license_headers = mpd_headers .copy ()
8686 license_headers .update ({
8787 "x-cr-content-id" : url_id ,
88- "x-cr-video-token" : query_params [ 'playbackGuid' ][ 0 ] ,
88+ "x-cr-video-token" : playback_guid ,
8989 })
9090
9191 if dash_process .download_and_decrypt (custom_headers = license_headers ):
@@ -100,14 +100,11 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
100100 except Exception :
101101 pass
102102
103- # Delete episode stream to avoid TOO_MANY_ACTIVE_STREAMS
104- playback_token = token or query_params .get ('playbackGuid' , [None ])[0 ]
105- if playback_token :
106- client .delete_active_stream (url_id , playback_token )
107- console .print ("[dim]Playback session closed" )
108-
103+ # Small delay between episodes to avoid rate limiting
104+ time .sleep (1 )
109105 return status ['path' ], status ['stopped' ]
110106
107+
111108def download_episode (index_season_selected : int , scrape_serie : GetSerieInfo , download_all : bool = False , episode_selection : str = None ) -> None :
112109 """
113110 Handle downloading episodes for a specific season.
@@ -116,7 +113,7 @@ def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, dow
116113 - index_season_selected (int): Season number
117114 - scrape_serie (GetSerieInfo): Scraper object with series information
118115 - download_all (bool): Whether to download all episodes
119- - episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
116+ - episode_selection (str, optional): Pre-defined episode selection
120117 """
121118 # Get episodes for the selected season
122119 episodes = scrape_serie .getEpisodeSeasons (index_season_selected )
@@ -154,19 +151,20 @@ def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, dow
154151 if stopped :
155152 break
156153
154+
157155def download_series (select_season : MediaItem , season_selection : str = None , episode_selection : str = None ) -> None :
158156 """
159157 Handle downloading a complete series.
160158
161159 Parameters:
162160 - select_season (MediaItem): Series metadata from search
163- - season_selection (str, optional): Pre-defined season selection that bypasses manual input
164- - episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
161+ - season_selection (str, optional): Pre-defined season selection
162+ - episode_selection (str, optional): Pre-defined episode selection
165163 """
166164 scrape_serie = GetSerieInfo (select_season .url .split ("/" )[- 1 ])
167165 seasons_count = scrape_serie .getNumberSeason ()
168166
169- # If season_selection is provided, use it instead of asking for input
167+ # If season_selection is provided, use it
170168 if season_selection is None :
171169 index_season_selected = display_seasons_list (scrape_serie .seasons_manager )
172170 else :
0 commit comments