StreamingCommunity 1.7.6__py3-none-any.whl → 1.9.1__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/{Src/Api → Api}/Player/Helper/Vixcloud/js_parser.py +4 -1
- StreamingCommunity/{Src/Api → Api}/Player/Helper/Vixcloud/util.py +166 -166
- StreamingCommunity/{Src/Api → Api}/Player/ddl.py +89 -89
- StreamingCommunity/{Src/Api → Api}/Player/maxstream.py +151 -151
- StreamingCommunity/{Src/Api → Api}/Player/supervideo.py +193 -193
- StreamingCommunity/{Src/Api → Api}/Player/vixcloud.py +224 -212
- StreamingCommunity/{Src/Api → Api}/Site/1337xx/__init__.py +50 -50
- StreamingCommunity/{Src/Api → Api}/Site/1337xx/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/1337xx/site.py +83 -83
- StreamingCommunity/{Src/Api → Api}/Site/1337xx/title.py +66 -66
- StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/__init__.py +50 -50
- StreamingCommunity/{Src/Api/Site/mostraguarda → Api/Site/altadefinizione}/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/film.py +69 -69
- StreamingCommunity/{Src/Api → Api}/Site/altadefinizione/site.py +86 -86
- StreamingCommunity/{Src/Api → Api}/Site/animeunity/__init__.py +50 -50
- StreamingCommunity/{Src/Api/Site/altadefinizione → Api/Site/animeunity}/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/animeunity/film_serie.py +130 -131
- StreamingCommunity/{Src/Api → Api}/Site/animeunity/site.py +164 -164
- StreamingCommunity/{Src/Api → Api}/Site/animeunity/util/ScrapeSerie.py +3 -3
- StreamingCommunity/{Src/Api → Api}/Site/bitsearch/__init__.py +51 -51
- StreamingCommunity/{Src/Api → Api}/Site/bitsearch/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/bitsearch/site.py +84 -84
- StreamingCommunity/{Src/Api → Api}/Site/bitsearch/title.py +47 -47
- StreamingCommunity/{Src/Api → Api}/Site/cb01new/__init__.py +51 -51
- StreamingCommunity/{Src/Api → Api}/Site/cb01new/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/cb01new/film.py +69 -69
- StreamingCommunity/{Src/Api → Api}/Site/cb01new/site.py +74 -74
- StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/__init__.py +57 -57
- StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/costant.py +16 -16
- StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/series.py +141 -142
- StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/site.py +92 -92
- StreamingCommunity/{Src/Api → Api}/Site/ddlstreamitaly/util/ScrapeSerie.py +84 -82
- StreamingCommunity/{Src/Api → Api}/Site/guardaserie/__init__.py +52 -52
- StreamingCommunity/{Src/Api/Site/piratebays → Api/Site/guardaserie}/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/guardaserie/series.py +195 -195
- StreamingCommunity/{Src/Api → Api}/Site/guardaserie/site.py +84 -84
- StreamingCommunity/{Src/Api → Api}/Site/guardaserie/util/ScrapeSerie.py +110 -110
- StreamingCommunity/{Src/Api → Api}/Site/mostraguarda/__init__.py +48 -48
- StreamingCommunity/{Src/Api/Site/animeunity → Api/Site/mostraguarda}/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/mostraguarda/film.py +94 -94
- StreamingCommunity/{Src/Api → Api}/Site/piratebays/__init__.py +50 -50
- StreamingCommunity/{Src/Api/Site/guardaserie → Api/Site/piratebays}/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/piratebays/site.py +88 -88
- StreamingCommunity/{Src/Api → Api}/Site/piratebays/title.py +45 -45
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/__init__.py +55 -55
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/costant.py +15 -15
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/film.py +70 -70
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/series.py +205 -203
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/site.py +125 -125
- StreamingCommunity/{Src/Api → Api}/Site/streamingcommunity/util/ScrapeSerie.py +3 -3
- StreamingCommunity/{Src/Api → Api}/Template/Class/SearchType.py +101 -101
- StreamingCommunity/{Src/Api → Api}/Template/Util/__init__.py +4 -4
- StreamingCommunity/{Src/Api → Api}/Template/Util/get_domain.py +137 -137
- StreamingCommunity/{Src/Api → Api}/Template/Util/manage_ep.py +153 -153
- StreamingCommunity/{Src/Api → Api}/Template/Util/recall_search.py +37 -37
- StreamingCommunity/Api/Template/__init__.py +3 -0
- StreamingCommunity/{Src/Api → Api}/Template/site.py +87 -87
- StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/downloader.py +968 -968
- StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/proxyes.py +110 -110
- StreamingCommunity/{Src/Lib → Lib}/Downloader/HLS/segments.py +538 -540
- StreamingCommunity/{Src/Lib → Lib}/Downloader/MP4/downloader.py +156 -156
- StreamingCommunity/{Src/Lib → Lib}/Downloader/TOR/downloader.py +222 -222
- StreamingCommunity/{Src/Lib → Lib}/Downloader/__init__.py +4 -4
- StreamingCommunity/{Src/Lib → Lib}/Driver/driver_1.py +76 -76
- StreamingCommunity/{Src/Lib → Lib}/FFmpeg/__init__.py +4 -4
- StreamingCommunity/{Src/Lib → Lib}/FFmpeg/capture.py +170 -170
- StreamingCommunity/{Src/Lib → Lib}/FFmpeg/command.py +292 -292
- StreamingCommunity/{Src/Lib → Lib}/FFmpeg/util.py +241 -241
- StreamingCommunity/{Src/Lib → Lib}/M3U8/__init__.py +5 -5
- StreamingCommunity/{Src/Lib → Lib}/M3U8/decryptor.py +164 -129
- StreamingCommunity/{Src/Lib → Lib}/M3U8/estimator.py +175 -172
- StreamingCommunity/{Src/Lib → Lib}/M3U8/parser.py +666 -666
- StreamingCommunity/{Src/Lib → Lib}/M3U8/url_fixer.py +51 -51
- StreamingCommunity/Lib/TMBD/__init__.py +2 -0
- StreamingCommunity/{Src/Lib → Lib}/TMBD/obj_tmbd.py +39 -39
- StreamingCommunity/{Src/Lib → Lib}/TMBD/tmdb.py +345 -345
- StreamingCommunity/{Src/Upload → Upload}/update.py +68 -64
- StreamingCommunity/{Src/Upload → Upload}/version.py +5 -5
- StreamingCommunity/{Src/Util → Util}/_jsonConfig.py +204 -204
- StreamingCommunity/{Src/Util → Util}/call_stack.py +42 -42
- StreamingCommunity/{Src/Util → Util}/color.py +20 -20
- StreamingCommunity/{Src/Util → Util}/console.py +12 -12
- StreamingCommunity/Util/ffmpeg_installer.py +275 -0
- StreamingCommunity/{Src/Util → Util}/headers.py +147 -147
- StreamingCommunity/{Src/Util → Util}/logger.py +53 -53
- StreamingCommunity/{Src/Util → Util}/message.py +46 -46
- StreamingCommunity/{Src/Util → Util}/os.py +514 -417
- StreamingCommunity/{Src/Util → Util}/table.py +163 -163
- StreamingCommunity/run.py +202 -196
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/METADATA +126 -60
- StreamingCommunity-1.9.1.dist-info/RECORD +95 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/WHEEL +1 -1
- StreamingCommunity/Src/Api/Site/animeunity/anime.py +0 -126
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/Player/ScrapeSerie.py +0 -83
- StreamingCommunity/Src/Api/Site/guardaserie/Player/ScrapeSerie.py +0 -110
- StreamingCommunity/Src/Api/Template/__init__.py +0 -3
- StreamingCommunity/Src/Lib/TMBD/__init__.py +0 -2
- StreamingCommunity-1.7.6.dist-info/RECORD +0 -97
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/LICENSE +0 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.9.1.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# 24.05.24
|
|
2
|
-
|
|
3
|
-
class Colors:
|
|
4
|
-
BLACK = "\033[30m"
|
|
5
|
-
RED = "\033[31m"
|
|
6
|
-
GREEN = "\033[32m"
|
|
7
|
-
YELLOW = "\033[33m"
|
|
8
|
-
BLUE = "\033[34m"
|
|
9
|
-
MAGENTA = "\033[35m"
|
|
10
|
-
CYAN = "\033[36m"
|
|
11
|
-
LIGHT_GRAY = "\033[37m"
|
|
12
|
-
DARK_GRAY = "\033[90m"
|
|
13
|
-
LIGHT_RED = "\033[91m"
|
|
14
|
-
LIGHT_GREEN = "\033[92m"
|
|
15
|
-
LIGHT_YELLOW = "\033[93m"
|
|
16
|
-
LIGHT_BLUE = "\033[94m"
|
|
17
|
-
LIGHT_MAGENTA = "\033[95m"
|
|
18
|
-
LIGHT_CYAN = "\033[96m"
|
|
19
|
-
WHITE = "\033[97m"
|
|
20
|
-
RESET = "\033[0m"
|
|
1
|
+
# 24.05.24
|
|
2
|
+
|
|
3
|
+
class Colors:
|
|
4
|
+
BLACK = "\033[30m"
|
|
5
|
+
RED = "\033[31m"
|
|
6
|
+
GREEN = "\033[32m"
|
|
7
|
+
YELLOW = "\033[33m"
|
|
8
|
+
BLUE = "\033[34m"
|
|
9
|
+
MAGENTA = "\033[35m"
|
|
10
|
+
CYAN = "\033[36m"
|
|
11
|
+
LIGHT_GRAY = "\033[37m"
|
|
12
|
+
DARK_GRAY = "\033[90m"
|
|
13
|
+
LIGHT_RED = "\033[91m"
|
|
14
|
+
LIGHT_GREEN = "\033[92m"
|
|
15
|
+
LIGHT_YELLOW = "\033[93m"
|
|
16
|
+
LIGHT_BLUE = "\033[94m"
|
|
17
|
+
LIGHT_MAGENTA = "\033[95m"
|
|
18
|
+
LIGHT_CYAN = "\033[96m"
|
|
19
|
+
WHITE = "\033[97m"
|
|
20
|
+
RESET = "\033[0m"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# 24.02.24
|
|
2
|
-
|
|
3
|
-
from rich.console import Console
|
|
4
|
-
from rich.prompt import Prompt, Confirm
|
|
5
|
-
from rich.panel import Panel
|
|
6
|
-
from rich.table import Table
|
|
7
|
-
from rich.text import Text
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Variable
|
|
11
|
-
msg = Prompt()
|
|
12
|
-
console = Console()
|
|
1
|
+
# 24.02.24
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.prompt import Prompt, Confirm
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
from rich.text import Text
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Variable
|
|
11
|
+
msg = Prompt()
|
|
12
|
+
console = Console()
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# 24.01.2024
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import subprocess
|
|
6
|
+
import zipfile
|
|
7
|
+
import tarfile
|
|
8
|
+
import logging
|
|
9
|
+
import requests
|
|
10
|
+
import shutil
|
|
11
|
+
import glob
|
|
12
|
+
from typing import Optional, Tuple
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# External library
|
|
16
|
+
from rich.console import Console
|
|
17
|
+
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRemainingColumn
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Variable
|
|
21
|
+
console = Console()
|
|
22
|
+
FFMPEG_CONFIGURATION = {
|
|
23
|
+
'windows': {
|
|
24
|
+
'base_dir': lambda home: os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary'),
|
|
25
|
+
'download_url': 'https://github.com/GyanD/codexffmpeg/releases/download/{version}/ffmpeg-{version}-full_build.zip',
|
|
26
|
+
'file_extension': '.zip',
|
|
27
|
+
'executables': ['ffmpeg.exe', 'ffprobe.exe', 'ffplay.exe']
|
|
28
|
+
},
|
|
29
|
+
'darwin': {
|
|
30
|
+
'base_dir': lambda home: os.path.join(home, 'Applications', 'binary'),
|
|
31
|
+
'download_url': 'https://evermeet.cx/ffmpeg/ffmpeg-{version}.zip',
|
|
32
|
+
'file_extension': '.zip',
|
|
33
|
+
'executables': ['ffmpeg', 'ffprobe', 'ffplay']
|
|
34
|
+
},
|
|
35
|
+
'linux': {
|
|
36
|
+
'base_dir': lambda home: os.path.join(home, '.local', 'bin', 'binary'),
|
|
37
|
+
'download_url': 'https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-{arch}-static.tar.xz',
|
|
38
|
+
'file_extension': '.tar.xz',
|
|
39
|
+
'executables': ['ffmpeg', 'ffprobe', 'ffplay']
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class FFMPEGDownloader:
|
|
46
|
+
def __init__(self):
|
|
47
|
+
self.os_name = self._detect_system()
|
|
48
|
+
self.arch = self._detect_arch()
|
|
49
|
+
self.home_dir = os.path.expanduser('~')
|
|
50
|
+
self.base_dir = self._get_base_directory()
|
|
51
|
+
|
|
52
|
+
def _detect_system(self) -> str:
|
|
53
|
+
"""Detect and normalize operating system name."""
|
|
54
|
+
system = platform.system().lower()
|
|
55
|
+
|
|
56
|
+
if system in FFMPEG_CONFIGURATION:
|
|
57
|
+
return system
|
|
58
|
+
|
|
59
|
+
raise ValueError(f"Unsupported operating system: {system}")
|
|
60
|
+
|
|
61
|
+
def _detect_arch(self) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Detect system architecture
|
|
64
|
+
"""
|
|
65
|
+
machine = platform.machine().lower()
|
|
66
|
+
|
|
67
|
+
arch_map = {
|
|
68
|
+
'amd64': 'x86_64',
|
|
69
|
+
'x86_64': 'x86_64',
|
|
70
|
+
'x64': 'x86_64',
|
|
71
|
+
'arm64': 'arm64',
|
|
72
|
+
'aarch64': 'arm64'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return arch_map.get(machine, machine)
|
|
76
|
+
|
|
77
|
+
def _get_base_directory(self) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Get base directory for binaries
|
|
80
|
+
"""
|
|
81
|
+
base_dir = FFMPEG_CONFIGURATION[self.os_name]['base_dir'](self.home_dir)
|
|
82
|
+
os.makedirs(base_dir, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
return base_dir
|
|
85
|
+
|
|
86
|
+
def _check_existing_binaries(self) -> Tuple[Optional[str], Optional[str]]:
|
|
87
|
+
"""
|
|
88
|
+
Check if FFmpeg binaries already exist in the base directory
|
|
89
|
+
"""
|
|
90
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
91
|
+
executables = config['executables']
|
|
92
|
+
|
|
93
|
+
found_executables = []
|
|
94
|
+
for executable in executables:
|
|
95
|
+
|
|
96
|
+
# Search for exact executable in base directory
|
|
97
|
+
exe_paths = glob.glob(os.path.join(self.base_dir, executable))
|
|
98
|
+
if exe_paths:
|
|
99
|
+
found_executables.append(exe_paths[0])
|
|
100
|
+
|
|
101
|
+
# Return paths if both executables are found
|
|
102
|
+
if len(found_executables) == len(executables):
|
|
103
|
+
return tuple(found_executables)
|
|
104
|
+
|
|
105
|
+
return None, None
|
|
106
|
+
|
|
107
|
+
def _get_latest_version(self) -> str:
|
|
108
|
+
"""
|
|
109
|
+
Get the latest FFmpeg version
|
|
110
|
+
"""
|
|
111
|
+
try:
|
|
112
|
+
version_url = 'https://www.gyan.dev/ffmpeg/builds/release-version'
|
|
113
|
+
return requests.get(version_url).text.strip()
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logging.error(f"Unable to get version: {e}")
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
def _download_file(self, url: str, destination: str) -> bool:
|
|
120
|
+
"""
|
|
121
|
+
Download with Rich progress bar
|
|
122
|
+
"""
|
|
123
|
+
try:
|
|
124
|
+
response = requests.get(url, stream=True)
|
|
125
|
+
response.raise_for_status()
|
|
126
|
+
|
|
127
|
+
total_size = int(response.headers.get('content-length', 0))
|
|
128
|
+
|
|
129
|
+
with open(destination, 'wb') as file, \
|
|
130
|
+
Progress(
|
|
131
|
+
SpinnerColumn(),
|
|
132
|
+
TextColumn("[progress.description]{task.description}"),
|
|
133
|
+
BarColumn(),
|
|
134
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
135
|
+
TimeRemainingColumn()
|
|
136
|
+
) as progress:
|
|
137
|
+
|
|
138
|
+
download_task = progress.add_task("[green]Downloading FFmpeg", total=total_size)
|
|
139
|
+
|
|
140
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
141
|
+
size = file.write(chunk)
|
|
142
|
+
progress.update(download_task, advance=size)
|
|
143
|
+
|
|
144
|
+
return True
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logging.error(f"Download error: {e}")
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
def _extract_and_copy_binaries(self, archive_path: str) -> Tuple[Optional[str], Optional[str]]:
|
|
151
|
+
"""
|
|
152
|
+
Extract archive and copy executables to base directory
|
|
153
|
+
"""
|
|
154
|
+
try:
|
|
155
|
+
# Temporary extraction path
|
|
156
|
+
extraction_path = os.path.join(self.base_dir, 'temp_extract')
|
|
157
|
+
os.makedirs(extraction_path, exist_ok=True)
|
|
158
|
+
|
|
159
|
+
# Extract based on file type
|
|
160
|
+
if archive_path.endswith('.zip'):
|
|
161
|
+
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
|
|
162
|
+
zip_ref.extractall(extraction_path)
|
|
163
|
+
elif archive_path.endswith('.tar.xz'):
|
|
164
|
+
import lzma
|
|
165
|
+
with lzma.open(archive_path, 'rb') as xz_file:
|
|
166
|
+
with tarfile.open(fileobj=xz_file) as tar_ref:
|
|
167
|
+
tar_ref.extractall(extraction_path)
|
|
168
|
+
|
|
169
|
+
# Find and copy executables
|
|
170
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
171
|
+
executables = config['executables']
|
|
172
|
+
|
|
173
|
+
found_paths = []
|
|
174
|
+
for executable in executables:
|
|
175
|
+
# Find executable in extracted files
|
|
176
|
+
exe_paths = glob.glob(os.path.join(extraction_path, '**', executable), recursive=True)
|
|
177
|
+
|
|
178
|
+
if exe_paths:
|
|
179
|
+
# Copy to base directory
|
|
180
|
+
dest_path = os.path.join(self.base_dir, executable)
|
|
181
|
+
shutil.copy2(exe_paths[0], dest_path)
|
|
182
|
+
|
|
183
|
+
# Set execution permissions for Unix-like systems
|
|
184
|
+
if self.os_name != 'windows':
|
|
185
|
+
os.chmod(dest_path, 0o755)
|
|
186
|
+
|
|
187
|
+
found_paths.append(dest_path)
|
|
188
|
+
|
|
189
|
+
# Clean up temporary extraction directory
|
|
190
|
+
shutil.rmtree(extraction_path, ignore_errors=True)
|
|
191
|
+
|
|
192
|
+
# Remove downloaded archive
|
|
193
|
+
os.remove(archive_path)
|
|
194
|
+
|
|
195
|
+
# Return paths if both executables found
|
|
196
|
+
if len(found_paths) == len(executables):
|
|
197
|
+
return tuple(found_paths)
|
|
198
|
+
|
|
199
|
+
return None, None
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
logging.error(f"Extraction/copy error: {e}")
|
|
203
|
+
return None, None
|
|
204
|
+
|
|
205
|
+
def download(self) -> Tuple[Optional[str], Optional[str]]:
|
|
206
|
+
"""
|
|
207
|
+
Main download procedure
|
|
208
|
+
Returns paths of ffmpeg and ffprobe
|
|
209
|
+
"""
|
|
210
|
+
# First, check if binaries already exist in base directory
|
|
211
|
+
existing_ffmpeg, existing_ffprobe, existing_ffplay = self._check_existing_binaries()
|
|
212
|
+
if existing_ffmpeg and existing_ffprobe:
|
|
213
|
+
return existing_ffmpeg, existing_ffprobe
|
|
214
|
+
|
|
215
|
+
# Get latest version
|
|
216
|
+
version = self._get_latest_version()
|
|
217
|
+
if not version:
|
|
218
|
+
logging.error("Cannot proceed: version not found")
|
|
219
|
+
return None, None
|
|
220
|
+
|
|
221
|
+
# Prepare configurations
|
|
222
|
+
config = FFMPEG_CONFIGURATION[self.os_name]
|
|
223
|
+
|
|
224
|
+
# Build download URL
|
|
225
|
+
download_url = config['download_url'].format(
|
|
226
|
+
version=version,
|
|
227
|
+
arch=self.arch
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Download path
|
|
231
|
+
download_path = os.path.join(
|
|
232
|
+
self.base_dir,
|
|
233
|
+
f'ffmpeg-{version}{config["file_extension"]}'
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Download
|
|
237
|
+
console.print(
|
|
238
|
+
f"[bold blue]Downloading FFmpeg from:[/] {download_url}",
|
|
239
|
+
)
|
|
240
|
+
if not self._download_file(download_url, download_path):
|
|
241
|
+
return None, None
|
|
242
|
+
|
|
243
|
+
# Extract and copy binaries
|
|
244
|
+
ffmpeg_path, ffprobe_path = self._extract_and_copy_binaries(download_path)
|
|
245
|
+
|
|
246
|
+
if ffmpeg_path and ffprobe_path:
|
|
247
|
+
return ffmpeg_path, ffprobe_path
|
|
248
|
+
|
|
249
|
+
logging.error("FFmpeg executables not found")
|
|
250
|
+
return None, None
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def check_ffmpeg():
|
|
254
|
+
try:
|
|
255
|
+
# First, use 'where' command to check existing binaries on Windows
|
|
256
|
+
if platform.system().lower() == 'windows':
|
|
257
|
+
ffmpeg_path = subprocess.check_output(['where', 'ffmpeg'], text=True).strip().split('\n')[0] if subprocess.call(['where', 'ffmpeg'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 else None
|
|
258
|
+
ffprobe_path = subprocess.check_output(['where', 'ffprobe'], text=True).strip().split('\n')[0] if subprocess.call(['where', 'ffprobe'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 else None
|
|
259
|
+
|
|
260
|
+
if ffmpeg_path and ffprobe_path:
|
|
261
|
+
return ffmpeg_path, ffprobe_path
|
|
262
|
+
|
|
263
|
+
# Fallback to which/shutil method for Unix-like systems
|
|
264
|
+
ffmpeg_path = shutil.which('ffmpeg')
|
|
265
|
+
ffprobe_path = shutil.which('ffprobe')
|
|
266
|
+
|
|
267
|
+
if ffmpeg_path and ffprobe_path:
|
|
268
|
+
return ffmpeg_path, ffprobe_path
|
|
269
|
+
|
|
270
|
+
downloader = FFMPEGDownloader()
|
|
271
|
+
return downloader.download()
|
|
272
|
+
|
|
273
|
+
except Exception as e:
|
|
274
|
+
logging.error(f"Error checking FFmpeg: {e}")
|
|
275
|
+
return None, None
|
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
# 4.04.24
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import random
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# External library
|
|
8
|
-
from fake_useragent import UserAgent
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# Variable
|
|
12
|
-
ua = UserAgent()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def extract_versions(user_agent):
|
|
16
|
-
"""
|
|
17
|
-
Extract browser versions from the user agent.
|
|
18
|
-
|
|
19
|
-
Parameters:
|
|
20
|
-
user_agent (str): User agent of the browser.
|
|
21
|
-
|
|
22
|
-
Returns:
|
|
23
|
-
list: List of browser versions.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
# Patterns to extract versions from various user agents
|
|
27
|
-
patterns = {
|
|
28
|
-
'chrome': re.compile(r'Chrome/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
29
|
-
'firefox': re.compile(r'Firefox/(\d+)\.?(\d+)?\.?(\d+)?'),
|
|
30
|
-
'safari': re.compile(r'Version/(\d+)\.(\d+)\.(\d+) Safari/(\d+)\.(\d+)\.(\d+)'),
|
|
31
|
-
'edge': re.compile(r'Edg/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
32
|
-
'edgios': re.compile(r'EdgiOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
33
|
-
'crios': re.compile(r'CriOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
for key, pattern in patterns.items():
|
|
37
|
-
match = pattern.search(user_agent)
|
|
38
|
-
if match:
|
|
39
|
-
return [match.group(i+1) for i in range(match.lastindex)]
|
|
40
|
-
|
|
41
|
-
# Fallback values if specific versions are not found
|
|
42
|
-
return ['99', '0', '0', '0']
|
|
43
|
-
|
|
44
|
-
def get_platform(user_agent):
|
|
45
|
-
"""
|
|
46
|
-
Determine the device platform from the user agent.
|
|
47
|
-
|
|
48
|
-
Parameters:
|
|
49
|
-
user_agent (str): User agent of the browser.
|
|
50
|
-
|
|
51
|
-
Returns:
|
|
52
|
-
str: Device platform.
|
|
53
|
-
"""
|
|
54
|
-
if 'Windows' in user_agent:
|
|
55
|
-
return '"Windows"'
|
|
56
|
-
elif 'Mac OS X' in user_agent:
|
|
57
|
-
return '"macOS"'
|
|
58
|
-
elif 'Android' in user_agent:
|
|
59
|
-
return '"Android"'
|
|
60
|
-
elif 'iPhone' in user_agent or 'iPad' in user_agent:
|
|
61
|
-
return '"iOS"'
|
|
62
|
-
elif 'Linux' in user_agent:
|
|
63
|
-
return '"Linux"'
|
|
64
|
-
return '"Unknown"'
|
|
65
|
-
|
|
66
|
-
def get_model(user_agent):
|
|
67
|
-
"""
|
|
68
|
-
Determine the device model from the user agent.
|
|
69
|
-
|
|
70
|
-
Parameters:
|
|
71
|
-
user_agent (str): User agent of the browser.
|
|
72
|
-
|
|
73
|
-
Returns:
|
|
74
|
-
str: Device model.
|
|
75
|
-
"""
|
|
76
|
-
if 'iPhone' in user_agent:
|
|
77
|
-
return '"iPhone"'
|
|
78
|
-
elif 'iPad' in user_agent:
|
|
79
|
-
return '"iPad"'
|
|
80
|
-
elif 'Android' in user_agent:
|
|
81
|
-
return '"Android"'
|
|
82
|
-
elif 'Windows' in user_agent:
|
|
83
|
-
return '"PC"'
|
|
84
|
-
elif 'Mac OS X' in user_agent:
|
|
85
|
-
return '"Mac"'
|
|
86
|
-
elif 'Linux' in user_agent:
|
|
87
|
-
return '"Linux"'
|
|
88
|
-
return '"Unknown"'
|
|
89
|
-
|
|
90
|
-
def random_headers(referer: str = None):
|
|
91
|
-
"""
|
|
92
|
-
Generate random HTTP headers to simulate human-like behavior.
|
|
93
|
-
|
|
94
|
-
Returns:
|
|
95
|
-
dict: Generated HTTP headers.
|
|
96
|
-
"""
|
|
97
|
-
user_agent = ua.random
|
|
98
|
-
versions = extract_versions(user_agent)
|
|
99
|
-
platform = get_platform(user_agent)
|
|
100
|
-
model = get_model(user_agent)
|
|
101
|
-
is_mobile = 'Mobi' in user_agent or 'Android' in user_agent
|
|
102
|
-
|
|
103
|
-
# Generate sec-ch-ua string based on the browser
|
|
104
|
-
if 'Chrome' in user_agent or 'CriOS' in user_agent:
|
|
105
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Google Chrome";v="{versions[0]}"'
|
|
106
|
-
elif 'Edg' in user_agent or 'EdgiOS' in user_agent:
|
|
107
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Microsoft Edge";v="{versions[0]}"'
|
|
108
|
-
elif 'Firefox' in user_agent:
|
|
109
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Firefox";v="{versions[0]}"'
|
|
110
|
-
elif 'Safari' in user_agent:
|
|
111
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Safari";v="{versions[0]}"'
|
|
112
|
-
else:
|
|
113
|
-
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}"'
|
|
114
|
-
|
|
115
|
-
headers = {
|
|
116
|
-
'User-Agent': user_agent,
|
|
117
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
|
118
|
-
'Accept-Language': random.choice(['en-US', 'en-GB', 'fr-FR', 'es-ES', 'de-DE']),
|
|
119
|
-
'Accept-Encoding': 'gzip, deflate, br',
|
|
120
|
-
'Connection': 'keep-alive',
|
|
121
|
-
'Upgrade-Insecure-Requests': '1',
|
|
122
|
-
'Sec-Fetch-Dest': 'document',
|
|
123
|
-
'Sec-Fetch-Mode': 'navigate',
|
|
124
|
-
'Sec-Fetch-Site': 'none',
|
|
125
|
-
'Sec-Fetch-User': '?1',
|
|
126
|
-
'sec-ch-ua-mobile': '?1' if is_mobile else '?0',
|
|
127
|
-
'sec-ch-ua-platform': platform,
|
|
128
|
-
'sec-ch-ua': sec_ch_ua,
|
|
129
|
-
'sec-ch-ua-model': model
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if referer:
|
|
133
|
-
headers['Origin'] = referer
|
|
134
|
-
headers['Referer'] = referer
|
|
135
|
-
|
|
136
|
-
return headers
|
|
137
|
-
|
|
138
|
-
def get_headers() -> str:
|
|
139
|
-
"""
|
|
140
|
-
Generate a random user agent to use in HTTP requests.
|
|
141
|
-
|
|
142
|
-
Returns:
|
|
143
|
-
- str: A random user agent string.
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
# Get a random user agent string from the user agent rotator
|
|
147
|
-
return str(ua.chrome)
|
|
1
|
+
# 4.04.24
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# External library
|
|
8
|
+
from fake_useragent import UserAgent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Variable
|
|
12
|
+
ua = UserAgent(use_external_data=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def extract_versions(user_agent):
|
|
16
|
+
"""
|
|
17
|
+
Extract browser versions from the user agent.
|
|
18
|
+
|
|
19
|
+
Parameters:
|
|
20
|
+
user_agent (str): User agent of the browser.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
list: List of browser versions.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Patterns to extract versions from various user agents
|
|
27
|
+
patterns = {
|
|
28
|
+
'chrome': re.compile(r'Chrome/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
29
|
+
'firefox': re.compile(r'Firefox/(\d+)\.?(\d+)?\.?(\d+)?'),
|
|
30
|
+
'safari': re.compile(r'Version/(\d+)\.(\d+)\.(\d+) Safari/(\d+)\.(\d+)\.(\d+)'),
|
|
31
|
+
'edge': re.compile(r'Edg/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
32
|
+
'edgios': re.compile(r'EdgiOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
33
|
+
'crios': re.compile(r'CriOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for key, pattern in patterns.items():
|
|
37
|
+
match = pattern.search(user_agent)
|
|
38
|
+
if match:
|
|
39
|
+
return [match.group(i+1) for i in range(match.lastindex)]
|
|
40
|
+
|
|
41
|
+
# Fallback values if specific versions are not found
|
|
42
|
+
return ['99', '0', '0', '0']
|
|
43
|
+
|
|
44
|
+
def get_platform(user_agent):
|
|
45
|
+
"""
|
|
46
|
+
Determine the device platform from the user agent.
|
|
47
|
+
|
|
48
|
+
Parameters:
|
|
49
|
+
user_agent (str): User agent of the browser.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: Device platform.
|
|
53
|
+
"""
|
|
54
|
+
if 'Windows' in user_agent:
|
|
55
|
+
return '"Windows"'
|
|
56
|
+
elif 'Mac OS X' in user_agent:
|
|
57
|
+
return '"macOS"'
|
|
58
|
+
elif 'Android' in user_agent:
|
|
59
|
+
return '"Android"'
|
|
60
|
+
elif 'iPhone' in user_agent or 'iPad' in user_agent:
|
|
61
|
+
return '"iOS"'
|
|
62
|
+
elif 'Linux' in user_agent:
|
|
63
|
+
return '"Linux"'
|
|
64
|
+
return '"Unknown"'
|
|
65
|
+
|
|
66
|
+
def get_model(user_agent):
|
|
67
|
+
"""
|
|
68
|
+
Determine the device model from the user agent.
|
|
69
|
+
|
|
70
|
+
Parameters:
|
|
71
|
+
user_agent (str): User agent of the browser.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: Device model.
|
|
75
|
+
"""
|
|
76
|
+
if 'iPhone' in user_agent:
|
|
77
|
+
return '"iPhone"'
|
|
78
|
+
elif 'iPad' in user_agent:
|
|
79
|
+
return '"iPad"'
|
|
80
|
+
elif 'Android' in user_agent:
|
|
81
|
+
return '"Android"'
|
|
82
|
+
elif 'Windows' in user_agent:
|
|
83
|
+
return '"PC"'
|
|
84
|
+
elif 'Mac OS X' in user_agent:
|
|
85
|
+
return '"Mac"'
|
|
86
|
+
elif 'Linux' in user_agent:
|
|
87
|
+
return '"Linux"'
|
|
88
|
+
return '"Unknown"'
|
|
89
|
+
|
|
90
|
+
def random_headers(referer: str = None):
|
|
91
|
+
"""
|
|
92
|
+
Generate random HTTP headers to simulate human-like behavior.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
dict: Generated HTTP headers.
|
|
96
|
+
"""
|
|
97
|
+
user_agent = ua.random
|
|
98
|
+
versions = extract_versions(user_agent)
|
|
99
|
+
platform = get_platform(user_agent)
|
|
100
|
+
model = get_model(user_agent)
|
|
101
|
+
is_mobile = 'Mobi' in user_agent or 'Android' in user_agent
|
|
102
|
+
|
|
103
|
+
# Generate sec-ch-ua string based on the browser
|
|
104
|
+
if 'Chrome' in user_agent or 'CriOS' in user_agent:
|
|
105
|
+
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Google Chrome";v="{versions[0]}"'
|
|
106
|
+
elif 'Edg' in user_agent or 'EdgiOS' in user_agent:
|
|
107
|
+
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Microsoft Edge";v="{versions[0]}"'
|
|
108
|
+
elif 'Firefox' in user_agent:
|
|
109
|
+
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Firefox";v="{versions[0]}"'
|
|
110
|
+
elif 'Safari' in user_agent:
|
|
111
|
+
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Safari";v="{versions[0]}"'
|
|
112
|
+
else:
|
|
113
|
+
sec_ch_ua = f'" Not;A Brand";v="{versions[0]}"'
|
|
114
|
+
|
|
115
|
+
headers = {
|
|
116
|
+
'User-Agent': user_agent,
|
|
117
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
|
118
|
+
'Accept-Language': random.choice(['en-US', 'en-GB', 'fr-FR', 'es-ES', 'de-DE']),
|
|
119
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
120
|
+
'Connection': 'keep-alive',
|
|
121
|
+
'Upgrade-Insecure-Requests': '1',
|
|
122
|
+
'Sec-Fetch-Dest': 'document',
|
|
123
|
+
'Sec-Fetch-Mode': 'navigate',
|
|
124
|
+
'Sec-Fetch-Site': 'none',
|
|
125
|
+
'Sec-Fetch-User': '?1',
|
|
126
|
+
'sec-ch-ua-mobile': '?1' if is_mobile else '?0',
|
|
127
|
+
'sec-ch-ua-platform': platform,
|
|
128
|
+
'sec-ch-ua': sec_ch_ua,
|
|
129
|
+
'sec-ch-ua-model': model
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if referer:
|
|
133
|
+
headers['Origin'] = referer
|
|
134
|
+
headers['Referer'] = referer
|
|
135
|
+
|
|
136
|
+
return headers
|
|
137
|
+
|
|
138
|
+
def get_headers() -> str:
|
|
139
|
+
"""
|
|
140
|
+
Generate a random user agent to use in HTTP requests.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
- str: A random user agent string.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
# Get a random user agent string from the user agent rotator
|
|
147
|
+
return str(ua.chrome)
|