StreamingCommunity 3.2.7__py3-none-any.whl → 3.2.9__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/Helper/Vixcloud/util.py +2 -1
- StreamingCommunity/Api/Player/hdplayer.py +2 -2
- StreamingCommunity/Api/Player/sweetpixel.py +5 -8
- StreamingCommunity/Api/Site/altadefinizione/__init__.py +2 -2
- StreamingCommunity/Api/Site/altadefinizione/film.py +10 -8
- StreamingCommunity/Api/Site/altadefinizione/series.py +9 -7
- StreamingCommunity/Api/Site/altadefinizione/site.py +1 -1
- StreamingCommunity/Api/Site/animeunity/__init__.py +2 -2
- StreamingCommunity/Api/Site/animeunity/serie.py +2 -2
- StreamingCommunity/Api/Site/animeworld/site.py +3 -5
- StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +8 -10
- StreamingCommunity/Api/Site/cb01new/film.py +7 -5
- StreamingCommunity/Api/Site/crunchyroll/__init__.py +1 -3
- StreamingCommunity/Api/Site/crunchyroll/film.py +9 -7
- StreamingCommunity/Api/Site/crunchyroll/series.py +9 -7
- StreamingCommunity/Api/Site/crunchyroll/site.py +10 -1
- StreamingCommunity/Api/Site/guardaserie/series.py +8 -6
- StreamingCommunity/Api/Site/guardaserie/site.py +0 -3
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +1 -2
- StreamingCommunity/Api/Site/mediasetinfinity/__init__.py +1 -1
- StreamingCommunity/Api/Site/mediasetinfinity/film.py +10 -16
- StreamingCommunity/Api/Site/mediasetinfinity/series.py +12 -18
- StreamingCommunity/Api/Site/mediasetinfinity/site.py +11 -3
- StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +214 -180
- StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +2 -31
- StreamingCommunity/Api/Site/raiplay/__init__.py +1 -1
- StreamingCommunity/Api/Site/raiplay/film.py +41 -10
- StreamingCommunity/Api/Site/raiplay/series.py +44 -12
- StreamingCommunity/Api/Site/raiplay/site.py +4 -1
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +2 -1
- StreamingCommunity/Api/Site/raiplay/util/get_license.py +40 -0
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +0 -1
- StreamingCommunity/Api/Site/streamingcommunity/film.py +7 -5
- StreamingCommunity/Api/Site/streamingcommunity/series.py +9 -7
- StreamingCommunity/Api/Site/streamingcommunity/site.py +4 -2
- StreamingCommunity/Api/Site/streamingwatch/film.py +7 -5
- StreamingCommunity/Api/Site/streamingwatch/series.py +8 -6
- StreamingCommunity/Api/Site/streamingwatch/site.py +3 -1
- StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +3 -3
- StreamingCommunity/Api/Template/Util/__init__.py +10 -1
- StreamingCommunity/Api/Template/Util/manage_ep.py +4 -4
- StreamingCommunity/Api/Template/__init__.py +5 -1
- StreamingCommunity/Api/Template/site.py +10 -6
- StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +5 -12
- StreamingCommunity/Lib/Downloader/DASH/decrypt.py +1 -1
- StreamingCommunity/Lib/Downloader/DASH/downloader.py +1 -1
- StreamingCommunity/Lib/Downloader/DASH/parser.py +1 -1
- StreamingCommunity/Lib/Downloader/DASH/segments.py +4 -3
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +11 -9
- StreamingCommunity/Lib/Downloader/HLS/segments.py +253 -144
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +4 -3
- StreamingCommunity/Lib/Downloader/TOR/downloader.py +3 -5
- StreamingCommunity/Lib/Downloader/__init__.py +9 -1
- StreamingCommunity/Lib/FFmpeg/__init__.py +10 -1
- StreamingCommunity/Lib/FFmpeg/command.py +4 -6
- StreamingCommunity/Lib/FFmpeg/util.py +1 -1
- StreamingCommunity/Lib/M3U8/__init__.py +9 -1
- StreamingCommunity/Lib/M3U8/decryptor.py +8 -4
- StreamingCommunity/Lib/M3U8/estimator.py +0 -6
- StreamingCommunity/Lib/M3U8/parser.py +1 -1
- StreamingCommunity/Lib/M3U8/url_fixer.py +1 -1
- StreamingCommunity/Lib/TMBD/__init__.py +6 -1
- StreamingCommunity/TelegramHelp/config.json +1 -5
- StreamingCommunity/TelegramHelp/telegram_bot.py +9 -10
- StreamingCommunity/Upload/version.py +2 -2
- StreamingCommunity/Util/config_json.py +139 -59
- StreamingCommunity/Util/http_client.py +201 -0
- StreamingCommunity/Util/message.py +1 -1
- StreamingCommunity/Util/os.py +5 -5
- StreamingCommunity/Util/table.py +3 -3
- StreamingCommunity/__init__.py +9 -1
- StreamingCommunity/run.py +396 -260
- {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/METADATA +143 -45
- streamingcommunity-3.2.9.dist-info/RECORD +113 -0
- streamingcommunity-3.2.7.dist-info/RECORD +0 -111
- {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/WHEEL +0 -0
- {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# 09.08.25
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import random
|
|
6
|
+
from typing import Any, Dict, Optional, Union
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# External library
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Logic class
|
|
14
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
15
|
+
from StreamingCommunity.Util.headers import get_userAgent
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Defaults from config
|
|
19
|
+
def _get_timeout() -> int:
|
|
20
|
+
try:
|
|
21
|
+
return int(config_manager.get_int("REQUESTS", "timeout"))
|
|
22
|
+
except Exception:
|
|
23
|
+
return 20
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _get_max_retry() -> int:
|
|
27
|
+
try:
|
|
28
|
+
return int(config_manager.get_int("REQUESTS", "max_retry"))
|
|
29
|
+
except Exception:
|
|
30
|
+
return 3
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_verify() -> bool:
|
|
34
|
+
try:
|
|
35
|
+
return bool(config_manager.get_bool("REQUESTS", "verify"))
|
|
36
|
+
except Exception:
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_proxies() -> Optional[Dict[str, str]]:
|
|
41
|
+
"""Return proxies dict if present in config and non-empty, else None."""
|
|
42
|
+
try:
|
|
43
|
+
proxies = config_manager.get_dict("REQUESTS", "proxy")
|
|
44
|
+
if not isinstance(proxies, dict):
|
|
45
|
+
return None
|
|
46
|
+
# Normalize empty strings to None (httpx ignores None)
|
|
47
|
+
cleaned: Dict[str, str] = {}
|
|
48
|
+
for scheme, url in proxies.items():
|
|
49
|
+
if isinstance(url, str) and url.strip():
|
|
50
|
+
cleaned[scheme] = url.strip()
|
|
51
|
+
return cleaned or None
|
|
52
|
+
except Exception:
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _default_headers(extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
57
|
+
headers = {"User-Agent": get_userAgent()}
|
|
58
|
+
if extra:
|
|
59
|
+
headers.update(extra)
|
|
60
|
+
return headers
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def create_client(
|
|
64
|
+
*,
|
|
65
|
+
headers: Optional[Dict[str, str]] = None,
|
|
66
|
+
cookies: Optional[Dict[str, str]] = None,
|
|
67
|
+
timeout: Optional[Union[int, float]] = None,
|
|
68
|
+
verify: Optional[bool] = None,
|
|
69
|
+
proxies: Optional[Dict[str, str]] = None,
|
|
70
|
+
http2: bool = False,
|
|
71
|
+
follow_redirects: bool = True,
|
|
72
|
+
) -> httpx.Client:
|
|
73
|
+
"""Factory for a configured httpx.Client."""
|
|
74
|
+
return httpx.Client(
|
|
75
|
+
headers=_default_headers(headers),
|
|
76
|
+
cookies=cookies,
|
|
77
|
+
timeout=timeout if timeout is not None else _get_timeout(),
|
|
78
|
+
verify=_get_verify() if verify is None else verify,
|
|
79
|
+
follow_redirects=follow_redirects,
|
|
80
|
+
http2=http2,
|
|
81
|
+
proxy=proxies if proxies is not None else _get_proxies(),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def create_async_client(
|
|
86
|
+
*,
|
|
87
|
+
headers: Optional[Dict[str, str]] = None,
|
|
88
|
+
cookies: Optional[Dict[str, str]] = None,
|
|
89
|
+
timeout: Optional[Union[int, float]] = None,
|
|
90
|
+
verify: Optional[bool] = None,
|
|
91
|
+
proxies: Optional[Dict[str, str]] = None,
|
|
92
|
+
http2: bool = False,
|
|
93
|
+
follow_redirects: bool = True,
|
|
94
|
+
) -> httpx.AsyncClient:
|
|
95
|
+
"""Factory for a configured httpx.AsyncClient."""
|
|
96
|
+
return httpx.AsyncClient(
|
|
97
|
+
headers=_default_headers(headers),
|
|
98
|
+
cookies=cookies,
|
|
99
|
+
timeout=timeout if timeout is not None else _get_timeout(),
|
|
100
|
+
verify=_get_verify() if verify is None else verify,
|
|
101
|
+
follow_redirects=follow_redirects,
|
|
102
|
+
http2=http2,
|
|
103
|
+
proxies=proxies if proxies is not None else _get_proxies(),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _sleep_with_backoff(attempt: int, base: float = 1.1, cap: float = 10.0) -> None:
|
|
108
|
+
"""Exponential backoff with jitter."""
|
|
109
|
+
delay = min(base * (2 ** attempt), cap)
|
|
110
|
+
# Add small jitter to avoid thundering herd
|
|
111
|
+
delay += random.uniform(0.0, 0.25)
|
|
112
|
+
time.sleep(delay)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def fetch(
|
|
116
|
+
url: str,
|
|
117
|
+
*,
|
|
118
|
+
method: str = "GET",
|
|
119
|
+
params: Optional[Dict[str, Any]] = None,
|
|
120
|
+
data: Optional[Any] = None,
|
|
121
|
+
json: Optional[Any] = None,
|
|
122
|
+
headers: Optional[Dict[str, str]] = None,
|
|
123
|
+
cookies: Optional[Dict[str, str]] = None,
|
|
124
|
+
timeout: Optional[Union[int, float]] = None,
|
|
125
|
+
verify: Optional[bool] = None,
|
|
126
|
+
proxies: Optional[Dict[str, str]] = None,
|
|
127
|
+
follow_redirects: bool = True,
|
|
128
|
+
http2: bool = False,
|
|
129
|
+
max_retry: Optional[int] = None,
|
|
130
|
+
return_content: bool = False,
|
|
131
|
+
) -> Optional[Union[str, bytes]]:
|
|
132
|
+
"""
|
|
133
|
+
Perform an HTTP request with retry. Returns text or bytes according to return_content.
|
|
134
|
+
Returns None if all retries fail.
|
|
135
|
+
"""
|
|
136
|
+
attempts = max_retry if max_retry is not None else _get_max_retry()
|
|
137
|
+
|
|
138
|
+
with create_client(
|
|
139
|
+
headers=headers,
|
|
140
|
+
cookies=cookies,
|
|
141
|
+
timeout=timeout,
|
|
142
|
+
verify=verify,
|
|
143
|
+
proxies=proxies,
|
|
144
|
+
http2=http2,
|
|
145
|
+
follow_redirects=follow_redirects,
|
|
146
|
+
) as client:
|
|
147
|
+
for attempt in range(attempts):
|
|
148
|
+
try:
|
|
149
|
+
resp = client.request(method, url, params=params, data=data, json=json)
|
|
150
|
+
resp.raise_for_status()
|
|
151
|
+
return resp.content if return_content else resp.text
|
|
152
|
+
except Exception:
|
|
153
|
+
if attempt + 1 >= attempts:
|
|
154
|
+
break
|
|
155
|
+
_sleep_with_backoff(attempt)
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
async def async_fetch(
|
|
160
|
+
url: str,
|
|
161
|
+
*,
|
|
162
|
+
method: str = "GET",
|
|
163
|
+
params: Optional[Dict[str, Any]] = None,
|
|
164
|
+
data: Optional[Any] = None,
|
|
165
|
+
json: Optional[Any] = None,
|
|
166
|
+
headers: Optional[Dict[str, str]] = None,
|
|
167
|
+
cookies: Optional[Dict[str, str]] = None,
|
|
168
|
+
timeout: Optional[Union[int, float]] = None,
|
|
169
|
+
verify: Optional[bool] = None,
|
|
170
|
+
proxies: Optional[Dict[str, str]] = None,
|
|
171
|
+
follow_redirects: bool = True,
|
|
172
|
+
http2: bool = False,
|
|
173
|
+
max_retry: Optional[int] = None,
|
|
174
|
+
return_content: bool = False,
|
|
175
|
+
) -> Optional[Union[str, bytes]]:
|
|
176
|
+
"""
|
|
177
|
+
Async HTTP request with retry. Returns text or bytes according to return_content.
|
|
178
|
+
Returns None if all retries fail.
|
|
179
|
+
"""
|
|
180
|
+
attempts = max_retry if max_retry is not None else _get_max_retry()
|
|
181
|
+
|
|
182
|
+
async with create_async_client(
|
|
183
|
+
headers=headers,
|
|
184
|
+
cookies=cookies,
|
|
185
|
+
timeout=timeout,
|
|
186
|
+
verify=verify,
|
|
187
|
+
proxies=proxies,
|
|
188
|
+
http2=http2,
|
|
189
|
+
follow_redirects=follow_redirects,
|
|
190
|
+
) as client:
|
|
191
|
+
for attempt in range(attempts):
|
|
192
|
+
try:
|
|
193
|
+
resp = await client.request(method, url, params=params, data=data, json=json)
|
|
194
|
+
resp.raise_for_status()
|
|
195
|
+
return resp.content if return_content else resp.text
|
|
196
|
+
except Exception:
|
|
197
|
+
if attempt + 1 >= attempts:
|
|
198
|
+
break
|
|
199
|
+
# Use same backoff logic for async by sleeping in thread (short duration)
|
|
200
|
+
_sleep_with_backoff(attempt)
|
|
201
|
+
return None
|
|
@@ -14,7 +14,7 @@ from StreamingCommunity.Util.config_json import config_manager
|
|
|
14
14
|
|
|
15
15
|
# Variable
|
|
16
16
|
console = Console()
|
|
17
|
-
CLEAN = config_manager.get_bool('DEFAULT', '
|
|
17
|
+
CLEAN = config_manager.get_bool('DEFAULT', 'show_message')
|
|
18
18
|
SHOW = config_manager.get_bool('DEFAULT', 'show_message')
|
|
19
19
|
|
|
20
20
|
|
StreamingCommunity/Util/os.py
CHANGED
|
@@ -5,7 +5,6 @@ import os
|
|
|
5
5
|
import glob
|
|
6
6
|
import sys
|
|
7
7
|
import shutil
|
|
8
|
-
import hashlib
|
|
9
8
|
import logging
|
|
10
9
|
import platform
|
|
11
10
|
import inspect
|
|
@@ -432,10 +431,11 @@ class OsSummary:
|
|
|
432
431
|
|
|
433
432
|
if not self.mp4decrypt_path:
|
|
434
433
|
console.log("[yellow]Warning: mp4decrypt not found")
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if self.
|
|
438
|
-
|
|
434
|
+
|
|
435
|
+
ffmpeg_str = f"'{self.ffmpeg_path}'" if self.ffmpeg_path else "None"
|
|
436
|
+
ffprobe_str = f"'{self.ffprobe_path}'" if self.ffprobe_path else "None"
|
|
437
|
+
mp4decrypt_str = f"'{self.mp4decrypt_path}'" if self.mp4decrypt_path else "None"
|
|
438
|
+
console.print(f"[cyan]Path: [red]ffmpeg [bold yellow]{ffmpeg_str}[/bold yellow][white], [red]ffprobe [bold yellow]{ffprobe_str}[/bold yellow][white], [red]mp4decrypt [bold yellow]{mp4decrypt_str}[/bold yellow]")
|
|
439
439
|
|
|
440
440
|
|
|
441
441
|
os_manager = OsManager()
|
StreamingCommunity/Util/table.py
CHANGED
|
@@ -107,7 +107,7 @@ class TVShowManager:
|
|
|
107
107
|
search_func = getattr(module, 'search')
|
|
108
108
|
search_func(None)
|
|
109
109
|
|
|
110
|
-
except Exception
|
|
110
|
+
except Exception:
|
|
111
111
|
logging.error("Error during search execution")
|
|
112
112
|
|
|
113
113
|
finally:
|
|
@@ -142,7 +142,7 @@ class TVShowManager:
|
|
|
142
142
|
|
|
143
143
|
# Handle pagination and user input
|
|
144
144
|
if self.slice_end < total_items:
|
|
145
|
-
self.console.print(
|
|
145
|
+
self.console.print("\n[green]Press [red]Enter [green]for next page, [red]'q' [green]to quit, or [red]'back' [green]to search.")
|
|
146
146
|
|
|
147
147
|
if not force_int_input:
|
|
148
148
|
prompt_msg = ("\n[cyan]Insert media index [yellow](e.g., 1), [red]* [cyan]to download all media, "
|
|
@@ -184,7 +184,7 @@ class TVShowManager:
|
|
|
184
184
|
|
|
185
185
|
else:
|
|
186
186
|
# Last page handling
|
|
187
|
-
self.console.print(
|
|
187
|
+
self.console.print("\n[green]You've reached the end. [red]Enter [green]for first page, [red]'q' [green]to quit, or [red]'back' [green]to search.")
|
|
188
188
|
|
|
189
189
|
if not force_int_input:
|
|
190
190
|
prompt_msg = ("\n[cyan]Insert media index [yellow](e.g., 1), [red]* [cyan]to download all media, "
|
StreamingCommunity/__init__.py
CHANGED
|
@@ -4,4 +4,12 @@ from .run import main
|
|
|
4
4
|
from .Lib.Downloader.HLS.downloader import HLS_Downloader
|
|
5
5
|
from .Lib.Downloader.MP4.downloader import MP4_downloader
|
|
6
6
|
from .Lib.Downloader.TOR.downloader import TOR_downloader
|
|
7
|
-
from .Lib.Downloader.DASH.downloader import DASH_Downloader
|
|
7
|
+
from .Lib.Downloader.DASH.downloader import DASH_Downloader
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"main",
|
|
11
|
+
"HLS_Downloader",
|
|
12
|
+
"MP4_downloader",
|
|
13
|
+
"TOR_downloader",
|
|
14
|
+
"DASH_Downloader"
|
|
15
|
+
]
|