StreamingCommunity 2.6.0__py3-none-any.whl → 2.7.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/Helper/Vixcloud/util.py +26 -2
- StreamingCommunity/Api/Player/ddl.py +2 -2
- StreamingCommunity/Api/Player/maxstream.py +3 -3
- StreamingCommunity/Api/Player/supervideo.py +2 -2
- StreamingCommunity/Api/Player/vixcloud.py +16 -18
- StreamingCommunity/Api/Site/1337xx/site.py +11 -4
- StreamingCommunity/Api/Site/1337xx/title.py +3 -4
- StreamingCommunity/Api/Site/animeunity/film_serie.py +5 -4
- StreamingCommunity/Api/Site/animeunity/site.py +9 -3
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +8 -9
- StreamingCommunity/Api/Site/cb01new/site.py +12 -4
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +10 -4
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +2 -2
- StreamingCommunity/Api/Site/guardaserie/site.py +17 -11
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +4 -3
- StreamingCommunity/Api/Site/mostraguarda/film.py +11 -6
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +3 -5
- StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -1
- StreamingCommunity/Api/Site/streamingcommunity/series.py +6 -7
- StreamingCommunity/Api/Site/streamingcommunity/site.py +14 -63
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +9 -24
- StreamingCommunity/Api/Template/Util/get_domain.py +11 -72
- StreamingCommunity/Api/Template/Util/manage_ep.py +28 -23
- StreamingCommunity/Api/Template/config_loader.py +6 -2
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +2 -2
- StreamingCommunity/Lib/Downloader/HLS/proxyes.py +2 -2
- StreamingCommunity/Lib/Downloader/HLS/segments.py +5 -5
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +2 -2
- StreamingCommunity/Upload/update.py +3 -3
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/_jsonConfig.py +209 -96
- StreamingCommunity/Util/headers.py +8 -1
- StreamingCommunity/Util/table.py +6 -6
- StreamingCommunity/run.py +13 -9
- {StreamingCommunity-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/METADATA +39 -24
- {StreamingCommunity-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/RECORD +40 -47
- StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +0 -76
- StreamingCommunity/Api/Site/altadefinizionegratis/film.py +0 -76
- StreamingCommunity/Api/Site/altadefinizionegratis/site.py +0 -109
- 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-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/LICENSE +0 -0
- {StreamingCommunity-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-2.6.0.dist-info → StreamingCommunity-2.7.0.dist-info}/top_level.txt +0 -0
|
@@ -4,97 +4,230 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
|
-
|
|
7
|
+
import requests
|
|
8
8
|
from typing import Any, List
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
# External library
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Variable
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
11
19
|
class ConfigManager:
|
|
12
20
|
def __init__(self, file_name: str = 'config.json') -> None:
|
|
13
21
|
"""Initialize the ConfigManager.
|
|
14
22
|
|
|
15
23
|
Parameters:
|
|
16
|
-
-
|
|
24
|
+
- file_name (str, optional): The name of the configuration file. Default is 'config.json'.
|
|
17
25
|
"""
|
|
18
|
-
|
|
26
|
+
if getattr(sys, 'frozen', False):
|
|
27
|
+
base_path = os.path.join(".")
|
|
28
|
+
else:
|
|
29
|
+
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
30
|
+
|
|
31
|
+
self.file_path = os.path.join(base_path, file_name)
|
|
32
|
+
self.domains_path = os.path.join(base_path, 'domains.json')
|
|
19
33
|
self.config = {}
|
|
34
|
+
self.configSite = {}
|
|
20
35
|
self.cache = {}
|
|
36
|
+
self.reference_config_url = 'https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/config.json'
|
|
37
|
+
|
|
38
|
+
# Validate and update config before proceeding
|
|
39
|
+
self._validate_and_update_config()
|
|
40
|
+
self._read_initial_config()
|
|
41
|
+
|
|
42
|
+
console.print(f"[bold cyan]📂 Configuration file path:[/bold cyan] [green]{self.file_path}[/green]")
|
|
43
|
+
|
|
44
|
+
def _validate_and_update_config(self) -> None:
|
|
45
|
+
"""Validate local config against reference config and update missing keys."""
|
|
46
|
+
try:
|
|
47
|
+
# Load local config if exists
|
|
48
|
+
local_config = {}
|
|
49
|
+
if os.path.exists(self.file_path):
|
|
50
|
+
with open(self.file_path, 'r') as f:
|
|
51
|
+
local_config = json.load(f)
|
|
52
|
+
console.print("[bold cyan]📖 Local configuration found.[/bold cyan]")
|
|
53
|
+
|
|
54
|
+
# Download reference config
|
|
55
|
+
console.print("[bold cyan]🌍 Downloading reference configuration...[/bold cyan]")
|
|
56
|
+
response = requests.get(self.reference_config_url)
|
|
57
|
+
if response.status_code != 200:
|
|
58
|
+
raise Exception(f"Failed to download reference config. Status code: {response.status_code}")
|
|
59
|
+
reference_config = response.json()
|
|
60
|
+
|
|
61
|
+
# Compare and update missing keys
|
|
62
|
+
merged_config = self._deep_merge_configs(local_config, reference_config)
|
|
63
|
+
|
|
64
|
+
if merged_config != local_config:
|
|
65
|
+
# Save the merged config
|
|
66
|
+
with open(self.file_path, 'w') as f:
|
|
67
|
+
json.dump(merged_config, f, indent=4)
|
|
68
|
+
console.print("[bold green]✅ Configuration updated with missing keys.[/bold green]")
|
|
69
|
+
else:
|
|
70
|
+
console.print("[bold green]✅ Configuration is up to date.[/bold green]")
|
|
71
|
+
|
|
72
|
+
self.config = merged_config
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
console.print(f"[bold red]❌ Error validating configuration: {e}[/bold red]")
|
|
76
|
+
if not self.config:
|
|
77
|
+
# If validation failed and we have no config, download the reference config
|
|
78
|
+
self.download_requirements(self.reference_config_url, self.file_path)
|
|
79
|
+
with open(self.file_path, 'r') as f:
|
|
80
|
+
self.config = json.load(f)
|
|
81
|
+
|
|
82
|
+
def _deep_merge_configs(self, local_config: dict, reference_config: dict) -> dict:
|
|
83
|
+
"""
|
|
84
|
+
Recursively merge reference config into local config, preserving local values.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
local_config (dict): The local configuration
|
|
88
|
+
reference_config (dict): The reference configuration
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
dict: Merged configuration
|
|
92
|
+
"""
|
|
93
|
+
merged = local_config.copy()
|
|
94
|
+
|
|
95
|
+
for key, value in reference_config.items():
|
|
96
|
+
if key not in merged:
|
|
97
|
+
merged[key] = value
|
|
98
|
+
elif isinstance(value, dict) and isinstance(merged[key], dict):
|
|
99
|
+
merged[key] = self._deep_merge_configs(merged[key], value)
|
|
100
|
+
|
|
101
|
+
return merged
|
|
102
|
+
|
|
103
|
+
def _read_initial_config(self) -> None:
|
|
104
|
+
"""Read initial configuration to get use_api setting."""
|
|
105
|
+
try:
|
|
106
|
+
if os.path.exists(self.file_path):
|
|
107
|
+
with open(self.file_path, 'r') as f:
|
|
108
|
+
self.config = json.load(f)
|
|
109
|
+
self.use_api = self.config.get('DEFAULT', {}).get('use_api', True)
|
|
110
|
+
else:
|
|
111
|
+
self.use_api = True # Default to True if config file doesn't exist
|
|
112
|
+
console.print("[bold yellow]⚠️ Configuration file not found. Using default settings.[/bold yellow]")
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
self.use_api = True # Default to True in case of error
|
|
116
|
+
logging.error(f"❌ Error reading initial configuration: {e}")
|
|
21
117
|
|
|
22
118
|
def read_config(self) -> None:
|
|
23
119
|
"""Read the configuration file."""
|
|
24
120
|
try:
|
|
25
|
-
logging.info(f"Reading file: {self.file_path}")
|
|
121
|
+
logging.info(f"📖 Reading file: {self.file_path}")
|
|
26
122
|
|
|
27
123
|
# Check if file exists
|
|
28
124
|
if os.path.exists(self.file_path):
|
|
29
125
|
with open(self.file_path, 'r') as f:
|
|
30
126
|
self.config = json.load(f)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Download config.json if it doesn't exist locally
|
|
127
|
+
console.print("[bold green]✅ Configuration file loaded successfully.[/bold green]")
|
|
34
128
|
else:
|
|
35
|
-
|
|
36
|
-
self.download_requirements(
|
|
37
|
-
'https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/config.json',
|
|
38
|
-
self.file_path
|
|
39
|
-
)
|
|
129
|
+
console.print("[bold yellow]⚠️ Configuration file not found. Downloading...[/bold yellow]")
|
|
130
|
+
self.download_requirements(self.reference_config_url, self.file_path)
|
|
40
131
|
|
|
41
132
|
# Load the downloaded config.json into the config attribute
|
|
42
133
|
with open(self.file_path, 'r') as f:
|
|
43
134
|
self.config = json.load(f)
|
|
44
|
-
|
|
135
|
+
console.print("[bold green]✅ Configuration file downloaded and saved.[/bold green]")
|
|
45
136
|
|
|
46
|
-
|
|
137
|
+
# Update site configuration separately
|
|
138
|
+
self.update_site_config()
|
|
139
|
+
|
|
140
|
+
console.print("[bold cyan]🔧 Configuration file processing complete.[/bold cyan]")
|
|
47
141
|
|
|
48
142
|
except Exception as e:
|
|
49
|
-
logging.error(f"Error reading configuration file: {e}")
|
|
143
|
+
logging.error(f"❌ Error reading configuration file: {e}")
|
|
50
144
|
|
|
51
|
-
def download_requirements(self, url: str, filename: str):
|
|
145
|
+
def download_requirements(self, url: str, filename: str) -> None:
|
|
52
146
|
"""
|
|
53
|
-
Download
|
|
147
|
+
Download a file from the specified URL if not found locally using requests.
|
|
54
148
|
|
|
55
149
|
Args:
|
|
56
|
-
url (str): The URL to download the
|
|
57
|
-
filename (str): The local filename to save the
|
|
150
|
+
url (str): The URL to download the file from.
|
|
151
|
+
filename (str): The local filename to save the file as.
|
|
58
152
|
"""
|
|
59
153
|
try:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
logging.info(f"{filename} not found locally. Downloading from {url}...")
|
|
154
|
+
logging.info(f"🌍 Downloading {filename} from {url}...")
|
|
63
155
|
response = requests.get(url)
|
|
64
156
|
|
|
65
157
|
if response.status_code == 200:
|
|
66
158
|
with open(filename, 'wb') as f:
|
|
67
159
|
f.write(response.content)
|
|
68
|
-
|
|
160
|
+
console.print(f"[bold green]✅ Successfully downloaded {filename}.[/bold green]")
|
|
161
|
+
|
|
69
162
|
else:
|
|
70
|
-
logging.error(f"Failed to download {filename}. HTTP Status code: {response.status_code}")
|
|
163
|
+
logging.error(f"❌ Failed to download {filename}. HTTP Status code: {response.status_code}")
|
|
71
164
|
sys.exit(0)
|
|
72
165
|
|
|
73
166
|
except Exception as e:
|
|
74
|
-
logging.error(f"Failed to download {filename}: {e}")
|
|
167
|
+
logging.error(f"❌ Failed to download {filename}: {e}")
|
|
75
168
|
sys.exit(0)
|
|
76
169
|
|
|
77
|
-
def
|
|
78
|
-
"""
|
|
170
|
+
def update_site_config(self) -> None:
|
|
171
|
+
"""Fetch and update the site configuration with data from the API or local file."""
|
|
172
|
+
if self.use_api:
|
|
173
|
+
headers = {
|
|
174
|
+
"apikey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inp2Zm5ncG94d3Jnc3duenl0YWRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDAxNTIxNjMsImV4cCI6MjA1NTcyODE2M30.FNTCCMwi0QaKjOu8gtZsT5yQttUW8QiDDGXmzkn89QE",
|
|
175
|
+
"Authorization": f"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inp2Zm5ncG94d3Jnc3duenl0YWRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDAxNTIxNjMsImV4cCI6MjA1NTcyODE2M30.FNTCCMwi0QaKjOu8gtZsT5yQttUW8QiDDGXmzkn89QE",
|
|
176
|
+
"Content-Type": "application/json"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
console.print("[bold cyan]🌍 Fetching SITE data from API...[/bold cyan]")
|
|
181
|
+
response = requests.get("https://zvfngpoxwrgswnzytadh.supabase.co/rest/v1/public", headers=headers)
|
|
182
|
+
|
|
183
|
+
if response.status_code == 200:
|
|
184
|
+
self.configSite = response.json()[0]['data']
|
|
185
|
+
console.print("[bold green]✅ SITE data successfully fetched.[/bold green]")
|
|
186
|
+
else:
|
|
187
|
+
console.print(f"[bold red]❌ Failed to fetch SITE data. HTTP Status code: {response.status_code}[/bold red]")
|
|
188
|
+
|
|
189
|
+
except Exception as e:
|
|
190
|
+
console.print(f"[bold red]❌ Error fetching SITE data: {e}[/bold red]")
|
|
191
|
+
else:
|
|
192
|
+
try:
|
|
193
|
+
if os.path.exists(self.domains_path):
|
|
194
|
+
console.print("[bold cyan]📖 Reading domains from local file...[/bold cyan]")
|
|
195
|
+
with open(self.domains_path, 'r') as f:
|
|
196
|
+
self.configSite = json.load(f)
|
|
197
|
+
console.print("[bold green]✅ Domains loaded successfully from local file.[/bold green]")
|
|
198
|
+
else:
|
|
199
|
+
error_msg = "❌ domains.json not found and API usage is disabled"
|
|
200
|
+
console.print(f"[bold red]{error_msg}[/bold red]")
|
|
201
|
+
raise FileNotFoundError(error_msg)
|
|
202
|
+
|
|
203
|
+
except Exception as e:
|
|
204
|
+
console.print(f"[bold red]❌ Error reading domains file: {e}[/bold red]")
|
|
205
|
+
raise
|
|
206
|
+
|
|
207
|
+
def read_key(self, section: str, key: str, data_type: type = str, from_site: bool = False) -> Any:
|
|
208
|
+
"""Read a key from the configuration.
|
|
79
209
|
|
|
80
210
|
Parameters:
|
|
81
|
-
- section (str): The section in the configuration
|
|
211
|
+
- section (str): The section in the configuration.
|
|
82
212
|
- key (str): The key to be read.
|
|
83
213
|
- data_type (type, optional): The expected data type of the key's value. Default is str.
|
|
214
|
+
- from_site (bool, optional): Whether to read from site config. Default is False.
|
|
84
215
|
|
|
85
216
|
Returns:
|
|
86
217
|
The value of the key converted to the specified data type.
|
|
87
218
|
"""
|
|
88
|
-
cache_key = f"{section}.{key}"
|
|
219
|
+
cache_key = f"{'site' if from_site else 'config'}.{section}.{key}"
|
|
89
220
|
logging.info(f"Read key: {cache_key}")
|
|
90
221
|
|
|
91
222
|
if cache_key in self.cache:
|
|
92
223
|
return self.cache[cache_key]
|
|
93
224
|
|
|
94
|
-
|
|
95
|
-
|
|
225
|
+
config_source = self.configSite if from_site else self.config
|
|
226
|
+
|
|
227
|
+
if section in config_source and key in config_source[section]:
|
|
228
|
+
value = config_source[section][key]
|
|
96
229
|
else:
|
|
97
|
-
raise ValueError(f"Key '{key}' not found in section '{section}'")
|
|
230
|
+
raise ValueError(f"Key '{key}' not found in section '{section}' of {'site' if from_site else 'main'} config")
|
|
98
231
|
|
|
99
232
|
value = self._convert_to_data_type(value, data_type)
|
|
100
233
|
self.cache[cache_key] = value
|
|
@@ -122,100 +255,80 @@ class ConfigManager:
|
|
|
122
255
|
else:
|
|
123
256
|
return value
|
|
124
257
|
|
|
258
|
+
# Main config getters
|
|
125
259
|
def get(self, section: str, key: str) -> Any:
|
|
126
|
-
"""Read a value from the configuration
|
|
127
|
-
|
|
128
|
-
Parameters:
|
|
129
|
-
- section (str): The section in the configuration file.
|
|
130
|
-
- key (str): The key to be read.
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
The value associated with the key.
|
|
134
|
-
"""
|
|
260
|
+
"""Read a value from the main configuration."""
|
|
135
261
|
return self.read_key(section, key)
|
|
136
262
|
|
|
137
263
|
def get_int(self, section: str, key: str) -> int:
|
|
138
|
-
"""Read an integer value from the configuration
|
|
139
|
-
|
|
140
|
-
Parameters:
|
|
141
|
-
- section (str): The section in the configuration file.
|
|
142
|
-
- key (str): The key to be read.
|
|
143
|
-
|
|
144
|
-
Returns:
|
|
145
|
-
int: The integer value.
|
|
146
|
-
"""
|
|
264
|
+
"""Read an integer value from the main configuration."""
|
|
147
265
|
return self.read_key(section, key, int)
|
|
148
266
|
|
|
149
|
-
def get_float(self, section: str, key: str) ->
|
|
150
|
-
"""Read
|
|
151
|
-
|
|
152
|
-
Parameters:
|
|
153
|
-
- section (str): The section in the configuration file.
|
|
154
|
-
- key (str): The key to be read.
|
|
155
|
-
|
|
156
|
-
Returns:
|
|
157
|
-
float: The float value.
|
|
158
|
-
"""
|
|
267
|
+
def get_float(self, section: str, key: str) -> float:
|
|
268
|
+
"""Read a float value from the main configuration."""
|
|
159
269
|
return self.read_key(section, key, float)
|
|
160
270
|
|
|
161
271
|
def get_bool(self, section: str, key: str) -> bool:
|
|
162
|
-
"""Read a boolean value from the configuration
|
|
163
|
-
|
|
164
|
-
Parameters:
|
|
165
|
-
- section (str): The section in the configuration file.
|
|
166
|
-
- key (str): The key to be read.
|
|
167
|
-
|
|
168
|
-
Returns:
|
|
169
|
-
bool: The boolean value.
|
|
170
|
-
"""
|
|
272
|
+
"""Read a boolean value from the main configuration."""
|
|
171
273
|
return self.read_key(section, key, bool)
|
|
172
274
|
|
|
173
275
|
def get_list(self, section: str, key: str) -> List[str]:
|
|
174
|
-
"""Read a list value from the configuration
|
|
175
|
-
|
|
176
|
-
Parameters:
|
|
177
|
-
- section (str): The section in the configuration file.
|
|
178
|
-
- key (str): The key to be read.
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
list: The list value.
|
|
182
|
-
"""
|
|
276
|
+
"""Read a list value from the main configuration."""
|
|
183
277
|
return self.read_key(section, key, list)
|
|
184
278
|
|
|
185
279
|
def get_dict(self, section: str, key: str) -> dict:
|
|
186
|
-
"""Read a dictionary value from the configuration
|
|
280
|
+
"""Read a dictionary value from the main configuration."""
|
|
281
|
+
return self.read_key(section, key, dict)
|
|
187
282
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
283
|
+
# Site config getters
|
|
284
|
+
def get_site(self, section: str, key: str) -> Any:
|
|
285
|
+
"""Read a value from the site configuration."""
|
|
286
|
+
return self.read_key(section, key, from_site=True)
|
|
191
287
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
288
|
+
def get_site_int(self, section: str, key: str) -> int:
|
|
289
|
+
"""Read an integer value from the site configuration."""
|
|
290
|
+
return self.read_key(section, key, int, from_site=True)
|
|
291
|
+
|
|
292
|
+
def get_site_float(self, section: str, key: str) -> float:
|
|
293
|
+
"""Read a float value from the site configuration."""
|
|
294
|
+
return self.read_key(section, key, float, from_site=True)
|
|
295
|
+
|
|
296
|
+
def get_site_bool(self, section: str, key: str) -> bool:
|
|
297
|
+
"""Read a boolean value from the site configuration."""
|
|
298
|
+
return self.read_key(section, key, bool, from_site=True)
|
|
299
|
+
|
|
300
|
+
def get_site_list(self, section: str, key: str) -> List[str]:
|
|
301
|
+
"""Read a list value from the site configuration."""
|
|
302
|
+
return self.read_key(section, key, list, from_site=True)
|
|
303
|
+
|
|
304
|
+
def get_site_dict(self, section: str, key: str) -> dict:
|
|
305
|
+
"""Read a dictionary value from the site configuration."""
|
|
306
|
+
return self.read_key(section, key, dict, from_site=True)
|
|
196
307
|
|
|
197
|
-
def set_key(self, section: str, key: str, value: Any) -> None:
|
|
198
|
-
"""Set a key in the configuration
|
|
308
|
+
def set_key(self, section: str, key: str, value: Any, to_site: bool = False) -> None:
|
|
309
|
+
"""Set a key in the configuration.
|
|
199
310
|
|
|
200
311
|
Parameters:
|
|
201
|
-
- section (str): The section in the configuration
|
|
312
|
+
- section (str): The section in the configuration.
|
|
202
313
|
- key (str): The key to be set.
|
|
203
314
|
- value (Any): The value to be associated with the key.
|
|
315
|
+
- to_site (bool, optional): Whether to set in site config. Default is False.
|
|
204
316
|
"""
|
|
205
317
|
try:
|
|
206
|
-
if
|
|
207
|
-
|
|
318
|
+
config_target = self.configSite if to_site else self.config
|
|
319
|
+
|
|
320
|
+
if section not in config_target:
|
|
321
|
+
config_target[section] = {}
|
|
208
322
|
|
|
209
|
-
|
|
210
|
-
cache_key = f"{section}.{key}"
|
|
323
|
+
config_target[section][key] = value
|
|
324
|
+
cache_key = f"{'site' if to_site else 'config'}.{section}.{key}"
|
|
211
325
|
self.cache[cache_key] = value
|
|
212
|
-
self.write_config()
|
|
213
326
|
|
|
214
327
|
except Exception as e:
|
|
215
|
-
print(f"Error setting key '{key}' in section '{section}': {e}")
|
|
328
|
+
print(f"Error setting key '{key}' in section '{section}' of {'site' if to_site else 'main'} config: {e}")
|
|
216
329
|
|
|
217
330
|
def write_config(self) -> None:
|
|
218
|
-
"""Write the configuration to the file."""
|
|
331
|
+
"""Write the main configuration to the file."""
|
|
219
332
|
try:
|
|
220
333
|
with open(self.file_path, 'w') as f:
|
|
221
334
|
json.dump(self.config, f, indent=4)
|
|
@@ -7,7 +7,10 @@ import random
|
|
|
7
7
|
import ua_generator
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# Variable
|
|
11
|
+
ua = ua_generator.generate(device='desktop', browser=('chrome', 'edge'))
|
|
12
|
+
|
|
13
|
+
def get_userAgent() -> str:
|
|
11
14
|
"""
|
|
12
15
|
Generate a random user agent to use in HTTP requests.
|
|
13
16
|
|
|
@@ -20,6 +23,10 @@ def get_headers() -> str:
|
|
|
20
23
|
return user_agent
|
|
21
24
|
|
|
22
25
|
|
|
26
|
+
def get_headers() -> dict:
|
|
27
|
+
return ua.headers.get()
|
|
28
|
+
|
|
29
|
+
|
|
23
30
|
def random_headers(referer: str = None):
|
|
24
31
|
"""
|
|
25
32
|
Generate random HTTP headers to simulate human-like behavior.
|
StreamingCommunity/Util/table.py
CHANGED
|
@@ -85,8 +85,9 @@ class TVShowManager:
|
|
|
85
85
|
table.add_row(*row_data)
|
|
86
86
|
|
|
87
87
|
self.console.print(table)
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def run_back_command(research_func: dict) -> None:
|
|
90
91
|
"""
|
|
91
92
|
Executes a back-end search command by dynamically importing a module and invoking its search function.
|
|
92
93
|
|
|
@@ -116,8 +117,7 @@ class TVShowManager:
|
|
|
116
117
|
search_func(None)
|
|
117
118
|
|
|
118
119
|
except Exception as e:
|
|
119
|
-
|
|
120
|
-
logging.exception("Error during search execution")
|
|
120
|
+
logging.error("Error during search execution")
|
|
121
121
|
|
|
122
122
|
finally:
|
|
123
123
|
if project_root in sys.path:
|
|
@@ -181,7 +181,7 @@ class TVShowManager:
|
|
|
181
181
|
if self.slice_end > total_items:
|
|
182
182
|
self.slice_end = total_items
|
|
183
183
|
elif (key.lower() in ["b", "back"]) and research_func:
|
|
184
|
-
|
|
184
|
+
TVShowManager.run_back_command(research_func)
|
|
185
185
|
else:
|
|
186
186
|
break
|
|
187
187
|
|
|
@@ -215,7 +215,7 @@ class TVShowManager:
|
|
|
215
215
|
self.slice_start = 0
|
|
216
216
|
self.slice_end = self.step
|
|
217
217
|
elif (key.lower() in ["b", "back"]) and research_func:
|
|
218
|
-
|
|
218
|
+
TVShowManager.run_back_command(research_func)
|
|
219
219
|
else:
|
|
220
220
|
break
|
|
221
221
|
|
StreamingCommunity/run.py
CHANGED
|
@@ -27,24 +27,26 @@ from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance, Teleg
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
# Config
|
|
30
|
+
SHOW_TRENDING = config_manager.get_bool('DEFAULT', 'show_trending')
|
|
30
31
|
CLOSE_CONSOLE = config_manager.get_bool('DEFAULT', 'not_close')
|
|
31
32
|
TELEGRAM_BOT = config_manager.get_bool('DEFAULT', 'telegram_bot')
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
def run_function(func: Callable[..., None], close_console: bool = False) -> None:
|
|
36
|
+
def run_function(func: Callable[..., None], close_console: bool = False, search_terms: str = None) -> None:
|
|
36
37
|
"""
|
|
37
38
|
Run a given function indefinitely or once, depending on the value of close_console.
|
|
38
39
|
|
|
39
40
|
Parameters:
|
|
40
41
|
func (Callable[..., None]): The function to run.
|
|
41
42
|
close_console (bool, optional): Whether to close the console after running the function once. Defaults to False.
|
|
43
|
+
search_terms (str, optional): Search terms to use for the function. Defaults to None.
|
|
42
44
|
"""
|
|
43
45
|
if close_console:
|
|
44
46
|
while 1:
|
|
45
|
-
func()
|
|
47
|
+
func(search_terms)
|
|
46
48
|
else:
|
|
47
|
-
func()
|
|
49
|
+
func(search_terms)
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
def load_search_functions():
|
|
@@ -134,10 +136,10 @@ def initialize():
|
|
|
134
136
|
sys.exit(0)
|
|
135
137
|
|
|
136
138
|
# Trending tmbd
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
if SHOW_TRENDING:
|
|
140
|
+
print()
|
|
141
|
+
tmdb.display_trending_films()
|
|
142
|
+
tmdb.display_trending_tv_shows()
|
|
141
143
|
|
|
142
144
|
# Attempting GitHub update
|
|
143
145
|
try:
|
|
@@ -248,9 +250,11 @@ def main(script_id = 0):
|
|
|
248
250
|
long_option = alias
|
|
249
251
|
parser.add_argument(f'-{short_option}', f'--{long_option}', action='store_true', help=f'Search for {alias.split("_")[0]} on streaming platforms.')
|
|
250
252
|
|
|
253
|
+
parser.add_argument('-s', '--search', default=None, help='Search terms')
|
|
251
254
|
# Parse command-line arguments
|
|
252
255
|
args = parser.parse_args()
|
|
253
256
|
|
|
257
|
+
search_terms = args.search
|
|
254
258
|
# Map command-line arguments to the config values
|
|
255
259
|
config_updates = {}
|
|
256
260
|
|
|
@@ -282,7 +286,7 @@ def main(script_id = 0):
|
|
|
282
286
|
# Check which argument is provided and run the corresponding function
|
|
283
287
|
for arg, func in arg_to_function.items():
|
|
284
288
|
if getattr(args, arg):
|
|
285
|
-
run_function(func)
|
|
289
|
+
run_function(func, search_terms=search_terms)
|
|
286
290
|
return
|
|
287
291
|
|
|
288
292
|
# Mapping user input to functions
|
|
@@ -335,7 +339,7 @@ def main(script_id = 0):
|
|
|
335
339
|
|
|
336
340
|
# Run the corresponding function based on user input
|
|
337
341
|
if category in input_to_function:
|
|
338
|
-
run_function(input_to_function[category])
|
|
342
|
+
run_function(input_to_function[category], search_terms = args.search)
|
|
339
343
|
else:
|
|
340
344
|
|
|
341
345
|
if TELEGRAM_BOT:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: StreamingCommunity
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Home-page: https://github.com/Lovi-0/StreamingCommunity
|
|
5
5
|
Author: Lovi-0
|
|
6
6
|
Project-URL: Bug Reports, https://github.com/Lovi-0/StreamingCommunity/issues
|
|
@@ -19,7 +19,6 @@ Requires-Dist: unidecode
|
|
|
19
19
|
Requires-Dist: jsbeautifier
|
|
20
20
|
Requires-Dist: pathvalidate
|
|
21
21
|
Requires-Dist: pycryptodomex
|
|
22
|
-
Requires-Dist: googlesearch-python
|
|
23
22
|
Requires-Dist: ua-generator
|
|
24
23
|
Requires-Dist: qbittorrent-api
|
|
25
24
|
Requires-Dist: python-qbittorrent
|
|
@@ -59,7 +58,7 @@ Requires-Dist: pyTelegramBotAPI
|
|
|
59
58
|
|
|
60
59
|
# 📋 Table of Contents
|
|
61
60
|
|
|
62
|
-
-
|
|
61
|
+
- 🔄 [Update Domains](#update-domains)
|
|
63
62
|
- 🛠️ [Installation](#installation)
|
|
64
63
|
- 📦 [PyPI Installation](#1-pypi-installation)
|
|
65
64
|
- 🔄 [Automatic Installation](#2-automatic-installation)
|
|
@@ -86,18 +85,15 @@ Requires-Dist: pyTelegramBotAPI
|
|
|
86
85
|
# Installation
|
|
87
86
|
|
|
88
87
|
<p align="center">
|
|
89
|
-
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_win.exe">
|
|
88
|
+
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_win.exe" style="margin: 0 20px;">
|
|
90
89
|
<img src="https://img.shields.io/badge/-Windows-blue.svg?style=for-the-badge&logo=windows" alt="Windows">
|
|
91
90
|
</a>
|
|
92
|
-
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_mac">
|
|
91
|
+
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_mac" style="margin: 0 20px;">
|
|
93
92
|
<img src="https://img.shields.io/badge/-macOS-black.svg?style=for-the-badge&logo=apple" alt="macOS">
|
|
94
93
|
</a>
|
|
95
|
-
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_linux">
|
|
94
|
+
<a href="https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_linux" style="margin: 0 20px;">
|
|
96
95
|
<img src="https://img.shields.io/badge/-Linux-orange.svg?style=for-the-badge&logo=linux" alt="Linux">
|
|
97
96
|
</a>
|
|
98
|
-
<a href="https://github.com/Arrowar/StreamingCommunity/releases">
|
|
99
|
-
<img src="https://img.shields.io/badge/-All_Versions-lightgrey.svg?style=for-the-badge" alt="All Versions">
|
|
100
|
-
</a>
|
|
101
97
|
</p>
|
|
102
98
|
|
|
103
99
|
|
|
@@ -478,6 +474,40 @@ You can download VLC Media Player from the [official website](https://www.videol
|
|
|
478
474
|
- `get_only_link`: Return M3U8 playlist/index URL instead of downloading
|
|
479
475
|
|
|
480
476
|
|
|
477
|
+
## Update Domains
|
|
478
|
+
|
|
479
|
+
There are two ways to update the domains for the supported websites:
|
|
480
|
+
|
|
481
|
+
### 1. Using Local Configuration
|
|
482
|
+
|
|
483
|
+
1. Create a `domains.json` file in the root directory of the project
|
|
484
|
+
|
|
485
|
+
2. Add your domain configuration in the following format:
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"altadefinizione": {
|
|
489
|
+
"domain": "si",
|
|
490
|
+
"full_url": "https://altadefinizione.si/"
|
|
491
|
+
},
|
|
492
|
+
...
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
3. Set `use_api` to `false` in the `DEFAULT` section of your `config.json`:
|
|
497
|
+
```json
|
|
498
|
+
{
|
|
499
|
+
"DEFAULT": {
|
|
500
|
+
"use_api": false
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 2. Using API (Legacy)
|
|
506
|
+
|
|
507
|
+
The API-based domain updates are currently deprecated. To use it anyway, set `use_api` to `true` in your `config.json` file.
|
|
508
|
+
|
|
509
|
+
Note: If `use_api` is set to `false` and no `domains.json` file is found, the script will raise an error.
|
|
510
|
+
|
|
481
511
|
# COMMAND
|
|
482
512
|
|
|
483
513
|
- Download a specific season by entering its number.
|
|
@@ -587,21 +617,6 @@ Start the bot from the folder /StreamingCommunity/TelegramHelp
|
|
|
587
617
|
python3 telegram_bot.py
|
|
588
618
|
```
|
|
589
619
|
|
|
590
|
-
# Website Status
|
|
591
|
-
|
|
592
|
-
| Website | Status | Command |
|
|
593
|
-
|:-------------------|:------:|:--------:|
|
|
594
|
-
| [1337xx](https://1337xx.to/) | ✅ | -133 |
|
|
595
|
-
| [AltadefinizioneGratis](https://altadefinizionegratis.pro/) | ✅ | -ALT |
|
|
596
|
-
| [AnimeUnity](https://animeunity.so/) | ✅ | -ANI |
|
|
597
|
-
| [Ilcorsaronero](https://ilcorsaronero.link/) | ✅ | `-ILC` |
|
|
598
|
-
| [CB01New](https://cb01new.gold/) | ✅ | -CB0 |
|
|
599
|
-
| [DDLStreamItaly](https://ddlstreamitaly.co/) | ✅ | -DDL |
|
|
600
|
-
| [GuardaSerie](https://guardaserie.now/) | ✅ | -GUA |
|
|
601
|
-
| [MostraGuarda](https://mostraguarda.stream/) | ✅ | -MOS |
|
|
602
|
-
| [StreamingCommunity](https://streamingcommunity.paris/) | ✅ | -STR |
|
|
603
|
-
|
|
604
|
-
|
|
605
620
|
# Tutorials
|
|
606
621
|
|
|
607
622
|
- [Windows Tutorial](https://www.youtube.com/watch?v=mZGqK4wdN-k)
|