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,42 +0,0 @@
|
|
|
1
|
-
# 02.07.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# Internal utilities
|
|
7
|
-
from StreamingCommunity.Util.console import console
|
|
8
|
-
from StreamingCommunity.Util.os import os_manager
|
|
9
|
-
from StreamingCommunity.Util.message import start_message
|
|
10
|
-
from StreamingCommunity.Lib.Downloader import TOR_downloader
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Logic class
|
|
14
|
-
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
15
|
-
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def download_title(select_title: MediaItem):
|
|
20
|
-
"""
|
|
21
|
-
Downloads a media item and saves it as an MP4 file.
|
|
22
|
-
|
|
23
|
-
Parameters:
|
|
24
|
-
- select_title (MediaItem): The media item to be downloaded. This should be an instance of the MediaItem class, containing attributes like `name` and `url`.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
start_message()
|
|
28
|
-
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
|
29
|
-
print()
|
|
30
|
-
|
|
31
|
-
# Define output path
|
|
32
|
-
title_name = os_manager.get_sanitize_file(select_title.name)
|
|
33
|
-
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
|
34
|
-
|
|
35
|
-
# Create output folder
|
|
36
|
-
os_manager.create_path(mp4_path)
|
|
37
|
-
|
|
38
|
-
# Tor manager
|
|
39
|
-
manager = TOR_downloader()
|
|
40
|
-
manager.add_magnet_link(select_title.url)
|
|
41
|
-
manager.start_download()
|
|
42
|
-
manager.move_downloaded_files(mp4_path)
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# 12.14.24
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import asyncio
|
|
5
|
-
from typing import List, Dict, Optional
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# External libraries
|
|
9
|
-
import httpx
|
|
10
|
-
from bs4 import BeautifulSoup
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Internal utilities
|
|
14
|
-
from StreamingCommunity.Util._jsonConfig import config_manager
|
|
15
|
-
from StreamingCommunity.Util.headers import get_headers
|
|
16
|
-
from StreamingCommunity.Util.console import console
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# Variable
|
|
20
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class IlCorsaroNeroScraper:
|
|
24
|
-
def __init__(self, base_url: str, max_page: int = 1):
|
|
25
|
-
self.base_url = base_url
|
|
26
|
-
self.max_page = max_page
|
|
27
|
-
self.headers = {
|
|
28
|
-
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
29
|
-
'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
30
|
-
'cache-control': 'max-age=0',
|
|
31
|
-
'priority': 'u=0, i',
|
|
32
|
-
'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
|
|
33
|
-
'sec-ch-ua-mobile': '?0',
|
|
34
|
-
'sec-ch-ua-platform': '"Windows"',
|
|
35
|
-
'sec-fetch-dest': 'document',
|
|
36
|
-
'sec-fetch-mode': 'navigate',
|
|
37
|
-
'sec-fetch-site': 'same-origin',
|
|
38
|
-
'sec-fetch-user': '?1',
|
|
39
|
-
'upgrade-insecure-requests': '1',
|
|
40
|
-
'user-agent': get_headers()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async def fetch_url(self, url: str) -> Optional[str]:
|
|
44
|
-
"""
|
|
45
|
-
Fetch the HTML content of a given URL.
|
|
46
|
-
"""
|
|
47
|
-
try:
|
|
48
|
-
console.print(f"[cyan]Fetching url[white]: [red]{url}")
|
|
49
|
-
async with httpx.AsyncClient(headers=self.headers, follow_redirects=True, timeout=max_timeout) as client:
|
|
50
|
-
response = await client.get(url)
|
|
51
|
-
|
|
52
|
-
# If the request was successful, return the HTML content
|
|
53
|
-
response.raise_for_status()
|
|
54
|
-
return response.text
|
|
55
|
-
|
|
56
|
-
except Exception as e:
|
|
57
|
-
logging.error(f"Error fetching from {url}: {e}")
|
|
58
|
-
return None
|
|
59
|
-
|
|
60
|
-
def parse_torrents(self, html: str) -> List[Dict[str, str]]:
|
|
61
|
-
"""
|
|
62
|
-
Parse the HTML content and extract torrent details.
|
|
63
|
-
"""
|
|
64
|
-
torrents = []
|
|
65
|
-
soup = BeautifulSoup(html, "html.parser")
|
|
66
|
-
table = soup.find("tbody")
|
|
67
|
-
|
|
68
|
-
for row in table.find_all("tr"):
|
|
69
|
-
try:
|
|
70
|
-
columns = row.find_all("td")
|
|
71
|
-
|
|
72
|
-
torrents.append({
|
|
73
|
-
'type': columns[0].get_text(strip=True),
|
|
74
|
-
'name': row.find("th").find("a").get_text(strip=True),
|
|
75
|
-
'seed': columns[1].get_text(strip=True),
|
|
76
|
-
'leech': columns[2].get_text(strip=True),
|
|
77
|
-
'size': columns[3].get_text(strip=True),
|
|
78
|
-
'date': columns[4].get_text(strip=True),
|
|
79
|
-
'url': "https://ilcorsaronero.link" + row.find("th").find("a").get("href")
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
except Exception as e:
|
|
83
|
-
logging.error(f"Error parsing row: {e}")
|
|
84
|
-
continue
|
|
85
|
-
|
|
86
|
-
return torrents
|
|
87
|
-
|
|
88
|
-
async def fetch_real_url(self, url: str) -> Optional[str]:
|
|
89
|
-
"""
|
|
90
|
-
Fetch the real torrent URL from the detailed page.
|
|
91
|
-
"""
|
|
92
|
-
response_html = await self.fetch_url(url)
|
|
93
|
-
if not response_html:
|
|
94
|
-
return None
|
|
95
|
-
|
|
96
|
-
soup = BeautifulSoup(response_html, "html.parser")
|
|
97
|
-
links = soup.find_all("a")
|
|
98
|
-
|
|
99
|
-
# Find and return the magnet link
|
|
100
|
-
for link in links:
|
|
101
|
-
if "magnet" in str(link):
|
|
102
|
-
return link.get("href")
|
|
103
|
-
|
|
104
|
-
return None
|
|
105
|
-
|
|
106
|
-
async def search(self, query: str) -> List[Dict[str, str]]:
|
|
107
|
-
"""
|
|
108
|
-
Search for torrents based on the query string.
|
|
109
|
-
"""
|
|
110
|
-
all_torrents = []
|
|
111
|
-
|
|
112
|
-
# Loop through each page
|
|
113
|
-
for page in range(self.max_page):
|
|
114
|
-
url = f'{self.base_url}search?q={query}&page={page}'
|
|
115
|
-
|
|
116
|
-
html = await self.fetch_url(url)
|
|
117
|
-
if not html:
|
|
118
|
-
console.print(f"[bold red]No HTML content for page {page}[/bold red]")
|
|
119
|
-
break
|
|
120
|
-
|
|
121
|
-
torrents = self.parse_torrents(html)
|
|
122
|
-
if not torrents:
|
|
123
|
-
console.print(f"[bold red]No torrents found on page {page}[/bold red]")
|
|
124
|
-
break
|
|
125
|
-
|
|
126
|
-
# Use asyncio.gather to fetch all real URLs concurrently
|
|
127
|
-
tasks = [self.fetch_real_url(result['url']) for result in torrents]
|
|
128
|
-
real_urls = await asyncio.gather(*tasks)
|
|
129
|
-
|
|
130
|
-
# Attach real URLs to the torrent data
|
|
131
|
-
for i, result in enumerate(torrents):
|
|
132
|
-
result['url'] = real_urls[i]
|
|
133
|
-
|
|
134
|
-
all_torrents.extend(torrents)
|
|
135
|
-
|
|
136
|
-
return all_torrents
|
|
137
|
-
|
|
138
|
-
async def main():
|
|
139
|
-
scraper = IlCorsaroNeroScraper("https://ilcorsaronero.link/")
|
|
140
|
-
results = await scraper.search("cars")
|
|
141
|
-
|
|
142
|
-
if results:
|
|
143
|
-
for i, torrent in enumerate(results):
|
|
144
|
-
console.print(f"[bold green]{i} = {torrent}[/bold green] \n")
|
|
145
|
-
else:
|
|
146
|
-
console.print("[bold red]No torrents found.[/bold red]")
|
|
147
|
-
|
|
148
|
-
if __name__ == '__main__':
|
|
149
|
-
asyncio.run(main())
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# 19.10.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
def execute_search(info):
|
|
7
|
-
"""
|
|
8
|
-
Dynamically imports and executes a specified function from a module defined in the info dictionary.
|
|
9
|
-
|
|
10
|
-
Parameters:
|
|
11
|
-
info (dict): A dictionary containing the function name, folder, and module information.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
# Define the project path using the folder from the info dictionary
|
|
15
|
-
project_path = os.path.dirname(info['folder']) # Get the base path for the project
|
|
16
|
-
|
|
17
|
-
# Add the project path to sys.path
|
|
18
|
-
if project_path not in sys.path:
|
|
19
|
-
sys.path.append(project_path)
|
|
20
|
-
|
|
21
|
-
# Attempt to import the specified function from the module
|
|
22
|
-
try:
|
|
23
|
-
# Construct the import statement dynamically
|
|
24
|
-
module_path = f"StreamingCommunity.Api.Site{info['folder_base']}"
|
|
25
|
-
exec(f"from {module_path} import {info['function']}")
|
|
26
|
-
|
|
27
|
-
# Call the specified function
|
|
28
|
-
eval(info['function'])() # Calls the search function
|
|
29
|
-
|
|
30
|
-
except ModuleNotFoundError as e:
|
|
31
|
-
print(f"ModuleNotFoundError: {e}")
|
|
32
|
-
|
|
33
|
-
except ImportError as e:
|
|
34
|
-
print(f"ImportError: {e}")
|
|
35
|
-
|
|
36
|
-
except Exception as e:
|
|
37
|
-
print(f"An error occurred: {e}")
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# 09.06.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
import logging
|
|
6
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# External libraries
|
|
10
|
-
import httpx
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Internal utilities
|
|
14
|
-
from StreamingCommunity.Util._jsonConfig import config_manager
|
|
15
|
-
from StreamingCommunity.Util.headers import get_headers
|
|
16
|
-
from StreamingCommunity.Util.os import os_manager
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ProxyManager:
|
|
20
|
-
def __init__(self, proxy_list=None, url=None):
|
|
21
|
-
"""
|
|
22
|
-
Initialize ProxyManager with a list of proxies and timeout.
|
|
23
|
-
|
|
24
|
-
Parameters:
|
|
25
|
-
- proxy_list: List of proxy strings
|
|
26
|
-
- timeout: Timeout for proxy requests
|
|
27
|
-
"""
|
|
28
|
-
self.proxy_list = proxy_list or []
|
|
29
|
-
self.verified_proxies = []
|
|
30
|
-
self.timeout = config_manager.get_float('REQUESTS', 'timeout')
|
|
31
|
-
self.url = url
|
|
32
|
-
|
|
33
|
-
def _check_proxy(self, proxy):
|
|
34
|
-
"""
|
|
35
|
-
Check if a single proxy is working by making a request to Google.
|
|
36
|
-
|
|
37
|
-
Parameters:
|
|
38
|
-
- proxy: Proxy string to be checked
|
|
39
|
-
|
|
40
|
-
Returns:
|
|
41
|
-
- Proxy string if working, None otherwise
|
|
42
|
-
"""
|
|
43
|
-
protocol = proxy.split(":")[0].lower()
|
|
44
|
-
protocol = f'{protocol}://'
|
|
45
|
-
proxy = {protocol: proxy, "https://": proxy}
|
|
46
|
-
|
|
47
|
-
try:
|
|
48
|
-
with httpx.Client(proxies=proxy, verify=False) as client:
|
|
49
|
-
response = client.get(self.url, timeout=self.timeout, headers={'user-agent': get_headers()})
|
|
50
|
-
|
|
51
|
-
if response.status_code == 200:
|
|
52
|
-
logging.info(f"Proxy {proxy} is working.")
|
|
53
|
-
return proxy
|
|
54
|
-
|
|
55
|
-
except Exception as e:
|
|
56
|
-
logging.error(f"Test proxy {proxy} failed: {e}")
|
|
57
|
-
return None
|
|
58
|
-
|
|
59
|
-
def verify_proxies(self):
|
|
60
|
-
"""
|
|
61
|
-
Verify all proxies in the list and store the working ones.
|
|
62
|
-
"""
|
|
63
|
-
logging.info("Starting proxy verification...")
|
|
64
|
-
with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
|
|
65
|
-
self.verified_proxies = list(executor.map(self._check_proxy, self.proxy_list))
|
|
66
|
-
|
|
67
|
-
self.verified_proxies = [proxy for proxy in self.verified_proxies if proxy]
|
|
68
|
-
logging.info(f"Verification complete. {len(self.verified_proxies)} proxies are working.")
|
|
69
|
-
|
|
70
|
-
def get_verified_proxies(self):
|
|
71
|
-
"""
|
|
72
|
-
Get validate proxies.
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
if len(self.verified_proxies) > 0:
|
|
76
|
-
return self.verified_proxies
|
|
77
|
-
|
|
78
|
-
else:
|
|
79
|
-
logging.error("Cant find valid proxy.")
|
|
80
|
-
sys.exit(0)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def main_test_proxy(url_test):
|
|
84
|
-
|
|
85
|
-
path_file_proxt_list = "list_proxy.txt"
|
|
86
|
-
|
|
87
|
-
if os_manager.check_file(path_file_proxt_list):
|
|
88
|
-
|
|
89
|
-
# Read file
|
|
90
|
-
with open(path_file_proxt_list, 'r') as file:
|
|
91
|
-
ip_addresses = file.readlines()
|
|
92
|
-
|
|
93
|
-
# Formatt ip
|
|
94
|
-
ip_addresses = [ip.strip() for ip in ip_addresses]
|
|
95
|
-
formatted_ips = [f"http://{ip}" for ip in ip_addresses]
|
|
96
|
-
|
|
97
|
-
# Get list of proxy from config.json
|
|
98
|
-
proxy_list = formatted_ips
|
|
99
|
-
|
|
100
|
-
# Verify proxy
|
|
101
|
-
manager = ProxyManager(proxy_list, url_test)
|
|
102
|
-
manager.verify_proxies()
|
|
103
|
-
|
|
104
|
-
# Write valid ip in txt file
|
|
105
|
-
with open(path_file_proxt_list, 'w') as file:
|
|
106
|
-
for ip in ip_addresses:
|
|
107
|
-
file.write(f"{ip}\n")
|
|
108
|
-
|
|
109
|
-
# Return valid proxy
|
|
110
|
-
return manager.get_verified_proxies()
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
# 29.01.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
import json
|
|
6
|
-
import logging
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Any, List
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# External library
|
|
12
|
-
from rich.console import Console
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# Variable
|
|
16
|
-
console = Console()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ConfigManager:
|
|
20
|
-
def __init__(self, file_name: str = 'config.json') -> None:
|
|
21
|
-
"""Initialize the ConfigManager.
|
|
22
|
-
|
|
23
|
-
Parameters:
|
|
24
|
-
- file_path (str, optional): The path to the configuration file. Default is 'config.json'.
|
|
25
|
-
"""
|
|
26
|
-
if getattr(sys, 'frozen', False):
|
|
27
|
-
base_path = Path(sys._MEIPASS)
|
|
28
|
-
else:
|
|
29
|
-
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
30
|
-
self.file_path = os.path.join(base_path, file_name)
|
|
31
|
-
self.config = {}
|
|
32
|
-
self.cache = {}
|
|
33
|
-
console.print(f"[green]Configuration file path: {self.file_path}[/green]")
|
|
34
|
-
|
|
35
|
-
def read_config(self) -> None:
|
|
36
|
-
"""Read the configuration file."""
|
|
37
|
-
try:
|
|
38
|
-
logging.info(f"Reading file: {self.file_path}")
|
|
39
|
-
|
|
40
|
-
# Check if file exists
|
|
41
|
-
if os.path.exists(self.file_path):
|
|
42
|
-
with open(self.file_path, 'r') as f:
|
|
43
|
-
self.config = json.load(f)
|
|
44
|
-
logging.info("Configuration file loaded successfully.")
|
|
45
|
-
|
|
46
|
-
# Download config.json if it doesn't exist locally
|
|
47
|
-
else:
|
|
48
|
-
logging.info("Configuration file does not exist. Downloading...")
|
|
49
|
-
self.download_requirements(
|
|
50
|
-
'https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/config.json',
|
|
51
|
-
self.file_path
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
# Load the downloaded config.json into the config attribute
|
|
55
|
-
with open(self.file_path, 'r') as f:
|
|
56
|
-
self.config = json.load(f)
|
|
57
|
-
logging.info("Configuration file downloaded and saved.")
|
|
58
|
-
|
|
59
|
-
logging.info("Configuration file processed successfully.")
|
|
60
|
-
|
|
61
|
-
except Exception as e:
|
|
62
|
-
logging.error(f"Error reading configuration file: {e}")
|
|
63
|
-
|
|
64
|
-
def download_requirements(self, url: str, filename: str):
|
|
65
|
-
"""
|
|
66
|
-
Download the requirements.txt file from the specified URL if not found locally using requests.
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
url (str): The URL to download the requirements file from.
|
|
70
|
-
filename (str): The local filename to save the requirements file as.
|
|
71
|
-
"""
|
|
72
|
-
try:
|
|
73
|
-
import requests
|
|
74
|
-
|
|
75
|
-
logging.info(f"{filename} not found locally. Downloading from {url}...")
|
|
76
|
-
response = requests.get(url)
|
|
77
|
-
|
|
78
|
-
if response.status_code == 200:
|
|
79
|
-
with open(filename, 'wb') as f:
|
|
80
|
-
f.write(response.content)
|
|
81
|
-
|
|
82
|
-
else:
|
|
83
|
-
logging.error(f"Failed to download {filename}. HTTP Status code: {response.status_code}")
|
|
84
|
-
sys.exit(0)
|
|
85
|
-
|
|
86
|
-
except Exception as e:
|
|
87
|
-
logging.error(f"Failed to download {filename}: {e}")
|
|
88
|
-
sys.exit(0)
|
|
89
|
-
|
|
90
|
-
def read_key(self, section: str, key: str, data_type: type = str) -> Any:
|
|
91
|
-
"""Read a key from the configuration file.
|
|
92
|
-
|
|
93
|
-
Parameters:
|
|
94
|
-
- section (str): The section in the configuration file.
|
|
95
|
-
- key (str): The key to be read.
|
|
96
|
-
- data_type (type, optional): The expected data type of the key's value. Default is str.
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
The value of the key converted to the specified data type.
|
|
100
|
-
"""
|
|
101
|
-
cache_key = f"{section}.{key}"
|
|
102
|
-
logging.info(f"Read key: {cache_key}")
|
|
103
|
-
|
|
104
|
-
if cache_key in self.cache:
|
|
105
|
-
return self.cache[cache_key]
|
|
106
|
-
|
|
107
|
-
if section in self.config and key in self.config[section]:
|
|
108
|
-
value = self.config[section][key]
|
|
109
|
-
else:
|
|
110
|
-
raise ValueError(f"Key '{key}' not found in section '{section}'")
|
|
111
|
-
|
|
112
|
-
value = self._convert_to_data_type(value, data_type)
|
|
113
|
-
self.cache[cache_key] = value
|
|
114
|
-
|
|
115
|
-
return value
|
|
116
|
-
|
|
117
|
-
def _convert_to_data_type(self, value: str, data_type: type) -> Any:
|
|
118
|
-
"""Convert the value to the specified data type.
|
|
119
|
-
|
|
120
|
-
Parameters:
|
|
121
|
-
- value (str): The value to be converted.
|
|
122
|
-
- data_type (type): The expected data type.
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
The value converted to the specified data type.
|
|
126
|
-
"""
|
|
127
|
-
if data_type == int:
|
|
128
|
-
return int(value)
|
|
129
|
-
elif data_type == bool:
|
|
130
|
-
return bool(value)
|
|
131
|
-
elif data_type == list:
|
|
132
|
-
return value if isinstance(value, list) else [item.strip() for item in value.split(',')]
|
|
133
|
-
elif data_type == type(None):
|
|
134
|
-
return None
|
|
135
|
-
else:
|
|
136
|
-
return value
|
|
137
|
-
|
|
138
|
-
def get(self, section: str, key: str) -> Any:
|
|
139
|
-
"""Read a value from the configuration file.
|
|
140
|
-
|
|
141
|
-
Parameters:
|
|
142
|
-
- section (str): The section in the configuration file.
|
|
143
|
-
- key (str): The key to be read.
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
The value associated with the key.
|
|
147
|
-
"""
|
|
148
|
-
return self.read_key(section, key)
|
|
149
|
-
|
|
150
|
-
def get_int(self, section: str, key: str) -> int:
|
|
151
|
-
"""Read an integer value from the configuration file.
|
|
152
|
-
|
|
153
|
-
Parameters:
|
|
154
|
-
- section (str): The section in the configuration file.
|
|
155
|
-
- key (str): The key to be read.
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
int: The integer value.
|
|
159
|
-
"""
|
|
160
|
-
return self.read_key(section, key, int)
|
|
161
|
-
|
|
162
|
-
def get_float(self, section: str, key: str) -> int:
|
|
163
|
-
"""Read an float value from the configuration file.
|
|
164
|
-
|
|
165
|
-
Parameters:
|
|
166
|
-
- section (str): The section in the configuration file.
|
|
167
|
-
- key (str): The key to be read.
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
float: The float value.
|
|
171
|
-
"""
|
|
172
|
-
return self.read_key(section, key, float)
|
|
173
|
-
|
|
174
|
-
def get_bool(self, section: str, key: str) -> bool:
|
|
175
|
-
"""Read a boolean value from the configuration file.
|
|
176
|
-
|
|
177
|
-
Parameters:
|
|
178
|
-
- section (str): The section in the configuration file.
|
|
179
|
-
- key (str): The key to be read.
|
|
180
|
-
|
|
181
|
-
Returns:
|
|
182
|
-
bool: The boolean value.
|
|
183
|
-
"""
|
|
184
|
-
return self.read_key(section, key, bool)
|
|
185
|
-
|
|
186
|
-
def get_list(self, section: str, key: str) -> List[str]:
|
|
187
|
-
"""Read a list value from the configuration file.
|
|
188
|
-
|
|
189
|
-
Parameters:
|
|
190
|
-
- section (str): The section in the configuration file.
|
|
191
|
-
- key (str): The key to be read.
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
list: The list value.
|
|
195
|
-
"""
|
|
196
|
-
return self.read_key(section, key, list)
|
|
197
|
-
|
|
198
|
-
def get_dict(self, section: str, key: str) -> dict:
|
|
199
|
-
"""Read a dictionary value from the configuration file.
|
|
200
|
-
|
|
201
|
-
Parameters:
|
|
202
|
-
- section (str): The section in the configuration file.
|
|
203
|
-
- key (str): The key to be read.
|
|
204
|
-
|
|
205
|
-
Returns:
|
|
206
|
-
dict: The dictionary value.
|
|
207
|
-
"""
|
|
208
|
-
return self.read_key(section, key, dict)
|
|
209
|
-
|
|
210
|
-
def set_key(self, section: str, key: str, value: Any) -> None:
|
|
211
|
-
"""Set a key in the configuration file.
|
|
212
|
-
|
|
213
|
-
Parameters:
|
|
214
|
-
- section (str): The section in the configuration file.
|
|
215
|
-
- key (str): The key to be set.
|
|
216
|
-
- value (Any): The value to be associated with the key.
|
|
217
|
-
"""
|
|
218
|
-
try:
|
|
219
|
-
if section not in self.config:
|
|
220
|
-
self.config[section] = {}
|
|
221
|
-
|
|
222
|
-
self.config[section][key] = value
|
|
223
|
-
cache_key = f"{section}.{key}"
|
|
224
|
-
self.cache[cache_key] = value
|
|
225
|
-
self.write_config()
|
|
226
|
-
|
|
227
|
-
except Exception as e:
|
|
228
|
-
print(f"Error setting key '{key}' in section '{section}': {e}")
|
|
229
|
-
|
|
230
|
-
def write_config(self) -> None:
|
|
231
|
-
"""Write the configuration to the file."""
|
|
232
|
-
try:
|
|
233
|
-
with open(self.file_path, 'w') as f:
|
|
234
|
-
json.dump(self.config, f, indent=4)
|
|
235
|
-
except Exception as e:
|
|
236
|
-
print(f"Error writing configuration file: {e}")
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
# Initialize
|
|
240
|
-
config_manager = ConfigManager()
|
|
241
|
-
config_manager.read_config()
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# 21.06.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import inspect
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def get_call_stack():
|
|
8
|
-
"""
|
|
9
|
-
Retrieves the current call stack with details about each call.
|
|
10
|
-
|
|
11
|
-
This function inspects the current call stack and returns a list of dictionaries,
|
|
12
|
-
where each dictionary contains details about a function call in the stack.
|
|
13
|
-
|
|
14
|
-
Returns:
|
|
15
|
-
list: A list of dictionaries, each containing the following keys:
|
|
16
|
-
- function (str): The name of the function.
|
|
17
|
-
- folder (str): The directory path of the script containing the function.
|
|
18
|
-
- folder_base (str): The base name of the directory path.
|
|
19
|
-
- script (str): The name of the script file containing the function.
|
|
20
|
-
- line (int): The line number in the script where the function is defined.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
stack = inspect.stack()
|
|
24
|
-
call_stack = []
|
|
25
|
-
|
|
26
|
-
for frame_info in stack:
|
|
27
|
-
function_name = frame_info.function
|
|
28
|
-
filename = frame_info.filename
|
|
29
|
-
lineno = frame_info.lineno
|
|
30
|
-
folder_name = os.path.dirname(filename)
|
|
31
|
-
folder_base = os.path.basename(folder_name)
|
|
32
|
-
script_name = os.path.basename(filename)
|
|
33
|
-
|
|
34
|
-
call_stack.append({
|
|
35
|
-
"function": function_name,
|
|
36
|
-
"folder": folder_name,
|
|
37
|
-
"folder_base": folder_base,
|
|
38
|
-
"script": script_name,
|
|
39
|
-
"line": lineno
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
return call_stack
|