StreamingCommunity 2.9.8__py3-none-any.whl → 3.0.0__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 (67) hide show
  1. StreamingCommunity/Api/Player/ddl.py +2 -10
  2. StreamingCommunity/Api/Player/mediapolisvod.py +64 -0
  3. StreamingCommunity/Api/Player/sweetpixel.py +3 -3
  4. StreamingCommunity/Api/Player/vixcloud.py +4 -9
  5. StreamingCommunity/Api/Site/1337xx/__init__.py +2 -3
  6. StreamingCommunity/Api/Site/1337xx/site.py +6 -1
  7. StreamingCommunity/Api/Site/altadefinizione/__init__.py +24 -9
  8. StreamingCommunity/Api/Site/altadefinizione/film.py +0 -1
  9. StreamingCommunity/Api/Site/altadefinizione/series.py +66 -70
  10. StreamingCommunity/Api/Site/altadefinizione/site.py +8 -2
  11. StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +37 -2
  12. StreamingCommunity/Api/Site/animeunity/__init__.py +30 -12
  13. StreamingCommunity/Api/Site/animeunity/film.py +40 -0
  14. StreamingCommunity/Api/Site/animeunity/serie.py +153 -0
  15. StreamingCommunity/Api/Site/animeunity/site.py +64 -37
  16. StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +41 -22
  17. StreamingCommunity/Api/Site/animeworld/__init__.py +26 -14
  18. StreamingCommunity/Api/Site/animeworld/film.py +63 -0
  19. StreamingCommunity/Api/Site/animeworld/serie.py +25 -22
  20. StreamingCommunity/Api/Site/animeworld/site.py +8 -2
  21. StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +32 -5
  22. StreamingCommunity/Api/Site/cb01new/__init__.py +2 -3
  23. StreamingCommunity/Api/Site/cb01new/site.py +7 -1
  24. StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +2 -3
  25. StreamingCommunity/Api/Site/ddlstreamitaly/series.py +31 -32
  26. StreamingCommunity/Api/Site/ddlstreamitaly/site.py +8 -3
  27. StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +30 -2
  28. StreamingCommunity/Api/Site/guardaserie/__init__.py +22 -9
  29. StreamingCommunity/Api/Site/guardaserie/series.py +55 -53
  30. StreamingCommunity/Api/Site/guardaserie/site.py +10 -3
  31. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +27 -1
  32. StreamingCommunity/Api/Site/raiplay/__init__.py +92 -0
  33. StreamingCommunity/Api/Site/raiplay/film.py +65 -0
  34. StreamingCommunity/Api/Site/raiplay/series.py +162 -0
  35. StreamingCommunity/Api/Site/raiplay/site.py +173 -0
  36. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +127 -0
  37. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +30 -24
  38. StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -2
  39. StreamingCommunity/Api/Site/streamingcommunity/series.py +76 -90
  40. StreamingCommunity/Api/Site/streamingcommunity/site.py +8 -4
  41. StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +41 -15
  42. StreamingCommunity/Api/Template/site.py +2 -2
  43. StreamingCommunity/Lib/Downloader/HLS/downloader.py +1 -1
  44. StreamingCommunity/Lib/Downloader/HLS/segments.py +9 -18
  45. StreamingCommunity/Lib/Downloader/MP4/downloader.py +2 -1
  46. StreamingCommunity/Lib/Downloader/TOR/downloader.py +7 -14
  47. StreamingCommunity/Lib/FFmpeg/capture.py +1 -5
  48. StreamingCommunity/Lib/FFmpeg/util.py +57 -19
  49. StreamingCommunity/Lib/M3U8/estimator.py +57 -41
  50. StreamingCommunity/Lib/M3U8/parser.py +26 -6
  51. StreamingCommunity/Upload/update.py +22 -3
  52. StreamingCommunity/Upload/version.py +1 -1
  53. StreamingCommunity/Util/ffmpeg_installer.py +26 -1
  54. StreamingCommunity/Util/os.py +13 -15
  55. StreamingCommunity/Util/table.py +4 -2
  56. StreamingCommunity/global_search.py +1 -4
  57. StreamingCommunity/run.py +1 -4
  58. {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/METADATA +1 -1
  59. streamingcommunity-3.0.0.dist-info/RECORD +91 -0
  60. {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/WHEEL +1 -1
  61. StreamingCommunity/Api/Site/animeunity/film_serie.py +0 -181
  62. StreamingCommunity/Api/Site/mostraguarda/__init__.py +0 -73
  63. StreamingCommunity/Api/Site/mostraguarda/film.py +0 -93
  64. streamingcommunity-2.9.8.dist-info/RECORD +0 -85
  65. {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/entry_points.txt +0 -0
  66. {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/licenses/LICENSE +0 -0
  67. {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/top_level.txt +0 -0
@@ -132,31 +132,66 @@ def print_duration_table(file_path: str, description: str = "Duration", return_s
132
132
  def get_ffprobe_info(file_path):
133
133
  """
134
134
  Get format and codec information for a media file using ffprobe.
135
-
136
135
  Parameters:
137
136
  - file_path (str): Path to the media file.
138
-
139
137
  Returns:
140
138
  dict: A dictionary containing the format name and a list of codec names.
139
+ Returns None if file does not exist or ffprobe crashes.
141
140
  """
141
+ if not os.path.exists(file_path):
142
+ logging.error(f"File not found: {file_path}")
143
+ return None
144
+
145
+ # Get ffprobe path and verify it exists
146
+ ffprobe_path = get_ffprobe_path()
147
+ if not ffprobe_path or not os.path.exists(ffprobe_path):
148
+ logging.error(f"FFprobe not found at path: {ffprobe_path}")
149
+ return None
150
+
151
+ # Verify file permissions
152
+ try:
153
+ file_stat = os.stat(file_path)
154
+ logging.info(f"File permissions: {oct(file_stat.st_mode)}")
155
+ if not os.access(file_path, os.R_OK):
156
+ logging.error(f"No read permission for file: {file_path}")
157
+ return None
158
+ except OSError as e:
159
+ logging.error(f"Cannot access file {file_path}: {e}")
160
+ return None
161
+
142
162
  try:
163
+ cmd = [ffprobe_path, '-v', 'error', '-show_format', '-show_streams', '-print_format', 'json', file_path]
164
+ logging.info(f"Running FFprobe command: {' '.join(cmd)}")
165
+
166
+ # Use subprocess.run instead of Popen for better error handling
143
167
  result = subprocess.run(
144
- [get_ffprobe_path(), '-v', 'error', '-show_format', '-show_streams', '-print_format', 'json', file_path],
145
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True
168
+ cmd,
169
+ capture_output=True,
170
+ text=True,
171
+ check=False # Don't raise exception on non-zero exit
146
172
  )
147
- output = result.stdout
148
- info = json.loads(output)
149
-
150
- format_name = info['format']['format_name'] if 'format' in info else None
151
- codec_names = [stream['codec_name'] for stream in info['streams']] if 'streams' in info else []
152
-
153
- return {
154
- 'format_name': format_name,
155
- 'codec_names': codec_names
156
- }
157
-
173
+
174
+ if result.returncode != 0:
175
+ logging.error(f"FFprobe failed with return code {result.returncode}")
176
+ logging.error(f"FFprobe stderr: {result.stderr}")
177
+ logging.error(f"FFprobe stdout: {result.stdout}")
178
+ logging.error(f"Command: {' '.join(cmd)}")
179
+ logging.error(f"FFprobe path permissions: {oct(os.stat(ffprobe_path).st_mode)}")
180
+ return None
181
+
182
+ # Parse JSON output
183
+ try:
184
+ info = json.loads(result.stdout)
185
+ return {
186
+ 'format_name': info.get('format', {}).get('format_name'),
187
+ 'codec_names': [stream.get('codec_name') for stream in info.get('streams', [])]
188
+ }
189
+ except json.JSONDecodeError as e:
190
+ logging.error(f"Failed to parse FFprobe output: {e}")
191
+ return None
192
+
158
193
  except Exception as e:
159
- logging.error(f"Failed to parse JSON output from ffprobe for file {file_path}: {e}")
194
+ logging.error(f"FFprobe execution failed: {e}")
160
195
  return None
161
196
 
162
197
 
@@ -173,8 +208,11 @@ def is_png_format_or_codec(file_info):
173
208
  if not file_info:
174
209
  return False
175
210
 
176
- #console.print(f"[yellow][FFmpeg] [cyan]Avaiable codec[white]: [red]{file_info['codec_names']}")
177
- return file_info['format_name'] == 'png_pipe' or 'png' in file_info['codec_names']
211
+ # Handle None values in format_name gracefully
212
+ format_name = file_info.get('format_name')
213
+ codec_names = file_info.get('codec_names', [])
214
+
215
+ return format_name == 'png_pipe' or 'png' in codec_names
178
216
 
179
217
 
180
218
  def need_to_force_to_ts(file_path):
@@ -225,4 +263,4 @@ def check_duration_v_a(video_path, audio_path, tolerance=1.0):
225
263
  if duration_difference <= tolerance:
226
264
  return True, duration_difference
227
265
  else:
228
- return False, duration_difference
266
+ return False, duration_difference
@@ -1,6 +1,5 @@
1
1
  # 21.04.25
2
2
 
3
- import sys
4
3
  import time
5
4
  import logging
6
5
  import threading
@@ -14,7 +13,6 @@ from tqdm import tqdm
14
13
 
15
14
  # Internal utilities
16
15
  from StreamingCommunity.Util.color import Colors
17
- from StreamingCommunity.Util.config_json import get_use_large_bar
18
16
  from StreamingCommunity.Util.os import internet_manager
19
17
 
20
18
 
@@ -31,16 +29,16 @@ class M3U8_Ts_Estimator:
31
29
  self.segments_instance = segments_instance
32
30
  self.lock = threading.Lock()
33
31
  self.speed = {"upload": "N/A", "download": "N/A"}
32
+ self._running = True
33
+
34
+ self.speed_thread = threading.Thread(target=self.capture_speed)
35
+ self.speed_thread.daemon = True
36
+ self.speed_thread.start()
34
37
 
35
- if get_use_large_bar():
36
- logging.debug("USE_LARGE_BAR is True, starting speed capture thread")
37
- self.speed_thread = threading.Thread(target=self.capture_speed)
38
- self.speed_thread.daemon = True
39
- self.speed_thread.start()
40
-
41
- else:
42
- logging.debug("USE_LARGE_BAR is False, speed capture thread not started")
43
-
38
+ def __del__(self):
39
+ """Ensure thread is properly stopped when the object is destroyed."""
40
+ self._running = False
41
+
44
42
  def add_ts_file(self, size: int):
45
43
  """Add a file size to the list of file sizes."""
46
44
  if size <= 0:
@@ -50,32 +48,44 @@ class M3U8_Ts_Estimator:
50
48
  self.ts_file_sizes.append(size)
51
49
 
52
50
  def capture_speed(self, interval: float = 1.5):
53
- """Capture the internet speed periodically."""
51
+ """Capture the internet speed periodically with improved efficiency."""
54
52
  last_upload, last_download = 0, 0
55
53
  speed_buffer = deque(maxlen=3)
56
54
 
57
- while True:
55
+ while self._running:
58
56
  try:
57
+ # Get IO counters only once per loop to reduce function calls
59
58
  io_counters = psutil.net_io_counters()
60
59
  if not io_counters:
61
60
  raise ValueError("No IO counters available")
62
61
 
63
62
  current_upload, current_download = io_counters.bytes_sent, io_counters.bytes_recv
63
+
64
64
  if last_upload and last_download:
65
65
  upload_speed = (current_upload - last_upload) / interval
66
66
  download_speed = (current_download - last_download) / interval
67
- speed_buffer.append(max(0, download_speed))
68
67
 
68
+ # Only update buffer when we have valid data
69
+ if download_speed > 0:
70
+ speed_buffer.append(download_speed)
71
+
72
+ # Use a more efficient approach for thread synchronization
73
+ avg_speed = sum(speed_buffer) / len(speed_buffer) if speed_buffer else 0
74
+ formatted_upload = internet_manager.format_transfer_speed(max(0, upload_speed))
75
+ formatted_download = internet_manager.format_transfer_speed(avg_speed)
76
+
77
+ # Minimize lock time by preparing data outside the lock
69
78
  with self.lock:
70
79
  self.speed = {
71
- "upload": internet_manager.format_transfer_speed(max(0, upload_speed)),
72
- "download": internet_manager.format_transfer_speed(sum(speed_buffer) / len(speed_buffer))
80
+ "upload": formatted_upload,
81
+ "download": formatted_download
73
82
  }
74
- logging.debug(f"Updated speeds - Upload: {self.speed['upload']}, Download: {self.speed['download']}")
75
83
 
76
84
  last_upload, last_download = current_upload, current_download
85
+
77
86
  except Exception as e:
78
- logging.error(f"Error in speed capture: {str(e)}")
87
+ if self._running: # Only log if we're still supposed to be running
88
+ logging.error(f"Error in speed capture: {str(e)}")
79
89
  self.speed = {"upload": "N/A", "download": "N/A"}
80
90
 
81
91
  time.sleep(interval)
@@ -88,6 +98,10 @@ class M3U8_Ts_Estimator:
88
98
  str: The mean size of the files in a human-readable format.
89
99
  """
90
100
  try:
101
+ # Only do calculations if we have data
102
+ if not self.ts_file_sizes:
103
+ return "0 B"
104
+
91
105
  total_size = sum(self.ts_file_sizes)
92
106
  mean_size = total_size / len(self.ts_file_sizes)
93
107
  return internet_manager.format_file_size(mean_size)
@@ -101,32 +115,34 @@ class M3U8_Ts_Estimator:
101
115
  self.add_ts_file(total_downloaded * self.total_segments)
102
116
 
103
117
  file_total_size = self.calculate_total_size()
118
+ if file_total_size == "Error":
119
+ return
120
+
104
121
  number_file_total_size = file_total_size.split(' ')[0]
105
122
  units_file_total_size = file_total_size.split(' ')[1]
106
123
 
107
- if get_use_large_bar():
108
- speed_data = self.speed['download'].split(" ")
109
-
110
- if len(speed_data) >= 2:
111
- average_internet_speed = speed_data[0]
112
- average_internet_unit = speed_data[1]
113
- else:
114
- average_internet_speed = "N/A"
115
- average_internet_unit = ""
116
-
117
- retry_count = self.segments_instance.active_retries if self.segments_instance else 0
118
- progress_str = (
119
- f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
120
- f"{Colors.WHITE}, {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit}"
121
- f"{Colors.WHITE}, {Colors.GREEN}CRR {Colors.RED}{retry_count} "
122
- )
123
-
124
- else:
125
- retry_count = self.segments_instance.active_retries if self.segments_instance else 0
126
- progress_str = (
127
- f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
128
- f"{Colors.WHITE}, {Colors.GREEN}CRR {Colors.RED}{retry_count} "
129
- )
124
+ # Reduce lock contention by acquiring data with minimal synchronization
125
+ retry_count = 0
126
+ if self.segments_instance:
127
+ with self.segments_instance.active_retries_lock:
128
+ retry_count = self.segments_instance.active_retries
129
+
130
+ # Get speed data outside of any locks
131
+ speed_data = ["N/A", ""]
132
+ with self.lock:
133
+ download_speed = self.speed['download']
134
+
135
+ if download_speed != "N/A":
136
+ speed_data = download_speed.split(" ")
137
+
138
+ average_internet_speed = speed_data[0] if len(speed_data) >= 1 else "N/A"
139
+ average_internet_unit = speed_data[1] if len(speed_data) >= 2 else ""
140
+
141
+ progress_str = (
142
+ f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
143
+ f"{Colors.WHITE}, {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit} "
144
+ #f"{Colors.WHITE}, {Colors.GREEN}CRR {Colors.RED}{retry_count} "
145
+ )
130
146
 
131
147
  progress_counter.set_postfix_str(progress_str)
132
148
 
@@ -1,6 +1,6 @@
1
1
  # 20.04.25
2
2
 
3
- import sys
3
+ import re
4
4
  import logging
5
5
 
6
6
 
@@ -418,18 +418,38 @@ class M3U8_Parser:
418
418
  - uri (str): The URI containing video information.
419
419
 
420
420
  Returns:
421
- int: The video resolution if found, otherwise 0.
421
+ tuple: The video resolution (width, height) if found, otherwise (0, 0).
422
422
  """
423
-
424
423
  # Log
425
424
  logging.info(f"Try extract resolution from: {uri}")
426
-
425
+
426
+ # First try: Check for known resolutions
427
427
  for resolution in RESOLUTIONS:
428
428
  if "http" in str(uri):
429
429
  if str(resolution[1]) in uri:
430
430
  return resolution
431
-
432
- # Default resolution return (not best)
431
+
432
+ # Pattern to match common resolution formats like 854x480, 1280x720, etc.
433
+ resolution_patterns = [
434
+ r'(\d+)x(\d+)', # Match format: 854x480
435
+ r'(\d+)p', # Match format: 480p, 720p, etc.
436
+ r'_(\d+)x(\d+)' # Match format: _854x480
437
+ ]
438
+
439
+ for pattern in resolution_patterns:
440
+ matches = re.findall(pattern, uri)
441
+ if matches:
442
+ if len(matches[0]) == 2: # Format like 854x480
443
+ width, height = int(matches[0][0]), int(matches[0][1])
444
+ return (width, height)
445
+
446
+ elif len(matches[0]) == 1: # Format like 480p
447
+ height = int(matches[0])
448
+
449
+ # Estimate width based on common aspect ratios (16:9)
450
+ width = int(height * 16 / 9)
451
+ return (width, height)
452
+
433
453
  logging.warning("No resolution found with custom parsing.")
434
454
  return (0, 0)
435
455
 
@@ -43,6 +43,13 @@ def update():
43
43
  timeout=config_manager.get_int("REQUESTS", "timeout"),
44
44
  follow_redirects=True
45
45
  ).json()
46
+
47
+ response_commits = httpx.get(
48
+ url=f"https://api.github.com/repos/{__author__}/{__title__}/commits",
49
+ headers={'user-agent': get_userAgent()},
50
+ timeout=config_manager.get_int("REQUESTS", "timeout"),
51
+ follow_redirects=True
52
+ ).json()
46
53
 
47
54
  except Exception as e:
48
55
  console.print(f"[red]Error accessing GitHub API: {e}")
@@ -66,11 +73,23 @@ def update():
66
73
  else:
67
74
  percentual_stars = 0
68
75
 
69
- # Check installed version
70
- if str(__version__).replace('v', '') != str(last_version).replace('v', '') :
76
+ # Get the current version (installed version)
77
+ current_version = __version__
78
+
79
+ # Get commit details
80
+ latest_commit = response_commits[0] if response_commits else None
81
+ if latest_commit:
82
+ latest_commit_message = latest_commit.get('commit', {}).get('message', 'No commit message')
83
+ else:
84
+ latest_commit_message = 'No commit history available'
85
+
86
+ console.print(f"\n[cyan]Current installed version: [yellow]{current_version}")
87
+ console.print(f"[cyan]Last commit: [yellow]{latest_commit_message}")
88
+
89
+ if str(current_version).replace('v', '') != str(last_version).replace('v', ''):
71
90
  console.print(f"\n[cyan]New version available: [yellow]{last_version}")
72
91
 
73
92
  console.print(f"\n[red]{__title__} has been downloaded [yellow]{total_download_count} [red]times, but only [yellow]{percentual_stars}% [red]of users have starred it.\n\
74
93
  [cyan]Help the repository grow today by leaving a [yellow]star [cyan]and [yellow]sharing [cyan]it with others online!")
75
94
 
76
- time.sleep(3)
95
+ time.sleep(3)
@@ -1,5 +1,5 @@
1
1
  __title__ = 'StreamingCommunity'
2
- __version__ = '2.9.8'
2
+ __version__ = '3.0.0'
3
3
  __author__ = 'Arrowar'
4
4
  __description__ = 'A command-line program to download film'
5
5
  __copyright__ = 'Copyright 2024'
@@ -238,6 +238,31 @@ class FFMPEGDownloader:
238
238
  Returns:
239
239
  Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
240
240
  """
241
+ if self.os_name == 'linux':
242
+ try:
243
+ # Attempt to install FFmpeg using apt
244
+ console.print("[bold blue]Trying to install FFmpeg using 'sudo apt install ffmpeg'[/]")
245
+ result = subprocess.run(
246
+ ['sudo', 'apt', 'install', '-y', 'ffmpeg'],
247
+ stdout=subprocess.PIPE,
248
+ stderr=subprocess.PIPE,
249
+ text=True
250
+ )
251
+ if result.returncode == 0:
252
+ ffmpeg_path = shutil.which('ffmpeg')
253
+ ffprobe_path = shutil.which('ffprobe')
254
+
255
+ if ffmpeg_path and ffprobe_path:
256
+ console.print("[bold green]FFmpeg successfully installed via apt[/]")
257
+ return ffmpeg_path, ffprobe_path, None
258
+ else:
259
+ console.print("[bold yellow]Failed to install FFmpeg via apt. Proceeding with static download.[/]")
260
+
261
+ except Exception as e:
262
+ logging.error(f"Error during 'sudo apt install ffmpeg': {e}")
263
+ console.print("[bold red]Error during 'sudo apt install ffmpeg'. Proceeding with static download.[/]")
264
+
265
+ # Proceed with static download if apt installation fails or is not applicable
241
266
  config = FFMPEG_CONFIGURATION[self.os_name]
242
267
  executables = [exe.format(arch=self.arch) for exe in config['executables']]
243
268
  successful_extractions = []
@@ -346,4 +371,4 @@ def check_ffmpeg() -> Tuple[Optional[str], Optional[str], Optional[str]]:
346
371
 
347
372
  except Exception as e:
348
373
  logging.error(f"Error checking or downloading FFmpeg executables: {e}")
349
- return None, None, None
374
+ return None, None, None
@@ -4,7 +4,6 @@ import io
4
4
  import os
5
5
  import glob
6
6
  import sys
7
- import time
8
7
  import shutil
9
8
  import hashlib
10
9
  import logging
@@ -13,11 +12,9 @@ import inspect
13
12
  import subprocess
14
13
  import contextlib
15
14
  import importlib.metadata
16
- from pathlib import Path
17
15
 
18
16
 
19
17
  # External library
20
- import httpx
21
18
  from unidecode import unidecode
22
19
  from rich.console import Console
23
20
  from rich.prompt import Prompt
@@ -107,16 +104,14 @@ class OsManager:
107
104
  if not path:
108
105
  return path
109
106
 
110
- # Decode unicode characters
107
+ # Decode unicode characters and perform basic sanitization
111
108
  decoded = unidecode(path)
112
-
113
- # Basic path sanitization
114
109
  sanitized = sanitize_filepath(decoded)
115
110
 
116
111
  if self.system == 'windows':
117
112
  # Handle network paths (UNC or IP-based)
118
- if path.startswith('\\\\') or path.startswith('//'):
119
- parts = path.replace('/', '\\').split('\\')
113
+ if sanitized.startswith('\\\\') or sanitized.startswith('//'):
114
+ parts = sanitized.replace('/', '\\').split('\\')
120
115
  # Keep server/IP and share name as is
121
116
  sanitized_parts = parts[:4]
122
117
  # Sanitize remaining parts
@@ -129,9 +124,9 @@ class OsManager:
129
124
  return '\\'.join(sanitized_parts)
130
125
 
131
126
  # Handle drive letters
132
- elif len(path) >= 2 and path[1] == ':':
133
- drive = path[:2]
134
- rest = path[2:].lstrip('\\').lstrip('/')
127
+ elif len(sanitized) >= 2 and sanitized[1] == ':':
128
+ drive = sanitized[:2]
129
+ rest = sanitized[2:].lstrip('\\').lstrip('/')
135
130
  path_parts = [drive] + [
136
131
  self.get_sanitize_file(part)
137
132
  for part in rest.replace('/', '\\').split('\\')
@@ -141,12 +136,12 @@ class OsManager:
141
136
 
142
137
  # Regular path
143
138
  else:
144
- parts = path.replace('/', '\\').split('\\')
139
+ parts = sanitized.replace('/', '\\').split('\\')
145
140
  return '\\'.join(p for p in parts if p)
146
141
  else:
147
142
  # Handle Unix-like paths (Linux and macOS)
148
- is_absolute = path.startswith('/')
149
- parts = path.replace('\\', '/').split('/')
143
+ is_absolute = sanitized.startswith('/')
144
+ parts = sanitized.replace('\\', '/').split('/')
150
145
  sanitized_parts = [
151
146
  self.get_sanitize_file(part)
152
147
  for part in parts
@@ -357,12 +352,15 @@ class OsSummary:
357
352
  Exits with a message if not the official version.
358
353
  """
359
354
  python_implementation = platform.python_implementation()
355
+ python_version = platform.python_version()
360
356
 
361
357
  if python_implementation != "CPython":
362
358
  console.print(f"[bold red]Warning: You are using a non-official Python distribution: {python_implementation}.[/bold red]")
363
359
  console.print("Please install the official Python from [bold blue]https://www.python.org[/bold blue] and try again.", style="bold yellow")
364
360
  sys.exit(0)
365
361
 
362
+ console.print(f"[cyan]Python version: [bold red]{python_version}[/bold red]")
363
+
366
364
  def get_system_summary(self):
367
365
  self.check_python_version()
368
366
 
@@ -454,4 +452,4 @@ def get_ffmpeg_path():
454
452
 
455
453
  def get_ffprobe_path():
456
454
  """Returns the path of FFprobe."""
457
- return os_summary.ffprobe_path
455
+ return os_summary.ffprobe_path
@@ -158,7 +158,8 @@ class TVShowManager:
158
158
  else:
159
159
  key = Prompt.ask(prompt_msg)
160
160
  else:
161
- choices = [str(i) for i in range(max_int_input + 1)] + ["q", "quit", "b", "back"]
161
+ # Include empty string in choices to allow pagination with Enter key
162
+ choices = [""] + [str(i) for i in range(max_int_input + 1)] + ["q", "quit", "b", "back"]
162
163
  prompt_msg = "[cyan]Insert media [red]index"
163
164
  telegram_msg = "Scegli il contenuto da scaricare:\n Serie TV - Film - Anime\noppure `back` per tornare indietro"
164
165
 
@@ -199,7 +200,8 @@ class TVShowManager:
199
200
  else:
200
201
  key = Prompt.ask(prompt_msg)
201
202
  else:
202
- choices = [str(i) for i in range(max_int_input + 1)] + ["q", "quit", "b", "back"]
203
+ # Include empty string in choices to allow pagination with Enter key
204
+ choices = [""] + [str(i) for i in range(max_int_input + 1)] + ["q", "quit", "b", "back"]
203
205
  prompt_msg = "[cyan]Insert media [red]index"
204
206
  telegram_msg = "Scegli il contenuto da scaricare:\n Serie TV - Film - Anime\noppure `back` per tornare indietro"
205
207
 
@@ -57,11 +57,8 @@ def load_search_functions():
57
57
 
58
58
  # Get 'indice' from the module
59
59
  indice = getattr(mod, 'indice', 0)
60
- is_deprecate = bool(getattr(mod, '_deprecate', True))
61
60
  use_for = getattr(mod, '_useFor', 'other')
62
-
63
- if not is_deprecate:
64
- modules.append((module_name, indice, use_for))
61
+ modules.append((module_name, indice, use_for))
65
62
 
66
63
  except Exception as e:
67
64
  console.print(f"[red]Failed to import module {module_name}: {str(e)}")
StreamingCommunity/run.py CHANGED
@@ -90,11 +90,8 @@ def load_search_functions():
90
90
 
91
91
  # Get 'indice' from the module
92
92
  indice = getattr(mod, 'indice', 0)
93
- is_deprecate = bool(getattr(mod, '_deprecate', True))
94
93
  use_for = getattr(mod, '_useFor', 'other')
95
-
96
- if not is_deprecate:
97
- modules.append((module_name, indice, use_for))
94
+ modules.append((module_name, indice, use_for))
98
95
 
99
96
  except Exception as e:
100
97
  console.print(f"[red]Failed to import module {module_name}: {str(e)}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: StreamingCommunity
3
- Version: 2.9.8
3
+ Version: 3.0.0
4
4
  Home-page: https://github.com/Lovi-0/StreamingCommunity
5
5
  Author: Lovi-0
6
6
  Project-URL: Bug Reports, https://github.com/Lovi-0/StreamingCommunity/issues
@@ -0,0 +1,91 @@
1
+ StreamingCommunity/__init__.py,sha256=Cw-N0VCg7sef1WqdtvVwrhs1zc4LoUhs5C8k7vpM1lQ,207
2
+ StreamingCommunity/global_search.py,sha256=LgRTjVBJYyLiKYa3EIb33vRnVQ-COoQT7gASfVW8-Dg,12022
3
+ StreamingCommunity/run.py,sha256=xBq2GS3JznLZBAF5DnJplNtJBzqOl_zHQXVmXxDMnBs,13108
4
+ StreamingCommunity/Api/Player/ddl.py,sha256=S3UZFonJl3d3xU1fQrosRFXFhwAm8hGVQ8Ff8g-6xSI,2071
5
+ StreamingCommunity/Api/Player/maxstream.py,sha256=WXg8xncFXFiaUmTVXxB3NyknQtbvd0sF1eRaoDO24bU,4822
6
+ StreamingCommunity/Api/Player/mediapolisvod.py,sha256=OcdnE1BMSwPZM-nw74GXNJ44E9RYwGnc_kFEA-G8XyY,2294
7
+ StreamingCommunity/Api/Player/supervideo.py,sha256=hr9QViI-XD0Dqhcx90oaH8_j0d6cxpVaf-EuCjMs6hI,5199
8
+ StreamingCommunity/Api/Player/sweetpixel.py,sha256=gJSe1fop5J216CB3u8vstxLPP5YbcyoGUH4y3X3-JaQ,1643
9
+ StreamingCommunity/Api/Player/vixcloud.py,sha256=qI9ppYEMGaJ1B5y693BOMeRQri-F4-94SfRkS-9udfM,6287
10
+ StreamingCommunity/Api/Player/Helper/Vixcloud/js_parser.py,sha256=U-8QlD5kGzIk3-4t4D6QyYmiDe8UBrSuVi1YHRQb7AU,4295
11
+ StreamingCommunity/Api/Player/Helper/Vixcloud/util.py,sha256=QLUgbwQrpuPIVNzdBlAiEJXnd-eCj_JQFckZZEEL55w,5214
12
+ StreamingCommunity/Api/Site/1337xx/__init__.py,sha256=OdQxYoJ9UyGSAutZwqH1FgmOH-Z6vGVHb0CLKhwEZGM,1999
13
+ StreamingCommunity/Api/Site/1337xx/site.py,sha256=lwpZt8ALBd9_ImuFWKrRx6KCIqPmDMdqZCM-n-pxvGI,2283
14
+ StreamingCommunity/Api/Site/1337xx/title.py,sha256=8T3cVRb-Mt9QdOtKWVVFHz8iOHqspf7iw28E7bfTV78,1865
15
+ StreamingCommunity/Api/Site/altadefinizione/__init__.py,sha256=Oxjfyg6VolwV6n2VGgICLvdRVPPMzJXMSdz8oI2Xs0M,4145
16
+ StreamingCommunity/Api/Site/altadefinizione/film.py,sha256=0XeqMrMHnk5nbFkVTFaNZWtlXI8pETl7dsORDtIMbjg,4395
17
+ StreamingCommunity/Api/Site/altadefinizione/series.py,sha256=-rCYx-Fa7aZiYepcIne7OdH1aaUFZZAPX-ToBv6mxFs,8192
18
+ StreamingCommunity/Api/Site/altadefinizione/site.py,sha256=S-ucgLNXUYZPjgSNjEYVxlkpMkJyjpr7mYf_jBcYwqM,2860
19
+ StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py,sha256=bSApjfY9xd5dw0tZ1t7vB6ifAo5vAkeeEwX6IS7yH1o,3756
20
+ StreamingCommunity/Api/Site/animeunity/__init__.py,sha256=EayZqxyWltgjRRDNfM32JRzgeyElK85o6s0_YJ0dpBk,4031
21
+ StreamingCommunity/Api/Site/animeunity/film.py,sha256=Vqg6yag2siR-Y3ougBsV8mzdQXChxg6ghz_KVXFQ3pE,998
22
+ StreamingCommunity/Api/Site/animeunity/serie.py,sha256=ib86sLXYsYbrvrFNbzKdhlwMUO3DT7JS5yTTrrSr2jk,5711
23
+ StreamingCommunity/Api/Site/animeunity/site.py,sha256=KLBQ08TAMyzsrZ3SAxw8hZefreCtZAuU1KwEbaJnUAE,5646
24
+ StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py,sha256=9q108tS2St3ogR73nGZhMlCTHoZH-taE_CTBC6LY6d0,3374
25
+ StreamingCommunity/Api/Site/animeworld/__init__.py,sha256=UzHQbfxx_i6qzM586LL940CoiI3Y98IGIVP4-hXUxn4,2790
26
+ StreamingCommunity/Api/Site/animeworld/film.py,sha256=W9KOS9Wvx3Mlqx5WojR-NgnF9WX8mI79JZPS7UwG-dc,1763
27
+ StreamingCommunity/Api/Site/animeworld/serie.py,sha256=MXyV1fK05jPW4iV9NWrRKW-R4ect-TSN78-2APayniU,3516
28
+ StreamingCommunity/Api/Site/animeworld/site.py,sha256=1Ah4CmKXdqsoCGTbyPRSVJRAxtcW449kpBnPKnzR1K8,3650
29
+ StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py,sha256=CBTCH_wnTXUK_MKwq9a1k_XdvOlUrMpbUmpkD5fXVQ0,3589
30
+ StreamingCommunity/Api/Site/cb01new/__init__.py,sha256=fy0dPL0NnZxSz3UL_i_zE809Rus7-ZI60WsXq9S4NUs,2039
31
+ StreamingCommunity/Api/Site/cb01new/film.py,sha256=vjd1ftm4LhxxG0TTKEwlOXtx0AYgxBbV5ZlQH8aSxGU,1695
32
+ StreamingCommunity/Api/Site/cb01new/site.py,sha256=ROT3yh6mpC85qHJAvPkWply91tFd8-V7ayX_3KsdtR4,2152
33
+ StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py,sha256=2FGeGNJ5SHPQzKEEmVMFWft4woGgJ-XLeNxjbSb6L9s,2141
34
+ StreamingCommunity/Api/Site/ddlstreamitaly/series.py,sha256=F_D_2lwHHWN5hgLs8oUDNCYe-4SEPtWzJoU4yT_Nzfg,3726
35
+ StreamingCommunity/Api/Site/ddlstreamitaly/site.py,sha256=hspimNOnIkLdJMrYLgXHmXepLz_mu8z257camnlGfaI,2596
36
+ StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py,sha256=tETaN-2GyFBeRsoLnGw3Kz4D4j2TMcnPzGjzlC62w_Y,3655
37
+ StreamingCommunity/Api/Site/guardaserie/__init__.py,sha256=p5hzqshw5hwDl9nJ8FBWbzfPe2j7c5eNYiaftDThGcU,2768
38
+ StreamingCommunity/Api/Site/guardaserie/series.py,sha256=U9rMZCjRqHLFjo468vikxl-2RqO6DCJjebB-G8Y6LDg,6492
39
+ StreamingCommunity/Api/Site/guardaserie/site.py,sha256=DrtHD365Ezh3GGcluvTIJxWYSjhaJpiY1w6pg4M1odw,2321
40
+ StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py,sha256=_aXU-YcUtSwbC2b6QpNnWDZR8m6vp9xzBEx_zdu5tgI,4196
41
+ StreamingCommunity/Api/Site/raiplay/__init__.py,sha256=xkxVkFsSxA6DHRqPuzQYXnCVNUBhfUG5xxlz6iwf1mw,3132
42
+ StreamingCommunity/Api/Site/raiplay/film.py,sha256=wBv5kQXx7-aCKhAZ5LABZ8zUzu_jPGdXOl9OM2p8dpY,1982
43
+ StreamingCommunity/Api/Site/raiplay/series.py,sha256=uQVbeA_g3Z1Ciqeq99gsY2F8mC5DssH3ueGbCW8gd9Q,6161
44
+ StreamingCommunity/Api/Site/raiplay/site.py,sha256=FtIR_oT-ag1sh5XnaOAhEOE8biHZmXtZnsFAjKszU8U,5154
45
+ StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py,sha256=5F6abToCTtsvW8iIACbChZ0fPlymJiCSF_y8FRsDu7M,5002
46
+ StreamingCommunity/Api/Site/streamingcommunity/__init__.py,sha256=Ej-xZ6x99zeq3p5O7-e_Evi_529x3eq_VryBLejCBiA,3796
47
+ StreamingCommunity/Api/Site/streamingcommunity/film.py,sha256=TPt0yB1DKShDIz_1OEVG1IolMoAKBOaWIZ8lQF61dfM,2575
48
+ StreamingCommunity/Api/Site/streamingcommunity/series.py,sha256=jWwgawBovZkL7pafvd55L68AMAy7ZyvCPNZdh72bqq8,8859
49
+ StreamingCommunity/Api/Site/streamingcommunity/site.py,sha256=nKII_DjKN1ePeYdMn4titYgvPRMbm8PmEXIM6npGkeI,3129
50
+ StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py,sha256=3sNz9uD-o9xz0dKpSnQsLPC_45v5fnW9Mzas2rQ8-Uc,5579
51
+ StreamingCommunity/Api/Template/__init__.py,sha256=oyfd_4_g5p5q6mxb_rKwSsudZnTM3W3kg1tLwxg-v-Q,46
52
+ StreamingCommunity/Api/Template/config_loader.py,sha256=2RT_0mqQmWzXM4rYaqss-yhXztYAcfNkTalFPjzv270,2056
53
+ StreamingCommunity/Api/Template/site.py,sha256=BJjQktdu2q2pkGflJv3UdrpSEmzJCJnaT-u-jD5zhgs,2861
54
+ StreamingCommunity/Api/Template/Class/SearchType.py,sha256=LOlE8UgraEM0UAVeNCThDGi8bleei31p7KpryuZm3VE,2530
55
+ StreamingCommunity/Api/Template/Util/__init__.py,sha256=ZWQQd6iymNFDol9HaKPhVBoRX1W-xHJZgU_mZvLVdsM,196
56
+ StreamingCommunity/Api/Template/Util/manage_ep.py,sha256=FYe2DC9SXIXzlRYI7fW4ieBpfrxYzsUgt2C47tYRk7U,9252
57
+ StreamingCommunity/Lib/Downloader/__init__.py,sha256=JhbBh5hOnSM7VmtkxJ7zZ_FtWEC1JdnKThsSBjLV5FY,140
58
+ StreamingCommunity/Lib/Downloader/HLS/downloader.py,sha256=wlujaWn5I5KtP0m61iYExtnEhwmsy_jdFqd9cM1A-2E,21588
59
+ StreamingCommunity/Lib/Downloader/HLS/segments.py,sha256=Q_YZxkWfUqd6TRkHoYt58Iy-xMWVLH6fCnBnQImQK2I,18059
60
+ StreamingCommunity/Lib/Downloader/MP4/downloader.py,sha256=L03fpjaJ2pvZ_McaOShv3iCsdbefCGW3WM1QIa2TGJo,7514
61
+ StreamingCommunity/Lib/Downloader/TOR/downloader.py,sha256=CrRGdLGI_45AnhtTZm8r7KO7uGmU9k6pywy-qO18LG8,19242
62
+ StreamingCommunity/Lib/FFmpeg/__init__.py,sha256=6PBsZdE1jrD2EKOVyx3JEHnyDZzVeKlPkH5T0zyfOgU,130
63
+ StreamingCommunity/Lib/FFmpeg/capture.py,sha256=QZYtuUG3L5_BsHFdzBU-5pZrX1PYxfCTx8bXShGF_bs,5029
64
+ StreamingCommunity/Lib/FFmpeg/command.py,sha256=ubpffE02nsZM7xch5gbwGlEiUzecpxcFOd63n2cqM1k,10708
65
+ StreamingCommunity/Lib/FFmpeg/util.py,sha256=byM5DzAA-8Ts0FtviEPfbFJKN_PuxVFGjELgD_FEhsk,9287
66
+ StreamingCommunity/Lib/M3U8/__init__.py,sha256=H_KS2eDd3kVXMziFJnD0FCPvPHEizaqfoA36ElTv_r8,170
67
+ StreamingCommunity/Lib/M3U8/decryptor.py,sha256=kuxxsd3eN0VGRrMJWXzHo8gCpT0u3fSZs_lwxlE5Fqs,2948
68
+ StreamingCommunity/Lib/M3U8/estimator.py,sha256=8gwTxJ3poRqZdHUTD9_oqXegiPWSXFuqLmqCZBnXS8A,5893
69
+ StreamingCommunity/Lib/M3U8/parser.py,sha256=cSjXPOSgTewrfLgREyQ47wzoOeoYo3L4lOfEWZKxad8,22485
70
+ StreamingCommunity/Lib/M3U8/url_fixer.py,sha256=zldE4yOuNBV6AAvL1KI6p7XdRI_R5YZRscbDgT1564M,1735
71
+ StreamingCommunity/Lib/TMBD/__init__.py,sha256=XzE42tw3Ws59DD1PF8WmGtZ0D4D7Hk3Af8QthNE-22U,66
72
+ StreamingCommunity/Lib/TMBD/obj_tmbd.py,sha256=dRSvJFS5yqmsBZcw2wqbStcBtXNjU_3n5czMyremAtU,1187
73
+ StreamingCommunity/Lib/TMBD/tmdb.py,sha256=byg0EFnlmd9JeLvn1N9K3QkB1KEfeMuFa7OVfGqks1Y,10685
74
+ StreamingCommunity/TelegramHelp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
+ StreamingCommunity/TelegramHelp/telegram_bot.py,sha256=Qe1__aoK4PpDuing8JtWgdHzLee8LuYYyfeLNA7yADU,26307
76
+ StreamingCommunity/Upload/update.py,sha256=mJTKUIOhC2j03sWXUK6oAZxHyObNP2r1fl3y0BC2jes,3351
77
+ StreamingCommunity/Upload/version.py,sha256=w7FJx8AjjjVxIMxI1IxHS70oEvmUKg7KBImjlhijaMI,171
78
+ StreamingCommunity/Util/color.py,sha256=NvD0Eni-25oOOkY-szCEoc0lGvzQxyL7xhM0RE4EvUM,458
79
+ StreamingCommunity/Util/config_json.py,sha256=xiE5JNw9HgbBdBqKhlywwWw1EnoyDdG47wcxFDTC8sA,24960
80
+ StreamingCommunity/Util/ffmpeg_installer.py,sha256=yRVIPwbh05tZ-duZmXkH0qasLNxaQCAT_E4cTP79Z3c,14890
81
+ StreamingCommunity/Util/headers.py,sha256=TItkaFMx1GqsVNEIS3Tr0BGU5EHyF-HkZVliHORT3P8,308
82
+ StreamingCommunity/Util/logger.py,sha256=9kGD6GmWj2pM8ADpJc85o7jm8DD0c5Aguqnq-9kmxos,3314
83
+ StreamingCommunity/Util/message.py,sha256=SJaIPLvWeQqsIODVUKw3TgYRmBChovmlbcF6OUxqMI8,1425
84
+ StreamingCommunity/Util/os.py,sha256=0AD2DYoan9dl1ZC1pjDoUM7D8sRa9p81cGdI-lP1OX4,14993
85
+ StreamingCommunity/Util/table.py,sha256=Nw5PlsvfEIOQZWy5VhsU5OK3heuBXGwsqmLl0k8yQzc,9813
86
+ streamingcommunity-3.0.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
87
+ streamingcommunity-3.0.0.dist-info/METADATA,sha256=OwSAYErIcsUYH-VDC9VlXEpNByWJpCBCCZgC-vMu5UY,25012
88
+ streamingcommunity-3.0.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
89
+ streamingcommunity-3.0.0.dist-info/entry_points.txt,sha256=Qph9XYfDC8n4LfDLOSl6gJGlkb9eFb5f-JOr_Wb_5rk,67
90
+ streamingcommunity-3.0.0.dist-info/top_level.txt,sha256=YsOcxKP-WOhWpIWgBlh0coll9XUx7aqmRPT7kmt3fH0,19
91
+ streamingcommunity-3.0.0.dist-info/RECORD,,