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
|
@@ -3,4 +3,12 @@
|
|
|
3
3
|
from .decryptor import M3U8_Decryption
|
|
4
4
|
from .estimator import M3U8_Ts_Estimator
|
|
5
5
|
from .parser import M3U8_Parser, M3U8_Codec
|
|
6
|
-
from .url_fixer import M3U8_UrlFix
|
|
6
|
+
from .url_fixer import M3U8_UrlFix
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"M3U8_Decryption",
|
|
10
|
+
"M3U8_Ts_Estimator",
|
|
11
|
+
"M3U8_Parser",
|
|
12
|
+
"M3U8_Codec",
|
|
13
|
+
"M3U8_UrlFix"
|
|
14
|
+
]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# 03.04.24
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
-
import time
|
|
5
4
|
import logging
|
|
6
5
|
import importlib.util
|
|
7
6
|
|
|
@@ -10,18 +9,23 @@ import importlib.util
|
|
|
10
9
|
from rich.console import Console
|
|
11
10
|
|
|
12
11
|
|
|
12
|
+
# Cryptodome imports
|
|
13
|
+
from Cryptodome.Cipher import AES
|
|
14
|
+
from Cryptodome.Util.Padding import unpad
|
|
15
|
+
|
|
16
|
+
|
|
13
17
|
# Check if Cryptodome module is installed
|
|
14
18
|
console = Console()
|
|
15
19
|
crypto_spec = importlib.util.find_spec("Cryptodome")
|
|
16
20
|
crypto_installed = crypto_spec is not None
|
|
17
21
|
|
|
22
|
+
|
|
18
23
|
if not crypto_installed:
|
|
19
24
|
console.log("[red]pycryptodomex non è installato. Per favore installalo. Leggi readme.md [Requirement].")
|
|
20
25
|
sys.exit(0)
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
from Cryptodome.Util.Padding import unpad
|
|
27
|
+
|
|
28
|
+
logging.info("[cyan]Decryption use: Cryptodomex")
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
|
|
@@ -121,12 +121,6 @@ class M3U8_Ts_Estimator:
|
|
|
121
121
|
number_file_total_size = file_total_size.split(' ')[0]
|
|
122
122
|
units_file_total_size = file_total_size.split(' ')[1]
|
|
123
123
|
|
|
124
|
-
# Reduce lock contention by acquiring data with minimal synchronization
|
|
125
|
-
retry_count = 0
|
|
126
|
-
if self.segments_instance:
|
|
127
|
-
with self.segments_instance.active_retries_lock:
|
|
128
|
-
retry_count = self.segments_instance.active_retries
|
|
129
|
-
|
|
130
124
|
# Get speed data outside of any locks
|
|
131
125
|
speed_data = ["N/A", ""]
|
|
132
126
|
with self.lock:
|
|
@@ -485,7 +485,7 @@ class M3U8_Parser:
|
|
|
485
485
|
try:
|
|
486
486
|
for playlist in m3u8_obj.playlists:
|
|
487
487
|
|
|
488
|
-
there_is_codec =
|
|
488
|
+
there_is_codec = playlist.stream_info.codecs is not None
|
|
489
489
|
logging.info(f"There is coded: {there_is_codec}")
|
|
490
490
|
|
|
491
491
|
if there_is_codec:
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
"DEFAULT": {
|
|
3
3
|
"debug": false,
|
|
4
4
|
"show_message": true,
|
|
5
|
-
"clean_console": true,
|
|
6
5
|
"show_trending": true,
|
|
7
6
|
"use_api": true,
|
|
8
|
-
"not_close": false,
|
|
9
7
|
"telegram_bot": true,
|
|
10
8
|
"download_site_data": true,
|
|
11
9
|
"validate_github_config": true
|
|
@@ -45,9 +43,7 @@
|
|
|
45
43
|
"use_acodec": true,
|
|
46
44
|
"use_bitrate": true,
|
|
47
45
|
"use_gpu": false,
|
|
48
|
-
"default_preset": "ultrafast"
|
|
49
|
-
},
|
|
50
|
-
"M3U8_PARSER": {
|
|
46
|
+
"default_preset": "ultrafast",
|
|
51
47
|
"force_resolution": "Best"
|
|
52
48
|
},
|
|
53
49
|
"REQUESTS": {
|
|
@@ -9,7 +9,6 @@ import uuid
|
|
|
9
9
|
import json
|
|
10
10
|
import threading
|
|
11
11
|
import subprocess
|
|
12
|
-
import threading
|
|
13
12
|
from typing import Optional
|
|
14
13
|
|
|
15
14
|
# External libraries
|
|
@@ -305,7 +304,7 @@ class TelegramBot:
|
|
|
305
304
|
|
|
306
305
|
def handle_get_id(self, message):
|
|
307
306
|
if not self.is_authorized(message.from_user.id):
|
|
308
|
-
print(
|
|
307
|
+
print(" Non sei autorizzato.")
|
|
309
308
|
self.bot.send_message(message.chat.id, " Non sei autorizzato.")
|
|
310
309
|
return
|
|
311
310
|
|
|
@@ -384,7 +383,7 @@ class TelegramBot:
|
|
|
384
383
|
|
|
385
384
|
def handle_list_scripts(self, message):
|
|
386
385
|
if not self.is_authorized(message.from_user.id):
|
|
387
|
-
print(
|
|
386
|
+
print(" Non sei autorizzato.")
|
|
388
387
|
self.bot.send_message(message.chat.id, " Non sei autorizzato.")
|
|
389
388
|
return
|
|
390
389
|
|
|
@@ -395,7 +394,7 @@ class TelegramBot:
|
|
|
395
394
|
scripts_data = []
|
|
396
395
|
|
|
397
396
|
if not scripts_data:
|
|
398
|
-
print(
|
|
397
|
+
print(" Nessuno script registrato.")
|
|
399
398
|
self.bot.send_message(message.chat.id, " Nessuno script registrato.")
|
|
400
399
|
return
|
|
401
400
|
|
|
@@ -437,7 +436,7 @@ class TelegramBot:
|
|
|
437
436
|
|
|
438
437
|
def handle_stop_script(self, message):
|
|
439
438
|
if not self.is_authorized(message.from_user.id):
|
|
440
|
-
print(
|
|
439
|
+
print(" Non sei autorizzato.")
|
|
441
440
|
self.bot.send_message(message.chat.id, " Non sei autorizzato.")
|
|
442
441
|
return
|
|
443
442
|
|
|
@@ -452,7 +451,7 @@ class TelegramBot:
|
|
|
452
451
|
running_scripts = [s for s in scripts_data if s["status"] == "running"]
|
|
453
452
|
|
|
454
453
|
if not running_scripts:
|
|
455
|
-
print(
|
|
454
|
+
print(" Nessuno script attivo da fermare.")
|
|
456
455
|
self.bot.send_message(
|
|
457
456
|
message.chat.id, " Nessuno script attivo da fermare."
|
|
458
457
|
)
|
|
@@ -526,7 +525,7 @@ class TelegramBot:
|
|
|
526
525
|
def handle_screen_status(self, message):
|
|
527
526
|
command_parts = message.text.split()
|
|
528
527
|
if len(command_parts) < 2:
|
|
529
|
-
print(
|
|
528
|
+
print(" ID mancante nel comando. Usa: /screen <ID>")
|
|
530
529
|
self.bot.send_message(
|
|
531
530
|
message.chat.id, " ID mancante nel comando. Usa: /screen <ID>"
|
|
532
531
|
)
|
|
@@ -557,9 +556,9 @@ class TelegramBot:
|
|
|
557
556
|
return
|
|
558
557
|
|
|
559
558
|
if not os.path.exists(temp_file):
|
|
560
|
-
print(
|
|
559
|
+
print(" Impossibile catturare l'output della screen.")
|
|
561
560
|
self.bot.send_message(
|
|
562
|
-
message.chat.id,
|
|
561
|
+
message.chat.id, " Impossibile catturare l'output della screen."
|
|
563
562
|
)
|
|
564
563
|
return
|
|
565
564
|
|
|
@@ -669,7 +668,7 @@ class TelegramBot:
|
|
|
669
668
|
return response
|
|
670
669
|
time.sleep(1)
|
|
671
670
|
|
|
672
|
-
print(
|
|
671
|
+
print(" Timeout: nessuna risposta ricevuta.")
|
|
673
672
|
for chat_id in self.authorized_users: # Manda a tutti gli ID autorizzati
|
|
674
673
|
self.bot.send_message(chat_id, " Timeout: nessuna risposta ricevuta.")
|
|
675
674
|
self.request_manager.clear_file()
|
|
@@ -18,8 +18,6 @@ from StreamingCommunity.Util.headers import get_userAgent
|
|
|
18
18
|
|
|
19
19
|
# Variable
|
|
20
20
|
console = Console()
|
|
21
|
-
download_site_data = True
|
|
22
|
-
validate_github_config = True
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
class ConfigManager:
|
|
@@ -54,8 +52,7 @@ class ConfigManager:
|
|
|
54
52
|
self.configSite = {}
|
|
55
53
|
self.cache = {}
|
|
56
54
|
|
|
57
|
-
self.
|
|
58
|
-
self.download_site_data = False
|
|
55
|
+
self.fetch_domain_online = True
|
|
59
56
|
self.validate_github_config = False
|
|
60
57
|
|
|
61
58
|
console.print(f"[bold cyan]Initializing ConfigManager:[/bold cyan] [green]{self.file_path}[/green]")
|
|
@@ -67,7 +64,7 @@ class ConfigManager:
|
|
|
67
64
|
"""Load the configuration and initialize all settings."""
|
|
68
65
|
if not os.path.exists(self.file_path):
|
|
69
66
|
console.print(f"[bold red]WARNING: Configuration file not found:[/bold red] {self.file_path}")
|
|
70
|
-
console.print(
|
|
67
|
+
console.print("[bold yellow]Attempting to download from reference repository...[/bold yellow]")
|
|
71
68
|
self._download_reference_config()
|
|
72
69
|
|
|
73
70
|
# Load the configuration file
|
|
@@ -85,11 +82,8 @@ class ConfigManager:
|
|
|
85
82
|
else:
|
|
86
83
|
console.print("[bold yellow]GitHub validation disabled[/bold yellow]")
|
|
87
84
|
|
|
88
|
-
# Load site data
|
|
89
|
-
|
|
90
|
-
self._load_site_data()
|
|
91
|
-
else:
|
|
92
|
-
console.print("[bold yellow]Site data download disabled[/bold yellow]")
|
|
85
|
+
# Load site data based on fetch_domain_online setting
|
|
86
|
+
self._load_site_data()
|
|
93
87
|
|
|
94
88
|
except json.JSONDecodeError as e:
|
|
95
89
|
console.print(f"[bold red]Error parsing JSON:[/bold red] {str(e)}")
|
|
@@ -119,18 +113,11 @@ class ConfigManager:
|
|
|
119
113
|
"""Update internal settings from loaded configurations."""
|
|
120
114
|
default_section = self.config.get('DEFAULT', {})
|
|
121
115
|
|
|
122
|
-
#
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
temp_validate_github_config = default_section.get('validate_github_config', False)
|
|
126
|
-
|
|
127
|
-
# Update settings with found values (False by default)
|
|
128
|
-
self.use_api = temp_use_api
|
|
129
|
-
self.download_site_data = temp_download_site_data
|
|
130
|
-
self.validate_github_config = temp_validate_github_config
|
|
116
|
+
# Get fetch_domain_online setting (True by default)
|
|
117
|
+
self.fetch_domain_online = default_section.get('fetch_domain_online', True)
|
|
118
|
+
self.validate_github_config = default_section.get('validate_github_config', False)
|
|
131
119
|
|
|
132
|
-
console.print(f"[bold cyan]
|
|
133
|
-
console.print(f"[bold cyan]Site data download:[/bold cyan] [{'green' if self.download_site_data else 'yellow'}]{self.download_site_data}[/{'green' if self.download_site_data else 'yellow'}]")
|
|
120
|
+
console.print(f"[bold cyan]Fetch domains online:[/bold cyan] [{'green' if self.fetch_domain_online else 'yellow'}]{self.fetch_domain_online}[/{'green' if self.fetch_domain_online else 'yellow'}]")
|
|
134
121
|
console.print(f"[bold cyan]GitHub configuration validation:[/bold cyan] [{'green' if self.validate_github_config else 'yellow'}]{self.validate_github_config}[/{'green' if self.validate_github_config else 'yellow'}]")
|
|
135
122
|
|
|
136
123
|
def _download_reference_config(self) -> None:
|
|
@@ -159,7 +146,7 @@ class ConfigManager:
|
|
|
159
146
|
"""Validate the local configuration against the reference one and update missing keys."""
|
|
160
147
|
try:
|
|
161
148
|
# Download the reference configuration
|
|
162
|
-
console.print(
|
|
149
|
+
console.print("[bold cyan]Validating configuration with GitHub...[/bold cyan]")
|
|
163
150
|
response = requests.get(self.reference_config_url, timeout=8, headers={'User-Agent': get_userAgent()})
|
|
164
151
|
|
|
165
152
|
if not response.ok:
|
|
@@ -242,11 +229,9 @@ class ConfigManager:
|
|
|
242
229
|
# Make sure control keys maintain local values
|
|
243
230
|
merged_section = self._deep_merge_configs(merged[key], value)
|
|
244
231
|
|
|
245
|
-
# Preserve local values for
|
|
246
|
-
if '
|
|
247
|
-
merged_section['
|
|
248
|
-
if 'download_site_data' in merged[key]:
|
|
249
|
-
merged_section['download_site_data'] = merged[key]['download_site_data']
|
|
232
|
+
# Preserve local values for critical settings
|
|
233
|
+
if 'fetch_domain_online' in merged[key]:
|
|
234
|
+
merged_section['fetch_domain_online'] = merged[key]['fetch_domain_online']
|
|
250
235
|
if 'validate_github_config' in merged[key]:
|
|
251
236
|
merged_section['validate_github_config'] = merged[key]['validate_github_config']
|
|
252
237
|
|
|
@@ -259,28 +244,31 @@ class ConfigManager:
|
|
|
259
244
|
return merged
|
|
260
245
|
|
|
261
246
|
def _load_site_data(self) -> None:
|
|
262
|
-
"""Load site data
|
|
263
|
-
if self.
|
|
264
|
-
self.
|
|
247
|
+
"""Load site data based on fetch_domain_online setting."""
|
|
248
|
+
if self.fetch_domain_online:
|
|
249
|
+
self._load_site_data_online()
|
|
265
250
|
else:
|
|
266
251
|
self._load_site_data_from_file()
|
|
267
252
|
|
|
268
|
-
def
|
|
269
|
-
"""Load site data from GitHub."""
|
|
253
|
+
def _load_site_data_online(self) -> None:
|
|
254
|
+
"""Load site data from GitHub and update local domains.json file."""
|
|
270
255
|
domains_github_url = "https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/.github/.domain/domains.json"
|
|
271
256
|
headers = {
|
|
272
257
|
"User-Agent": get_userAgent()
|
|
273
258
|
}
|
|
274
259
|
|
|
275
260
|
try:
|
|
276
|
-
console.print("[bold cyan]
|
|
261
|
+
console.print("[bold cyan]Fetching domains from GitHub:[/bold cyan]")
|
|
277
262
|
response = requests.get(domains_github_url, timeout=8, headers=headers)
|
|
278
263
|
|
|
279
264
|
if response.ok:
|
|
280
265
|
self.configSite = response.json()
|
|
281
266
|
|
|
267
|
+
# Determine which file to save to
|
|
268
|
+
self._save_domains_to_appropriate_location()
|
|
269
|
+
|
|
282
270
|
site_count = len(self.configSite) if isinstance(self.configSite, dict) else 0
|
|
283
|
-
console.print(f"[bold green]
|
|
271
|
+
console.print(f"[bold green]Domains loaded from GitHub:[/bold green] {site_count} streaming services found.")
|
|
284
272
|
|
|
285
273
|
else:
|
|
286
274
|
console.print(f"[bold red]GitHub request failed:[/bold red] HTTP {response.status_code}, {response.text[:100]}")
|
|
@@ -294,42 +282,129 @@ class ConfigManager:
|
|
|
294
282
|
console.print(f"[bold red]GitHub connection error:[/bold red] {str(e)}")
|
|
295
283
|
self._handle_site_data_fallback()
|
|
296
284
|
|
|
285
|
+
def _save_domains_to_appropriate_location(self) -> None:
|
|
286
|
+
"""Save domains to the appropriate location based on existing files."""
|
|
287
|
+
if getattr(sys, 'frozen', False):
|
|
288
|
+
# If the application is frozen (e.g., PyInstaller)
|
|
289
|
+
base_path = os.path.dirname(sys.executable)
|
|
290
|
+
else:
|
|
291
|
+
# Use the current working directory where the script is executed
|
|
292
|
+
base_path = os.getcwd()
|
|
293
|
+
|
|
294
|
+
# Check for GitHub structure first
|
|
295
|
+
github_domains_path = os.path.join(base_path, '.github', '.domain', 'domains.json')
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
if os.path.exists(github_domains_path):
|
|
299
|
+
|
|
300
|
+
# Update existing GitHub structure file
|
|
301
|
+
with open(github_domains_path, 'w', encoding='utf-8') as f:
|
|
302
|
+
json.dump(self.configSite, f, indent=4, ensure_ascii=False)
|
|
303
|
+
console.print(f"[bold green]Domains updated in GitHub structure:[/bold green] {github_domains_path}")
|
|
304
|
+
|
|
305
|
+
elif not os.path.exists(self.domains_path):
|
|
306
|
+
|
|
307
|
+
# Save to root only if it doesn't exist and GitHub structure doesn't exist
|
|
308
|
+
with open(self.domains_path, 'w', encoding='utf-8') as f:
|
|
309
|
+
json.dump(self.configSite, f, indent=4, ensure_ascii=False)
|
|
310
|
+
console.print(f"[bold green]Domains saved to:[/bold green] {self.domains_path}")
|
|
311
|
+
|
|
312
|
+
else:
|
|
313
|
+
|
|
314
|
+
# Root file exists, don't overwrite it
|
|
315
|
+
console.print(f"[bold yellow]Local domains.json already exists, not overwriting:[/bold yellow] {self.domains_path}")
|
|
316
|
+
console.print("[bold yellow]Tip: Delete the file if you want to recreate it from GitHub[/bold yellow]")
|
|
317
|
+
|
|
318
|
+
except Exception as save_error:
|
|
319
|
+
console.print(f"[bold yellow]Warning: Could not save domains to file:[/bold yellow] {str(save_error)}")
|
|
320
|
+
|
|
321
|
+
# Try to save to root as fallback only if it doesn't exist
|
|
322
|
+
if not os.path.exists(self.domains_path):
|
|
323
|
+
try:
|
|
324
|
+
with open(self.domains_path, 'w', encoding='utf-8') as f:
|
|
325
|
+
json.dump(self.configSite, f, indent=4, ensure_ascii=False)
|
|
326
|
+
console.print(f"[bold green]Domains saved to fallback location:[/bold green] {self.domains_path}")
|
|
327
|
+
except Exception as fallback_error:
|
|
328
|
+
console.print(f"[bold red]Failed to save to fallback location:[/bold red] {str(fallback_error)}")
|
|
329
|
+
|
|
297
330
|
def _load_site_data_from_file(self) -> None:
|
|
298
|
-
"""Load site data from local file."""
|
|
331
|
+
"""Load site data from local domains.json file."""
|
|
299
332
|
try:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
333
|
+
# Determine the base path
|
|
334
|
+
if getattr(sys, 'frozen', False):
|
|
335
|
+
|
|
336
|
+
# If the application is frozen (e.g., PyInstaller)
|
|
337
|
+
base_path = os.path.dirname(sys.executable)
|
|
338
|
+
else:
|
|
339
|
+
|
|
340
|
+
# Use the current working directory where the script is executed
|
|
341
|
+
base_path = os.getcwd()
|
|
342
|
+
|
|
343
|
+
# Check for GitHub structure first
|
|
344
|
+
github_domains_path = os.path.join(base_path, '.github', '.domain', 'domains.json')
|
|
345
|
+
|
|
346
|
+
if os.path.exists(github_domains_path):
|
|
347
|
+
console.print(f"[bold cyan]Reading domains from GitHub structure:[/bold cyan] {github_domains_path}")
|
|
348
|
+
with open(github_domains_path, 'r', encoding='utf-8') as f:
|
|
349
|
+
self.configSite = json.load(f)
|
|
350
|
+
|
|
351
|
+
site_count = len(self.configSite) if isinstance(self.configSite, dict) else 0
|
|
352
|
+
console.print(f"[bold green]Domains loaded from GitHub structure:[/bold green] {site_count} streaming services")
|
|
353
|
+
|
|
354
|
+
elif os.path.exists(self.domains_path):
|
|
355
|
+
console.print(f"[bold cyan]Reading domains from root:[/bold cyan] {self.domains_path}")
|
|
356
|
+
with open(self.domains_path, 'r', encoding='utf-8') as f:
|
|
303
357
|
self.configSite = json.load(f)
|
|
304
358
|
|
|
305
359
|
site_count = len(self.configSite) if isinstance(self.configSite, dict) else 0
|
|
306
|
-
console.print(f"[bold green]
|
|
360
|
+
console.print(f"[bold green]Domains loaded from root file:[/bold green] {site_count} streaming services")
|
|
307
361
|
|
|
308
362
|
else:
|
|
309
|
-
error_msg = f"domains.json not found
|
|
363
|
+
error_msg = f"domains.json not found in GitHub structure ({github_domains_path}) or root ({self.domains_path}) and fetch_domain_online is disabled"
|
|
310
364
|
console.print(f"[bold red]Configuration error:[/bold red] {error_msg}")
|
|
311
|
-
|
|
365
|
+
console.print("[bold yellow]Tip: Set 'fetch_domain_online' to true to download domains from GitHub[/bold yellow]")
|
|
366
|
+
self.configSite = {}
|
|
312
367
|
|
|
313
368
|
except Exception as e:
|
|
314
|
-
console.print(f"[bold red]
|
|
315
|
-
self.
|
|
369
|
+
console.print(f"[bold red]Local domain file error:[/bold red] {str(e)}")
|
|
370
|
+
self.configSite = {}
|
|
316
371
|
|
|
317
372
|
def _handle_site_data_fallback(self) -> None:
|
|
318
373
|
"""Handle site data fallback in case of error."""
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
374
|
+
# Determine the base path
|
|
375
|
+
if getattr(sys, 'frozen', False):
|
|
376
|
+
|
|
377
|
+
# If the application is frozen (e.g., PyInstaller)
|
|
378
|
+
base_path = os.path.dirname(sys.executable)
|
|
379
|
+
else:
|
|
380
|
+
# Use the current working directory where the script is executed
|
|
381
|
+
base_path = os.getcwd()
|
|
382
|
+
|
|
383
|
+
# Check for GitHub structure first
|
|
384
|
+
github_domains_path = os.path.join(base_path, '.github', '.domain', 'domains.json')
|
|
385
|
+
|
|
386
|
+
if os.path.exists(github_domains_path):
|
|
387
|
+
console.print("[bold yellow]Attempting fallback to GitHub structure domains.json file...[/bold yellow]")
|
|
322
388
|
try:
|
|
323
|
-
with open(
|
|
389
|
+
with open(github_domains_path, 'r', encoding='utf-8') as f:
|
|
324
390
|
self.configSite = json.load(f)
|
|
325
|
-
console.print("[bold green]Fallback to
|
|
391
|
+
console.print("[bold green]Fallback to GitHub structure successful[/bold green]")
|
|
392
|
+
return
|
|
326
393
|
except Exception as fallback_error:
|
|
327
|
-
console.print(f"[bold red]
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
394
|
+
console.print(f"[bold red]GitHub structure fallback failed:[/bold red] {str(fallback_error)}")
|
|
395
|
+
|
|
396
|
+
if os.path.exists(self.domains_path):
|
|
397
|
+
console.print("[bold yellow]Attempting fallback to root domains.json file...[/bold yellow]")
|
|
398
|
+
try:
|
|
399
|
+
with open(self.domains_path, 'r', encoding='utf-8') as f:
|
|
400
|
+
self.configSite = json.load(f)
|
|
401
|
+
console.print("[bold green]Fallback to root domains successful[/bold green]")
|
|
402
|
+
return
|
|
403
|
+
except Exception as fallback_error:
|
|
404
|
+
console.print(f"[bold red]Root domains fallback failed:[/bold red] {str(fallback_error)}")
|
|
405
|
+
|
|
406
|
+
console.print("[bold red]No local domains.json file available for fallback[/bold red]")
|
|
407
|
+
self.configSite = {}
|
|
333
408
|
|
|
334
409
|
def download_file(self, url: str, filename: str) -> None:
|
|
335
410
|
"""
|
|
@@ -412,23 +487,28 @@ class ConfigManager:
|
|
|
412
487
|
Any: Converted value
|
|
413
488
|
"""
|
|
414
489
|
try:
|
|
415
|
-
if data_type
|
|
490
|
+
if data_type is int:
|
|
416
491
|
return int(value)
|
|
417
|
-
|
|
492
|
+
|
|
493
|
+
elif data_type is float:
|
|
418
494
|
return float(value)
|
|
419
|
-
|
|
495
|
+
|
|
496
|
+
elif data_type is bool:
|
|
420
497
|
if isinstance(value, str):
|
|
421
498
|
return value.lower() in ("yes", "true", "t", "1")
|
|
422
499
|
return bool(value)
|
|
423
|
-
|
|
500
|
+
|
|
501
|
+
elif data_type is list:
|
|
424
502
|
if isinstance(value, list):
|
|
425
503
|
return value
|
|
426
504
|
if isinstance(value, str):
|
|
427
505
|
return [item.strip() for item in value.split(',')]
|
|
428
506
|
return [value]
|
|
429
|
-
|
|
507
|
+
|
|
508
|
+
elif data_type is dict:
|
|
430
509
|
if isinstance(value, dict):
|
|
431
510
|
return value
|
|
511
|
+
|
|
432
512
|
raise ValueError(f"Cannot convert {type(value).__name__} to dict")
|
|
433
513
|
else:
|
|
434
514
|
return value
|