StreamingCommunity 2.5.6__py3-none-any.whl → 2.5.8__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.

Files changed (65) hide show
  1. StreamingCommunity/Api/Player/ddl.py +2 -3
  2. StreamingCommunity/Api/Site/1337xx/__init__.py +5 -6
  3. StreamingCommunity/Api/Site/1337xx/site.py +7 -14
  4. StreamingCommunity/Api/Site/1337xx/title.py +3 -5
  5. StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +7 -6
  6. StreamingCommunity/Api/Site/altadefinizionegratis/film.py +14 -19
  7. StreamingCommunity/Api/Site/altadefinizionegratis/site.py +6 -14
  8. StreamingCommunity/Api/Site/animeunity/__init__.py +7 -7
  9. StreamingCommunity/Api/Site/animeunity/film_serie.py +29 -31
  10. StreamingCommunity/Api/Site/animeunity/site.py +14 -22
  11. StreamingCommunity/Api/Site/cb01new/__init__.py +5 -4
  12. StreamingCommunity/Api/Site/cb01new/film.py +2 -5
  13. StreamingCommunity/Api/Site/cb01new/site.py +5 -13
  14. StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +5 -4
  15. StreamingCommunity/Api/Site/ddlstreamitaly/series.py +12 -49
  16. StreamingCommunity/Api/Site/ddlstreamitaly/site.py +6 -16
  17. StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +2 -3
  18. StreamingCommunity/Api/Site/guardaserie/__init__.py +5 -4
  19. StreamingCommunity/Api/Site/guardaserie/series.py +12 -46
  20. StreamingCommunity/Api/Site/guardaserie/site.py +5 -13
  21. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +10 -14
  22. StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +5 -4
  23. StreamingCommunity/Api/Site/ilcorsaronero/site.py +5 -13
  24. StreamingCommunity/Api/Site/ilcorsaronero/title.py +3 -5
  25. StreamingCommunity/Api/Site/mostraguarda/__init__.py +2 -2
  26. StreamingCommunity/Api/Site/mostraguarda/film.py +4 -8
  27. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +8 -7
  28. StreamingCommunity/Api/Site/streamingcommunity/film.py +14 -18
  29. StreamingCommunity/Api/Site/streamingcommunity/series.py +25 -76
  30. StreamingCommunity/Api/Site/streamingcommunity/site.py +11 -23
  31. StreamingCommunity/Api/Template/Util/__init__.py +8 -1
  32. StreamingCommunity/Api/Template/Util/manage_ep.py +46 -2
  33. StreamingCommunity/Api/Template/config_loader.py +71 -0
  34. StreamingCommunity/Lib/Downloader/HLS/downloader.py +60 -60
  35. StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -15
  36. StreamingCommunity/Lib/Downloader/MP4/downloader.py +47 -40
  37. StreamingCommunity/Lib/FFmpeg/command.py +59 -3
  38. StreamingCommunity/Lib/M3U8/estimator.py +10 -12
  39. StreamingCommunity/Lib/M3U8/parser.py +12 -51
  40. StreamingCommunity/Lib/TMBD/tmdb.py +66 -99
  41. StreamingCommunity/TelegramHelp/telegram_bot.py +222 -68
  42. StreamingCommunity/Util/_jsonConfig.py +14 -13
  43. StreamingCommunity/Util/ffmpeg_installer.py +70 -64
  44. StreamingCommunity/Util/headers.py +11 -122
  45. StreamingCommunity/Util/os.py +65 -56
  46. StreamingCommunity/Util/table.py +62 -108
  47. StreamingCommunity/run.py +16 -11
  48. {StreamingCommunity-2.5.6.dist-info → StreamingCommunity-2.5.8.dist-info}/METADATA +57 -23
  49. StreamingCommunity-2.5.8.dist-info/RECORD +86 -0
  50. StreamingCommunity/Api/Site/1337xx/costant.py +0 -15
  51. StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +0 -21
  52. StreamingCommunity/Api/Site/animeunity/costant.py +0 -21
  53. StreamingCommunity/Api/Site/cb01new/costant.py +0 -19
  54. StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -20
  55. StreamingCommunity/Api/Site/guardaserie/costant.py +0 -19
  56. StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -19
  57. StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -19
  58. StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -21
  59. StreamingCommunity/TelegramHelp/request_manager.py +0 -82
  60. StreamingCommunity/TelegramHelp/session.py +0 -56
  61. StreamingCommunity-2.5.6.dist-info/RECORD +0 -96
  62. {StreamingCommunity-2.5.6.dist-info → StreamingCommunity-2.5.8.dist-info}/LICENSE +0 -0
  63. {StreamingCommunity-2.5.6.dist-info → StreamingCommunity-2.5.8.dist-info}/WHEEL +0 -0
  64. {StreamingCommunity-2.5.6.dist-info → StreamingCommunity-2.5.8.dist-info}/entry_points.txt +0 -0
  65. {StreamingCommunity-2.5.6.dist-info → StreamingCommunity-2.5.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,71 @@
1
+ # 11.02.25
2
+
3
+ import os
4
+ import inspect
5
+
6
+
7
+ # Internal utilities
8
+ from StreamingCommunity.Util._jsonConfig import config_manager
9
+
10
+
11
+ def get_site_name_from_stack():
12
+ for frame_info in inspect.stack():
13
+ file_path = frame_info.filename
14
+
15
+ if "__init__" in file_path:
16
+ parts = file_path.split(f"Site{os.sep}")
17
+
18
+ if len(parts) > 1:
19
+ site_name = parts[1].split(os.sep)[0]
20
+ return site_name
21
+
22
+ return None
23
+
24
+
25
+ class SiteConstant:
26
+ @property
27
+ def SITE_NAME(self):
28
+ return get_site_name_from_stack()
29
+
30
+ @property
31
+ def ROOT_PATH(self):
32
+ return config_manager.get('DEFAULT', 'root_path')
33
+
34
+ @property
35
+ def DOMAIN_NOW(self):
36
+ return config_manager.get_dict('SITE', self.SITE_NAME)['domain']
37
+
38
+ @property
39
+ def SERIES_FOLDER(self):
40
+ base_path = self.ROOT_PATH
41
+ if config_manager.get_bool("DEFAULT", "add_siteName"):
42
+ base_path = os.path.join(base_path, self.SITE_NAME)
43
+ return os.path.join(base_path, config_manager.get('DEFAULT', 'serie_folder_name'))
44
+
45
+ @property
46
+ def MOVIE_FOLDER(self):
47
+ base_path = self.ROOT_PATH
48
+ if config_manager.get_bool("DEFAULT", "add_siteName"):
49
+ base_path = os.path.join(base_path, self.SITE_NAME)
50
+ return os.path.join(base_path, config_manager.get('DEFAULT', 'movie_folder_name'))
51
+
52
+ @property
53
+ def ANIME_FOLDER(self):
54
+ base_path = self.ROOT_PATH
55
+ if config_manager.get_bool("DEFAULT", "add_siteName"):
56
+ base_path = os.path.join(base_path, self.SITE_NAME)
57
+ return os.path.join(base_path, config_manager.get('DEFAULT', 'anime_folder_name'))
58
+
59
+ @property
60
+ def COOKIE(self):
61
+ try:
62
+ return config_manager.get_dict('SITE', self.SITE_NAME)['extra']
63
+ except KeyError:
64
+ return None
65
+
66
+ @property
67
+ def TELEGRAM_BOT(self):
68
+ return config_manager.get_bool('DEFAULT', 'telegram_bot')
69
+
70
+
71
+ site_constant = SiteConstant()
@@ -43,7 +43,7 @@ DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_DOWNLOAD', 'specific_
43
43
  MERGE_AUDIO = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_audio')
44
44
  MERGE_SUBTITLE = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_subs')
45
45
  CLEANUP_TMP = config_manager.get_bool('M3U8_DOWNLOAD', 'cleanup_tmp_folder')
46
- FILTER_CUSTOM_REOLUTION = config_manager.get_int('M3U8_PARSER', 'force_resolution')
46
+ FILTER_CUSTOM_REOLUTION = str(config_manager.get('M3U8_PARSER', 'force_resolution')).strip().lower()
47
47
  GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link')
48
48
  RETRY_LIMIT = config_manager.get_int('REQUESTS', 'max_retry')
49
49
  MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
@@ -60,11 +60,11 @@ class HLSClient:
60
60
  def request(self, url: str, return_content: bool = False) -> Optional[httpx.Response]:
61
61
  """
62
62
  Makes HTTP GET requests with retry logic.
63
-
63
+
64
64
  Args:
65
65
  url: Target URL to request
66
66
  return_content: If True, returns response content instead of text
67
-
67
+
68
68
  Returns:
69
69
  Response content/text or None if all retries fail
70
70
  """
@@ -74,7 +74,7 @@ class HLSClient:
74
74
  response = client.get(url)
75
75
  response.raise_for_status()
76
76
  return response.content if return_content else response.text
77
-
77
+
78
78
  except Exception as e:
79
79
  logging.error(f"Attempt {attempt+1} failed: {str(e)}")
80
80
  time.sleep(1.5 ** attempt)
@@ -103,7 +103,7 @@ class PathManager:
103
103
  root = config_manager.get('DEFAULT', 'root_path')
104
104
  hash_name = compute_sha1_hash(self.m3u8_url) + ".mp4"
105
105
  return os.path.join(root, "undefined", hash_name)
106
-
106
+
107
107
  if not path.endswith(".mp4"):
108
108
  path += ".mp4"
109
109
 
@@ -148,7 +148,7 @@ class M3U8Manager:
148
148
  content = self.client.request(self.m3u8_url)
149
149
  if not content:
150
150
  raise ValueError("Failed to fetch M3U8 content")
151
-
151
+
152
152
  self.parser.parse_data(uri=self.m3u8_url, raw_content=content)
153
153
  self.url_fixer.set_playlist(self.m3u8_url)
154
154
  self.is_master = self.parser.is_master_playlist
@@ -159,18 +159,19 @@ class M3U8Manager:
159
159
  If it's a master playlist, only selects video stream.
160
160
  """
161
161
  if not self.is_master:
162
- if FILTER_CUSTOM_REOLUTION != -1:
163
- self.video_url, self.video_res = self.parser._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION)
164
- else:
165
- self.video_url, self.video_res = self.parser._video.get_best_uri()
166
-
162
+ self.video_url, self.video_res = self.m3u8_url, "0p"
167
163
  self.audio_streams = []
168
164
  self.sub_streams = []
169
-
165
+
170
166
  else:
171
- if FILTER_CUSTOM_REOLUTION != -1:
172
- self.video_url, self.video_res = self.parser._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION)
167
+ if str(FILTER_CUSTOM_REOLUTION) == "best":
168
+ self.video_url, self.video_res = self.parser._video.get_best_uri()
169
+ elif str(FILTER_CUSTOM_REOLUTION) == "worst":
170
+ self.video_url, self.video_res = self.parser._video.get_worst_uri()
171
+ elif "p" in str(FILTER_CUSTOM_REOLUTION):
172
+ self.video_url, self.video_res = self.parser._video.get_custom_uri(int(FILTER_CUSTOM_REOLUTION.replace("p", "")))
173
173
  else:
174
+ logging.error("Resolution not recognized.")
174
175
  self.video_url, self.video_res = self.parser._video.get_best_uri()
175
176
 
176
177
  self.audio_streams = []
@@ -188,17 +189,12 @@ class M3U8Manager:
188
189
  ]
189
190
 
190
191
  def log_selection(self):
191
- if FILTER_CUSTOM_REOLUTION == -1:
192
- set_resolution = "Best"
193
- else:
194
- set_resolution = f"{FILTER_CUSTOM_REOLUTION}p"
195
-
196
192
  tuple_available_resolution = self.parser._video.get_list_resolution()
197
193
  list_available_resolution = [f"{r[0]}x{r[1]}" for r in tuple_available_resolution]
198
194
 
199
195
  console.print(
200
196
  f"[cyan bold]Video →[/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | "
201
- f"[red]Set:[/red] [purple]{set_resolution}[/purple] | "
197
+ f"[red]Set:[/red] [purple]{FILTER_CUSTOM_REOLUTION}[/purple] | "
202
198
  f"[yellow]Downloadable:[/yellow] [purple]{self.video_res[0]}x{self.video_res[1]}[/purple]"
203
199
  )
204
200
 
@@ -264,13 +260,14 @@ class DownloadManager:
264
260
 
265
261
  if result.get('stopped', False):
266
262
  self.stopped = True
263
+
267
264
  return self.stopped
268
265
 
269
266
  def download_audio(self, audio: Dict):
270
267
  """Downloads audio segments for a specific language track."""
271
- if self.stopped:
272
- return True
273
-
268
+ #if self.stopped:
269
+ # return True
270
+
274
271
  audio_full_url = self.url_fixer.generate_full_url(audio['uri'])
275
272
  audio_tmp_dir = os.path.join(self.temp_dir, 'audio', audio['language'])
276
273
 
@@ -284,14 +281,20 @@ class DownloadManager:
284
281
 
285
282
  def download_subtitle(self, sub: Dict):
286
283
  """Downloads and saves subtitle file for a specific language."""
287
- if self.stopped:
288
- return True
289
-
290
- content = self.client.request(sub['uri'])
291
- if content:
284
+ #if self.stopped:
285
+ # return True
286
+
287
+ raw_content = self.client.request(sub['uri'])
288
+ if raw_content:
292
289
  sub_path = os.path.join(self.temp_dir, 'subs', f"{sub['language']}.vtt")
293
- with open(sub_path, 'w', encoding='utf-8') as f:
294
- f.write(content)
290
+
291
+ subtitle_parser = M3U8_Parser()
292
+ subtitle_parser.parse_data(sub['uri'], raw_content)
293
+
294
+ with open(sub_path, 'wb') as f:
295
+ vtt_url = subtitle_parser.subtitle[-1]
296
+ vtt_content = self.client.request(vtt_url, True)
297
+ f.write(vtt_content)
295
298
 
296
299
  return self.stopped
297
300
 
@@ -299,30 +302,35 @@ class DownloadManager:
299
302
  """
300
303
  Downloads all selected streams (video, audio, subtitles).
301
304
  """
305
+ return_stopped = False
306
+
302
307
  video_file = os.path.join(self.temp_dir, 'video', '0.ts')
303
308
  if not os.path.exists(video_file):
304
309
  if self.download_video(video_url):
305
- return True
306
-
310
+ if not return_stopped:
311
+ return_stopped = True
312
+
307
313
  for audio in audio_streams:
308
- if self.stopped:
309
- break
314
+ #if self.stopped:
315
+ # break
310
316
 
311
317
  audio_file = os.path.join(self.temp_dir, 'audio', audio['language'], '0.ts')
312
318
  if not os.path.exists(audio_file):
313
319
  if self.download_audio(audio):
314
- return True
320
+ if not return_stopped:
321
+ return_stopped = True
315
322
 
316
323
  for sub in sub_streams:
317
- if self.stopped:
318
- break
324
+ #if self.stopped:
325
+ # break
319
326
 
320
327
  sub_file = os.path.join(self.temp_dir, 'subs', f"{sub['language']}.vtt")
321
328
  if not os.path.exists(sub_file):
322
329
  if self.download_subtitle(sub):
323
- return True
324
-
325
- return self.stopped
330
+ if not return_stopped:
331
+ return_stopped = True
332
+
333
+ return return_stopped
326
334
 
327
335
 
328
336
  class MergeManager:
@@ -344,7 +352,7 @@ class MergeManager:
344
352
  """
345
353
  Merges downloaded streams into final video file.
346
354
  Returns path to the final merged file.
347
-
355
+
348
356
  Process:
349
357
  1. If no audio/subs, just process video
350
358
  2. If audio exists, merge with video
@@ -387,7 +395,7 @@ class MergeManager:
387
395
  subtitles_list=sub_tracks,
388
396
  out_path=merged_subs_path
389
397
  )
