StreamingCommunity 2.0.5__tar.gz → 2.2.0__tar.gz

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 (107) hide show
  1. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/PKG-INFO +4 -1
  2. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/README.md +3 -0
  3. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/HLS/segments.py +2 -3
  4. StreamingCommunity-2.2.0/StreamingCommunity/Lib/M3U8/estimator.py +229 -0
  5. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Upload/version.py +1 -1
  6. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/ffmpeg_installer.py +8 -5
  7. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/PKG-INFO +4 -1
  8. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/setup.py +1 -1
  9. StreamingCommunity-2.0.5/StreamingCommunity/Lib/M3U8/estimator.py +0 -204
  10. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/MANIFEST.in +0 -0
  11. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/Helper/Vixcloud/js_parser.py +0 -0
  12. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/Helper/Vixcloud/util.py +0 -0
  13. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/ddl.py +0 -0
  14. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/maxstream.py +0 -0
  15. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/supervideo.py +0 -0
  16. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Player/vixcloud.py +0 -0
  17. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/1337xx/__init__.py +0 -0
  18. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/1337xx/costant.py +0 -0
  19. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/1337xx/site.py +0 -0
  20. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/1337xx/title.py +0 -0
  21. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/altadefinizione/__init__.py +0 -0
  22. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/altadefinizione/costant.py +0 -0
  23. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/altadefinizione/film.py +0 -0
  24. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/altadefinizione/site.py +0 -0
  25. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/animeunity/__init__.py +0 -0
  26. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/animeunity/costant.py +0 -0
  27. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/animeunity/film_serie.py +0 -0
  28. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/animeunity/site.py +0 -0
  29. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +0 -0
  30. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/cb01new/__init__.py +0 -0
  31. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/cb01new/costant.py +0 -0
  32. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/cb01new/film.py +0 -0
  33. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/cb01new/site.py +0 -0
  34. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +0 -0
  35. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -0
  36. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ddlstreamitaly/series.py +0 -0
  37. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ddlstreamitaly/site.py +0 -0
  38. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +0 -0
  39. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/guardaserie/__init__.py +0 -0
  40. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/guardaserie/costant.py +0 -0
  41. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/guardaserie/series.py +0 -0
  42. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/guardaserie/site.py +0 -0
  43. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +0 -0
  44. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +0 -0
  45. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -0
  46. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ilcorsaronero/site.py +0 -0
  47. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ilcorsaronero/title.py +0 -0
  48. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/ilcorsaronero/util/ilCorsarScraper.py +0 -0
  49. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/mostraguarda/__init__.py +0 -0
  50. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -0
  51. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/mostraguarda/film.py +0 -0
  52. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/__init__.py +0 -0
  53. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -0
  54. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/film.py +0 -0
  55. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/series.py +0 -0
  56. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/site.py +0 -0
  57. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +0 -0
  58. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/Class/SearchType.py +0 -0
  59. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/Util/__init__.py +0 -0
  60. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/Util/get_domain.py +0 -0
  61. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/Util/manage_ep.py +0 -0
  62. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/Util/recall_search.py +0 -0
  63. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/__init__.py +0 -0
  64. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Api/Template/site.py +0 -0
  65. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/HLS/downloader.py +0 -0
  66. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/HLS/proxyes.py +0 -0
  67. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/MP4/downloader.py +0 -0
  68. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/TOR/downloader.py +0 -0
  69. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/Downloader/__init__.py +0 -0
  70. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/FFmpeg/__init__.py +0 -0
  71. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/FFmpeg/capture.py +0 -0
  72. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/FFmpeg/command.py +0 -0
  73. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/FFmpeg/util.py +0 -0
  74. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/M3U8/__init__.py +0 -0
  75. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/M3U8/decryptor.py +0 -0
  76. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/M3U8/parser.py +0 -0
  77. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/M3U8/url_fixer.py +0 -0
  78. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/TMBD/__init__.py +0 -0
  79. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/TMBD/obj_tmbd.py +0 -0
  80. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Lib/TMBD/tmdb.py +0 -0
  81. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Upload/update.py +0 -0
  82. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/_jsonConfig.py +0 -0
  83. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/call_stack.py +0 -0
  84. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/color.py +0 -0
  85. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/console.py +0 -0
  86. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/headers.py +0 -0
  87. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/logger.py +0 -0
  88. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/message.py +0 -0
  89. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/os.py +0 -0
  90. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/Util/table.py +0 -0
  91. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/__init__.py +0 -0
  92. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity/run.py +0 -0
  93. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/SOURCES.txt +0 -0
  94. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/dependency_links.txt +0 -0
  95. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/entry_points.txt +0 -0
  96. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/requires.txt +0 -0
  97. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/StreamingCommunity.egg-info/top_level.txt +0 -0
  98. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Download/HLS.py +0 -0
  99. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Download/MP4.py +0 -0
  100. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Download/TOR.py +0 -0
  101. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Player/helper/vixcloud.py +0 -0
  102. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Player/maxtream.py +0 -0
  103. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Player/supervideo.py +0 -0
  104. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/Player/vixcloud.py +0 -0
  105. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/big_search.py +0 -0
  106. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/Test/call_updateDomain.py +0 -0
  107. {StreamingCommunity-2.0.5 → StreamingCommunity-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: StreamingCommunity
3
- Version: 2.0.5
3
+ Version: 2.2.0
4
4
  Summary: UNKNOWN
5
5
  Home-page: https://github.com/Lovi-0/StreamingCommunity
6
6
  Author: Lovi-0
@@ -288,6 +288,9 @@ Description: <p align="center">
288
288
  - `default_audio_workser`: Number of threads for audio download
289
289
  - `cleanup_tmp_folder`: Remove temporary .ts files after download
290
290
 
291
+ > [!IMPORTANT]
292
+ > Set `tqdm_use_large_bar` to `false` when using Termux or terminals with limited width to prevent display issues
293
+
291
294
 
292
295
  <br>
293
296
 
@@ -279,6 +279,9 @@ The configuration file is divided into several main sections:
279
279
  - `default_audio_workser`: Number of threads for audio download
280
280
  - `cleanup_tmp_folder`: Remove temporary .ts files after download
281
281
 
282
+ > [!IMPORTANT]
283
+ > Set `tqdm_use_large_bar` to `false` when using Termux or terminals with limited width to prevent display issues
284
+
282
285
 
283
286
  <br>
284
287
 
@@ -545,15 +545,14 @@ class M3U8_Segments:
545
545
  if file_size == 0:
546
546
  raise Exception("Output file is empty")
547
547
 
548
- # Display additional info only if there is failed segments
549
- if self.info_nFailed > 0:
548
+ # Display additional
549
+ if self.info_nRetry >= len(self.segments) * (1/3.33):
550
550
 
551
551
  # Get expected time
552
552
  ex_hours, ex_minutes, ex_seconds = format_duration(self.expected_real_time_s)
553
553
  ex_formatted_duration = f"[yellow]{int(ex_hours)}[red]h [yellow]{int(ex_minutes)}[red]m [yellow]{int(ex_seconds)}[red]s"
554
554
  console.print(f"[cyan]Max retry per URL[white]: [green]{self.info_maxRetry}[green] [white]| [cyan]Total retry done[white]: [green]{self.info_nRetry}[green] [white]| [cyan]Missing TS: [red]{self.info_nFailed} [white]| [cyan]Duration: {print_duration_table(self.tmp_file_path, None, True)} [white]| [cyan]Expected duation: {ex_formatted_duration} \n")
555
555
 
556
- if self.info_nRetry >= len(self.segments) * (1/3.33):
557
556
  console.print("[yellow]⚠ Warning:[/yellow] Too many retries detected! Consider reducing the number of [cyan]workers[/cyan] in the [magenta]config.json[/magenta] file. This will impact [bold]performance[/bold]. \n")
558
557
 
559
558
  # Info to return
@@ -0,0 +1,229 @@
1
+ # 21.04.25
2
+
3
+ import os
4
+ import time
5
+ import logging
6
+ import threading
7
+ from collections import deque
8
+
9
+
10
+ # External libraries
11
+ import psutil
12
+ from tqdm import tqdm
13
+
14
+
15
+ # Internal utilities
16
+ from StreamingCommunity.Util.color import Colors
17
+ from StreamingCommunity.Util.os import internet_manager
18
+ from StreamingCommunity.Util._jsonConfig import config_manager
19
+
20
+
21
+ # Variable
22
+ TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar')
23
+
24
+
25
+ class M3U8_Ts_Estimator:
26
+ def __init__(self, total_segments: int):
27
+ """
28
+ Initialize the M3U8_Ts_Estimator object.
29
+
30
+ Parameters:
31
+ - total_segments (int): Length of total segments to download.
32
+ """
33
+ self.ts_file_sizes = []
34
+ self.now_downloaded_size = 0
35
+ self.total_segments = total_segments
36
+ self.lock = threading.Lock()
37
+ self.speed = {"upload": "N/A", "download": "N/A"}
38
+ self.process_pid = os.getpid() # Get current process PID
39
+ logging.debug(f"Initializing M3U8_Ts_Estimator with PID: {self.process_pid}")
40
+
41
+ # Start the speed capture thread if TQDM_USE_LARGE_BAR is True
42
+ if TQDM_USE_LARGE_BAR:
43
+ logging.debug("TQDM_USE_LARGE_BAR is True, starting speed capture thread")
44
+ self.speed_thread = threading.Thread(target=self.capture_speed, args=(1, self.process_pid))
45
+ self.speed_thread.daemon = True
46
+ self.speed_thread.start()
47
+
48
+ else:
49
+ logging.debug("TQDM_USE_LARGE_BAR is False, speed capture thread not started")
50
+
51
+ def add_ts_file(self, size: int, size_download: int, duration: float):
52
+ """Add a file size to the list of file sizes."""
53
+ logging.debug(f"Adding ts file - size: {size}, download size: {size_download}, duration: {duration}")
54
+
55
+ if size <= 0 or size_download <= 0 or duration <= 0:
56
+ logging.error(f"Invalid input values: size={size}, size_download={size_download}, duration={duration}")
57
+ return
58
+
59
+ self.ts_file_sizes.append(size)
60
+ self.now_downloaded_size += size_download
61
+ logging.debug(f"Current total downloaded size: {self.now_downloaded_size}")
62
+
63
+ def capture_speed(self, interval: float = 1, pid: int = None):
64
+ """Capture the internet speed periodically."""
65
+ logging.debug(f"Starting speed capture with interval {interval}s for PID: {pid}")
66
+
67
+ def get_network_io(process=None):
68
+ try:
69
+ if process:
70
+
71
+ # For process-specific monitoring
72
+ connections = process.connections(kind='inet')
73
+ if connections:
74
+ io_counters = process.io_counters()
75
+ logging.debug(f"Process IO counters: {io_counters}")
76
+ return io_counters
77
+
78
+ else:
79
+ logging.debug("No active internet connections found for process")
80
+ return None
81
+ else:
82
+
83
+ # For system-wide monitoring
84
+ io_counters = psutil.net_io_counters()
85
+ logging.debug(f"System IO counters: {io_counters}")
86
+ return io_counters
87
+
88
+ except Exception as e:
89
+ logging.error(f"Error getting network IO: {str(e)}")
90
+ return None
91
+
92
+ try:
93
+ process = psutil.Process(pid) if pid else None
94
+ logging.debug(f"Monitoring process: {process}")
95
+
96
+ except Exception as e:
97
+ logging.error(f"Failed to get process with PID {pid}: {str(e)}")
98
+ process = None
99
+
100
+ last_upload = None
101
+ last_download = None
102
+ first_run = True
103
+
104
+ # Buffer circolare per le ultime N misurazioni
105
+ speed_buffer_size = 3
106
+ speed_buffer = deque(maxlen=speed_buffer_size)
107
+
108
+ while True:
109
+ try:
110
+ io_counters = get_network_io()
111
+
112
+ if io_counters:
113
+ current_upload = io_counters.bytes_sent
114
+ current_download = io_counters.bytes_recv
115
+
116
+ if not first_run and last_upload is not None and last_download is not None:
117
+
118
+ # Calcola la velocità istantanea
119
+ upload_speed = max(0, (current_upload - last_upload) / interval)
120
+ download_speed = max(0, (current_download - last_download) / interval)
121
+
122
+ # Aggiungi al buffer
123
+ speed_buffer.append(download_speed)
124
+
125
+ # Calcola la media mobile delle velocità
126
+ if len(speed_buffer) > 0:
127
+ avg_download_speed = sum(speed_buffer) / len(speed_buffer)
128
+
129
+ if avg_download_speed > 0:
130
+ with self.lock:
131
+ self.speed = {
132
+ "upload": internet_manager.format_transfer_speed(upload_speed),
133
+ "download": internet_manager.format_transfer_speed(avg_download_speed)
134
+ }
135
+ logging.debug(f"Updated speeds - Upload: {self.speed['upload']}, Download: {self.speed['download']}")
136
+
137
+ last_upload = current_upload
138
+ last_download = current_download
139
+ first_run = False
140
+
141
+ time.sleep(interval)
142
+ except Exception as e:
143
+ logging.error(f"Error in speed capture loop: {str(e)}")
144
+ logging.exception("Full traceback:")
145
+ logging.sleep(interval)
146
+
147
+ def get_average_speed(self) -> list:
148
+ """Calculate the average internet speed."""
149
+ with self.lock:
150
+ logging.debug(f"Current speed data: {self.speed}")
151
+ return self.speed['download'].split(" ")
152
+
153
+ def calculate_total_size(self) -> str:
154
+ """
155
+ Calculate the total size of the files.
156
+
157
+ Returns:
158
+ str: The mean size of the files in a human-readable format.
159
+ """
160
+ try:
161
+ if len(self.ts_file_sizes) == 0:
162
+ raise ValueError("No file sizes available to calculate total size.")
163
+
164
+ total_size = sum(self.ts_file_sizes)
165
+ mean_size = total_size / len(self.ts_file_sizes)
166
+
167
+ # Return formatted mean size
168
+ return internet_manager.format_file_size(mean_size)
169
+
170
+ except ZeroDivisionError as e:
171
+ logging.error("Division by zero error occurred: %s", e)
172
+ return "0B"
173
+
174
+ except Exception as e:
175
+ logging.error("An unexpected error occurred: %s", e)
176
+ return "Error"
177
+
178
+ def get_downloaded_size(self) -> str:
179
+ """
180
+ Get the total downloaded size formatted as a human-readable string.
181
+
182
+ Returns:
183
+ str: The total downloaded size as a human-readable string.
184
+ """
185
+ return internet_manager.format_file_size(self.now_downloaded_size)
186
+
187
+ def update_progress_bar(self, total_downloaded: int, duration: float, progress_counter: tqdm) -> None:
188
+ """Updates the progress bar with download information."""
189
+ try:
190
+ self.add_ts_file(total_downloaded * self.total_segments, total_downloaded, duration)
191
+
192
+ downloaded_file_size_str = self.get_downloaded_size()
193
+ file_total_size = self.calculate_total_size()
194
+
195
+ number_file_downloaded = downloaded_file_size_str.split(' ')[0]
196
+ number_file_total_size = file_total_size.split(' ')[0]
197
+ units_file_downloaded = downloaded_file_size_str.split(' ')[1]
198
+ units_file_total_size = file_total_size.split(' ')[1]
199
+
200
+ if TQDM_USE_LARGE_BAR:
201
+ speed_data = self.get_average_speed()
202
+ logging.debug(f"Speed data for progress bar: {speed_data}")
203
+
204
+ if len(speed_data) >= 2:
205
+ average_internet_speed = speed_data[0]
206
+ average_internet_unit = speed_data[1]
207
+
208
+ else:
209
+ logging.warning(f"Invalid speed data format: {speed_data}")
210
+ average_internet_speed = "N/A"
211
+ average_internet_unit = ""
212
+
213
+ progress_str = (
214
+ f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded} {Colors.WHITE}< "
215
+ f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
216
+ f"{Colors.WHITE}| {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit}"
217
+ )
218
+
219
+ else:
220
+ progress_str = (
221
+ f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded} {Colors.WHITE}< "
222
+ f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
223
+ )
224
+
225
+ progress_counter.set_postfix_str(progress_str)
226
+ logging.debug(f"Updated progress bar: {progress_str}")
227
+
228
+ except Exception as e:
229
+ logging.error(f"Error updating progress bar: {str(e)}")
@@ -1,5 +1,5 @@
1
1
  __title__ = 'StreamingCommunity'
