StreamingCommunity 2.6.1__py3-none-any.whl → 2.8.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 +4 -4
- StreamingCommunity/Api/Player/maxstream.py +10 -16
- StreamingCommunity/Api/Player/supervideo.py +9 -35
- StreamingCommunity/Api/Player/vixcloud.py +18 -92
- StreamingCommunity/Api/Site/1337xx/__init__.py +8 -1
- StreamingCommunity/Api/Site/1337xx/site.py +16 -15
- StreamingCommunity/Api/Site/1337xx/title.py +7 -5
- StreamingCommunity/Api/Site/animeunity/__init__.py +9 -2
- StreamingCommunity/Api/Site/animeunity/film_serie.py +12 -5
- StreamingCommunity/Api/Site/animeunity/site.py +14 -10
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +9 -10
- StreamingCommunity/Api/Site/cb01new/__init__.py +8 -1
- StreamingCommunity/Api/Site/cb01new/film.py +7 -1
- StreamingCommunity/Api/Site/cb01new/site.py +24 -15
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +9 -2
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +7 -1
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +16 -15
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +3 -3
- StreamingCommunity/Api/Site/guardaserie/__init__.py +9 -2
- StreamingCommunity/Api/Site/guardaserie/series.py +9 -1
- StreamingCommunity/Api/Site/guardaserie/site.py +23 -22
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +5 -4
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +6 -2
- StreamingCommunity/Api/Site/mostraguarda/film.py +10 -6
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +9 -2
- StreamingCommunity/Api/Site/streamingcommunity/film.py +9 -2
- StreamingCommunity/Api/Site/streamingcommunity/series.py +15 -6
- StreamingCommunity/Api/Site/streamingcommunity/site.py +16 -14
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +10 -11
- StreamingCommunity/Api/Template/Util/__init__.py +0 -1
- StreamingCommunity/Api/Template/Util/get_domain.py +31 -134
- StreamingCommunity/Api/Template/Util/manage_ep.py +10 -5
- StreamingCommunity/Api/Template/config_loader.py +14 -10
- StreamingCommunity/Api/Template/site.py +3 -6
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +12 -15
- StreamingCommunity/Lib/Downloader/HLS/segments.py +14 -34
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +14 -11
- StreamingCommunity/Lib/Downloader/TOR/downloader.py +109 -101
- StreamingCommunity/Lib/FFmpeg/__init__.py +1 -1
- StreamingCommunity/Lib/FFmpeg/capture.py +10 -12
- StreamingCommunity/Lib/FFmpeg/command.py +15 -14
- StreamingCommunity/Lib/FFmpeg/util.py +9 -38
- StreamingCommunity/Lib/M3U8/decryptor.py +72 -146
- StreamingCommunity/Lib/M3U8/estimator.py +8 -16
- StreamingCommunity/Lib/M3U8/parser.py +1 -17
- StreamingCommunity/Lib/M3U8/url_fixer.py +1 -4
- StreamingCommunity/Lib/TMBD/__init__.py +2 -0
- StreamingCommunity/Lib/TMBD/obj_tmbd.py +3 -17
- StreamingCommunity/Lib/TMBD/tmdb.py +4 -9
- StreamingCommunity/TelegramHelp/telegram_bot.py +50 -50
- StreamingCommunity/Upload/update.py +6 -5
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/color.py +1 -1
- StreamingCommunity/Util/config_json.py +435 -0
- StreamingCommunity/Util/headers.py +7 -36
- StreamingCommunity/Util/logger.py +72 -42
- StreamingCommunity/Util/message.py +8 -3
- StreamingCommunity/Util/os.py +41 -93
- StreamingCommunity/Util/table.py +8 -17
- StreamingCommunity/run.py +39 -43
- {StreamingCommunity-2.6.1.dist-info → StreamingCommunity-2.8.0.dist-info}/METADATA +203 -114
- StreamingCommunity-2.8.0.dist-info/RECORD +75 -0
- StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +0 -53
- StreamingCommunity/Api/Site/ilcorsaronero/site.py +0 -64
- StreamingCommunity/Api/Site/ilcorsaronero/title.py +0 -42
- StreamingCommunity/Api/Site/ilcorsaronero/util/ilCorsarScraper.py +0 -149
- StreamingCommunity/Api/Template/Util/recall_search.py +0 -37
- StreamingCommunity/Lib/Downloader/HLS/proxyes.py +0 -110
- StreamingCommunity/Util/_jsonConfig.py +0 -241
- StreamingCommunity/Util/call_stack.py +0 -42
- StreamingCommunity/Util/console.py +0 -12
- StreamingCommunity-2.6.1.dist-info/RECORD +0 -83
- {StreamingCommunity-2.6.1.dist-info → StreamingCommunity-2.8.0.dist-info}/LICENSE +0 -0
- {StreamingCommunity-2.6.1.dist-info → StreamingCommunity-2.8.0.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.6.1.dist-info → StreamingCommunity-2.8.0.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-2.6.1.dist-info → StreamingCommunity-2.8.0.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# 10.12.23
|
|
2
2
|
|
|
3
|
+
import sys
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
# External libraries
|
|
5
7
|
import httpx
|
|
8
|
+
from rich.console import Console
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
# Internal utilities
|
|
9
|
-
from StreamingCommunity.Util.
|
|
10
|
-
from StreamingCommunity.Util.
|
|
11
|
-
from StreamingCommunity.Util.headers import get_headers
|
|
12
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
13
|
+
from StreamingCommunity.Util.headers import get_userAgent
|
|
12
14
|
from StreamingCommunity.Util.table import TVShowManager
|
|
13
15
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
14
16
|
|
|
@@ -19,12 +21,11 @@ from StreamingCommunity.Api.Template.Util import search_domain
|
|
|
19
21
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
|
|
23
24
|
# Variable
|
|
25
|
+
console = Console()
|
|
24
26
|
media_search_manager = MediaManager()
|
|
25
27
|
table_show_manager = TVShowManager()
|
|
26
28
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
27
|
-
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
def title_search(title_search: str) -> int:
|
|
@@ -37,23 +38,24 @@ def title_search(title_search: str) -> int:
|
|
|
37
38
|
Returns:
|
|
38
39
|
int: The number of titles found.
|
|
39
40
|
"""
|
|
40
|
-
domain_to_use = site_constant
|
|
41
|
+
domain_to_use, base_url = search_domain(site_constant.SITE_NAME, site_constant.FULL_URL)
|
|
41
42
|
|
|
42
|
-
if
|
|
43
|
-
|
|
43
|
+
if domain_to_use is None or base_url is None:
|
|
44
|
+
console.print("[bold red]Error: Unable to determine valid domain or base URL.[/bold red]")
|
|
45
|
+
console.print("[yellow]The service might be temporarily unavailable or the domain may have changed.[/yellow]")
|
|
46
|
+
sys.exit(1)
|
|
44
47
|
|
|
45
48
|
if site_constant.TELEGRAM_BOT:
|
|
46
49
|
bot = get_bot_instance()
|
|
47
50
|
|
|
48
51
|
media_search_manager.clear()
|
|
49
52
|
table_show_manager.clear()
|
|
50
|
-
|
|
53
|
+
|
|
54
|
+
search_url = f"{site_constant.FULL_URL}/api/search?q={title_search}"
|
|
55
|
+
console.print(f"[cyan]Search url: [yellow]{search_url}")
|
|
56
|
+
|
|
51
57
|
try:
|
|
52
|
-
response = httpx.get(
|
|
53
|
-
url=f"https://{site_constant.SITE_NAME}.{domain_to_use}/api/search?q={title_search.replace(' ', '+')}",
|
|
54
|
-
headers={'user-agent': get_headers()},
|
|
55
|
-
timeout=max_timeout
|
|
56
|
-
)
|
|
58
|
+
response = httpx.get(search_url, headers={'user-agent': get_userAgent()}, timeout=max_timeout, follow_redirects=True)
|
|
57
59
|
response.raise_for_status()
|
|
58
60
|
|
|
59
61
|
except Exception as e:
|
|
@@ -10,8 +10,8 @@ from bs4 import BeautifulSoup
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
# Internal utilities
|
|
13
|
-
from StreamingCommunity.Util.headers import
|
|
14
|
-
from StreamingCommunity.Util.
|
|
13
|
+
from StreamingCommunity.Util.headers import get_userAgent
|
|
14
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
15
15
|
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import Season, EpisodeManager
|
|
16
16
|
|
|
17
17
|
|
|
@@ -19,18 +19,17 @@ from StreamingCommunity.Api.Player.Helper.Vixcloud.util import Season, EpisodeMa
|
|
|
19
19
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
class
|
|
23
|
-
def __init__(self,
|
|
22
|
+
class GetSerieInfo:
|
|
23
|
+
def __init__(self, url):
|
|
24
24
|
"""
|
|
25
25
|
Initialize the ScrapeSerie class for scraping TV series information.
|
|
26
26
|
|
|
27
27
|
Args:
|
|
28
|
-
|
|
28
|
+
- url (str): The URL of the streaming site.
|
|
29
29
|
"""
|
|
30
30
|
self.is_series = False
|
|
31
|
-
self.headers = {'user-agent':
|
|
32
|
-
self.
|
|
33
|
-
self.domain = config_manager.get_dict('SITE', self.base_name)['domain']
|
|
31
|
+
self.headers = {'user-agent': get_userAgent()}
|
|
32
|
+
self.url = url
|
|
34
33
|
|
|
35
34
|
def setup(self, media_id: int = None, series_name: str = None):
|
|
36
35
|
"""
|
|
@@ -58,7 +57,7 @@ class ScrapeSerie:
|
|
|
58
57
|
"""
|
|
59
58
|
try:
|
|
60
59
|
response = httpx.get(
|
|
61
|
-
url=f"
|
|
60
|
+
url=f"{self.url}/titles/{self.media_id}-{self.series_name}",
|
|
62
61
|
headers=self.headers,
|
|
63
62
|
timeout=max_timeout
|
|
64
63
|
)
|
|
@@ -88,9 +87,9 @@ class ScrapeSerie:
|
|
|
88
87
|
"""
|
|
89
88
|
try:
|
|
90
89
|
response = httpx.get(
|
|
91
|
-
url=f'
|
|
90
|
+
url=f'{self.url}/titles/{self.media_id}-{self.series_name}/stagione-{number_season}',
|
|
92
91
|
headers={
|
|
93
|
-
'User-Agent':
|
|
92
|
+
'User-Agent': get_userAgent(),
|
|
94
93
|
'x-inertia': 'true',
|
|
95
94
|
'x-inertia-version': self.version,
|
|
96
95
|
},
|
|
@@ -1,35 +1,23 @@
|
|
|
1
1
|
# 18.06.24
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import time
|
|
3
|
+
import certifi
|
|
5
4
|
from urllib.parse import urlparse, unquote
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
# External libraries
|
|
9
8
|
import httpx
|
|
10
|
-
from
|
|
9
|
+
from rich.console import Console
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
# Internal utilities
|
|
14
13
|
from StreamingCommunity.Util.headers import get_headers
|
|
15
|
-
from StreamingCommunity.Util.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'priority': 'u=0, i',
|
|
23
|
-
'referer': '',
|
|
24
|
-
'sec-ch-ua-mobile': '?0',
|
|
25
|
-
'sec-ch-ua-platform': '"Windows"',
|
|
26
|
-
'sec-fetch-dest': 'document',
|
|
27
|
-
'sec-fetch-mode': 'navigate',
|
|
28
|
-
'sec-fetch-site': 'same-origin',
|
|
29
|
-
'sec-fetch-user': '?1',
|
|
30
|
-
'upgrade-insecure-requests': '1',
|
|
31
|
-
'user-agent': ''
|
|
32
|
-
}
|
|
14
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Variable
|
|
18
|
+
console = Console()
|
|
19
|
+
VERIFY = config_manager.get("REQUESTS", "verify")
|
|
20
|
+
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
33
21
|
|
|
34
22
|
|
|
35
23
|
def get_tld(url_str):
|
|
@@ -58,24 +46,15 @@ def get_base_domain(url_str):
|
|
|
58
46
|
|
|
59
47
|
# Check if domain has multiple parts separated by dots
|
|
60
48
|
parts = domain.split('.')
|
|
61
|
-
if len(parts) > 2:
|
|
62
|
-
return '.'.join(parts[:-1])
|
|
49
|
+
if len(parts) > 2:
|
|
50
|
+
return '.'.join(parts[:-1])
|
|
63
51
|
|
|
64
|
-
return parts[0]
|
|
52
|
+
return parts[0]
|
|
65
53
|
|
|
66
54
|
except Exception:
|
|
67
55
|
return None
|
|
68
56
|
|
|
69
|
-
def
|
|
70
|
-
"""Extract base URL including protocol and domain, removing path and query parameters."""
|
|
71
|
-
try:
|
|
72
|
-
parsed = urlparse(url_str)
|
|
73
|
-
return f"{parsed.scheme}://{parsed.netloc}"
|
|
74
|
-
|
|
75
|
-
except Exception:
|
|
76
|
-
return None
|
|
77
|
-
|
|
78
|
-
def validate_url(url, base_url, max_timeout, max_retries=2, sleep=1):
|
|
57
|
+
def validate_url(url, base_url):
|
|
79
58
|
"""Validate if URL is accessible and matches expected base domain."""
|
|
80
59
|
console.print(f"\n[cyan]Starting validation for URL[white]: [yellow]{url}")
|
|
81
60
|
|
|
@@ -83,120 +62,38 @@ def validate_url(url, base_url, max_timeout, max_retries=2, sleep=1):
|
|
|
83
62
|
base_domain = get_base_domain(base_url)
|
|
84
63
|
url_domain = get_base_domain(url)
|
|
85
64
|
|
|
86
|
-
base_headers['referer'] = url
|
|
87
|
-
base_headers['user-agent'] = get_headers()
|
|
88
|
-
|
|
89
65
|
if base_domain != url_domain:
|
|
90
66
|
console.print(f"[red]Domain structure mismatch: {url_domain} != {base_domain}")
|
|
91
67
|
return False, None
|
|
92
68
|
|
|
93
|
-
# Count dots to ensure we don't have extra subdomains
|
|
94
|
-
base_dots = base_url.count('.')
|
|
95
|
-
url_dots = url.count('.')
|
|
96
|
-
if url_dots > base_dots + 1: # Allow for one extra dot for TLD change
|
|
97
|
-
console.print(f"[red]Too many subdomains in URL")
|
|
98
|
-
return False, None
|
|
99
|
-
|
|
100
69
|
client = httpx.Client(
|
|
101
|
-
verify=
|
|
102
|
-
headers=
|
|
103
|
-
timeout=
|
|
70
|
+
verify=VERIFY,
|
|
71
|
+
headers=get_headers(),
|
|
72
|
+
timeout=MAX_TIMEOUT
|
|
104
73
|
)
|
|
105
74
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if response.status_code >= 400:
|
|
117
|
-
console.print(f"[red]Check failed: HTTP {response.status_code}")
|
|
118
|
-
return False, None
|
|
119
|
-
|
|
120
|
-
# Follow redirects and verify final domain
|
|
121
|
-
final_response = client.get(url, follow_redirects=True)
|
|
122
|
-
final_domain = get_base_domain(str(final_response.url))
|
|
123
|
-
console.print(f"[cyan]Redirect url: [red]{final_response.url}")
|
|
124
|
-
|
|
125
|
-
if final_domain != base_domain:
|
|
126
|
-
console.print(f"[red]Final domain mismatch: {final_domain} != {base_domain}")
|
|
127
|
-
return False, None
|
|
128
|
-
|
|
129
|
-
new_tld = get_tld(str(final_response.url))
|
|
130
|
-
if new_tld != get_tld(url):
|
|
131
|
-
return True, new_tld
|
|
132
|
-
|
|
133
|
-
return True, None
|
|
134
|
-
|
|
135
|
-
except (httpx.RequestError, ssl.SSLError) as e:
|
|
136
|
-
console.print(f"[red]Connection error: {str(e)}")
|
|
137
|
-
time.sleep(sleep)
|
|
138
|
-
continue
|
|
139
|
-
|
|
140
|
-
return False, None
|
|
75
|
+
# Make request to web site
|
|
76
|
+
response = client.get(url, follow_redirects=False)
|
|
77
|
+
|
|
78
|
+
if response.status_code >= 400:
|
|
79
|
+
console.print(f"[red]Check failed: HTTP {response.status_code}")
|
|
80
|
+
console.print(f"[red]Response content: {response.text}")
|
|
81
|
+
return False, None
|
|
82
|
+
|
|
83
|
+
return True, base_domain
|
|
141
84
|
|
|
142
85
|
def search_domain(site_name: str, base_url: str, get_first: bool = False):
|
|
143
|
-
"""Search for valid domain matching site name and base URL."""
|
|
144
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
145
|
-
domain = str(config_manager.get_dict("SITE", site_name)['domain'])
|
|
146
|
-
|
|
147
|
-
# Test initial URL
|
|
86
|
+
"""Search for valid domain matching site name and base URL."""
|
|
148
87
|
try:
|
|
149
|
-
is_correct, redirect_tld = validate_url(base_url, base_url
|
|
88
|
+
is_correct, redirect_tld = validate_url(base_url, base_url)
|
|
150
89
|
|
|
151
90
|
if is_correct:
|
|
152
91
|
tld = redirect_tld or get_tld(base_url)
|
|
153
|
-
config_manager.config['SITE'][site_name]['domain'] = tld
|
|
154
|
-
config_manager.write_config()
|
|
155
|
-
console.print(f"[green]Successfully validated initial URL")
|
|
156
92
|
return tld, base_url
|
|
157
93
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
# Google search phase
|
|
162
|
-
base_domain = get_base_domain(base_url)
|
|
163
|
-
console.print(f"\n[cyan]Searching for alternate domains for[white]: [yellow]{base_domain}")
|
|
164
|
-
|
|
165
|
-
try:
|
|
166
|
-
search_results = list(search(base_domain, num_results=20, lang="it"))
|
|
167
|
-
|
|
168
|
-
base_urls = set()
|
|
169
|
-
for url in search_results:
|
|
170
|
-
element_url = get_base_url(url)
|
|
171
|
-
if element_url:
|
|
172
|
-
base_urls.add(element_url)
|
|
94
|
+
else:
|
|
95
|
+
return None, None
|
|
173
96
|
|
|
174
|
-
# Filter URLs based on domain matching and subdomain count
|
|
175
|
-
filtered_results = [
|
|
176
|
-
url for url in base_urls
|
|
177
|
-
if get_base_domain(url) == base_domain
|
|
178
|
-
and url.count('.') <= base_url.count('.') + 1
|
|
179
|
-
]
|
|
180
|
-
|
|
181
|
-
for idx, result_url in enumerate(filtered_results, 1):
|
|
182
|
-
console.print(f"\n[cyan]Checking result {idx}/{len(filtered_results)}[white]: [yellow]{result_url}")
|
|
183
|
-
|
|
184
|
-
is_valid, new_tld = validate_url(result_url, base_url, max_timeout)
|
|
185
|
-
if is_valid:
|
|
186
|
-
final_tld = new_tld or get_tld(result_url)
|
|
187
|
-
|
|
188
|
-
if get_first or msg.ask(
|
|
189
|
-
f"\n[cyan]Update site[white] [red]'{site_name}'[cyan] with domain[white] [red]'{final_tld}'",
|
|
190
|
-
choices=["y", "n"],
|
|
191
|
-
default="y"
|
|
192
|
-
).lower() == "y":
|
|
193
|
-
|
|
194
|
-
config_manager.config['SITE'][site_name]['domain'] = final_tld
|
|
195
|
-
config_manager.write_config()
|
|
196
|
-
return final_tld, f"{base_url}.{final_tld}"
|
|
197
|
-
|
|
198
97
|
except Exception as e:
|
|
199
|
-
console.print(f"[red]Error
|
|
200
|
-
|
|
201
|
-
console.print("[bold red]No valid URLs found matching the base URL.")
|
|
202
|
-
return domain, f"{base_url}.{domain}"
|
|
98
|
+
console.print(f"[red]Error testing initial URL: {str(e)}")
|
|
99
|
+
return None, None
|
|
@@ -5,15 +5,21 @@ import logging
|
|
|
5
5
|
from typing import List
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
# External library
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.prompt import Prompt
|
|
11
|
+
|
|
12
|
+
|
|
8
13
|
# Internal utilities
|
|
9
|
-
from StreamingCommunity.Util.console import console, msg
|
|
10
14
|
from StreamingCommunity.Util.os import os_manager
|
|
11
|
-
from StreamingCommunity.Util.
|
|
15
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
12
16
|
from StreamingCommunity.Util.table import TVShowManager
|
|
13
17
|
|
|
14
18
|
|
|
15
|
-
#
|
|
16
|
-
|
|
19
|
+
# Variable
|
|
20
|
+
msg = Prompt()
|
|
21
|
+
console = Console()
|
|
22
|
+
MAP_EPISODE = config_manager.get('OUT_FOLDER', 'map_episode_name')
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
def dynamic_format_number(n: int) -> str:
|
|
@@ -195,7 +201,6 @@ def display_episodes_list(episodes_manager) -> str:
|
|
|
195
201
|
"""
|
|
196
202
|
# Set up table for displaying episodes
|
|
197
203
|
table_show_manager = TVShowManager()
|
|
198
|
-
table_show_manager.set_slice_end(10)
|
|
199
204
|
|
|
200
205
|
# Add columns to the table
|
|
201
206
|
column_info = {
|
|
@@ -5,7 +5,7 @@ import inspect
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
# Internal utilities
|
|
8
|
-
from StreamingCommunity.Util.
|
|
8
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def get_site_name_from_stack():
|
|
@@ -29,37 +29,41 @@ class SiteConstant:
|
|
|
29
29
|
|
|
30
30
|
@property
|
|
31
31
|
def ROOT_PATH(self):
|
|
32
|
-
return config_manager.get('
|
|
32
|
+
return config_manager.get('OUT_FOLDER', 'root_path')
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
35
|
def DOMAIN_NOW(self):
|
|
36
|
-
return config_manager.
|
|
36
|
+
return config_manager.get_site(self.SITE_NAME, 'domain')
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def FULL_URL(self):
|
|
40
|
+
return config_manager.get_site(self.SITE_NAME, 'full_url').rstrip('/')
|
|
37
41
|
|
|
38
42
|
@property
|
|
39
43
|
def SERIES_FOLDER(self):
|
|
40
44
|
base_path = self.ROOT_PATH
|
|
41
|
-
if config_manager.get_bool("
|
|
45
|
+
if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
|
|
42
46
|
base_path = os.path.join(base_path, self.SITE_NAME)
|
|
43
|
-
return os.path.join(base_path, config_manager.get('
|
|
47
|
+
return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'serie_folder_name'))
|
|
44
48
|
|
|
45
49
|
@property
|
|
46
50
|
def MOVIE_FOLDER(self):
|
|
47
51
|
base_path = self.ROOT_PATH
|
|
48
|
-
if config_manager.get_bool("
|
|
52
|
+
if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
|
|
49
53
|
base_path = os.path.join(base_path, self.SITE_NAME)
|
|
50
|
-
return os.path.join(base_path, config_manager.get('
|
|
54
|
+
return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'movie_folder_name'))
|
|
51
55
|
|
|
52
56
|
@property
|
|
53
57
|
def ANIME_FOLDER(self):
|
|
54
58
|
base_path = self.ROOT_PATH
|
|
55
|
-
if config_manager.get_bool("
|
|
59
|
+
if config_manager.get_bool("OUT_FOLDER", "add_siteName"):
|
|
56
60
|
base_path = os.path.join(base_path, self.SITE_NAME)
|
|
57
|
-
return os.path.join(base_path, config_manager.get('
|
|
61
|
+
return os.path.join(base_path, config_manager.get('OUT_FOLDER', 'anime_folder_name'))
|
|
58
62
|
|
|
59
63
|
@property
|
|
60
64
|
def COOKIE(self):
|
|
61
65
|
try:
|
|
62
|
-
return config_manager.get_dict('
|
|
66
|
+
return config_manager.get_dict('SITE_EXTRA', self.SITE_NAME)
|
|
63
67
|
except KeyError:
|
|
64
68
|
return None
|
|
65
69
|
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
from
|
|
6
|
+
# External library
|
|
7
|
+
from rich.console import Console
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# Variable
|
|
11
|
+
console = Console()
|
|
11
12
|
available_colors = ['red', 'magenta', 'yellow', 'cyan', 'green', 'blue', 'white']
|
|
12
13
|
column_to_hide = ['Slug', 'Sub_ita', 'Last_air_date', 'Seasons_count', 'Url']
|
|
13
14
|
|
|
@@ -19,10 +20,6 @@ def get_select_title(table_show_manager, media_search_manager):
|
|
|
19
20
|
Returns:
|
|
20
21
|
MediaItem: The selected media item.
|
|
21
22
|
"""
|
|
22
|
-
|
|
23
|
-
# Set up table for displaying titles
|
|
24
|
-
table_show_manager.set_slice_end(10)
|
|
25
|
-
|
|
26
23
|
# Determine column_info dynamically for (search site)
|
|
27
24
|
if not media_search_manager.media_list:
|
|
28
25
|
console.print("\n[red]No media items available.")
|
|
@@ -10,17 +10,14 @@ from typing import Any, Dict, List, Optional
|
|
|
10
10
|
|
|
11
11
|
# External libraries
|
|
12
12
|
import httpx
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
from rich.panel import Panel
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
# Internal utilities
|
|
16
|
-
from StreamingCommunity.Util.
|
|
17
|
-
from StreamingCommunity.Util.headers import
|
|
18
|
-
from StreamingCommunity.Util.
|
|
19
|
-
from StreamingCommunity.Util.os import (
|
|
20
|
-
compute_sha1_hash,
|
|
21
|
-
os_manager,
|
|
22
|
-
internet_manager
|
|
23
|
-
)
|
|
18
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
19
|
+
from StreamingCommunity.Util.headers import get_userAgent
|
|
20
|
+
from StreamingCommunity.Util.os import compute_sha1_hash, os_manager, internet_manager
|
|
24
21
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
25
22
|
|
|
26
23
|
|
|
@@ -47,15 +44,15 @@ FILTER_CUSTOM_REOLUTION = str(config_manager.get('M3U8_PARSER', 'force_resolutio
|
|
|
47
44
|
GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link')
|
|
48
45
|
RETRY_LIMIT = config_manager.get_int('REQUESTS', 'max_retry')
|
|
49
46
|
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
50
|
-
|
|
51
47
|
TELEGRAM_BOT = config_manager.get_bool('DEFAULT', 'telegram_bot')
|
|
52
48
|
|
|
49
|
+
console = Console()
|
|
53
50
|
|
|
54
51
|
|
|
55
52
|
class HLSClient:
|
|
56
53
|
"""Client for making HTTP requests to HLS endpoints with retry mechanism."""
|
|
57
54
|
def __init__(self):
|
|
58
|
-
self.headers = {'User-Agent':
|
|
55
|
+
self.headers = {'User-Agent': get_userAgent()}
|
|
59
56
|
|
|
60
57
|
def request(self, url: str, return_content: bool = False) -> Optional[httpx.Response]:
|
|
61
58
|
"""
|
|
@@ -100,7 +97,7 @@ class PathManager:
|
|
|
100
97
|
Creates a hash-based filename if no path is provided.
|
|
101
98
|
"""
|
|
102
99
|
if not path:
|
|
103
|
-
root = config_manager.get('
|
|
100
|
+
root = config_manager.get('OUT_FOLDER', 'root_path')
|
|
104
101
|
hash_name = compute_sha1_hash(self.m3u8_url) + ".mp4"
|
|
105
102
|
return os.path.join(root, "undefined", hash_name)
|
|
106
103
|
|
|
@@ -193,7 +190,7 @@ class M3U8Manager:
|
|
|
193
190
|
list_available_resolution = [f"{r[0]}x{r[1]}" for r in tuple_available_resolution]
|
|
194
191
|
|
|
195
192
|
console.print(
|
|
196
|
-
f"[cyan bold]Video
|
|
193
|
+
f"[cyan bold]Video [/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | "
|
|
197
194
|
f"[red]Set:[/red] [purple]{FILTER_CUSTOM_REOLUTION}[/purple] | "
|
|
198
195
|
f"[yellow]Downloadable:[/yellow] [purple]{self.video_res[0]}x{self.video_res[1]}[/purple]"
|
|
199
196
|
)
|
|
@@ -208,7 +205,7 @@ class M3U8Manager:
|
|
|
208
205
|
set_codec_info = available_codec_info if config_manager.get_bool("M3U8_CONVERSION", "use_codec") else "[purple]copy[/purple]"
|
|
209
206
|
|
|
210
207
|
console.print(
|
|
211
|
-
f"[bold cyan]Codec
|
|
208
|
+
f"[bold cyan]Codec [/bold cyan] [green]Available:[/green] {available_codec_info} | "
|
|
212
209
|
f"[red]Set:[/red] {set_codec_info}"
|
|
213
210
|
)
|
|
214
211
|
|
|
@@ -217,7 +214,7 @@ class M3U8Manager:
|
|
|
217
214
|
downloadable_sub_languages = list(set(available_sub_languages) & set(DOWNLOAD_SPECIFIC_SUBTITLE))
|
|
218
215
|
if available_sub_languages:
|
|
219
216
|
console.print(
|
|
220
|
-
f"[cyan bold]Subtitle
|
|
217
|
+
f"[cyan bold]Subtitle [/cyan bold] [green]Available:[/green] [purple]{', '.join(available_sub_languages)}[/purple] | "
|
|
221
218
|
f"[red]Set:[/red] [purple]{', '.join(DOWNLOAD_SPECIFIC_SUBTITLE)}[/purple] | "
|
|
222
219
|
f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_sub_languages)}[/purple]"
|
|
223
220
|
)
|
|
@@ -227,7 +224,7 @@ class M3U8Manager:
|
|
|
227
224
|
downloadable_audio_languages = list(set(available_audio_languages) & set(DOWNLOAD_SPECIFIC_AUDIO))
|
|
228
225
|
if available_audio_languages:
|
|
229
226
|
console.print(
|
|
230
|
-
f"[cyan bold]Audio
|
|
227
|
+
f"[cyan bold]Audio [/cyan bold] [green]Available:[/green] [purple]{', '.join(available_audio_languages)}[/purple] | "
|
|
231
228
|
f"[red]Set:[/red] [purple]{', '.join(DOWNLOAD_SPECIFIC_AUDIO)}[/purple] | "
|
|
232
229
|
f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_audio_languages)}[/purple]"
|
|
233
230
|
)
|