390
-
398
+
391
399
  return merged_file
392
400
 
393
401
 
@@ -404,14 +412,16 @@ class HLS_Downloader:
404
412
  def start(self) -> Dict[str, Any]:
405
413
  """
406
414
  Main execution flow with handling for both index and playlist M3U8s.
407
-
415
+
408
416
  Returns:
409
417
  Dict containing:
410
418
  - path: Output file path
411
419
  - url: Original M3U8 URL
412
420
  - is_master: Whether the M3U8 was a master playlist
413
421
  Or raises an exception if there's an error
414
- """
422
+ """
423
+ console.print(f"[cyan]You can safely stop the download with [bold]Ctrl+c[bold] [cyan] \n")
424
+
415
425
  if TELEGRAM_BOT:
416
426
  bot = get_bot_instance()
417
427
 
@@ -421,12 +431,12 @@ class HLS_Downloader:
421
431
  response = {
422
432
  'path': self.path_manager.output_path,
423
433
  'url': self.m3u8_url,
424
- 'is_master': False,
434
+ 'is_master': False,
425
435
  'error': 'File already exists',
426
436
  'stopped': False
427
437
  }
428
438
  if TELEGRAM_BOT:
429
- bot.send_message(response)
439
+ bot.send_message(f"Contenuto già scaricato!", None)
430
440
  return response
431
441
 
432
442
  self.path_manager.setup_directories()
@@ -441,7 +451,7 @@ class HLS_Downloader:
441
451
  client=self.client,
442
452
  url_fixer=self.m3u8_manager.url_fixer
443
453
  )
444
-
454
+
445
455
  # Check if download was stopped
446
456
  download_stopped = self.download_manager.download_all(
447
457
  video_url=self.m3u8_manager.video_url,
@@ -449,15 +459,6 @@ class HLS_Downloader:
449
459
  sub_streams=self.m3u8_manager.sub_streams
450
460
  )
451
461
 
452
- if download_stopped:
453
- return {
454
- 'path': None,
455
- 'url': self.m3u8_url,
456
- 'is_master': self.m3u8_manager.is_master,
457
- 'error': 'Download stopped by user',
458
- 'stopped': True
459
- }
460
-
461
462
  self.merge_manager = MergeManager(
462
463
  temp_dir=self.path_manager.temp_dir,
463
464
  parser=self.m3u8_manager.parser,
@@ -475,14 +476,14 @@ class HLS_Downloader:
475
476
  'path': self.path_manager.output_path,
476
477
  'url': self.m3u8_url,
477
478
  'is_master': self.m3u8_manager.is_master,
478
- 'stopped': False
479
+ 'stopped': download_stopped
479
480
  }
480
481
 
481
482
  except Exception as e:
482
483
  error_msg = str(e)
483
484
  console.print(f"[red]Download failed: {error_msg}[/red]")
484
485
  logging.error("Download error", exc_info=True)
485
-
486
+
486
487
  return {
487
488
  'path': None,
488
489
  'url': self.m3u8_url,
@@ -490,7 +491,7 @@ class HLS_Downloader:
490
491
  'error': error_msg,
491
492
  'stopped': False
492
493
  }
493
-
494
+
494
495
  def _print_summary(self):
495
496
  """Prints download summary including file size, duration, and any missing segments."""
496
497
  if TELEGRAM_BOT:
@@ -506,7 +507,6 @@ class HLS_Downloader:
506
507
  file_size = internet_manager.format_file_size(os.path.getsize(self.path_manager.output_path))
507
508
  duration = print_duration_table(self.path_manager.output_path, description=False, return_string=True)
508
509
 
509
- print()
510
510
  panel_content = (
511
511
  f"[cyan]File size: [bold red]{file_size}[/bold red]\n"
512
512
  f"[cyan]Duration: [bold]{duration}[/bold]\n"
@@ -47,6 +47,9 @@ PROXY_START_MAX = config_manager.get_float('REQUESTS', 'proxy_start_max')
47
47
  DEFAULT_VIDEO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_video_workser')
48
48
  DEFAULT_AUDIO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_audio_workser')
49
49
  MAX_TIMEOOUT = config_manager.get_int("REQUESTS", "timeout")
50
+ MAX_INTERRUPT_COUNT = 3
51
+ SEGMENT_MAX_TIMEOUT = config_manager.get_int("M3U8_DOWNLOAD", "segment_timeout")
52
+ TELEGRAM_BOT = config_manager.get_bool('DEFAULT', 'telegram_bot')
50
53
 
51
54
 
52
55
 
@@ -82,12 +85,14 @@ class M3U8_Segments:
82
85
  # Stopping
83
86
  self.interrupt_flag = threading.Event()
84
87
  self.download_interrupted = False
88
+ self.interrupt_count = 0
89
+ self.force_stop = False
90
+ self.interrupt_lock = threading.Lock()
85
91
 
86
92
  # OTHER INFO
87
93
  self.info_maxRetry = 0
88
94
  self.info_nRetry = 0
89
95
  self.info_nFailed = 0
90
-
91
96
  self.active_retries = 0
92
97
  self.active_retries_lock = threading.Lock()
93
98
 
@@ -156,12 +161,24 @@ class M3U8_Segments:
156
161
  Set up a signal handler for graceful interruption.
157
162
  """