2
- __version__ = '2.1.0'
2
+ __version__ = '2.2.0'
3
3
  __author__ = 'Lovi-0'
4
4
  __description__ = 'A command-line program to download film'
5
5
  __copyright__ = 'Copyright 2024'
@@ -140,6 +140,7 @@ class FFMPEGDownloader:
140
140
  break
141
141
  found_executables.append(found)
142
142
  else:
143
+
143
144
  # Original behavior for other operating systems
144
145
  for executable in executables:
145
146
  exe_paths = glob.glob(os.path.join(self.base_dir, executable))
@@ -298,13 +299,14 @@ def check_ffmpeg() -> Tuple[Optional[str], Optional[str], Optional[str]]:
298
299
 
299
300
  # Special handling for macOS
300
301
  if system_platform == 'darwin':
302
+
301
303
  # Common installation paths on macOS
302
304
  potential_paths = [
303
- '/usr/local/bin', # Homebrew default
304
- '/opt/homebrew/bin', # Apple Silicon Homebrew
305
- '/usr/bin', # System default
306
- os.path.expanduser('~/Applications/binary'), # Custom installation
307
- '/Applications/binary' # Custom installation
305
+ '/usr/local/bin', # Homebrew default
306
+ '/opt/homebrew/bin', # Apple Silicon Homebrew
307
+ '/usr/bin', # System default
308
+ os.path.expanduser('~/Applications/binary'), # Custom installation
309
+ '/Applications/binary' # Custom installation
308
310
  ]
