StreamingCommunity 3.3.1__py3-none-any.whl → 3.3.3__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 (30) hide show
  1. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +28 -1
  2. StreamingCommunity/Api/Site/raiplay/site.py +6 -4
  3. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +6 -2
  4. StreamingCommunity/Api/Site/streamingcommunity/site.py +0 -3
  5. StreamingCommunity/Api/Site/streamingwatch/site.py +0 -3
  6. StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +1 -18
  7. StreamingCommunity/Lib/Downloader/DASH/downloader.py +18 -14
  8. StreamingCommunity/Lib/Downloader/HLS/downloader.py +22 -10
  9. StreamingCommunity/Lib/Downloader/HLS/segments.py +126 -72
  10. StreamingCommunity/Lib/M3U8/decryptor.py +0 -14
  11. StreamingCommunity/Lib/M3U8/estimator.py +44 -34
  12. StreamingCommunity/Lib/TMBD/tmdb.py +0 -12
  13. StreamingCommunity/Upload/update.py +1 -1
  14. StreamingCommunity/Upload/version.py +1 -1
  15. StreamingCommunity/Util/{bento4_installer.py → installer/bento4_install.py} +56 -44
  16. StreamingCommunity/Util/installer/binary_paths.py +83 -0
  17. StreamingCommunity/Util/installer/device_install.py +133 -0
  18. StreamingCommunity/Util/{ffmpeg_installer.py → installer/ffmpeg_install.py} +100 -138
  19. StreamingCommunity/Util/logger.py +3 -8
  20. StreamingCommunity/Util/os.py +34 -150
  21. StreamingCommunity/run.py +2 -3
  22. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/METADATA +295 -532
  23. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/RECORD +27 -28
  24. StreamingCommunity/Api/Player/ddl.py +0 -82
  25. StreamingCommunity/Api/Player/maxstream.py +0 -141
  26. StreamingCommunity/Api/Player/mixdrop.py +0 -146
  27. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/WHEEL +0 -0
  28. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/entry_points.txt +0 -0
  29. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/licenses/LICENSE +0 -0
  30. {streamingcommunity-3.3.1.dist-info → streamingcommunity-3.3.3.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,11 @@
1
1
  # 18.07.25
2
2
 
3
3
  import os
4
- import platform
5
- import logging
6
4
  import shutil
7
5
  import zipfile
6
+ import logging
7
+ import subprocess
8
+ from typing import Optional
8
9
 
9
10
 
10
11
  # External library
@@ -13,12 +14,15 @@ from rich.console import Console
13
14
  from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRemainingColumn
14
15
 
15
16
 
17
+ # Internal utilities
18
+ from .binary_paths import binary_paths
19
+
20
+
16
21
  # Variable
17
22
  console = Console()
18
23
 
19
24
  BENTO4_CONFIGURATION = {
20
25
  'windows': {
21
- 'base_dir': lambda home: os.path.join(os.path.splitdrive(home)[0] + os.sep, 'binary'),
22
26
  'download_url': 'https://www.bok.net/Bento4/binaries/Bento4-SDK-{version}.{platform}.zip',
23
27
  'versions': {
24
28
  'x64': 'x86_64-microsoft-win32',
@@ -27,7 +31,6 @@ BENTO4_CONFIGURATION = {
27
31
  'executables': ['mp4decrypt.exe']
28
32
  },
29
33
  'darwin': {
30
- 'base_dir': lambda home: os.path.join(home, 'Applications', 'binary'),
31
34
  'download_url': 'https://www.bok.net/Bento4/binaries/Bento4-SDK-{version}.{platform}.zip',
32
35
  'versions': {
33
36
  'x64': 'universal-apple-macosx',
@@ -36,7 +39,6 @@ BENTO4_CONFIGURATION = {
36
39
  'executables': ['mp4decrypt']
37
40
  },
38
41
  'linux': {
39
- 'base_dir': lambda home: os.path.join(home, '.local', 'bin', 'binary'),
40
42
  'download_url': 'https://www.bok.net/Bento4/binaries/Bento4-SDK-{version}.{platform}.zip',
41
43
  'versions': {
42
44
  'x64': 'x86_64-unknown-linux',
@@ -50,26 +52,11 @@ BENTO4_CONFIGURATION = {
50
52
 
51
53
  class Bento4Downloader:
52
54
  def __init__(self):
53
- self.os_name = platform.system().lower()
54
- self.arch = self._detect_arch()
55
- self.home_dir = os.path.expanduser('~')
56
- self.base_dir = BENTO4_CONFIGURATION[self.os_name]['base_dir'](self.home_dir)
55
+ self.os_name = binary_paths.system
56
+ self.arch = binary_paths.arch
57
+ self.home_dir = binary_paths.home_dir
58
+ self.base_dir = binary_paths.ensure_binary_directory()
57
59
  self.version = "1-6-0-641" # Latest stable version as of Nov 2023
58
- os.makedirs(self.base_dir, exist_ok=True)
59
-
60
- def _detect_arch(self) -> str:
61
- machine = platform.machine().lower()
62
- arch_map = {
63
- 'amd64': 'x64',
64
- 'x86_64': 'x64',
65
- 'x64': 'x64',
66
- 'arm64': 'arm64',
67
- 'aarch64': 'arm64',
68
- 'x86': 'x86',
69
- 'i386': 'x86',
70
- 'i686': 'x86'
71
- }
72
- return arch_map.get(machine, machine)
73
60
 
74
61
  def _download_file(self, url: str, destination: str) -> bool:
75
62
  try:
@@ -150,7 +137,6 @@ class Bento4Downloader:
150
137
  os.remove(zip_path)
151
138
 
152
139
  if extracted_files:
153
- console.print("[bold green]Bento4 successfully installed[/]")
154
140
  return extracted_files
155
141
 
156
142
  raise Exception("Failed to install Bento4")
@@ -160,32 +146,58 @@ class Bento4Downloader:
160
146
  console.print(f"[bold red]Error downloading Bento4: {str(e)}[/]")
161
147
  return []
162
148
 
163
- def check_mp4decrypt() -> str:
164
- """Check for mp4decrypt in the system and download if not found."""
149
+
150
+ def check_mp4decrypt() -> Optional[str]:
151
+ """
152
+ Check for mp4decrypt in the system and download if not found.
153
+ Order: system PATH (where/which) -> binary directory -> download
154
+
155
+ Returns:
156
+ Optional[str]: Path to mp4decrypt executable or None if not found/downloaded
157
+ """
165
158
  try:
166
- # First check if mp4decrypt is in PATH
167
- mp4decrypt = "mp4decrypt.exe" if platform.system().lower() == "windows" else "mp4decrypt"
168
- mp4decrypt_path = shutil.which(mp4decrypt)
159
+ system_platform = binary_paths.system
169
160
 
170
- if mp4decrypt_path:
171
- return mp4decrypt_path
172
-
173
- # If not found, check in binary directory
174
- downloader = Bento4Downloader()
175
- base_dir = downloader.base_dir
176
- local_path = os.path.join(base_dir, mp4decrypt)
161
+ # STEP 1: Check system PATH
162
+ console.print("[cyan]Checking for mp4decrypt in system PATH...[/]")
163
+ mp4decrypt_name = "mp4decrypt.exe" if system_platform == "windows" else "mp4decrypt"
164
+ mp4decrypt_path = None
177
165
 
178
- if os.path.exists(local_path):
166
+ if system_platform == 'windows':
167
+ try:
168
+ mp4decrypt_path = subprocess.check_output(
169
+ ['where', mp4decrypt_name], stderr=subprocess.DEVNULL, text=True
170
+ ).strip().split('\n')[0]
171
+
172
+ if mp4decrypt_path:
173
+ logging.info("mp4decrypt found in Windows system PATH")
174
+ return mp4decrypt_path
175
+
176
+ except subprocess.CalledProcessError:
177
+ logging.info("mp4decrypt not found in Windows system PATH")
178
+
179
+ else:
180
+ mp4decrypt_path = shutil.which(mp4decrypt_name)
181
+
182
+ if mp4decrypt_path:
183
+ logging.info("mp4decrypt found in system PATH")
184
+ return mp4decrypt_path
185
+
186
+ # STEP 2: Check in binary directory
187
+ console.print("[cyan]Checking for mp4decrypt in binary directory...[/]")
188
+ binary_dir = binary_paths.get_binary_directory()
189
+ local_path = os.path.join(binary_dir, mp4decrypt_name)
190
+
191
+ if os.path.exists(local_path) and os.access(local_path, os.X_OK):
192
+ logging.info("mp4decrypt found in binary directory")
179
193
  return local_path
180
194
 
181
- # Download if not found
195
+ # STEP 3: Download if not found
196
+ console.print("[cyan]mp4decrypt not found. Downloading...[/]")
197
+ downloader = Bento4Downloader()
182
198
  extracted_files = downloader.download()
183
199
  return extracted_files[0] if extracted_files else None
184
200
 
185
201
  except Exception as e:
186
202
  logging.error(f"Error checking or downloading mp4decrypt: {e}")
187
- return None
188
-
189
- except Exception as e:
190
- logging.error(f"Error checking or downloading mp4decrypt: {e}")
191
- return None
203
+ return None
@@ -0,0 +1,83 @@
1
+ # 19.09.25
2
+
3
+ import os
4
+ import platform
5
+
6
+
7
+ class BinaryPaths:
8
+ def __init__(self):
9
+ self.system = self._detect_system()
10
+ self.arch = self._detect_arch()
11
+ self.home_dir = os.path.expanduser('~')
12
+
13
+ def _detect_system(self) -> str:
14
+ """
15
+ Detect and normalize the operating system name.
16
+
17
+ Returns:
18
+ str: Normalized operating system name ('windows', 'darwin', or 'linux')
19
+
20
+ Raises:
21
+ ValueError: If the operating system is not supported
22
+ """
23
+ system = platform.system().lower()
24
+ supported_systems = ['windows', 'darwin', 'linux']
25
+
26
+ if system not in supported_systems:
27
+ raise ValueError(f"Unsupported operating system: {system}. Supported: {supported_systems}")
28
+
29
+ return system
30
+
31
+ def _detect_arch(self) -> str:
32
+ """
33
+ Detect and normalize the system architecture.
34
+
35
+ Returns:
36
+ str: Normalized architecture name
37
+ """
38
+ machine = platform.machine().lower()
39
+ arch_map = {
40
+ 'amd64': 'x64',
41
+ 'x86_64': 'x64',
42
+ 'x64': 'x64',
43
+ 'arm64': 'arm64',
44
+ 'aarch64': 'arm64',
45
+ 'armv7l': 'arm',
46
+ 'i386': 'ia32',
47
+ 'i686': 'ia32',
48
+ 'x86': 'x86'
49
+ }
50
+ return arch_map.get(machine, machine)
51
+
52
+ def get_binary_directory(self) -> str:
53
+ """
54
+ Get the binary directory path based on the operating system.
55
+
56
+ Returns:
57
+ str: Path to the binary directory
58
+ """
59
+ if self.system == 'windows':
60
+ return os.path.join(os.path.splitdrive(self.home_dir)[0] + os.path.sep, 'binary')
61
+
62
+ elif self.system == 'darwin':
63
+ return os.path.join(self.home_dir, 'Applications', 'binary')
64
+
65
+ else: # linux
66
+ return os.path.join(self.home_dir, '.local', 'bin', 'binary')
67
+
68
+ def ensure_binary_directory(self, mode: int = 0o755) -> str:
69
+ """
70
+ Create the binary directory if it doesn't exist and return its path.
71
+
72
+ Args:
73
+ mode (int, optional): Directory permissions. Defaults to 0o755.
74
+
75
+ Returns:
76
+ str: Path to the binary directory
77
+ """
78
+ binary_dir = self.get_binary_directory()
79
+ os.makedirs(binary_dir, mode=mode, exist_ok=True)
80
+ return binary_dir
81
+
82
+
83
+ binary_paths = BinaryPaths()
@@ -0,0 +1,133 @@
1
+ # 18.07.25
2
+
3
+ import os
4
+ import struct
5
+ import logging
6
+ from typing import Optional
7
+
8
+
9
+ # External library
10
+ from rich.console import Console
11
+
12
+
13
+ # Internal utilities
14
+ from .binary_paths import binary_paths
15
+
16
+
17
+ # Variable
18
+ console = Console()
19
+
20
+
21
+ class DeviceDownloader:
22
+ def __init__(self):
23
+ self.base_dir = binary_paths.ensure_binary_directory()
24
+
25
+ def extract_png_chunk(self, png_with_wvd: str, out_wvd_path: str) -> bool:
26
+ """Extract WVD data"""
27
+ try:
28
+ with open(png_with_wvd, "rb") as f:
29
+ data = f.read()
30
+ pos = 8
31
+
32
+ while pos < len(data):
33
+ length = struct.unpack(">I", data[pos:pos+4])[0]
34
+ chunk_type = data[pos+4:pos+8]
35
+ chunk_data = data[pos+8:pos+8+length]
36
+
37
+ if chunk_type == b"stEg":
38
+ with open(out_wvd_path, "wb") as f:
39
+ f.write(chunk_data)
40
+ return True
41
+
42
+ pos += 12 + length
43
+
44
+ return False
45
+
46
+ except Exception as e:
47
+ logging.error(f"Error extracting PNG chunk: {e}")
48
+ return False
49
+
50
+ def _check_existing_wvd(self) -> Optional[str]:
51
+ """Check for existing WVD files in binary directory."""
52
+ try:
53
+ console.print("[cyan]Checking for existing device.wvd files...")
54
+ if not os.path.exists(self.base_dir):
55
+ return None
56
+
57
+ # Look for any .wvd file first
58
+ for file in os.listdir(self.base_dir):
59
+ if file.lower().endswith('.wvd'):
60
+ wvd_path = os.path.join(self.base_dir, file)
61
+ if os.path.exists(wvd_path) and os.path.getsize(wvd_path) > 0:
62
+ logging.info(f"Found existing .wvd file: {file}")
63
+ return wvd_path
64
+
65
+ return None
66
+
67
+ except Exception as e:
68
+ logging.error(f"Error checking existing WVD files: {e}")
69
+ return None
70
+
71
+ def _find_png_recursively(self, start_dir: str = ".") -> Optional[str]:
72
+ """Find crunchyroll_etp_rt.png recursively starting from start_dir."""
73
+ target_filename = "crunchyroll_etp_rt.png"
74
+
75
+ try:
76
+ for root, dirs, files in os.walk(start_dir):
77
+ if target_filename in files:
78
+ png_path = os.path.join(root, target_filename)
79
+ logging.info(f"Found PNG file at: {png_path}")
80
+ return png_path
81
+
82
+ logging.warning(f"PNG file '{target_filename}' not found in '{start_dir}' and subdirectories")
83
+ return None
84
+
85
+ except Exception as e:
86
+ logging.error(f"Error during recursive PNG search: {e}")
87
+ return None
88
+
89
+ def download(self) -> Optional[str]:
90
+ """
91
+ Main method to extract WVD file from PNG.
92
+ """
93
+ try:
94
+ png_path = self._find_png_recursively()
95
+ if not png_path:
96
+ logging.error("PNG file not found, cannot extract device.wvd")
97
+ return None
98
+
99
+ device_wvd_path = os.path.join(self.base_dir, 'device.wvd')
100
+
101
+ if self.extract_png_chunk(png_path, device_wvd_path):
102
+ if os.path.exists(device_wvd_path) and os.path.getsize(device_wvd_path) > 0:
103
+ logging.info("Successfully extracted device.wvd from PNG")
104
+ return device_wvd_path
105
+ else:
106
+ logging.error("Extraction completed but resulting file is invalid")
107
+ return None
108
+ else:
109
+ logging.error("Failed to extract device.wvd from PNG")
110
+ return None
111
+
112
+ except Exception as e:
113
+ logging.error(f"Error during WVD extraction: {e}")
114
+ return None
115
+
116
+
117
+ def check_wvd_path() -> Optional[str]:
118
+ """
119
+ Check for device.wvd file in binary directory and extract from PNG if not found.
120
+ """
121
+ try:
122
+ downloader = DeviceDownloader()
123
+
124
+ existing_wvd = downloader._check_existing_wvd()
125
+ if existing_wvd:
126
+ return existing_wvd
127
+
128
+ logging.info("device.wvd not found, attempting extraction from PNG")
129
+ return downloader.download()
130
+
131
+ except Exception as e:
132
+ logging.error(f"Error checking for device.wvd: {e}")
133
+ return None