158
163
  def interrupt_handler(signum, frame):
159
- if not self.interrupt_flag.is_set():
160
- console.log("\n[red] Stopping download gracefully...")
161
- self.interrupt_flag.set()
162
- self.download_interrupted = True
163
- self.stop_event.set()
164
+ with self.interrupt_lock:
165
+ self.interrupt_count += 1
166
+ if self.interrupt_count >= MAX_INTERRUPT_COUNT:
167
+ self.force_stop = True
168
+
169
+ if self.force_stop:
170
+ console.print("\n[red]Force stop triggered! Exiting immediately.")
171
+
172
+ else:
173
+ if not self.interrupt_flag.is_set():
174
+ remaining = MAX_INTERRUPT_COUNT - self.interrupt_count
175
+ console.print(f"\n[red]- Stopping gracefully... (Ctrl+C {remaining}x to force)")
176
+ self.download_interrupted = True
177
+
178
+ if remaining == 1:
179
+ self.interrupt_flag.set()
164
180
 
181
+
165
182
  if threading.current_thread() is threading.main_thread():
166
183
  signal.signal(signal.SIGINT, interrupt_handler)
167
184
  else:
@@ -169,8 +186,9 @@ class M3U8_Segments:
169
186
 
170
187
  def _get_http_client(self, index: int = None):