309
311
 
310
312
  for path in potential_paths:
@@ -314,6 +316,7 @@ def check_ffmpeg() -> Tuple[Optional[str], Optional[str], Optional[str]]:
314
316
 
315
317
  if (os.path.exists(ffmpeg_path) and os.path.exists(ffprobe_path) and
316
318
  os.access(ffmpeg_path, os.X_OK) and os.access(ffprobe_path, os.X_OK)):
319
+
317
320
  # Return found executables, with ffplay being optional
318
321
  ffplay_path = ffplay_path if os.path.exists(ffplay_path) else None
319
322
  return ffmpeg_path, ffprobe_path, ffplay_path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: StreamingCommunity
3
- Version: 2.0.5
3
+ Version: 2.2.0
4
4
  Summary: UNKNOWN
5
5
  Home-page: https://github.com/Lovi-0/StreamingCommunity
6
6
  Author: Lovi-0
@@ -288,6 +288,9 @@ Description: <p align="center">
288
288
  - `default_audio_workser`: Number of threads for audio download
289
289
  - `cleanup_tmp_folder`: Remove temporary .ts files after download
290
290
 
291
+ > [!IMPORTANT]
292
+ > Set `tqdm_use_large_bar` to `false` when using Termux or terminals with limited width to prevent display issues
293
+
291
294
 
