StreamingCommunity 3.4.0__py3-none-any.whl → 3.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of StreamingCommunity might be problematic. Click here for more details.
- StreamingCommunity/Api/Site/altadefinizione/film.py +0 -1
- StreamingCommunity/Api/Site/altadefinizione/series.py +3 -12
- StreamingCommunity/Api/Site/altadefinizione/site.py +0 -2
- StreamingCommunity/Api/Site/animeunity/site.py +3 -3
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +3 -3
- StreamingCommunity/Api/Site/crunchyroll/series.py +3 -14
- StreamingCommunity/Api/Site/crunchyroll/site.py +2 -4
- StreamingCommunity/Api/Site/guardaserie/series.py +3 -14
- StreamingCommunity/Api/Site/mediasetinfinity/series.py +3 -13
- StreamingCommunity/Api/Site/mediasetinfinity/site.py +14 -22
- StreamingCommunity/Api/Site/raiplay/film.py +0 -1
- StreamingCommunity/Api/Site/raiplay/series.py +5 -18
- StreamingCommunity/Api/Site/raiplay/site.py +42 -36
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +88 -45
- StreamingCommunity/Api/Site/streamingcommunity/series.py +5 -10
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +0 -1
- StreamingCommunity/Api/Site/streamingwatch/series.py +3 -13
- StreamingCommunity/Api/Template/Util/__init__.py +4 -2
- StreamingCommunity/Api/Template/Util/manage_ep.py +66 -0
- StreamingCommunity/Lib/Downloader/DASH/downloader.py +55 -16
- StreamingCommunity/Lib/Downloader/DASH/segments.py +45 -16
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +71 -34
- StreamingCommunity/Lib/Downloader/HLS/segments.py +18 -1
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +16 -4
- StreamingCommunity/Lib/M3U8/estimator.py +47 -1
- StreamingCommunity/Upload/update.py +19 -6
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/table.py +50 -8
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/METADATA +1 -1
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/RECORD +34 -34
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/WHEEL +0 -0
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-3.4.0.dist-info → streamingcommunity-3.4.2.dist-info}/top_level.txt +0 -0
|
@@ -16,13 +16,14 @@ class GetSerieInfo:
|
|
|
16
16
|
self.base_url = "https://www.raiplay.it"
|
|
17
17
|
self.path_id = path_id
|
|
18
18
|
self.series_name = None
|
|
19
|
-
self.prog_tipology = "film"
|
|
20
19
|
self.prog_description = None
|
|
21
20
|
self.prog_year = None
|
|
22
21
|
self.seasons_manager = SeasonManager()
|
|
22
|
+
self.season_block_mapping = {} # Map season number to block_id
|
|
23
|
+
self.all_seasons_data = [] # Store all seasons before filtering
|
|
23
24
|
|
|
24
25
|
def collect_info_title(self) -> None:
|
|
25
|
-
"""Get series info including seasons."""
|
|
26
|
+
"""Get series info including seasons from all multimedia blocks."""
|
|
26
27
|
try:
|
|
27
28
|
program_url = f"{self.base_url}/{self.path_id}"
|
|
28
29
|
response = create_client(headers=get_headers()).get(program_url)
|
|
@@ -36,76 +37,118 @@ class GetSerieInfo:
|
|
|
36
37
|
json_data = response.json()
|
|
37
38
|
|
|
38
39
|
# Get basic program info
|
|
39
|
-
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
40
|
+
program_info = json_data.get('program_info', {})
|
|
41
|
+
self.prog_description = program_info.get('vanity', '') or program_info.get('description', '')
|
|
42
|
+
self.prog_year = program_info.get('year', '')
|
|
43
|
+
self.series_name = program_info.get('title', '') or program_info.get('name', '')
|
|
44
|
+
|
|
45
|
+
# Collect all seasons from all multimedia blocks
|
|
46
|
+
self.all_seasons_data = []
|
|
47
|
+
blocks_found = {}
|
|
42
48
|
|
|
43
|
-
# Look for seasons in the 'blocks' property
|
|
44
49
|
for block in json_data.get('blocks', []):
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
block_type = block.get('type', '')
|
|
51
|
+
block_name = block.get('name', 'N/A')
|
|
52
|
+
block_id = block.get('id', '')
|
|
53
|
+
|
|
54
|
+
# Only process multimedia blocks with sets
|
|
55
|
+
if block_type == 'RaiPlay Multimedia Block' and 'sets' in block:
|
|
56
|
+
sets = block.get('sets', [])
|
|
57
|
+
|
|
58
|
+
for season_set in sets:
|
|
59
|
+
episode_size = season_set.get('episode_size', {})
|
|
60
|
+
episode_count = episode_size.get('number', 0)
|
|
61
|
+
|
|
62
|
+
# Only add sets with episodes
|
|
63
|
+
if episode_count > 0:
|
|
64
|
+
self.all_seasons_data.append({
|
|
65
|
+
'season_set': season_set,
|
|
66
|
+
'block_id': block_id,
|
|
67
|
+
'block_name': block_name
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
# Track which blocks we found
|
|
71
|
+
if block_name not in blocks_found:
|
|
72
|
+
blocks_found[block_name] = 0
|
|
73
|
+
blocks_found[block_name] += 1
|
|
74
|
+
|
|
75
|
+
# Add all collected seasons without any filtering (oldest first)
|
|
76
|
+
for season_data in reversed(self.all_seasons_data):
|
|
77
|
+
self._add_season(
|
|
78
|
+
season_data['season_set'],
|
|
79
|
+
season_data['block_id'],
|
|
80
|
+
season_data['block_name']
|
|
81
|
+
)
|
|
65
82
|
|
|
66
83
|
except Exception as e:
|
|
67
84
|
logging.error(f"Unexpected error collecting series info: {e}")
|
|
68
85
|
|
|
69
|
-
def _add_season(self, season_set: dict, block_id: str):
|
|
86
|
+
def _add_season(self, season_set: dict, block_id: str, block_name: str):
|
|
87
|
+
"""Add a season combining set name and block name."""
|
|
88
|
+
set_name = season_set.get('name', '')
|
|
89
|
+
season_number = len(self.seasons_manager.seasons) + 1
|
|
90
|
+
|
|
91
|
+
# Store block_id mapping
|
|
92
|
+
self.season_block_mapping[season_number] = {
|
|
93
|
+
'block_id': block_id,
|
|
94
|
+
'set_id': season_set.get('id', '')
|
|
95
|
+
}
|
|
96
|
+
|
|
70
97
|
self.seasons_manager.add_season({
|
|
71
98
|
'id': season_set.get('id', ''),
|
|
72
|
-
'number':
|
|
73
|
-
'name':
|
|
74
|
-
'
|
|
75
|
-
'
|
|
99
|
+
'number': season_number,
|
|
100
|
+
'name': set_name,
|
|
101
|
+
#'episodes_count': season_set.get('episode_size', {}).get('number', 0),
|
|
102
|
+
'type': block_name
|
|
76
103
|
})
|
|
77
104
|
|
|
78
105
|
def collect_info_season(self, number_season: int) -> None:
|
|
79
|
-
"""Get episodes for a specific season."""
|
|
106
|
+
"""Get episodes for a specific season using episodes.json endpoint."""
|
|
80
107
|
try:
|
|
81
108
|
season = self.seasons_manager.get_season_by_number(number_season)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
109
|
+
block_info = self.season_block_mapping[number_season]
|
|
110
|
+
block_id = block_info['block_id']
|
|
111
|
+
set_id = block_info['set_id']
|
|
112
|
+
|
|
113
|
+
# Build episodes endpoint URL
|
|
114
|
+
base_path = self.path_id.replace('.json', '')
|
|
115
|
+
url = f"{self.base_url}/{base_path}/{block_id}/{set_id}/episodes.json"
|
|
116
|
+
|
|
85
117
|
response = create_client(headers=get_headers()).get(url)
|
|
86
118
|
response.raise_for_status()
|
|
87
119
|
|
|
88
120
|
episodes_data = response.json()
|
|
89
|
-
cards = []
|
|
90
121
|
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
122
|
+
# Navigate nested structure to find cards
|
|
123
|
+
cards = []
|
|
124
|
+
seasons = episodes_data.get('seasons', [])
|
|
125
|
+
if seasons:
|
|
126
|
+
for season_data in seasons:
|
|
127
|
+
episodes = season_data.get('episodes', [])
|
|
128
|
+
for episode in episodes:
|
|
129
|
+
cards.extend(episode.get('cards', []))
|
|
96
130
|
|
|
131
|
+
# Fallback to direct cards if nested structure not found
|
|
97
132
|
if not cards:
|
|
98
133
|
cards = episodes_data.get('cards', [])
|
|
99
134
|
|
|
100
135
|
# Add episodes to season
|
|
101
136
|
for ep in cards:
|
|
137
|
+
video_url = ep.get('video_url', '')
|
|
138
|
+
mpd_id = ''
|
|
139
|
+
if video_url and '=' in video_url:
|
|
140
|
+
mpd_id = video_url.split("=")[1].strip()
|
|
141
|
+
|
|
142
|
+
weblink = ep.get('weblink', '') or ep.get('url', '')
|
|
143
|
+
episode_url = f"{self.base_url}{weblink}" if weblink else ''
|
|
144
|
+
|
|
102
145
|
episode = {
|
|
103
146
|
'id': ep.get('id', ''),
|
|
104
147
|
'number': ep.get('episode', ''),
|
|
105
|
-
'name': ep.get('episode_title', '') or ep.get('toptitle', ''),
|
|
106
|
-
'duration': ep.get('duration', ''),
|
|
107
|
-
'url':
|
|
108
|
-
'mpd_id':
|
|
148
|
+
'name': ep.get('episode_title', '') or ep.get('name', '') or ep.get('toptitle', ''),
|
|
149
|
+
'duration': ep.get('duration', '') or ep.get('duration_in_minutes', ''),
|
|
150
|
+
'url': episode_url,
|
|
151
|
+
'mpd_id': mpd_id
|
|
109
152
|
}
|
|
110
153
|
season.episodes.add(episode)
|
|
111
154
|
|
|
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
|
|
|
21
21
|
map_episode_title,
|
|
22
22
|
validate_selection,
|
|
23
23
|
validate_episode_selection,
|
|
24
|
-
display_episodes_list
|
|
24
|
+
display_episodes_list,
|
|
25
|
+
display_seasons_list
|
|
25
26
|
)
|
|
26
27
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
27
28
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
@@ -166,9 +167,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
166
167
|
if site_constant.TELEGRAM_BOT:
|
|
167
168
|
bot = get_bot_instance()
|
|
168
169
|
|
|
169
|
-
# Prompt user for season selection and download episodes
|
|
170
|
-
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
|
171
|
-
|
|
172
170
|
# If season_selection is provided, use it instead of asking for input
|
|
173
171
|
if season_selection is None:
|
|
174
172
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -188,10 +186,8 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
188
186
|
)
|
|
189
187
|
|
|
190
188
|
else:
|
|
191
|
-
index_season_selected =
|
|
192
|
-
|
|
193
|
-
"[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
|
|
194
|
-
)
|
|
189
|
+
index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
|
|
190
|
+
|
|
195
191
|
else:
|
|
196
192
|
index_season_selected = season_selection
|
|
197
193
|
console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
|
|
@@ -211,7 +207,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
211
207
|
|
|
212
208
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
213
209
|
download_episode(season_number, scrape_serie, video_source, download_all=True)
|
|
214
|
-
|
|
215
210
|
else:
|
|
216
211
|
download_episode(season_number, scrape_serie, video_source, download_all=False, episode_selection=episode_selection)
|
|
217
212
|
|
|
@@ -221,4 +216,4 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
221
216
|
# Get script_id
|
|
222
217
|
script_id = TelegramSession.get_session()
|
|
223
218
|
if script_id != "unknown":
|
|
224
|
-
TelegramSession.deleteScriptId(script_id)
|
|
219
|
+
TelegramSession.deleteScriptId(script_id)
|
|
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
|
|
|
21
21
|
map_episode_title,
|
|
22
22
|
validate_selection,
|
|
23
23
|
validate_episode_selection,
|
|
24
|
-
display_episodes_list
|
|
24
|
+
display_episodes_list,
|
|
25
|
+
display_seasons_list
|
|
25
26
|
)
|
|
26
27
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
27
28
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
@@ -134,20 +135,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
134
135
|
- episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
|
|
135
136
|
"""
|
|
136
137
|
scrape_serie = GetSerieInfo(select_season.url)
|
|
137
|
-
|
|
138
|
-
# Get total number of seasons
|
|
139
138
|
seasons_count = scrape_serie.getNumberSeason()
|
|
140
139
|
|
|
141
|
-
# Prompt user for season selection and download episodes
|
|
142
|
-
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
|
143
|
-
|
|
144
140
|
# If season_selection is provided, use it instead of asking for input
|
|
145
141
|
if season_selection is None:
|
|
146
|
-
index_season_selected =
|
|
147
|
-
"\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
|
|
148
|
-
"[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
|
|
149
|
-
)
|
|
150
|
-
|
|
142
|
+
index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
|
|
151
143
|
else:
|
|
152
144
|
index_season_selected = season_selection
|
|
153
145
|
console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
|
|
@@ -159,8 +151,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
159
151
|
# Loop through the selected seasons and download episodes
|
|
160
152
|
for i_season in list_season_select:
|
|
161
153
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
162
|
-
# Download all episodes if multiple seasons are selected or if '*' is used
|
|
163
154
|
download_episode(i_season, scrape_serie, download_all=True)
|
|
164
155
|
else:
|
|
165
|
-
# Otherwise, let the user select specific episodes for the single season
|
|
166
156
|
download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
|
|
@@ -6,7 +6,8 @@ from .manage_ep import (
|
|
|
6
6
|
validate_episode_selection,
|
|
7
7
|
validate_selection,
|
|
8
8
|
dynamic_format_number,
|
|
9
|
-
display_episodes_list
|
|
9
|
+
display_episodes_list,
|
|
10
|
+
display_seasons_list
|
|
10
11
|
)
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
@@ -15,5 +16,6 @@ __all__ = [
|
|
|
15
16
|
"validate_episode_selection",
|
|
16
17
|
"validate_selection",
|
|
17
18
|
"dynamic_format_number",
|
|
18
|
-
"display_episodes_list"
|
|
19
|
+
"display_episodes_list",
|
|
20
|
+
display_seasons_list
|
|
19
21
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# 19.06.24
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
+
import time
|
|
4
5
|
import logging
|
|
5
6
|
from typing import List
|
|
6
7
|
|
|
@@ -209,6 +210,71 @@ def validate_episode_selection(list_episode_select: List[int], episodes_count: i
|
|
|
209
210
|
list_episode_select = list(map(int, input_episodes.split(',')))
|
|
210
211
|
|
|
211
212
|
|
|
213
|
+
def display_seasons_list(seasons_manager) -> str:
|
|
214
|
+
"""
|
|
215
|
+
Display seasons list and handle user input.
|
|
216
|
+
|
|
217
|
+
Parameters:
|
|
218
|
+
- seasons_manager: Manager object containing seasons information.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
last_command (str): Last command entered by the user.
|
|
222
|
+
"""
|
|
223
|
+
if len(seasons_manager.seasons) == 1:
|
|
224
|
+
console.print("\n[green]Only one season available, selecting it automatically[/green]")
|
|
225
|
+
time.sleep(1)
|
|
226
|
+
return "1"
|
|
227
|
+
|
|
228
|
+
# Set up table for displaying seasons
|
|
229
|
+
table_show_manager = TVShowManager()
|
|
230
|
+
|
|
231
|
+
# Check if 'type' and 'id' attributes exist in the first season
|
|
232
|
+
has_type = hasattr(seasons_manager.seasons[0], 'type') and (seasons_manager.seasons[0].type) is not None and str(seasons_manager.seasons[0].type) != ''
|
|
233
|
+
has_id = hasattr(seasons_manager.seasons[0], 'id') and (seasons_manager.seasons[0].id) is not None and str(seasons_manager.seasons[0].id) != ''
|
|
234
|
+
|
|
235
|
+
# Add columns to the table
|
|
236
|
+
column_info = {
|
|
237
|
+
"Index": {'color': 'red'},
|
|
238
|
+
"Name": {'color': 'yellow'}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if has_type:
|
|
242
|
+
column_info["Type"] = {'color': 'magenta'}
|
|
243
|
+
|
|
244
|
+
if has_id:
|
|
245
|
+
column_info["ID"] = {'color': 'cyan'}
|
|
246
|
+
|
|
247
|
+
table_show_manager.add_column(column_info)
|
|
248
|
+
|
|
249
|
+
# Populate the table with seasons information
|
|
250
|
+
for i, season in enumerate(seasons_manager.seasons):
|
|
251
|
+
season_name = season.name if hasattr(season, 'name') else 'N/A'
|
|
252
|
+
season_info = {
|
|
253
|
+
'Index': str(i + 1),
|
|
254
|
+
'Name': season_name
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# Add 'Type' and 'ID' if they exist
|
|
258
|
+
if has_type:
|
|
259
|
+
season_type = season.type if hasattr(season, 'type') else 'N/A'
|
|
260
|
+
season_info['Type'] = season_type
|
|
261
|
+
|
|
262
|
+
if has_id:
|
|
263
|
+
season_id = season.id if hasattr(season, 'id') else 'N/A'
|
|
264
|
+
season_info['ID'] = season_id
|
|
265
|
+
|
|
266
|
+
table_show_manager.add_tv_show(season_info)
|
|
267
|
+
|
|
268
|
+
# Run the table and handle user input
|
|
269
|
+
last_command = table_show_manager.run()
|
|
270
|
+
|
|
271
|
+
if last_command in ("q", "quit"):
|
|
272
|
+
console.print("\n[red]Quit ...")
|
|
273
|
+
sys.exit(0)
|
|
274
|
+
|
|
275
|
+
return last_command
|
|
276
|
+
|
|
277
|
+
|
|
212
278
|
def display_episodes_list(episodes_manager) -> str:
|
|
213
279
|
"""
|
|
214
280
|
Display episodes list and handle user input.
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import shutil
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Optional, Dict
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
# External libraries
|
|
8
10
|
from rich.console import Console
|
|
9
|
-
from rich.panel import Panel
|
|
10
11
|
from rich.table import Table
|
|
11
12
|
|
|
12
13
|
|
|
@@ -73,6 +74,10 @@ class DASH_Downloader:
|
|
|
73
74
|
self.error = None
|
|
74
75
|
self.stopped = False
|
|
75
76
|
self.output_file = None
|
|
77
|
+
|
|
78
|
+
# For progress tracking
|
|
79
|
+
self.current_downloader: Optional[MPD_Segments] = None
|
|
80
|
+
self.current_download_type: Optional[str] = None
|
|
76
81
|
|
|
77
82
|
def _setup_temp_dirs(self):
|
|
78
83
|
"""
|
|
@@ -269,6 +274,10 @@ class DASH_Downloader:
|
|
|
269
274
|
pssh=self.parser.pssh
|
|
270
275
|
)
|
|
271
276
|
|
|
277
|
+
# Set current downloader for progress tracking
|
|
278
|
+
self.current_downloader = video_downloader
|
|
279
|
+
self.current_download_type = 'video'
|
|
280
|
+
|
|
272
281
|
try:
|
|
273
282
|
result = video_downloader.download_streams(description="Video")
|
|
274
283
|
|
|
@@ -288,6 +297,10 @@ class DASH_Downloader:
|
|
|
288
297
|
except Exception as ex:
|
|
289
298
|
self.error = str(ex)
|
|
290
299
|
return False
|
|
300
|
+
|
|
301
|
+
finally:
|
|
302
|
+
self.current_downloader = None
|
|
303
|
+
self.current_download_type = None
|
|
291
304
|
|
|
292
305
|
# Decrypt video
|
|
293
306
|
decrypted_path = os.path.join(self.decrypted_dir, "video.mp4")
|
|
@@ -321,6 +334,10 @@ class DASH_Downloader:
|
|
|
321
334
|
limit_segments=video_segments_count if video_segments_count > 0 else None
|
|
322
335
|
)
|
|
323
336
|
|
|
337
|
+
# Set current downloader for progress tracking
|
|
338
|
+
self.current_downloader = audio_downloader
|
|
339
|
+
self.current_download_type = f"audio_{audio_language}"
|
|
340
|
+
|
|
324
341
|
try:
|
|
325
342
|
result = audio_downloader.download_streams(description=f"Audio {audio_language}")
|
|
326
343
|
|
|
@@ -337,6 +354,10 @@ class DASH_Downloader:
|
|
|
337
354
|
except Exception as ex:
|
|
338
355
|
self.error = str(ex)
|
|
339
356
|
return False
|
|
357
|
+
|
|
358
|
+
finally:
|
|
359
|
+
self.current_downloader = None
|
|
360
|
+
self.current_download_type = None
|
|
340
361
|
|
|
341
362
|
# Decrypt audio
|
|
342
363
|
decrypted_path = os.path.join(self.decrypted_dir, "audio.mp4")
|
|
@@ -385,6 +406,10 @@ class DASH_Downloader:
|
|
|
385
406
|
pssh=self.parser.pssh
|
|
386
407
|
)
|
|
387
408
|
|
|
409
|
+
# Set current downloader for progress tracking
|
|
410
|
+
self.current_downloader = video_downloader
|
|
411
|
+
self.current_download_type = 'video'
|
|
412
|
+
|
|
388
413
|
try:
|
|
389
414
|
result = video_downloader.download_streams(description="Video")
|
|
390
415
|
|
|
@@ -405,6 +430,10 @@ class DASH_Downloader:
|
|
|
405
430
|
self.error = str(ex)
|
|
406
431
|
console.print(f"[red]Error downloading video: {ex}[/red]")
|
|
407
432
|
return False
|
|
433
|
+
|
|
434
|
+
finally:
|
|
435
|
+
self.current_downloader = None
|
|
436
|
+
self.current_download_type = None
|
|
408
437
|
|
|
409
438
|
# NO DECRYPTION: just copy/move to decrypted folder
|
|
410
439
|
decrypted_path = os.path.join(self.decrypted_dir, "video.mp4")
|
|
@@ -432,6 +461,10 @@ class DASH_Downloader:
|
|
|
432
461
|
limit_segments=video_segments_count if video_segments_count > 0 else None
|
|
433
462
|
)
|
|
434
463
|
|
|
464
|
+
# Set current downloader for progress tracking
|
|
465
|
+
self.current_downloader = audio_downloader
|
|
466
|
+
self.current_download_type = f"audio_{audio_language}"
|
|
467
|
+
|
|
435
468
|
try:
|
|
436
469
|
result = audio_downloader.download_streams(description=f"Audio {audio_language}")
|
|
437
470
|
|
|
@@ -449,6 +482,10 @@ class DASH_Downloader:
|
|
|
449
482
|
self.error = str(ex)
|
|
450
483
|
console.print(f"[red]Error downloading audio: {ex}[/red]")
|
|
451
484
|
return False
|
|
485
|
+
|
|
486
|
+
finally:
|
|
487
|
+
self.current_downloader = None
|
|
488
|
+
self.current_download_type = None
|
|
452
489
|
|
|
453
490
|
# NO DECRYPTION: just copy/move to decrypted folder
|
|
454
491
|
decrypted_path = os.path.join(self.decrypted_dir, "audio.mp4")
|
|
@@ -542,20 +579,7 @@ class DASH_Downloader:
|
|
|
542
579
|
if os.path.exists(output_file):
|
|
543
580
|
file_size = internet_manager.format_file_size(os.path.getsize(output_file))
|
|
544
581
|
duration = print_duration_table(output_file, description=False, return_string=True)
|
|
545
|
-
|
|
546
|
-
panel_content = (
|
|
547
|
-
f"[cyan]File size: [bold red]{file_size}[/bold red]\n"
|
|
548
|
-
f"[cyan]Duration: [bold]{duration}[/bold]\n"
|
|
549
|
-
f"[cyan]Output: [bold]{os.path.abspath(output_file)}[/bold]"
|
|
550
|
-
)
|
|
551
|
-
|
|
552
|
-
print("")
|
|
553
|
-
console.print(Panel(
|
|
554
|
-
panel_content,
|
|
555
|
-
title=f"{os.path.basename(output_file.replace('.mp4', ''))}",
|
|
556
|
-
border_style="green"
|
|
557
|
-
))
|
|
558
|
-
|
|
582
|
+
console.print(f"[yellow]Output [red]{os.path.abspath(output_file)} [cyan]with size [red]{file_size} [cyan]and duration [red]{duration}")
|
|
559
583
|
else:
|
|
560
584
|
console.print(f"[red]Output file not found: {output_file}")
|
|
561
585
|
|
|
@@ -591,4 +615,19 @@ class DASH_Downloader:
|
|
|
591
615
|
"path": self.output_file,
|
|
592
616
|
"error": self.error,
|
|
593
617
|
"stopped": self.stopped
|
|
594
|
-
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
def get_progress_data(self) -> Optional[Dict]:
|
|
621
|
+
"""Get current download progress data."""
|
|
622
|
+
if not self.current_downloader:
|
|
623
|
+
return None
|
|
624
|
+
|
|
625
|
+
try:
|
|
626
|
+
progress = self.current_downloader.get_progress_data()
|
|
627
|
+
if progress:
|
|
628
|
+
progress['download_type'] = self.current_download_type
|
|
629
|
+
return progress
|
|
630
|
+
|
|
631
|
+
except Exception as e:
|
|
632
|
+
logging.error(f"Error getting progress data: {e}")
|
|
633
|
+
return None
|