171
188
  client_params = {
172
- 'headers': random_headers(self.key_base_url) if hasattr(self, 'key_base_url') else {'User-Agent': get_headers()},
173
- 'timeout': MAX_TIMEOOUT,
189
+ #'headers': random_headers(self.key_base_url) if hasattr(self, 'key_base_url') else {'User-Agent': get_headers()},
190
+ 'headers': {'User-Agent': get_headers()},
191
+ 'timeout': SEGMENT_MAX_TIMEOUT,
174
192
  'follow_redirects': True,
175
193
  'http2': False
176
194
  }
@@ -189,7 +207,7 @@ class M3U8_Segments:
189
207
  - index (int): The index of the segment.
190
208
  - progress_bar (tqdm): Progress counter for tracking download progress.
191
209
  - backoff_factor (float): The backoff factor for exponential backoff (default is 1.5 seconds).
192
- """
210
+ """
193
211
  for attempt in range(REQUEST_MAX_RETRY):
194
212
  if self.interrupt_flag.is_set():
195
213
  return
@@ -291,6 +309,8 @@ class M3U8_Segments:
291
309
 
292
310
  except queue.Empty:
293
311
  self.current_timeout = min(MAX_TIMEOOUT, self.current_timeout * 1.1)
312
+ time.sleep(0.05)
313
+
294
314
  if self.stop_event.is_set():