292
295
  <br>
293
296
 
@@ -10,7 +10,7 @@ with open("requirements.txt", "r", encoding="utf-8-sig") as f:
10
10
 
11
11
  setup(
12
12
  name="StreamingCommunity",
13
- version="2.0.5",
13
+ version="2.2.0",
14
14
  long_description=read_readme(),
15
15
  long_description_content_type="text/markdown",
16
16
  author="Lovi-0",
@@ -1,204 +0,0 @@
1
- import os
2
- import time
3
- import logging
4
- import threading
5
- from collections import deque
6
-
7
-
8
- # External libraries
9
- import psutil
10
- from tqdm import tqdm
11
-
12
-
13
- # Internal utilities
14
- from StreamingCommunity.Util.color import Colors
15
- from StreamingCommunity.Util.os import internet_manager
16
- from StreamingCommunity.Util._jsonConfig import config_manager
17
-
18
-
19
- # Variable
20
- TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar')
21
-
22
-
23
- class M3U8_Ts_Estimator:
24
- def __init__(self, total_segments: int):
25
- """
26
- Initialize the M3U8_Ts_Estimator object.
27
-
28
- Parameters:
29
- - total_segments (int): Length of total segments to download.
30
- """
31
- self.ts_file_sizes = []
32
- self.now_downloaded_size = 0
33
- self.total_segments = total_segments
34
- self.lock = threading.Lock()
35
- self.speed = {"upload": "N/A", "download": "N/A"}
36
-
37
- # Only start the speed capture thread if TQDM_USE_LARGE_BAR is True
38
- if not TQDM_USE_LARGE_BAR:
39
- self.speed_thread = threading.Thread(target=self.capture_speed)
40
- self.speed_thread.daemon = True
41
- self.speed_thread.start()
42
-
43
- def add_ts_file(self, size: int, size_download: int, duration: float):
44
- """
45
- Add a file size to the list of file sizes.
46
-
47
- Parameters:
48
- - size (int): The size of the ts file to be added.
49
- - size_download (int): Single size of the ts file.
50
- - duration (float): Time to download segment file.
51
- """
52
- if size <= 0 or size_download <= 0 or duration <= 0:
53
- logging.error("Invalid input values: size=%d, size_download=%d, duration=%f", size, size_download, duration)
54
- return
55
-
56
- # Add total size bytes
57
- self.ts_file_sizes.append(size)
58
- self.now_downloaded_size += size_download
59
-
60
- def capture_speed(self, interval: float = 1, pid: int = None):
61
- """
62
- Capture the internet speed periodically for a specific process (identified by PID)
63
- or the entire system if no PID is provided.
64
- """
65
-
66
- def get_network_io(process=None):
67
- """
68
- Get network I/O counters for a specific process or system-wide if no process is specified.
69
- """
70
- try:
71
- if process:
72
- io_counters = process.io_counters()
73
- return io_counters
74
- else:
75
- io_counters = psutil.net_io_counters()
76
- return io_counters
77
- except Exception as e:
78
- logging.warning(f"Unable to access network I/O counters: {e}")
79
- return None
80
-
81
- # If a PID is provided, attempt to attach to the corresponding process
82
- process = None
83
- if pid is not None:
84
- try:
85
- process = psutil.Process(pid)
86
- except psutil.NoSuchProcess:
87
- logging.error(f"Process with PID {pid} does not exist.")
88
- return
89
- except Exception as e:
90
- logging.error(f"Failed to attach to process with PID {pid}: {e}")
91
- return
92
-
93
- while True:
94
- old_value = get_network_io(process)
95
-
96
- if old_value is None: # If psutil fails, continue with the next interval
97
- time.sleep(interval)
98
- continue
99
-
100
- time.sleep(interval)
101
- new_value = get_network_io(process)
102
-
103
- if new_value is None: # Handle again if psutil fails in the next call
104
- time.sleep(interval)
105
- continue
106
-
107
- with self.lock:
108
-
109
- # Calculate speed based on process-specific counters if process is specified
110
- if process:
111
- upload_speed = (new_value.write_bytes - old_value.write_bytes) / interval
112
- download_speed = (new_value.read_bytes - old_value.read_bytes) / interval
113
-
114
- else:
115
- # System-wide counters
116
- upload_speed = (new_value.bytes_sent - old_value.bytes_sent) / interval
117
- download_speed = (new_value.bytes_recv - old_value.bytes_recv) / interval
118
-
119
- self.speed = {
120
- "upload": internet_manager.format_transfer_speed(upload_speed),
121
- "download": internet_manager.format_transfer_speed(download_speed)
122
- }
123
-
124
-
125
- def get_average_speed(self) -> float:
126
- """
127
- Calculate the average internet speed.
128
-
129
- Returns:
130
- float: The average internet speed in Mbps.
131
- """
132
- with self.lock:
133
- return self.speed['download'].split(" ")
134
-
135
- def calculate_total_size(self) -> str:
136
- """
137
- Calculate the total size of the files.
138
-
139
- Returns:
140
- str: The mean size of the files in a human-readable format.
141
- """
142
- try:
143
- if len(self.ts_file_sizes) == 0:
144
- raise ValueError("No file sizes available to calculate total size.")
145
-
146
- total_size = sum(self.ts_file_sizes)
147
- mean_size = total_size / len(self.ts_file_sizes)
148
-
149
- # Return formatted mean size
150
- return internet_manager.format_file_size(mean_size)
151
-
152
- except ZeroDivisionError as e:
153
- logging.error("Division by zero error occurred: %s", e)
154
- return "0B"
155
-
156
- except Exception as e:
157
- logging.error("An unexpected error occurred: %s", e)
158
- return "Error"
159
-
160
- def get_downloaded_size(self) -> str:
161
- """
162
- Get the total downloaded size formatted as a human-readable string.
163
-
164
- Returns:
165
- str: The total downloaded size as a human-readable string.
166
- """
167
- return internet_manager.format_file_size(self.now_downloaded_size)
168
-
169
- def update_progress_bar(self, total_downloaded: int, duration: float, progress_counter: tqdm) -> None:
170
- """
171
- Updates the progress bar with information about the TS segment download.
172
-
173
- Parameters:
174
- total_downloaded (int): The length of the content of the downloaded TS segment.
175
- duration (float): The duration of the segment download in seconds.
176
- progress_counter (tqdm): The tqdm object representing the progress bar.
177
- """
178
- # Add the size of the downloaded segment to the estimator
179
- self.add_ts_file(total_downloaded * self.total_segments, total_downloaded, duration)
180
-
181
- # Get downloaded size and total estimated size
182
- downloaded_file_size_str = self.get_downloaded_size()
183
- file_total_size = self.calculate_total_size()
184
-
185
- # Fix parameter for prefix
186
- number_file_downloaded = downloaded_file_size_str.split(' ')[0]
187
- number_file_total_size = file_total_size.split(' ')[0]
188
- units_file_downloaded = downloaded_file_size_str.split(' ')[1]
189
- units_file_total_size = file_total_size.split(' ')[1]
190
-
191
- # Update the progress bar's postfix
192
- if TQDM_USE_LARGE_BAR:
193
- average_internet_speed = self.get_average_speed()[0]
194
- average_internet_unit = self.get_average_speed()[1]
195
- progress_counter.set_postfix_str(
196
- f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded} {Colors.WHITE}< {Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
197
- f"{Colors.WHITE}| {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit}"
198
- )
199
-
200
- else:
201
- progress_counter.set_postfix_str(
202
- f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded}{Colors.RED} {units_file_downloaded} "
203
- f"{Colors.WHITE}| {Colors.CYAN}N/A{Colors.RED} N/A"
204
- )