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.
- StreamingCommunity/Api/Player/ddl.py +2 -10
- StreamingCommunity/Api/Player/mediapolisvod.py +64 -0
- StreamingCommunity/Api/Player/sweetpixel.py +3 -3
- StreamingCommunity/Api/Player/vixcloud.py +4 -9
- StreamingCommunity/Api/Site/1337xx/__init__.py +2 -3
- StreamingCommunity/Api/Site/1337xx/site.py +6 -1
- StreamingCommunity/Api/Site/altadefinizione/__init__.py +24 -9
- StreamingCommunity/Api/Site/altadefinizione/film.py +0 -1
- StreamingCommunity/Api/Site/altadefinizione/series.py +66 -70
- StreamingCommunity/Api/Site/altadefinizione/site.py +8 -2
- StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +37 -2
- StreamingCommunity/Api/Site/animeunity/__init__.py +30 -12
- StreamingCommunity/Api/Site/animeunity/film.py +40 -0
- StreamingCommunity/Api/Site/animeunity/serie.py +153 -0
- StreamingCommunity/Api/Site/animeunity/site.py +64 -37
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +41 -22
- StreamingCommunity/Api/Site/animeworld/__init__.py +26 -14
- StreamingCommunity/Api/Site/animeworld/film.py +63 -0
- StreamingCommunity/Api/Site/animeworld/serie.py +25 -22
- StreamingCommunity/Api/Site/animeworld/site.py +8 -2
- StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +32 -5
- StreamingCommunity/Api/Site/cb01new/__init__.py +2 -3
- StreamingCommunity/Api/Site/cb01new/site.py +7 -1
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +2 -3
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +31 -32
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +8 -3
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +30 -2
- StreamingCommunity/Api/Site/guardaserie/__init__.py +22 -9
- StreamingCommunity/Api/Site/guardaserie/series.py +55 -53
- StreamingCommunity/Api/Site/guardaserie/site.py +10 -3
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +27 -1
- StreamingCommunity/Api/Site/raiplay/__init__.py +92 -0
- StreamingCommunity/Api/Site/raiplay/film.py +65 -0
- StreamingCommunity/Api/Site/raiplay/series.py +162 -0
- StreamingCommunity/Api/Site/raiplay/site.py +173 -0
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +127 -0
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +30 -24
- StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -2
- StreamingCommunity/Api/Site/streamingcommunity/series.py +76 -90
- StreamingCommunity/Api/Site/streamingcommunity/site.py +8 -4
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +41 -15
- StreamingCommunity/Api/Template/site.py +2 -2
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +1 -1
- StreamingCommunity/Lib/Downloader/HLS/segments.py +9 -18
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +2 -1
- StreamingCommunity/Lib/Downloader/TOR/downloader.py +7 -14
- StreamingCommunity/Lib/FFmpeg/capture.py +1 -5
- StreamingCommunity/Lib/FFmpeg/util.py +57 -19
- StreamingCommunity/Lib/M3U8/estimator.py +57 -41
- StreamingCommunity/Lib/M3U8/parser.py +26 -6
- StreamingCommunity/Upload/update.py +22 -3
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/ffmpeg_installer.py +26 -1
- StreamingCommunity/Util/os.py +13 -15
- StreamingCommunity/Util/table.py +4 -2
- StreamingCommunity/global_search.py +1 -4
- StreamingCommunity/run.py +1 -4
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/METADATA +1 -1
- streamingcommunity-3.0.0.dist-info/RECORD +91 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/WHEEL +1 -1
- StreamingCommunity/Api/Site/animeunity/film_serie.py +0 -181
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +0 -73
- StreamingCommunity/Api/Site/mostraguarda/film.py +0 -93
- streamingcommunity-2.9.8.dist-info/RECORD +0 -85
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
145
|
-
|
|
168
|
+
cmd,
|
|
169
|
+
capture_output=True,
|
|
170
|
+
text=True,
|
|
171
|
+
check=False # Don't raise exception on non-zero exit
|
|
146
172
|
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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"
|
|
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
|
-
#
|
|
177
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
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":
|
|
72
|
-
"download":
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
70
|
-
|
|
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)
|
|
@@ -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
|
StreamingCommunity/Util/os.py
CHANGED
|
@@ -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
|
|
119
|
-
parts =
|
|
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(
|
|
133
|
-
drive =
|
|
134
|
-
rest =
|
|
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 =
|
|
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 =
|
|
149
|
-
parts =
|
|
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
|
StreamingCommunity/Util/table.py
CHANGED
|
@@ -158,7 +158,8 @@ class TVShowManager:
|
|
|
158
158
|
else:
|
|
159
159
|
key = Prompt.ask(prompt_msg)
|
|
160
160
|
else:
|
|
161
|
-
|
|
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
|
-
|
|
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)}")
|
|
@@ -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,,
|