StreamingCommunity 3.2.1__py3-none-any.whl → 3.2.7__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 +4 -0
- StreamingCommunity/Api/Player/hdplayer.py +2 -2
- StreamingCommunity/Api/Player/mixdrop.py +1 -1
- StreamingCommunity/Api/Player/vixcloud.py +4 -5
- StreamingCommunity/Api/Site/altadefinizione/film.py +2 -2
- StreamingCommunity/Api/Site/altadefinizione/series.py +1 -1
- StreamingCommunity/Api/Site/animeunity/serie.py +1 -1
- StreamingCommunity/Api/Site/animeworld/film.py +1 -1
- StreamingCommunity/Api/Site/animeworld/serie.py +1 -2
- StreamingCommunity/Api/Site/cb01new/film.py +1 -1
- StreamingCommunity/Api/Site/crunchyroll/__init__.py +103 -0
- StreamingCommunity/Api/Site/crunchyroll/film.py +82 -0
- StreamingCommunity/Api/Site/crunchyroll/series.py +186 -0
- StreamingCommunity/Api/Site/crunchyroll/site.py +113 -0
- StreamingCommunity/Api/Site/crunchyroll/util/ScrapeSerie.py +238 -0
- StreamingCommunity/Api/Site/crunchyroll/util/get_license.py +227 -0
- StreamingCommunity/Api/Site/guardaserie/series.py +1 -2
- StreamingCommunity/Api/Site/guardaserie/site.py +1 -2
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +9 -8
- StreamingCommunity/Api/Site/mediasetinfinity/__init__.py +96 -0
- StreamingCommunity/Api/Site/mediasetinfinity/film.py +85 -0
- StreamingCommunity/Api/Site/mediasetinfinity/series.py +185 -0
- StreamingCommunity/Api/Site/mediasetinfinity/site.py +112 -0
- StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +259 -0
- StreamingCommunity/Api/Site/mediasetinfinity/util/fix_mpd.py +64 -0
- StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +214 -0
- StreamingCommunity/Api/Site/raiplay/film.py +2 -2
- StreamingCommunity/Api/Site/raiplay/series.py +2 -1
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +6 -17
- StreamingCommunity/Api/Site/streamingcommunity/film.py +3 -3
- StreamingCommunity/Api/Site/streamingcommunity/series.py +11 -11
- StreamingCommunity/Api/Site/streamingcommunity/site.py +2 -4
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +3 -6
- StreamingCommunity/Api/Site/streamingwatch/__init__.py +6 -14
- StreamingCommunity/Api/Site/streamingwatch/film.py +3 -3
- StreamingCommunity/Api/Site/streamingwatch/series.py +9 -9
- StreamingCommunity/Api/Site/streamingwatch/site.py +5 -7
- StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +2 -2
- StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +131 -0
- StreamingCommunity/Lib/Downloader/DASH/decrypt.py +79 -0
- StreamingCommunity/Lib/Downloader/DASH/downloader.py +218 -0
- StreamingCommunity/Lib/Downloader/DASH/parser.py +249 -0
- StreamingCommunity/Lib/Downloader/DASH/segments.py +332 -0
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +10 -30
- StreamingCommunity/Lib/Downloader/HLS/segments.py +146 -263
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +0 -5
- StreamingCommunity/Lib/FFmpeg/capture.py +3 -3
- StreamingCommunity/Lib/FFmpeg/command.py +1 -1
- StreamingCommunity/TelegramHelp/config.json +3 -7
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/bento4_installer.py +191 -0
- StreamingCommunity/Util/config_json.py +1 -1
- StreamingCommunity/Util/headers.py +0 -3
- StreamingCommunity/Util/os.py +36 -46
- StreamingCommunity/__init__.py +2 -1
- StreamingCommunity/run.py +11 -10
- {streamingcommunity-3.2.1.dist-info → streamingcommunity-3.2.7.dist-info}/METADATA +7 -9
- streamingcommunity-3.2.7.dist-info/RECORD +111 -0
- StreamingCommunity/Api/Site/1337xx/__init__.py +0 -72
- StreamingCommunity/Api/Site/1337xx/site.py +0 -82
- StreamingCommunity/Api/Site/1337xx/title.py +0 -61
- StreamingCommunity/Lib/Proxies/proxy.py +0 -72
- streamingcommunity-3.2.1.dist-info/RECORD +0 -96
- {streamingcommunity-3.2.1.dist-info → streamingcommunity-3.2.7.dist-info}/WHEEL +0 -0
- {streamingcommunity-3.2.1.dist-info → streamingcommunity-3.2.7.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-3.2.1.dist-info → streamingcommunity-3.2.7.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-3.2.1.dist-info → streamingcommunity-3.2.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 16.03.25
|
|
2
|
+
|
|
3
|
+
from urllib.parse import urlparse, urlunparse
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# External library
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def try_mpd(url, qualities):
|
|
11
|
+
"""
|
|
12
|
+
Given a url containing one of the qualities (hd/hr/sd), try to replace it with the others and check which manifest exists.
|
|
13
|
+
"""
|
|
14
|
+
parsed = urlparse(url)
|
|
15
|
+
path_parts = parsed.path.rsplit('/', 1)
|
|
16
|
+
|
|
17
|
+
if len(path_parts) != 2:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
dir_path, filename = path_parts
|
|
21
|
+
|
|
22
|
+
# Find the current quality in the filename
|
|
23
|
+
def replace_quality(filename, old_q, new_q):
|
|
24
|
+
if f"{old_q}_" in filename:
|
|
25
|
+
return filename.replace(f"{old_q}_", f"{new_q}_", 1)
|
|
26
|
+
elif filename.startswith(f"{old_q}_"):
|
|
27
|
+
return f"{new_q}_" + filename[len(f"{old_q}_") :]
|
|
28
|
+
return filename
|
|
29
|
+
|
|
30
|
+
for q in qualities:
|
|
31
|
+
|
|
32
|
+
# Search for which quality is present in the filename
|
|
33
|
+
for old_q in qualities:
|
|
34
|
+
if f"{old_q}_" in filename or filename.startswith(f"{old_q}_"):
|
|
35
|
+
new_filename = replace_quality(filename, old_q, q)
|
|
36
|
+
break
|
|
37
|
+
|
|
38
|
+
else:
|
|
39
|
+
new_filename = filename # No quality found, use original filename
|
|
40
|
+
|
|
41
|
+
new_path = f"{dir_path}/{new_filename}"
|
|
42
|
+
mpd_url = urlunparse(parsed._replace(path=new_path)).strip()
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
r = httpx.head(mpd_url, timeout=5)
|
|
46
|
+
if r.status_code == 200:
|
|
47
|
+
return mpd_url
|
|
48
|
+
|
|
49
|
+
except Exception:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
def get_manifest(base):
|
|
55
|
+
"""
|
|
56
|
+
Try to get the manifest URL by checking different qualities.
|
|
57
|
+
"""
|
|
58
|
+
manifest_qualities = ["hd", "hr", "sd"]
|
|
59
|
+
|
|
60
|
+
mpd_url = try_mpd(base, manifest_qualities)
|
|
61
|
+
if not mpd_url:
|
|
62
|
+
exit(1)
|
|
63
|
+
|
|
64
|
+
return mpd_url
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# 16.03.25
|
|
2
|
+
|
|
3
|
+
from urllib.parse import urlencode
|
|
4
|
+
import xml.etree.ElementTree as ET
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# External library
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Internal utilities
|
|
12
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
13
|
+
from StreamingCommunity.Util.headers import get_headers, get_userAgent
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Variable
|
|
17
|
+
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
18
|
+
bearer_token = None
|
|
19
|
+
playback_json = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_bearer_token():
|
|
23
|
+
"""
|
|
24
|
+
Gets the BEARER_TOKEN for authentication.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
str: The bearer token string.
|
|
28
|
+
"""
|
|
29
|
+
global bearer_token
|
|
30
|
+
|
|
31
|
+
if bearer_token:
|
|
32
|
+
return bearer_token
|
|
33
|
+
|
|
34
|
+
LOGIN_URL = "https://api-ott-prod-fe.mediaset.net/PROD/play/idm/anonymous/login/v2.0"
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
response = httpx.post(
|
|
38
|
+
LOGIN_URL,
|
|
39
|
+
json={'client_id': 'client_id', 'appName': 'embed//mediasetplay-embed'},
|
|
40
|
+
follow_redirects=True,
|
|
41
|
+
timeout=MAX_TIMEOUT
|
|
42
|
+
)
|
|
43
|
+
response.raise_for_status()
|
|
44
|
+
|
|
45
|
+
# Extract the bearer token from the response
|
|
46
|
+
data = response.json()
|
|
47
|
+
bearer_token = data["response"]["beToken"]
|
|
48
|
+
return bearer_token
|
|
49
|
+
|
|
50
|
+
except Exception as e:
|
|
51
|
+
raise RuntimeError(f"Failed to get bearer token: {e}")
|
|
52
|
+
|
|
53
|
+
def get_playback_url(BEARER_TOKEN, CONTENT_ID):
|
|
54
|
+
"""
|
|
55
|
+
Gets the playback URL for the specified content.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
BEARER_TOKEN (str): The authentication token.
|
|
59
|
+
CONTENT_ID (str): The content identifier.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
dict: The playback JSON object.
|
|
63
|
+
"""
|
|
64
|
+
global playback_json
|
|
65
|
+
|
|
66
|
+
if playback_json is not None:
|
|
67
|
+
return playback_json
|
|
68
|
+
|
|
69
|
+
headers = get_headers()
|
|
70
|
+
headers['authorization'] = f'Bearer {BEARER_TOKEN}'
|
|
71
|
+
|
|
72
|
+
json_data = {
|
|
73
|
+
'contentId': CONTENT_ID,
|
|
74
|
+
'streamType': 'VOD'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
response = httpx.post(
|
|
79
|
+
'https://api-ott-prod-fe.mediaset.net/PROD/play/playback/check/v2.0',
|
|
80
|
+
headers=headers,
|
|
81
|
+
json=json_data,
|
|
82
|
+
follow_redirects=True,
|
|
83
|
+
timeout=MAX_TIMEOUT
|
|
84
|
+
)
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
resp_json = response.json()
|
|
87
|
+
|
|
88
|
+
# Check for PL022 error (Infinity+ rights)
|
|
89
|
+
if 'error' in resp_json and resp_json['error'].get('code') == 'PL022':
|
|
90
|
+
raise RuntimeError("Infinity+ required for this content.")
|
|
91
|
+
|
|
92
|
+
# Check for PL402 error (TVOD not purchased)
|
|
93
|
+
if 'error' in resp_json and resp_json['error'].get('code') == 'PL402':
|
|
94
|
+
raise RuntimeError("Content available for rental: you must rent it first.")
|
|
95
|
+
|
|
96
|
+
playback_json = resp_json['response']['mediaSelector']
|
|
97
|
+
return playback_json
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
raise RuntimeError(f"Failed to get playback URL: {e}")
|
|
101
|
+
|
|
102
|
+
def parse_tracking_data(tracking_value):
|
|
103
|
+
"""
|
|
104
|
+
Parses the trackingData string into a dictionary.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
tracking_value (str): The tracking data string.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
dict: Parsed tracking data.
|
|
111
|
+
"""
|
|
112
|
+
return dict(item.split('=', 1) for item in tracking_value.split('|') if '=' in item)
|
|
113
|
+
|
|
114
|
+
def parse_smil_for_tracking_and_video(smil_xml):
|
|
115
|
+
"""
|
|
116
|
+
Extracts all video_src and trackingData pairs from the SMIL.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
smil_xml (str): The SMIL XML as a string.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
list: A list of dicts: {'video_src': ..., 'tracking_info': ...}
|
|
123
|
+
"""
|
|
124
|
+
results = []
|
|
125
|
+
root = ET.fromstring(smil_xml)
|
|
126
|
+
ns = {'smil': root.tag.split('}')[0].strip('{')}
|
|
127
|
+
|
|
128
|
+
# Search all <par>
|
|
129
|
+
for par in root.findall('.//smil:par', ns):
|
|
130
|
+
video_src = None
|
|
131
|
+
tracking_info = None
|
|
132
|
+
|
|
133
|
+
# Search <video> inside <par>
|
|
134
|
+
video_elem = par.find('.//smil:video', ns)
|
|
135
|
+
if video_elem is not None:
|
|
136
|
+
video_src = video_elem.attrib.get('src')
|
|
137
|
+
|
|
138
|
+
# Search <ref> inside <par>
|
|
139
|
+
ref_elem = par.find('.//smil:ref', ns)
|
|
140
|
+
if ref_elem is not None:
|
|
141
|
+
# Search <param name="trackingData">
|
|
142
|
+
for param in ref_elem.findall('.//smil:param', ns):
|
|
143
|
+
if param.attrib.get('name') == 'trackingData':
|
|
144
|
+
tracking_value = param.attrib.get('value')
|
|
145
|
+
if tracking_value:
|
|
146
|
+
tracking_info = parse_tracking_data(tracking_value)
|
|
147
|
+
break
|
|
148
|
+
|
|
149
|
+
if video_src and tracking_info:
|
|
150
|
+
results.append({'video_src': video_src, 'tracking_info': tracking_info})
|
|
151
|
+
|
|
152
|
+
return results
|
|
153
|
+
|
|
154
|
+
def get_tracking_info(BEARER_TOKEN, PLAYBACK_JSON):
|
|
155
|
+
"""
|
|
156
|
+
Retrieves tracking information from the playback JSON.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
BEARER_TOKEN (str): The authentication token.
|
|
160
|
+
PLAYBACK_JSON (dict): The playback JSON object.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
list or None: List of tracking info dicts, or None if request fails.
|
|
164
|
+
"""
|
|
165
|
+
params = {
|
|
166
|
+
"format": "SMIL",
|
|
167
|
+
"auth": BEARER_TOKEN,
|
|
168
|
+
"formats": "MPEG-DASH",
|
|
169
|
+
"assetTypes": "HR,browser,widevine,geoIT|geoNo:HR,browser,geoIT|geoNo:SD,browser,widevine,geoIT|geoNo:SD,browser,geoIT|geoNo:SS,browser,widevine,geoIT|geoNo:SS,browser,geoIT|geoNo",
|
|
170
|
+
"balance": "true",
|
|
171
|
+
"auto": "true",
|
|
172
|
+
"tracking": "true",
|
|
173
|
+
"delivery": "Streaming"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if 'publicUrl' in PLAYBACK_JSON:
|
|
177
|
+
params['publicUrl'] = PLAYBACK_JSON['publicUrl']
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
response = httpx.get(
|
|
181
|
+
PLAYBACK_JSON['url'],
|
|
182
|
+
headers={'user-agent': get_userAgent()},
|
|
183
|
+
params=params,
|
|
184
|
+
follow_redirects=True,
|
|
185
|
+
timeout=MAX_TIMEOUT
|
|
186
|
+
)
|
|
187
|
+
response.raise_for_status()
|
|
188
|
+
|
|
189
|
+
smil_xml = response.text
|
|
190
|
+
results = parse_smil_for_tracking_and_video(smil_xml)
|
|
191
|
+
return results
|
|
192
|
+
|
|
193
|
+
except Exception as e:
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
def generate_license_url(BEARER_TOKEN, tracking_info):
|
|
197
|
+
"""
|
|
198
|
+
Generates the URL to obtain the Widevine license.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
BEARER_TOKEN (str): The authentication token.
|
|
202
|
+
tracking_info (dict): The tracking info dictionary.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
str: The full license URL.
|
|
206
|
+
"""
|
|
207
|
+
params = {
|
|
208
|
+
'releasePid': tracking_info['tracking_info'].get('pid'),
|
|
209
|
+
'account': f"http://access.auth.theplatform.com/data/Account/{tracking_info['tracking_info'].get('aid')}",
|
|
210
|
+
'schema': '1.0',
|
|
211
|
+
'token': BEARER_TOKEN,
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return f"{'https://widevine.entitlement.theplatform.eu/wv/web/ModularDrm/getRawWidevineLicense'}?{urlencode(params)}"
|
|
@@ -11,9 +11,8 @@ from rich.console import Console
|
|
|
11
11
|
|
|
12
12
|
# Internal utilities
|
|
13
13
|
from StreamingCommunity.Util.os import os_manager
|
|
14
|
-
from StreamingCommunity.Util.message import start_message
|
|
15
|
-
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
|
16
14
|
from StreamingCommunity.Util.headers import get_headers
|
|
15
|
+
from StreamingCommunity.Util.message import start_message
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
# Logic class
|
|
@@ -22,6 +21,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
# Player
|
|
24
|
+
from StreamingCommunity import HLS_Downloader
|
|
25
25
|
from StreamingCommunity.Api.Player.mediapolisvod import VideoSource
|
|
26
26
|
|
|
27
27
|
|
|
@@ -11,7 +11,7 @@ from rich.prompt import Prompt
|
|
|
11
11
|
|
|
12
12
|
# Internal utilities
|
|
13
13
|
from StreamingCommunity.Util.message import start_message
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
|
|
16
16
|
# Logic class
|
|
17
17
|
from .util.ScrapeSerie import GetSerieInfo
|
|
@@ -27,6 +27,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
# Player
|
|
30
|
+
from StreamingCommunity import HLS_Downloader
|
|
30
31
|
from StreamingCommunity.Api.Player.mediapolisvod import VideoSource
|
|
31
32
|
|
|
32
33
|
|
|
@@ -12,7 +12,6 @@ from rich.prompt import Prompt
|
|
|
12
12
|
|
|
13
13
|
# Internal utilities
|
|
14
14
|
from StreamingCommunity.Api.Template import get_select_title
|
|
15
|
-
from StreamingCommunity.Lib.Proxies.proxy import ProxyFinder
|
|
16
15
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
17
16
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
18
17
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
@@ -33,7 +32,6 @@ _deprecate = False
|
|
|
33
32
|
|
|
34
33
|
msg = Prompt()
|
|
35
34
|
console = Console()
|
|
36
|
-
proxy = None
|
|
37
35
|
|
|
38
36
|
|
|
39
37
|
def get_user_input(string_to_search: str = None):
|
|
@@ -74,7 +72,7 @@ def get_user_input(string_to_search: str = None):
|
|
|
74
72
|
else:
|
|
75
73
|
return msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
76
74
|
|
|
77
|
-
def process_search_result(select_title, selections=None
|
|
75
|
+
def process_search_result(select_title, selections=None):
|
|
78
76
|
"""
|
|
79
77
|
Handles the search result and initiates the download for either a film or series.
|
|
80
78
|
|
|
@@ -82,7 +80,6 @@ def process_search_result(select_title, selections=None, proxy=None):
|
|
|
82
80
|
select_title (MediaItem): The selected media item. Can be None if selection fails.
|
|
83
81
|
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
84
82
|
e.g., {'season': season_selection, 'episode': episode_selection}
|
|
85
|
-
proxy (str, optional): The proxy to use for downloads.
|
|
86
83
|
"""
|
|
87
84
|
if not select_title:
|
|
88
85
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -100,10 +97,10 @@ def process_search_result(select_title, selections=None, proxy=None):
|
|
|
100
97
|
season_selection = selections.get('season')
|
|
101
98
|
episode_selection = selections.get('episode')
|
|
102
99
|
|
|
103
|
-
download_series(select_title, season_selection, episode_selection
|
|
100
|
+
download_series(select_title, season_selection, episode_selection)
|
|
104
101
|
|
|
105
102
|
else:
|
|
106
|
-
download_film(select_title
|
|
103
|
+
download_film(select_title)
|
|
107
104
|
|
|
108
105
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
109
106
|
"""
|
|
@@ -121,17 +118,11 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
121
118
|
if site_constant.TELEGRAM_BOT:
|
|
122
119
|
bot = get_bot_instance()
|
|
123
120
|
|
|
124
|
-
# Check proxy if not already set
|
|
125
|
-
finder = ProxyFinder(site_constant.FULL_URL)
|
|
126
|
-
proxy = finder.find_fast_proxy()
|
|
127
|
-
|
|
128
121
|
if direct_item:
|
|
129
122
|
select_title_obj = MediaItem(**direct_item)
|
|
130
|
-
process_search_result(select_title_obj, selections
|
|
123
|
+
process_search_result(select_title_obj, selections)
|
|
131
124
|
return
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
|
|
135
126
|
actual_search_query = get_user_input(string_to_search)
|
|
136
127
|
|
|
137
128
|
# Handle cases where user input is empty, or 'back' was handled (sys.exit or None return)
|
|
@@ -142,9 +133,7 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
142
133
|
return
|
|
143
134
|
|
|
144
135
|
# Perform search on the database using the obtained query
|
|
145
|
-
|
|
146
|
-
proxy = finder.find_fast_proxy()
|
|
147
|
-
len_database = title_search(actual_search_query, proxy)
|
|
136
|
+
len_database = title_search(actual_search_query)
|
|
148
137
|
|
|
149
138
|
# If only the database object (media_search_manager populated by title_search) is needed
|
|
150
139
|
if get_onlyDatabase:
|
|
@@ -152,7 +141,7 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
152
141
|
|
|
153
142
|
if len_database > 0:
|
|
154
143
|
select_title = get_select_title(table_show_manager, media_search_manager, len_database)
|
|
155
|
-
process_search_result(select_title, selections
|
|
144
|
+
process_search_result(select_title, selections)
|
|
156
145
|
|
|
157
146
|
else:
|
|
158
147
|
no_results_message = f"No results found for: '{actual_search_query}'"
|
|
@@ -10,7 +10,6 @@ from rich.console import Console
|
|
|
10
10
|
# Internal utilities
|
|
11
11
|
from StreamingCommunity.Util.os import os_manager
|
|
12
12
|
from StreamingCommunity.Util.message import start_message
|
|
13
|
-
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
|
14
13
|
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bot_instance
|
|
15
14
|
|
|
16
15
|
|
|
@@ -20,6 +19,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
# Player
|
|
22
|
+
from StreamingCommunity import HLS_Downloader
|
|
23
23
|
from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
|
24
24
|
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
|
|
27
27
|
console = Console()
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def download_film(select_title: MediaItem
|
|
30
|
+
def download_film(select_title: MediaItem) -> str:
|
|
31
31
|
"""
|
|
32
32
|
Downloads a film using the provided film ID, title name, and domain.
|
|
33
33
|
|
|
@@ -55,7 +55,7 @@ def download_film(select_title: MediaItem, proxy: str = None) -> str:
|
|
|
55
55
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
|
|
56
56
|
|
|
57
57
|
# Init class
|
|
58
|
-
video_source = VideoSource(f"{site_constant.FULL_URL}/it", False, select_title.id
|
|
58
|
+
video_source = VideoSource(f"{site_constant.FULL_URL}/it", False, select_title.id)
|
|
59
59
|
|
|
60
60
|
# Retrieve scws and if available master playlist
|
|
61
61
|
video_source.get_iframe(select_title.id)
|
|
@@ -11,15 +11,14 @@ from rich.prompt import Prompt
|
|
|
11
11
|
|
|
12
12
|
# Internal utilities
|
|
13
13
|
from StreamingCommunity.Util.message import start_message
|
|
14
|
-
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
|
15
14
|
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bot_instance
|
|
16
15
|
|
|
16
|
+
|
|
17
17
|
# Logic class
|
|
18
18
|
from .util.ScrapeSerie import GetSerieInfo
|
|
19
19
|
from StreamingCommunity.Api.Template.Util import (
|
|
20
20
|
manage_selection,
|
|
21
21
|
map_episode_title,
|
|
22
|
-
dynamic_format_number,
|
|
23
22
|
validate_selection,
|
|
24
23
|
validate_episode_selection,
|
|
25
24
|
display_episodes_list
|
|
@@ -29,6 +28,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
# Player
|
|
31
|
+
from StreamingCommunity import HLS_Downloader
|
|
32
32
|
from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
|
33
33
|
|
|
34
34
|
|
|
@@ -142,7 +142,7 @@ def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, vid
|
|
|
142
142
|
break
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
def download_series(select_season: MediaItem, season_selection: str = None, episode_selection: str = None
|
|
145
|
+
def download_series(select_season: MediaItem, season_selection: str = None, episode_selection: str = None) -> None:
|
|
146
146
|
"""
|
|
147
147
|
Handle downloading a complete series.
|
|
148
148
|
|
|
@@ -154,8 +154,8 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
154
154
|
start_message()
|
|
155
155
|
|
|
156
156
|
# Init class
|
|
157
|
-
video_source = VideoSource(f"{site_constant.FULL_URL}/it", True, select_season.id
|
|
158
|
-
scrape_serie = GetSerieInfo(f"{site_constant.FULL_URL}/it", select_season.id, select_season.slug
|
|
157
|
+
video_source = VideoSource(f"{site_constant.FULL_URL}/it", True, select_season.id)
|
|
158
|
+
scrape_serie = GetSerieInfo(f"{site_constant.FULL_URL}/it", select_season.id, select_season.slug)
|
|
159
159
|
|
|
160
160
|
# Collect information about season
|
|
161
161
|
scrape_serie.getNumberSeason()
|
|
@@ -200,11 +200,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
200
200
|
|
|
201
201
|
# Loop through the selected seasons and download episodes
|
|
202
202
|
for i_season in list_season_select:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
203
|
+
try:
|
|
204
|
+
season = scrape_serie.seasons_manager.seasons[i_season - 1]
|
|
205
|
+
except IndexError:
|
|
206
|
+
console.print(f"[red]Season index {i_season} not found! Available seasons: {[s.number for s in scrape_serie.seasons_manager.seasons]}")
|
|
207
|
+
continue
|
|
208
208
|
season_number = season.number
|
|
209
209
|
|
|
210
210
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
@@ -219,4 +219,4 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
219
219
|
# Get script_id
|
|
220
220
|
script_id = TelegramSession.get_session()
|
|
221
221
|
if script_id != "unknown":
|
|
222
|
-
TelegramSession.deleteScriptId(script_id)
|
|
222
|
+
TelegramSession.deleteScriptId(script_id)
|
|
@@ -28,7 +28,7 @@ table_show_manager = TVShowManager()
|
|
|
28
28
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def title_search(query: str
|
|
31
|
+
def title_search(query: str) -> int:
|
|
32
32
|
"""
|
|
33
33
|
Search for titles based on a search query.
|
|
34
34
|
|
|
@@ -49,7 +49,6 @@ def title_search(query: str, proxy: str) -> int:
|
|
|
49
49
|
f"{site_constant.FULL_URL}/it",
|
|
50
50
|
headers={'user-agent': get_userAgent()},
|
|
51
51
|
timeout=max_timeout,
|
|
52
|
-
proxy=proxy,
|
|
53
52
|
follow_redirects=True
|
|
54
53
|
)
|
|
55
54
|
response.raise_for_status()
|
|
@@ -74,8 +73,7 @@ def title_search(query: str, proxy: str) -> int:
|
|
|
74
73
|
'x-inertia': 'true',
|
|
75
74
|
'x-inertia-version': version
|
|
76
75
|
},
|
|
77
|
-
timeout=max_timeout
|
|
78
|
-
proxy=proxy
|
|
76
|
+
timeout=max_timeout
|
|
79
77
|
)
|
|
80
78
|
response.raise_for_status()
|
|
81
79
|
|
|
@@ -20,7 +20,7 @@ max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class GetSerieInfo:
|
|
23
|
-
def __init__(self, url, media_id: int = None, series_name: str = None
|
|
23
|
+
def __init__(self, url, media_id: int = None, series_name: str = None):
|
|
24
24
|
"""
|
|
25
25
|
Initialize the GetSerieInfo class for scraping TV series information.
|
|
26
26
|
|
|
@@ -32,7 +32,6 @@ class GetSerieInfo:
|
|
|
32
32
|
self.is_series = False
|
|
33
33
|
self.headers = {'user-agent': get_userAgent()}
|
|
34
34
|
self.url = url
|
|
35
|
-
self.proxy = proxy
|
|
36
35
|
self.media_id = media_id
|
|
37
36
|
self.seasons_manager = SeasonManager()
|
|
38
37
|
|
|
@@ -51,8 +50,7 @@ class GetSerieInfo:
|
|
|
51
50
|
response = httpx.get(
|
|
52
51
|
url=f"{self.url}/titles/{self.media_id}-{self.series_name}",
|
|
53
52
|
headers=self.headers,
|
|
54
|
-
timeout=max_timeout
|
|
55
|
-
proxy=self.proxy
|
|
53
|
+
timeout=max_timeout
|
|
56
54
|
)
|
|
57
55
|
response.raise_for_status()
|
|
58
56
|
|
|
@@ -106,8 +104,7 @@ class GetSerieInfo:
|
|
|
106
104
|
'x-inertia': 'true',
|
|
107
105
|
'x-inertia-version': self.version,
|
|
108
106
|
},
|
|
109
|
-
timeout=max_timeout
|
|
110
|
-
proxy=self.proxy
|
|
107
|
+
timeout=max_timeout
|
|
111
108
|
)
|
|
112
109
|
|
|
113
110
|
# Extract episodes from JSON response
|
|
@@ -7,7 +7,6 @@ from rich.prompt import Prompt
|
|
|
7
7
|
|
|
8
8
|
# Internal utilities
|
|
9
9
|
from StreamingCommunity.Api.Template import get_select_title
|
|
10
|
-
from StreamingCommunity.Lib.Proxies.proxy import ProxyFinder
|
|
11
10
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
12
11
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
13
12
|
|
|
@@ -27,7 +26,6 @@ _deprecate = False
|
|
|
27
26
|
|
|
28
27
|
msg = Prompt()
|
|
29
28
|
console = Console()
|
|
30
|
-
proxy = None
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
def get_user_input(string_to_search: str = None):
|
|
@@ -38,7 +36,7 @@ def get_user_input(string_to_search: str = None):
|
|
|
38
36
|
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
39
37
|
return string_to_search
|
|
40
38
|
|
|
41
|
-
def process_search_result(select_title, selections=None
|
|
39
|
+
def process_search_result(select_title, selections=None):
|
|
42
40
|
"""
|
|
43
41
|
Handles the search result and initiates the download for either a film or series.
|
|
44
42
|
|
|
@@ -55,10 +53,10 @@ def process_search_result(select_title, selections=None, proxy=None):
|
|
|
55
53
|
season_selection = selections.get('season')
|
|
56
54
|
episode_selection = selections.get('episode')
|
|
57
55
|
|
|
58
|
-
download_series(select_title, season_selection, episode_selection
|
|
56
|
+
download_series(select_title, season_selection, episode_selection)
|
|
59
57
|
|
|
60
58
|
else:
|
|
61
|
-
download_film(select_title
|
|
59
|
+
download_film(select_title)
|
|
62
60
|
|
|
63
61
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
64
62
|
"""
|
|
@@ -73,20 +71,14 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
73
71
|
"""
|
|
74
72
|
if direct_item:
|
|
75
73
|
select_title = MediaItem(**direct_item)
|
|
76
|
-
process_search_result(select_title, selections)
|
|
74
|
+
process_search_result(select_title, selections)
|
|
77
75
|
return
|
|
78
76
|
|
|
79
|
-
# Check proxy if not already set
|
|
80
|
-
finder = ProxyFinder(site_constant.FULL_URL)
|
|
81
|
-
proxy = finder.find_fast_proxy()
|
|
82
|
-
|
|
83
77
|
if string_to_search is None:
|
|
84
78
|
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
85
79
|
|
|
86
80
|
# Perform search on the database using the obtained query
|
|
87
|
-
|
|
88
|
-
proxy = finder.find_fast_proxy()
|
|
89
|
-
len_database = title_search(string_to_search, proxy)
|
|
81
|
+
len_database = title_search(string_to_search)
|
|
90
82
|
|
|
91
83
|
# If only the database is needed, return the manager
|
|
92
84
|
if get_onlyDatabase:
|
|
@@ -94,7 +86,7 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
94
86
|
|
|
95
87
|
if len_database > 0:
|
|
96
88
|
select_title = get_select_title(table_show_manager, media_search_manager,len_database)
|
|
97
|
-
process_search_result(select_title, selections
|
|
89
|
+
process_search_result(select_title, selections)
|
|
98
90
|
|
|
99
91
|
else:
|
|
100
92
|
# If no results are found, ask again
|
|
@@ -10,7 +10,6 @@ from rich.console import Console
|
|
|
10
10
|
# Internal utilities
|
|
11
11
|
from StreamingCommunity.Util.os import os_manager
|
|
12
12
|
from StreamingCommunity.Util.message import start_message
|
|
13
|
-
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
# Logic class
|
|
@@ -19,6 +18,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
# Player
|
|
21
|
+
from StreamingCommunity import HLS_Downloader
|
|
22
22
|
from StreamingCommunity.Api.Player.hdplayer import VideoSource
|
|
23
23
|
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ from StreamingCommunity.Api.Player.hdplayer import VideoSource
|
|
|
26
26
|
console = Console()
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def download_film(select_title: MediaItem
|
|
29
|
+
def download_film(select_title: MediaItem) -> str:
|
|
30
30
|
"""
|
|
31
31
|
Downloads a film using the provided film ID, title name, and domain.
|
|
32
32
|
|
|
@@ -41,7 +41,7 @@ def download_film(select_title: MediaItem, proxy) -> str:
|
|
|
41
41
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
|
|
42
42
|
|
|
43
43
|
# Get master playlists
|
|
44
|
-
video_source = VideoSource(
|
|
44
|
+
video_source = VideoSource()
|
|
45
45
|
master_playlist = video_source.get_m3u8_url(select_title.url)
|
|
46
46
|
|
|
47
47
|
# Define the filename and path for the downloaded film
|