StreamingCommunity 2.5.7__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.
- StreamingCommunity/Api/Player/ddl.py +2 -3
- StreamingCommunity/Api/Site/1337xx/__init__.py +5 -6
- StreamingCommunity/Api/Site/1337xx/site.py +7 -14
- StreamingCommunity/Api/Site/1337xx/title.py +3 -5
- StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +7 -6
- StreamingCommunity/Api/Site/altadefinizionegratis/film.py +14 -19
- StreamingCommunity/Api/Site/altadefinizionegratis/site.py +6 -14
- StreamingCommunity/Api/Site/animeunity/__init__.py +7 -7
- StreamingCommunity/Api/Site/animeunity/film_serie.py +29 -31
- StreamingCommunity/Api/Site/animeunity/site.py +14 -22
- StreamingCommunity/Api/Site/cb01new/__init__.py +5 -4
- StreamingCommunity/Api/Site/cb01new/film.py +2 -5
- StreamingCommunity/Api/Site/cb01new/site.py +5 -13
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +5 -4
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +12 -49
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +6 -16
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +2 -3
- StreamingCommunity/Api/Site/guardaserie/__init__.py +5 -4
- StreamingCommunity/Api/Site/guardaserie/series.py +11 -46
- StreamingCommunity/Api/Site/guardaserie/site.py +5 -13
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +10 -14
- StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +5 -4
- StreamingCommunity/Api/Site/ilcorsaronero/site.py +5 -13
- StreamingCommunity/Api/Site/ilcorsaronero/title.py +3 -5
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +2 -2
- StreamingCommunity/Api/Site/mostraguarda/film.py +4 -8
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +8 -7
- StreamingCommunity/Api/Site/streamingcommunity/film.py +14 -18
- StreamingCommunity/Api/Site/streamingcommunity/series.py +25 -76
- StreamingCommunity/Api/Site/streamingcommunity/site.py +11 -23
- StreamingCommunity/Api/Template/Util/__init__.py +8 -1
- StreamingCommunity/Api/Template/Util/manage_ep.py +46 -2
- StreamingCommunity/Api/Template/config_loader.py +71 -0
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +60 -59
- StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -14
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +47 -40
- StreamingCommunity/Lib/FFmpeg/command.py +59 -3
- StreamingCommunity/Lib/M3U8/estimator.py +5 -5
- StreamingCommunity/Lib/M3U8/parser.py +12 -51
- StreamingCommunity/Lib/TMBD/tmdb.py +66 -99
- StreamingCommunity/TelegramHelp/telegram_bot.py +222 -68
- StreamingCommunity/Util/_jsonConfig.py +14 -13
- StreamingCommunity/Util/ffmpeg_installer.py +70 -64
- StreamingCommunity/Util/headers.py +11 -122
- StreamingCommunity/Util/os.py +64 -55
- StreamingCommunity/Util/table.py +62 -108
- StreamingCommunity/run.py +15 -10
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/METADATA +56 -22
- StreamingCommunity-2.5.8.dist-info/RECORD +86 -0
- StreamingCommunity/Api/Site/1337xx/costant.py +0 -15
- StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +0 -21
- StreamingCommunity/Api/Site/animeunity/costant.py +0 -21
- StreamingCommunity/Api/Site/cb01new/costant.py +0 -19
- StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -20
- StreamingCommunity/Api/Site/guardaserie/costant.py +0 -19
- StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -19
- StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -19
- StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -21
- StreamingCommunity/TelegramHelp/request_manager.py +0 -82
- StreamingCommunity/TelegramHelp/session.py +0 -56
- StreamingCommunity-2.5.7.dist-info/RECORD +0 -96
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/LICENSE +0 -0
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/top_level.txt +0 -0
|
@@ -1,104 +1,24 @@
|
|
|
1
1
|
# 4.04.24
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
|
-
import sys
|
|
5
3
|
import random
|
|
6
|
-
from importlib.metadata import version, PackageNotFoundError
|
|
7
4
|
|
|
8
5
|
|
|
9
6
|
# External library
|
|
10
|
-
|
|
7
|
+
import ua_generator
|
|
11
8
|
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
ua_version = version('fake-useragent')
|
|
16
|
-
except PackageNotFoundError:
|
|
17
|
-
ua_version = None
|
|
18
|
-
|
|
19
|
-
if not getattr(sys, 'frozen', False):
|
|
20
|
-
if ua_version == '1.1.3':
|
|
21
|
-
ua = UserAgent(use_external_data=True)
|
|
22
|
-
else:
|
|
23
|
-
ua = UserAgent()
|
|
24
|
-
else:
|
|
25
|
-
ua = UserAgent()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def extract_versions(user_agent):
|
|
29
|
-
"""
|
|
30
|
-
Extract browser versions from the user agent.
|
|
31
|
-
|
|
32
|
-
Parameters:
|
|
33
|
-
user_agent (str): User agent of the browser.
|
|
34
|
-
|
|
35
|
-
Returns:
|
|
36
|
-
list: List of browser versions.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
# Patterns to extract versions from various user agents
|
|
40
|
-
patterns = {
|
|
41
|
-
'chrome': re.compile(r'Chrome/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
42
|
-
'firefox': re.compile(r'Firefox/(\d+)\.?(\d+)?\.?(\d+)?'),
|
|
43
|
-
'safari': re.compile(r'Version/(\d+)\.(\d+)\.(\d+) Safari/(\d+)\.(\d+)\.(\d+)'),
|
|
44
|
-
'edge': re.compile(r'Edg/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
45
|
-
'edgios': re.compile(r'EdgiOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
46
|
-
'crios': re.compile(r'CriOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for key, pattern in patterns.items():
|
|
50
|
-
match = pattern.search(user_agent)
|
|
51
|
-
if match:
|
|
52
|
-
return [match.group(i+1) for i in range(match.lastindex)]
|
|
53
|
-
|
|
54
|
-
# Fallback values if specific versions are not found
|
|
55
|
-
return ['99', '0', '0', '0']
|
|
56
|
-
|
|
57
|
-
def get_platform(user_agent):
|
|
10
|
+
def get_headers() -> str:
|
|
58
11
|
"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Parameters:
|
|
62
|
-
user_agent (str): User agent of the browser.
|
|
12
|
+
Generate a random user agent to use in HTTP requests.
|
|
63
13
|
|
|
64
14
|
Returns:
|
|
65
|
-
str:
|
|
66
|
-
"""
|
|
67
|
-
if 'Windows' in user_agent:
|
|
68
|
-
return '"Windows"'
|
|
69
|
-
elif 'Mac OS X' in user_agent:
|
|
70
|
-
return '"macOS"'
|
|
71
|
-
elif 'Android' in user_agent:
|
|
72
|
-
return '"Android"'
|
|
73
|
-
elif 'iPhone' in user_agent or 'iPad' in user_agent:
|
|
74
|
-
return '"iOS"'
|
|
75
|
-
elif 'Linux' in user_agent:
|
|
76
|
-
return '"Linux"'
|
|
77
|
-
return '"Unknown"'
|
|
78
|
-
|
|
79
|
-
def get_model(user_agent):
|
|
15
|
+
- str: A random user agent string.
|
|
80
16
|
"""
|
|
81
|
-
|
|
17
|
+
|
|
18
|
+
# Get a random user agent string from the user agent rotator
|
|
19
|
+
user_agent = ua_generator.generate().text
|
|
20
|
+
return user_agent
|
|
82
21
|
|
|
83
|
-
Parameters:
|
|
84
|
-
user_agent (str): User agent of the browser.
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
str: Device model.
|
|
88
|
-
"""
|
|
89
|
-
if 'iPhone' in user_agent:
|
|
90
|
-
return '"iPhone"'
|
|
91
|
-
elif 'iPad' in user_agent:
|
|
92
|
-
return '"iPad"'
|
|
93
|
-
elif 'Android' in user_agent:
|
|
94
|
-
return '"Android"'
|
|
95
|
-
elif 'Windows' in user_agent:
|
|
96
|
-
return '"PC"'
|
|
97
|
-
elif 'Mac OS X' in user_agent:
|
|
98
|
-
return '"Mac"'
|
|
99
|
-
elif 'Linux' in user_agent:
|
|
100
|
-
return '"Linux"'
|
|
101
|
-
return '"Unknown"'
|
|
102
22
|
|
|
103
23
|
def random_headers(referer: str = None):
|
|
104
24
|
"""
|
|
@@ -107,26 +27,10 @@ def random_headers(referer: str = None):
|
|
|
107
27
|
Returns:
|
|
108
28
|
dict: Generated HTTP headers.
|
|
109
29
|
"""
|
|
110
|
-
|
|
111
|
-
versions = extract_versions(user_agent)
|
|
112
|
-
platform = get_platform(user_agent)
|
|
113
|
-
model = get_model(user_agent)
|
|
114
|
-
is_mobile = 'Mobi' in user_agent or 'Android' in user_agent
|
|
115
|
-
|
|
116
|
-
# Generate sec-ch-ua string based on the browser
|
|
117
|
-
if 'Chrome' in user_agent or 'CriOS' in user_agent:
|
|
118
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Google Chrome";v="{versions[0]}"'
|
|
119
|
-
elif 'Edg' in user_agent or 'EdgiOS' in user_agent:
|
|
120
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Microsoft Edge";v="{versions[0]}"'
|
|
121
|
-
elif 'Firefox' in user_agent:
|
|
122
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Firefox";v="{versions[0]}"'
|
|
123
|
-
elif 'Safari' in user_agent:
|
|
124
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Safari";v="{versions[0]}"'
|
|
125
|
-
else:
|
|
126
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}"'
|
|
30
|
+
ua = ua_generator.generate()
|
|
127
31
|
|
|
128
32
|
headers = {
|
|
129
|
-
'User-Agent':
|
|
33
|
+
'User-Agent': ua.text,
|
|
130
34
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
|
131
35
|
'Accept-Language': random.choice(['en-US', 'en-GB', 'fr-FR', 'es-ES', 'de-DE']),
|
|
132
36
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
@@ -136,25 +40,10 @@ def random_headers(referer: str = None):
|
|
|
136
40
|
'Sec-Fetch-Mode': 'navigate',
|
|
137
41
|
'Sec-Fetch-Site': 'none',
|
|
138
42
|
'Sec-Fetch-User': '?1',
|
|
139
|
-
'sec-ch-ua-mobile': '?1' if is_mobile else '?0',
|
|
140
|
-
'sec-ch-ua-platform': platform,
|
|
141
|
-
'sec-ch-ua': sec_ch_ua,
|
|
142
|
-
'sec-ch-ua-model': model
|
|
143
43
|
}
|
|
144
44
|
|
|
145
45
|
if referer:
|
|
146
46
|
headers['Origin'] = referer
|
|
147
47
|
headers['Referer'] = referer
|
|
148
48
|
|
|
149
|
-
return headers
|
|
150
|
-
|
|
151
|
-
def get_headers() -> str:
|
|
152
|
-
"""
|
|
153
|
-
Generate a random user agent to use in HTTP requests.
|
|
154
|
-
|
|
155
|
-
Returns:
|
|
156
|
-
- str: A random user agent string.
|
|
157
|
-
"""
|
|
158
|
-
|
|
159
|
-
# Get a random user agent string from the user agent rotator
|
|
160
|
-
return str(ua.chrome)
|
|
49
|
+
return headers
|
StreamingCommunity/Util/os.py
CHANGED
|
@@ -13,6 +13,7 @@ import subprocess
|
|
|
13
13
|
import contextlib
|
|
14
14
|
import urllib.request
|
|
15
15
|
import importlib.metadata
|
|
16
|
+
from pathlib import Path
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
# External library
|
|
@@ -67,7 +68,7 @@ class OsManager:
|
|
|
67
68
|
|
|
68
69
|
# Convert Windows separators to Unix
|
|
69
70
|
normalized = path.replace('\\', '/')
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
# Ensure absolute paths start with /
|
|
72
73
|
if normalized.startswith('/'):
|
|
73
74
|
return os.path.normpath(normalized)
|
|
@@ -82,17 +83,17 @@ class OsManager:
|
|
|
82
83
|
# Decode and sanitize
|
|
83
84
|
decoded = unidecode(filename)
|
|
84
85
|
sanitized = sanitize_filename(decoded)
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
# Split name and extension
|
|
87
88
|
name, ext = os.path.splitext(sanitized)
|
|
88
|
-
|
|
89
|
+
|
|
89
90
|
# Calculate available length for name considering the '...' and extension
|
|
90
91
|
max_name_length = self.max_length - len('...') - len(ext)
|
|
91
|
-
|
|
92
|
+
|
|
92
93
|
# Truncate name if it exceeds the max name length
|
|
93
94
|
if len(name) > max_name_length:
|
|
94
95
|
name = name[:max_name_length] + '...'
|
|
95
|
-
|
|
96
|
+
|
|
96
97
|
# Ensure the final file name includes the extension
|
|
97
98
|
return name + ext
|
|
98
99
|
|
|
@@ -103,7 +104,7 @@ class OsManager:
|
|
|
103
104
|
|
|
104
105
|
# Decode unicode characters
|
|
105
106
|
decoded = unidecode(path)
|
|
106
|
-
|
|
107
|
+
|
|
107
108
|
# Basic path sanitization
|
|
108
109
|
sanitized = sanitize_filepath(decoded)
|
|
109
110
|
|
|
@@ -121,7 +122,7 @@ class OsManager:
|
|
|
121
122
|
if part
|
|
122
123
|
])
|
|
123
124
|
return '\\'.join(sanitized_parts)
|
|
124
|
-
|
|
125
|
+
|
|
125
126
|
# Handle drive letters
|
|
126
127
|
elif len(path) >= 2 and path[1] == ':':
|
|
127
128
|
drive = path[:2]
|
|
@@ -132,7 +133,7 @@ class OsManager:
|
|
|
132
133
|
if part
|
|
133
134
|
]
|
|
134
135
|
return '\\'.join(path_parts)
|
|
135
|
-
|
|
136
|
+
|
|
136
137
|
# Regular path
|
|
137
138
|
else:
|
|
138
139
|
parts = path.replace('/', '\\').split('\\')
|
|
@@ -146,21 +147,21 @@ class OsManager:
|
|
|
146
147
|
for part in parts
|
|
147
148
|
if part
|
|
148
149
|
]
|
|
149
|
-
|
|
150
|
+
|
|
150
151
|
result = '/'.join(sanitized_parts)
|
|
151
152
|
if is_absolute:
|
|
152
153
|
result = '/' + result
|
|
153
|
-
|
|
154
|
+
|
|
154
155
|
return result
|
|
155
|
-
|
|
156
|
+
|
|
156
157
|
def create_path(self, path: str, mode: int = 0o755) -> bool:
|
|
157
158
|
"""
|
|
158
159
|
Create directory path with specified permissions.
|
|
159
|
-
|
|
160
|
+
|
|
160
161
|
Args:
|
|
161
162
|
path (str): Path to create.
|
|
162
163
|
mode (int, optional): Directory permissions. Defaults to 0o755.
|
|
163
|
-
|
|
164
|
+
|
|
164
165
|
Returns:
|
|
165
166
|
bool: True if path created successfully, False otherwise.
|
|
166
167
|
"""
|
|
@@ -168,7 +169,7 @@ class OsManager:
|
|
|
168
169
|
sanitized_path = self.get_sanitize_path(path)
|
|
169
170
|
os.makedirs(sanitized_path, mode=mode, exist_ok=True)
|
|
170
171
|
return True
|
|
171
|
-
|
|
172
|
+
|
|
172
173
|
except Exception as e:
|
|
173
174
|
logging.error(f"Path creation error: {e}")
|
|
174
175
|
return False
|
|
@@ -176,21 +177,21 @@ class OsManager:
|
|
|
176
177
|
def remove_folder(self, folder_path: str) -> bool:
|
|
177
178
|
"""
|
|
178
179
|
Safely remove a folder.
|
|
179
|
-
|
|
180
|
+
|
|
180
181
|
Args:
|
|
181
182
|
folder_path (str): Path of directory to remove.
|
|
182
|
-
|
|
183
|
+
|
|
183
184
|
Returns:
|
|
184
185
|
bool: Removal status.
|
|
185
186
|
"""
|
|
186
187
|
try:
|
|
187
188
|
shutil.rmtree(folder_path)
|
|
188
189
|
return True
|
|
189
|
-
|
|
190
|
+
|
|
190
191
|
except OSError as e:
|
|
191
192
|
logging.error(f"Folder removal error: {e}")
|
|
192
193
|
return False
|
|
193
|
-
|
|
194
|
+
|
|
194
195
|
def remove_files_except_one(self, folder_path: str, keep_file: str) -> None:
|
|
195
196
|
"""
|
|
196
197
|
Delete all files in a folder except for one specified file.
|
|
@@ -201,21 +202,27 @@ class OsManager:
|
|
|
201
202
|
"""
|
|
202
203
|
|
|
203
204
|
try:
|
|
204
|
-
#
|
|
205
|
-
|
|
205
|
+
# First, try to make all files writable
|
|
206
|
+
for root, dirs, files in os.walk(self.temp_dir):
|
|
207
|
+
for dir_name in dirs:
|
|
208
|
+
dir_path = os.path.join(root, dir_name)
|
|
209
|
+
os.chmod(dir_path, 0o755) # rwxr-xr-x
|
|
210
|
+
for file_name in files:
|
|
211
|
+
file_path = os.path.join(root, file_name)
|
|
212
|
+
os.chmod(file_path, 0o644) # rw-r--r--
|
|
206
213
|
|
|
207
|
-
#
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
# Then remove the directory tree
|
|
215
|
+
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
|
216
|
+
|
|
217
|
+
# If directory still exists after rmtree, try force remove
|
|
218
|
+
if os.path.exists(self.temp_dir):
|
|
219
|
+
import subprocess
|
|
220
|
+
subprocess.run(['rm', '-rf', self.temp_dir], check=True)
|
|
210
221
|
|
|
211
|
-
# Check if the file is not the one to keep and is a regular file
|
|
212
|
-
if file_name != keep_file and os.path.isfile(file_path):
|
|
213
|
-
os.remove(file_path) # Delete the file
|
|
214
|
-
|
|
215
222
|
except Exception as e:
|
|
216
|
-
logging.error(f"
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
logging.error(f"Failed to cleanup temporary directory: {str(e)}")
|
|
224
|
+
pass
|
|
225
|
+
|
|
219
226
|
def check_file(self, file_path: str) -> bool:
|
|
220
227
|
"""
|
|
221
228
|
Check if a file exists at the given file path.
|
|
@@ -229,7 +236,7 @@ class OsManager:
|
|
|
229
236
|
try:
|
|
230
237
|
logging.info(f"Check if file exists: {file_path}")
|
|
231
238
|
return os.path.exists(file_path)
|
|
232
|
-
|
|
239
|
+
|
|
233
240
|
except Exception as e:
|
|
234
241
|
logging.error(f"An error occurred while checking file existence: {e}")
|
|
235
242
|
return False
|
|
@@ -280,12 +287,12 @@ class InternManager():
|
|
|
280
287
|
def check_internet():
|
|
281
288
|
while True:
|
|
282
289
|
try:
|
|
283
|
-
httpx.get("https://www.google.com", timeout=
|
|
290
|
+
httpx.get("https://www.google.com", timeout=5)
|
|
284
291
|
break
|
|
285
292
|
|
|
286
|
-
except
|
|
293
|
+
except Exception as e:
|
|
287
294
|
console.log("[bold red]Internet is not available. Waiting...[/bold red]")
|
|
288
|
-
time.sleep(
|
|
295
|
+
time.sleep(2)
|
|
289
296
|
|
|
290
297
|
|
|
291
298
|
class OsSummary:
|
|
@@ -299,7 +306,7 @@ class OsSummary:
|
|
|
299
306
|
"""Get the binary directory based on OS."""
|
|
300
307
|
system = platform.system().lower()
|
|
301
308
|
home = os.path.expanduser('~')
|
|
302
|
-
|
|
309
|
+
|
|
303
310
|
if system == 'windows':
|
|
304
311
|
return os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary')
|
|
305
312
|
elif system == 'darwin':
|
|
@@ -315,41 +322,41 @@ class OsSummary:
|
|
|
315
322
|
try:
|
|
316
323
|
result = subprocess.check_output(command, text=True).strip()
|
|
317
324
|
return result.split('\n')[0] if result else None
|
|
318
|
-
|
|
325
|
+
|
|
319
326
|
except subprocess.CalledProcessError:
|
|
320
327
|
return None
|
|
321
328
|
|
|
322
329
|
def get_library_version(self, lib_name: str):
|
|
323
330
|
"""
|
|
324
331
|
Retrieve the version of a Python library.
|
|
325
|
-
|
|
332
|
+
|
|
326
333
|
Args:
|
|
327
334
|
lib_name (str): The name of the Python library.
|
|
328
|
-
|
|
335
|
+
|
|
329
336
|
Returns:
|
|
330
337
|
str: The library name followed by its version, or `-not installed` if not found.
|
|
331
338
|
"""
|
|
332
339
|
try:
|
|
333
340
|
version = importlib.metadata.version(lib_name)
|
|
334
341
|
return f"{lib_name}-{version}"
|
|
335
|
-
|
|
342
|
+
|
|
336
343
|
except importlib.metadata.PackageNotFoundError:
|
|
337
344
|
return f"{lib_name}-not installed"
|
|
338
345
|
|
|
339
346
|
def download_requirements(self, url: str, filename: str):
|
|
340
347
|
"""
|
|
341
348
|
Download the requirements.txt file from the specified URL if not found locally using requests.
|
|
342
|
-
|
|
349
|
+
|
|
343
350
|
Args:
|
|
344
351
|
url (str): The URL to download the requirements file from.
|
|
345
352
|
filename (str): The local filename to save the requirements file as.
|
|
346
353
|
"""
|
|
347
354
|
try:
|
|
348
355
|
import requests
|
|
349
|
-
|
|
356
|
+
|
|
350
357
|
logging.info(f"{filename} not found locally. Downloading from {url}...")
|
|
351
358
|
response = requests.get(url)
|
|
352
|
-
|
|
359
|
+
|
|
353
360
|
if response.status_code == 200:
|
|
354
361
|
with open(filename, 'wb') as f:
|
|
355
362
|
f.write(response.content)
|
|
@@ -357,7 +364,7 @@ class OsSummary:
|
|
|
357
364
|
else:
|
|
358
365
|
logging.error(f"Failed to download {filename}. HTTP Status code: {response.status_code}")
|
|
359
366
|
sys.exit(0)
|
|
360
|
-
|
|
367
|
+
|
|
361
368
|
except Exception as e:
|
|
362
369
|
logging.error(f"Failed to download {filename}: {e}")
|
|
363
370
|
sys.exit(0)
|
|
@@ -373,7 +380,7 @@ class OsSummary:
|
|
|
373
380
|
console.print(f"Installing {lib_name}...", style="bold yellow")
|
|
374
381
|
subprocess.check_call([sys.executable, "-m", "pip", "install", lib_name])
|
|
375
382
|
console.print(f"{lib_name} installed successfully!", style="bold green")
|
|
376
|
-
|
|
383
|
+
|
|
377
384
|
except subprocess.CalledProcessError as e:
|
|
378
385
|
console.print(f"Failed to install {lib_name}: {e}", style="bold red")
|
|
379
386
|
sys.exit(1)
|
|
@@ -400,7 +407,7 @@ class OsSummary:
|
|
|
400
407
|
arch = platform.machine()
|
|
401
408
|
os_info = platform.platform()
|
|
402
409
|
glibc_version = 'glibc ' + '.'.join(map(str, platform.libc_ver()[1]))
|
|
403
|
-
|
|
410
|
+
|
|
404
411
|
console.print(f"[cyan]Python[white]: [bold red]{python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})[/bold red]")
|
|
405
412
|
logging.info(f"Python: {python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})")
|
|
406
413
|
|
|
@@ -408,10 +415,10 @@ class OsSummary:
|
|
|
408
415
|
binary_dir = self.get_binary_directory()
|
|
409
416
|
system = platform.system().lower()
|
|
410
417
|
arch = platform.machine().lower()
|
|
411
|
-
|
|
418
|
+
|
|
412
419
|
# Map architecture names
|
|
413
420
|
arch_map = {
|
|
414
|
-
'amd64': 'x64',
|
|
421
|
+
'amd64': 'x64',
|
|
415
422
|
'x86_64': 'x64',
|
|
416
423
|
'x64': 'x64',
|
|
417
424
|
'arm64': 'arm64',
|
|
@@ -424,15 +431,15 @@ class OsSummary:
|
|
|
424
431
|
|
|
425
432
|
# Check binary directory
|
|
426
433
|
if os.path.exists(binary_dir):
|
|
427
|
-
|
|
434
|
+
|
|
428
435
|
# Search for any file containing 'ffmpeg' and the architecture
|
|
429
436
|
ffmpeg_files = glob.glob(os.path.join(binary_dir, f'*ffmpeg*{arch}*'))
|
|
430
437
|
ffprobe_files = glob.glob(os.path.join(binary_dir, f'*ffprobe*{arch}*'))
|
|
431
|
-
|
|
438
|
+
|
|
432
439
|
if ffmpeg_files and ffprobe_files:
|
|
433
440
|
self.ffmpeg_path = ffmpeg_files[0]
|
|
434
441
|
self.ffprobe_path = ffprobe_files[0]
|
|
435
|
-
|
|
442
|
+
|
|
436
443
|
# Set executable permissions if needed
|
|
437
444
|
if system != 'windows':
|
|
438
445
|
os.chmod(self.ffmpeg_path, 0o755)
|
|
@@ -451,15 +458,17 @@ class OsSummary:
|
|
|
451
458
|
# Handle requirements.txt
|
|
452
459
|
if not getattr(sys, 'frozen', False):
|
|
453
460
|
requirements_file = 'requirements.txt'
|
|
454
|
-
|
|
461
|
+
|
|
462
|
+
requirements_file = Path(__file__).parent.parent.parent / requirements_file
|
|
463
|
+
|
|
455
464
|
if not os.path.exists(requirements_file):
|
|
456
465
|
self.download_requirements(
|
|
457
466
|
'https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/requirements.txt',
|
|
458
467
|
requirements_file
|
|
459
468
|
)
|
|
460
|
-
|
|
469
|
+
|
|
461
470
|
optional_libraries = [line.strip().split("=")[0] for line in open(requirements_file, 'r', encoding='utf-8-sig')]
|
|
462
|
-
|
|
471
|
+
|
|
463
472
|
for lib in optional_libraries:
|
|
464
473
|
installed_version = self.get_library_version(lib.split("<")[0])
|
|
465
474
|
if 'not installed' in installed_version:
|
|
@@ -468,7 +477,7 @@ class OsSummary:
|
|
|
468
477
|
self.install_library(lib)
|
|
469
478
|
else:
|
|
470
479
|
logging.info(f"Library: {installed_version}")
|
|
471
|
-
|
|
480
|
+
|
|
472
481
|
#console.print(f"[cyan]Libraries[white]: [bold red]{', '.join([self.get_library_version(lib) for lib in optional_libraries])}[/bold red]\n")
|
|
473
482
|
logging.info(f"Libraries: {', '.join([self.get_library_version(lib) for lib in optional_libraries])}")
|
|
474
483
|
|
|
@@ -495,6 +504,6 @@ def compute_sha1_hash(input_string: str) -> str:
|
|
|
495
504
|
"""
|
|
496
505
|
# Compute the SHA-1 hash
|
|
497
506
|
hashed_string = hashlib.sha1(input_string.encode()).hexdigest()
|
|
498
|
-
|
|
507
|
+
|
|
499
508
|
# Return the hashed string
|
|
500
509
|
return hashed_string
|