295
315
  break
296
316
 
@@ -305,6 +325,11 @@ class M3U8_Segments:
305
325
  - description: Description to insert on tqdm bar
306
326
  - type (str): Type of download: 'video' or 'audio'
307
327
  """
328
+ if TELEGRAM_BOT:
329
+
330
+ # Viene usato per lo screen
331
+ console.log("####")
332
+
308
333
  self.get_info()
309
334
  self.setup_interrupt_handler()
310
335
 
@@ -313,7 +338,9 @@ class M3U8_Segments:
313
338
  unit='s',
314
339
  ascii='░▒█',
315
340
  bar_format=self._get_bar_format(description),
316
- mininterval=0.05
341
+ mininterval=0.6,
342
+ maxinterval=1.0,
343
+ file=sys.stdout, # Using file=sys.stdout to force in-place updates because sys.stderr may not support carriage returns in this environment.
317
344
  )
318
345
 
319
346
  try:
@@ -382,7 +409,6 @@ class M3U8_Segments:
382
409
  return (
383
410
  f"{Colors.YELLOW}Proc{Colors.WHITE}: "
384
411
  f"{Colors.RED}{{percentage:.2f}}% "
385
- f"{Colors.WHITE}| "
386
412
  f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
387
413
  )
388
414
 
@@ -391,8 +417,7 @@ class M3U8_Segments:
391
417
  f"{Colors.YELLOW}[HLS] {Colors.WHITE}({Colors.CYAN}{description}{Colors.WHITE}): "
392
418
  f"{Colors.RED}{{percentage:.2f}}% "
393
419
  f"{Colors.MAGENTA}{{bar}} "
394
- f"{Colors.WHITE}[ {Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}] "
395
- f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
420
+ f"{Colors.YELLOW}{{elapsed}}{Colors.WHITE} < {Colors.CYAN}{{remaining}}{Colors.WHITE}{{postfix}}{Colors.WHITE}"
396
421
  )
397
422
 
398
423
  def _get_worker_count(self, stream_type: str) -> int:
@@ -429,8 +454,8 @@ class M3U8_Segments:
429
454
  writer_thread.join(timeout=30)
430
455
  progress_bar.close()
431
456
 
432
- if self.download_interrupted:
433
- console.print("\n[red]Download terminated by user")
457
+ #if self.download_interrupted:
458
+ # console.print("\n[red]Download terminated by user")
434
459
 
435
460
  if self.info_nFailed > 0:
436
461
  self._display_error_summary()