StreamingCommunity 1.7.6__py3-none-any.whl → 1.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/Src/Api/Player/Helper/Vixcloud/js_parser.py +4 -1
- StreamingCommunity/Src/Api/Player/Helper/Vixcloud/util.py +166 -166
- StreamingCommunity/Src/Api/Player/ddl.py +89 -89
- StreamingCommunity/Src/Api/Player/maxstream.py +151 -151
- StreamingCommunity/Src/Api/Player/supervideo.py +193 -193
- StreamingCommunity/Src/Api/Player/vixcloud.py +224 -212
- StreamingCommunity/Src/Api/Site/1337xx/__init__.py +50 -50
- StreamingCommunity/Src/Api/Site/1337xx/costant.py +14 -14
- StreamingCommunity/Src/Api/Site/1337xx/site.py +83 -83
- StreamingCommunity/Src/Api/Site/1337xx/title.py +66 -66
- StreamingCommunity/Src/Api/Site/altadefinizione/__init__.py +50 -50
- StreamingCommunity/Src/Api/Site/altadefinizione/costant.py +14 -14
- StreamingCommunity/Src/Api/Site/altadefinizione/film.py +69 -69
- StreamingCommunity/Src/Api/Site/altadefinizione/site.py +86 -86
- StreamingCommunity/Src/Api/Site/animeunity/__init__.py +50 -50
- StreamingCommunity/Src/Api/Site/animeunity/costant.py +15 -15
- StreamingCommunity/Src/Api/Site/animeunity/film_serie.py +131 -131
- StreamingCommunity/Src/Api/Site/animeunity/site.py +164 -164
- StreamingCommunity/Src/Api/Site/bitsearch/__init__.py +51 -51
- StreamingCommunity/Src/Api/Site/bitsearch/costant.py +15 -15
- StreamingCommunity/Src/Api/Site/bitsearch/site.py +84 -84
- StreamingCommunity/Src/Api/Site/bitsearch/title.py +47 -47
- StreamingCommunity/Src/Api/Site/cb01new/__init__.py +51 -51
- StreamingCommunity/Src/Api/Site/cb01new/costant.py +15 -15
- StreamingCommunity/Src/Api/Site/cb01new/film.py +69 -69
- StreamingCommunity/Src/Api/Site/cb01new/site.py +74 -74
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/__init__.py +57 -57
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/costant.py +16 -16
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/series.py +142 -142
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/site.py +92 -92
- StreamingCommunity/Src/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +82 -82
- StreamingCommunity/Src/Api/Site/guardaserie/__init__.py +52 -52
- StreamingCommunity/Src/Api/Site/guardaserie/costant.py +15 -15
- StreamingCommunity/Src/Api/Site/guardaserie/series.py +195 -195
- StreamingCommunity/Src/Api/Site/guardaserie/site.py +84 -84
- StreamingCommunity/Src/Api/Site/guardaserie/util/ScrapeSerie.py +110 -110
- StreamingCommunity/Src/Api/Site/mostraguarda/__init__.py +48 -48
- StreamingCommunity/Src/Api/Site/mostraguarda/costant.py +14 -14
- StreamingCommunity/Src/Api/Site/mostraguarda/film.py +94 -94
- StreamingCommunity/Src/Api/Site/piratebays/__init__.py +50 -50
- StreamingCommunity/Src/Api/Site/piratebays/costant.py +14 -14
- StreamingCommunity/Src/Api/Site/piratebays/site.py +88 -88
- StreamingCommunity/Src/Api/Site/piratebays/title.py +45 -45
- StreamingCommunity/Src/Api/Site/streamingcommunity/__init__.py +55 -55
- StreamingCommunity/Src/Api/Site/streamingcommunity/costant.py +14 -14
- StreamingCommunity/Src/Api/Site/streamingcommunity/film.py +70 -70
- StreamingCommunity/Src/Api/Site/streamingcommunity/series.py +203 -203
- StreamingCommunity/Src/Api/Site/streamingcommunity/site.py +125 -125
- StreamingCommunity/Src/Api/Template/Class/SearchType.py +101 -101
- StreamingCommunity/Src/Api/Template/Util/__init__.py +4 -4
- StreamingCommunity/Src/Api/Template/Util/get_domain.py +137 -137
- StreamingCommunity/Src/Api/Template/Util/manage_ep.py +153 -153
- StreamingCommunity/Src/Api/Template/Util/recall_search.py +37 -37
- StreamingCommunity/Src/Api/Template/__init__.py +2 -2
- StreamingCommunity/Src/Api/Template/site.py +87 -87
- StreamingCommunity/Src/Lib/Downloader/HLS/downloader.py +968 -968
- StreamingCommunity/Src/Lib/Downloader/HLS/proxyes.py +110 -110
- StreamingCommunity/Src/Lib/Downloader/HLS/segments.py +540 -540
- StreamingCommunity/Src/Lib/Downloader/MP4/downloader.py +156 -156
- StreamingCommunity/Src/Lib/Downloader/TOR/downloader.py +222 -222
- StreamingCommunity/Src/Lib/Downloader/__init__.py +4 -4
- StreamingCommunity/Src/Lib/Driver/driver_1.py +76 -76
- StreamingCommunity/Src/Lib/FFmpeg/__init__.py +4 -4
- StreamingCommunity/Src/Lib/FFmpeg/capture.py +170 -170
- StreamingCommunity/Src/Lib/FFmpeg/command.py +292 -292
- StreamingCommunity/Src/Lib/FFmpeg/util.py +241 -241
- StreamingCommunity/Src/Lib/M3U8/__init__.py +5 -5
- StreamingCommunity/Src/Lib/M3U8/decryptor.py +128 -128
- StreamingCommunity/Src/Lib/M3U8/estimator.py +172 -172
- StreamingCommunity/Src/Lib/M3U8/parser.py +666 -666
- StreamingCommunity/Src/Lib/M3U8/url_fixer.py +51 -51
- StreamingCommunity/Src/Lib/TMBD/__init__.py +1 -1
- StreamingCommunity/Src/Lib/TMBD/obj_tmbd.py +39 -39
- StreamingCommunity/Src/Lib/TMBD/tmdb.py +345 -345
- StreamingCommunity/Src/Upload/update.py +64 -64
- StreamingCommunity/Src/Upload/version.py +5 -5
- StreamingCommunity/Src/Util/_jsonConfig.py +204 -204
- StreamingCommunity/Src/Util/call_stack.py +42 -42
- StreamingCommunity/Src/Util/color.py +20 -20
- StreamingCommunity/Src/Util/console.py +12 -12
- StreamingCommunity/Src/Util/headers.py +147 -147
- StreamingCommunity/Src/Util/logger.py +53 -53
- StreamingCommunity/Src/Util/message.py +46 -46
- StreamingCommunity/Src/Util/os.py +417 -417
- StreamingCommunity/Src/Util/table.py +163 -163
- StreamingCommunity/run.py +196 -196
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.8.0.dist-info}/METADATA +1 -1
- StreamingCommunity-1.8.0.dist-info/RECORD +97 -0
- StreamingCommunity-1.7.6.dist-info/RECORD +0 -97
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.8.0.dist-info}/LICENSE +0 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.8.0.dist-info}/WHEEL +0 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.8.0.dist-info}/entry_points.txt +0 -0
- {StreamingCommunity-1.7.6.dist-info → StreamingCommunity-1.8.0.dist-info}/top_level.txt +0 -0
|
@@ -1,222 +1,222 @@
|
|
|
1
|
-
# 23.06.24
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
import time
|
|
6
|
-
import shutil
|
|
7
|
-
import logging
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Internal utilities
|
|
11
|
-
from StreamingCommunity.Src.Util.color import Colors
|
|
12
|
-
from StreamingCommunity.Src.Util.os import internet_manager
|
|
13
|
-
from StreamingCommunity.Src.Util._jsonConfig import config_manager
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# External libraries
|
|
17
|
-
from tqdm import tqdm
|
|
18
|
-
from qbittorrent import Client
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# Tor config
|
|
22
|
-
HOST = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['host'])
|
|
23
|
-
PORT = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['port'])
|
|
24
|
-
USERNAME = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['user'])
|
|
25
|
-
PASSWORD = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['pass'])
|
|
26
|
-
|
|
27
|
-
# Config
|
|
28
|
-
TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar')
|
|
29
|
-
REQUEST_VERIFY = config_manager.get_float('REQUESTS', 'verify_ssl')
|
|
30
|
-
REQUEST_TIMEOUT = config_manager.get_float('REQUESTS', 'timeout')
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class TOR_downloader:
|
|
35
|
-
def __init__(self):
|
|
36
|
-
"""
|
|
37
|
-
Initializes the TorrentManager instance.
|
|
38
|
-
|
|
39
|
-
Parameters:
|
|
40
|
-
- host (str): IP address or hostname of the qBittorrent Web UI.
|
|
41
|
-
- port (int): Port number of the qBittorrent Web UI.
|
|
42
|
-
- username (str): Username for logging into qBittorrent.
|
|
43
|
-
- password (str): Password for logging into qBittorrent.
|
|
44
|
-
"""
|
|
45
|
-
try:
|
|
46
|
-
self.qb = Client(f'http://{HOST}:{PORT}/')
|
|
47
|
-
except:
|
|
48
|
-
logging.error("Start qbitorrent first.")
|
|
49
|
-
|
|
50
|
-
self.username = USERNAME
|
|
51
|
-
self.password = PASSWORD
|
|
52
|
-
self.logged_in = False
|
|
53
|
-
self.save_path = None
|
|
54
|
-
self.torrent_name = None
|
|
55
|
-
|
|
56
|
-
self.login()
|
|
57
|
-
|
|
58
|
-
def login(self):
|
|
59
|
-
"""
|
|
60
|
-
Logs into the qBittorrent Web UI.
|
|
61
|
-
"""
|
|
62
|
-
try:
|
|
63
|
-
self.qb.login(self.username, self.password)
|
|
64
|
-
self.logged_in = True
|
|
65
|
-
logging.info("Successfully logged in to qBittorrent.")
|
|
66
|
-
|
|
67
|
-
except Exception as e:
|
|
68
|
-
logging.error(f"Failed to log in: {str(e)}")
|
|
69
|
-
self.logged_in = False
|
|
70
|
-
|
|
71
|
-
def add_magnet_link(self, magnet_link):
|
|
72
|
-
"""
|
|
73
|
-
Adds a torrent via magnet link to qBittorrent.
|
|
74
|
-
|
|
75
|
-
Parameters:
|
|
76
|
-
- magnet_link (str): Magnet link of the torrent to be added.
|
|
77
|
-
"""
|
|
78
|
-
try:
|
|
79
|
-
self.qb.download_from_link(magnet_link)
|
|
80
|
-
logging.info("Added magnet link to qBittorrent.")
|
|
81
|
-
|
|
82
|
-
# Get the hash of the latest added torrent
|
|
83
|
-
torrents = self.qb.torrents()
|
|
84
|
-
if torrents:
|
|
85
|
-
self.latest_torrent_hash = torrents[-1]['hash']
|
|
86
|
-
logging.info(f"Latest torrent hash: {self.latest_torrent_hash}")
|
|
87
|
-
|
|
88
|
-
except Exception as e:
|
|
89
|
-
logging.error(f"Failed to add magnet link: {str(e)}")
|
|
90
|
-
|
|
91
|
-
def start_download(self):
|
|
92
|
-
"""
|
|
93
|
-
Starts downloading the latest added torrent and monitors progress.
|
|
94
|
-
"""
|
|
95
|
-
try:
|
|
96
|
-
|
|
97
|
-
torrents = self.qb.torrents()
|
|
98
|
-
if not torrents:
|
|
99
|
-
logging.error("No torrents found.")
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
# Sleep to load magnet to qbit app
|
|
103
|
-
time.sleep(10)
|
|
104
|
-
latest_torrent = torrents[-1]
|
|
105
|
-
torrent_hash = latest_torrent['hash']
|
|
106
|
-
|
|
107
|
-
# Custom bar for mobile and pc
|
|
108
|
-
if TQDM_USE_LARGE_BAR:
|
|
109
|
-
bar_format = (
|
|
110
|
-
f"{Colors.YELLOW}[TOR] {Colors.WHITE}({Colors.CYAN}video{Colors.WHITE}): "
|
|
111
|
-
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
|
112
|
-
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
113
|
-
)
|
|
114
|
-
else:
|
|
115
|
-
bar_format = (
|
|
116
|
-
f"{Colors.YELLOW}Proc{Colors.WHITE}: "
|
|
117
|
-
f"{Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| "
|
|
118
|
-
f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
progress_bar = tqdm(
|
|
122
|
-
total=100,
|
|
123
|
-
ascii='░▒█',
|
|
124
|
-
bar_format=bar_format,
|
|
125
|
-
unit_scale=True,
|
|
126
|
-
unit_divisor=1024,
|
|
127
|
-
mininterval=0.05
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
with progress_bar as pbar:
|
|
131
|
-
while True:
|
|
132
|
-
|
|
133
|
-
# Get variable from qtorrent
|
|
134
|
-
torrent_info = self.qb.get_torrent(torrent_hash)
|
|
135
|
-
self.save_path = torrent_info['save_path']
|
|
136
|
-
self.torrent_name = torrent_info['name']
|
|
137
|
-
|
|
138
|
-
# Fetch important variable
|
|
139
|
-
pieces_have = torrent_info['pieces_have']
|
|
140
|
-
pieces_num = torrent_info['pieces_num']
|
|
141
|
-
progress = (pieces_have / pieces_num) * 100 if pieces_num else 0
|
|
142
|
-
pbar.n = progress
|
|
143
|
-
|
|
144
|
-
download_speed = torrent_info['dl_speed']
|
|
145
|
-
total_size = torrent_info['total_size']
|
|
146
|
-
downloaded_size = torrent_info['total_downloaded']
|
|
147
|
-
|
|
148
|
-
# Format variable
|
|
149
|
-
downloaded_size_str = internet_manager.format_file_size(downloaded_size)
|
|
150
|
-
downloaded_size = downloaded_size_str.split(' ')[0]
|
|
151
|
-
|
|
152
|
-
total_size_str = internet_manager.format_file_size(total_size)
|
|
153
|
-
total_size = total_size_str.split(' ')[0]
|
|
154
|
-
total_size_unit = total_size_str.split(' ')[1]
|
|
155
|
-
|
|
156
|
-
average_internet_str = internet_manager.format_transfer_speed(download_speed)
|
|
157
|
-
average_internet = average_internet_str.split(' ')[0]
|
|
158
|
-
average_internet_unit = average_internet_str.split(' ')[1]
|
|
159
|
-
|
|
160
|
-
# Update the progress bar's postfix
|
|
161
|
-
if TQDM_USE_LARGE_BAR:
|
|
162
|
-
pbar.set_postfix_str(
|
|
163
|
-
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size} {Colors.WHITE}< {Colors.GREEN}{total_size} {Colors.RED}{total_size_unit} "
|
|
164
|
-
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
165
|
-
)
|
|
166
|
-
else:
|
|
167
|
-
pbar.set_postfix_str(
|
|
168
|
-
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size}{Colors.RED} {total_size} "
|
|
169
|
-
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
pbar.refresh()
|
|
173
|
-
time.sleep(0.2)
|
|
174
|
-
|
|
175
|
-
# Break at the end
|
|
176
|
-
if int(progress) == 100:
|
|
177
|
-
break
|
|
178
|
-
|
|
179
|
-
except KeyboardInterrupt:
|
|
180
|
-
logging.info("Download process interrupted.")
|
|
181
|
-
|
|
182
|
-
except Exception as e:
|
|
183
|
-
logging.error(f"Download error: {str(e)}")
|
|
184
|
-
sys.exit(0)
|
|
185
|
-
|
|
186
|
-
def move_downloaded_files(self, destination=None):
|
|
187
|
-
"""
|
|
188
|
-
Moves downloaded files of the latest torrent to another location.
|
|
189
|
-
|
|
190
|
-
Parameters:
|
|
191
|
-
- save_path (str): Current save path (output directory) of the torrent.
|
|
192
|
-
- destination (str, optional): Destination directory to move files. If None, moves to current directory.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
- bool: True if files are moved successfully, False otherwise.
|
|
196
|
-
"""
|
|
197
|
-
|
|
198
|
-
video_extensions = {'.mp4', '.mkv', 'avi'}
|
|
199
|
-
time.sleep(2)
|
|
200
|
-
|
|
201
|
-
# List directories in the save path
|
|
202
|
-
dirs = [d for d in os.listdir(self.save_path) if os.path.isdir(os.path.join(self.save_path, d))]
|
|
203
|
-
|
|
204
|
-
for dir_name in dirs:
|
|
205
|
-
if self.torrent_name.split(" ")[0] in dir_name:
|
|
206
|
-
dir_path = os.path.join(self.save_path, dir_name)
|
|
207
|
-
|
|
208
|
-
# Ensure destination is set; if not, use current directory
|
|
209
|
-
destination = destination or os.getcwd()
|
|
210
|
-
|
|
211
|
-
# Move only video files
|
|
212
|
-
for file_name in os.listdir(dir_path):
|
|
213
|
-
file_path = os.path.join(dir_path, file_name)
|
|
214
|
-
|
|
215
|
-
# Check if it's a file and if it has a video extension
|
|
216
|
-
if os.path.isfile(file_path) and os.path.splitext(file_name)[1] in video_extensions:
|
|
217
|
-
shutil.move(file_path, os.path.join(destination, file_name))
|
|
218
|
-
logging.info(f"Moved file {file_name} to {destination}")
|
|
219
|
-
|
|
220
|
-
time.sleep(2)
|
|
221
|
-
self.qb.delete_permanently(self.qb.torrents()[-1]['hash'])
|
|
222
|
-
return True
|
|
1
|
+
# 23.06.24
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
import shutil
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Internal utilities
|
|
11
|
+
from StreamingCommunity.Src.Util.color import Colors
|
|
12
|
+
from StreamingCommunity.Src.Util.os import internet_manager
|
|
13
|
+
from StreamingCommunity.Src.Util._jsonConfig import config_manager
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# External libraries
|
|
17
|
+
from tqdm import tqdm
|
|
18
|
+
from qbittorrent import Client
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Tor config
|
|
22
|
+
HOST = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['host'])
|
|
23
|
+
PORT = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['port'])
|
|
24
|
+
USERNAME = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['user'])
|
|
25
|
+
PASSWORD = str(config_manager.get_dict('DEFAULT', 'config_qbit_tor')['pass'])
|
|
26
|
+
|
|
27
|
+
# Config
|
|
28
|
+
TQDM_USE_LARGE_BAR = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_use_large_bar')
|
|
29
|
+
REQUEST_VERIFY = config_manager.get_float('REQUESTS', 'verify_ssl')
|
|
30
|
+
REQUEST_TIMEOUT = config_manager.get_float('REQUESTS', 'timeout')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TOR_downloader:
|
|
35
|
+
def __init__(self):
|
|
36
|
+
"""
|
|
37
|
+
Initializes the TorrentManager instance.
|
|
38
|
+
|
|
39
|
+
Parameters:
|
|
40
|
+
- host (str): IP address or hostname of the qBittorrent Web UI.
|
|
41
|
+
- port (int): Port number of the qBittorrent Web UI.
|
|
42
|
+
- username (str): Username for logging into qBittorrent.
|
|
43
|
+
- password (str): Password for logging into qBittorrent.
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
self.qb = Client(f'http://{HOST}:{PORT}/')
|
|
47
|
+
except:
|
|
48
|
+
logging.error("Start qbitorrent first.")
|
|
49
|
+
|
|
50
|
+
self.username = USERNAME
|
|
51
|
+
self.password = PASSWORD
|
|
52
|
+
self.logged_in = False
|
|
53
|
+
self.save_path = None
|
|
54
|
+
self.torrent_name = None
|
|
55
|
+
|
|
56
|
+
self.login()
|
|
57
|
+
|
|
58
|
+
def login(self):
|
|
59
|
+
"""
|
|
60
|
+
Logs into the qBittorrent Web UI.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
self.qb.login(self.username, self.password)
|
|
64
|
+
self.logged_in = True
|
|
65
|
+
logging.info("Successfully logged in to qBittorrent.")
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
logging.error(f"Failed to log in: {str(e)}")
|
|
69
|
+
self.logged_in = False
|
|
70
|
+
|
|
71
|
+
def add_magnet_link(self, magnet_link):
|
|
72
|
+
"""
|
|
73
|
+
Adds a torrent via magnet link to qBittorrent.
|
|
74
|
+
|
|
75
|
+
Parameters:
|
|
76
|
+
- magnet_link (str): Magnet link of the torrent to be added.
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
self.qb.download_from_link(magnet_link)
|
|
80
|
+
logging.info("Added magnet link to qBittorrent.")
|
|
81
|
+
|
|
82
|
+
# Get the hash of the latest added torrent
|
|
83
|
+
torrents = self.qb.torrents()
|
|
84
|
+
if torrents:
|
|
85
|
+
self.latest_torrent_hash = torrents[-1]['hash']
|
|
86
|
+
logging.info(f"Latest torrent hash: {self.latest_torrent_hash}")
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logging.error(f"Failed to add magnet link: {str(e)}")
|
|
90
|
+
|
|
91
|
+
def start_download(self):
|
|
92
|
+
"""
|
|
93
|
+
Starts downloading the latest added torrent and monitors progress.
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
|
|
97
|
+
torrents = self.qb.torrents()
|
|
98
|
+
if not torrents:
|
|
99
|
+
logging.error("No torrents found.")
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Sleep to load magnet to qbit app
|
|
103
|
+
time.sleep(10)
|
|
104
|
+
latest_torrent = torrents[-1]
|
|
105
|
+
torrent_hash = latest_torrent['hash']
|
|
106
|
+
|
|
107
|
+
# Custom bar for mobile and pc
|
|
108
|
+
if TQDM_USE_LARGE_BAR:
|
|
109
|
+
bar_format = (
|
|
110
|
+
f"{Colors.YELLOW}[TOR] {Colors.WHITE}({Colors.CYAN}video{Colors.WHITE}): "
|
|
111
|
+
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
|
112
|
+
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
113
|
+
)
|
|
114
|
+
else:
|
|
115
|
+
bar_format = (
|
|
116
|
+
f"{Colors.YELLOW}Proc{Colors.WHITE}: "
|
|
117
|
+
f"{Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| "
|
|
118
|
+
f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
progress_bar = tqdm(
|
|
122
|
+
total=100,
|
|
123
|
+
ascii='░▒█',
|
|
124
|
+
bar_format=bar_format,
|
|
125
|
+
unit_scale=True,
|
|
126
|
+
unit_divisor=1024,
|
|
127
|
+
mininterval=0.05
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
with progress_bar as pbar:
|
|
131
|
+
while True:
|
|
132
|
+
|
|
133
|
+
# Get variable from qtorrent
|
|
134
|
+
torrent_info = self.qb.get_torrent(torrent_hash)
|
|
135
|
+
self.save_path = torrent_info['save_path']
|
|
136
|
+
self.torrent_name = torrent_info['name']
|
|
137
|
+
|
|
138
|
+
# Fetch important variable
|
|
139
|
+
pieces_have = torrent_info['pieces_have']
|
|
140
|
+
pieces_num = torrent_info['pieces_num']
|
|
141
|
+
progress = (pieces_have / pieces_num) * 100 if pieces_num else 0
|
|
142
|
+
pbar.n = progress
|
|
143
|
+
|
|
144
|
+
download_speed = torrent_info['dl_speed']
|
|
145
|
+
total_size = torrent_info['total_size']
|
|
146
|
+
downloaded_size = torrent_info['total_downloaded']
|
|
147
|
+
|
|
148
|
+
# Format variable
|
|
149
|
+
downloaded_size_str = internet_manager.format_file_size(downloaded_size)
|
|
150
|
+
downloaded_size = downloaded_size_str.split(' ')[0]
|
|
151
|
+
|
|
152
|
+
total_size_str = internet_manager.format_file_size(total_size)
|
|
153
|
+
total_size = total_size_str.split(' ')[0]
|
|
154
|
+
total_size_unit = total_size_str.split(' ')[1]
|
|
155
|
+
|
|
156
|
+
average_internet_str = internet_manager.format_transfer_speed(download_speed)
|
|
157
|
+
average_internet = average_internet_str.split(' ')[0]
|
|
158
|
+
average_internet_unit = average_internet_str.split(' ')[1]
|
|
159
|
+
|
|
160
|
+
# Update the progress bar's postfix
|
|
161
|
+
if TQDM_USE_LARGE_BAR:
|
|
162
|
+
pbar.set_postfix_str(
|
|
163
|
+
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size} {Colors.WHITE}< {Colors.GREEN}{total_size} {Colors.RED}{total_size_unit} "
|
|
164
|
+
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
pbar.set_postfix_str(
|
|
168
|
+
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size}{Colors.RED} {total_size} "
|
|
169
|
+
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
pbar.refresh()
|
|
173
|
+
time.sleep(0.2)
|
|
174
|
+
|
|
175
|
+
# Break at the end
|
|
176
|
+
if int(progress) == 100:
|
|
177
|
+
break
|
|
178
|
+
|
|
179
|
+
except KeyboardInterrupt:
|
|
180
|
+
logging.info("Download process interrupted.")
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logging.error(f"Download error: {str(e)}")
|
|
184
|
+
sys.exit(0)
|
|
185
|
+
|
|
186
|
+
def move_downloaded_files(self, destination=None):
|
|
187
|
+
"""
|
|
188
|
+
Moves downloaded files of the latest torrent to another location.
|
|
189
|
+
|
|
190
|
+
Parameters:
|
|
191
|
+
- save_path (str): Current save path (output directory) of the torrent.
|
|
192
|
+
- destination (str, optional): Destination directory to move files. If None, moves to current directory.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
- bool: True if files are moved successfully, False otherwise.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
video_extensions = {'.mp4', '.mkv', 'avi'}
|
|
199
|
+
time.sleep(2)
|
|
200
|
+
|
|
201
|
+
# List directories in the save path
|
|
202
|
+
dirs = [d for d in os.listdir(self.save_path) if os.path.isdir(os.path.join(self.save_path, d))]
|
|
203
|
+
|
|
204
|
+
for dir_name in dirs:
|
|
205
|
+
if self.torrent_name.split(" ")[0] in dir_name:
|
|
206
|
+
dir_path = os.path.join(self.save_path, dir_name)
|
|
207
|
+
|
|
208
|
+
# Ensure destination is set; if not, use current directory
|
|
209
|
+
destination = destination or os.getcwd()
|
|
210
|
+
|
|
211
|
+
# Move only video files
|
|
212
|
+
for file_name in os.listdir(dir_path):
|
|
213
|
+
file_path = os.path.join(dir_path, file_name)
|
|
214
|
+
|
|
215
|
+
# Check if it's a file and if it has a video extension
|
|
216
|
+
if os.path.isfile(file_path) and os.path.splitext(file_name)[1] in video_extensions:
|
|
217
|
+
shutil.move(file_path, os.path.join(destination, file_name))
|
|
218
|
+
logging.info(f"Moved file {file_name} to {destination}")
|
|
219
|
+
|
|
220
|
+
time.sleep(2)
|
|
221
|
+
self.qb.delete_permanently(self.qb.torrents()[-1]['hash'])
|
|
222
|
+
return True
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# 23.06.24
|
|
2
|
-
|
|
3
|
-
from .HLS.downloader import HLS_Downloader
|
|
4
|
-
from .MP4.downloader import MP4_downloader
|
|
1
|
+
# 23.06.24
|
|
2
|
+
|
|
3
|
+
from .HLS.downloader import HLS_Downloader
|
|
4
|
+
from .MP4.downloader import MP4_downloader
|
|
5
5
|
from .TOR.downloader import TOR_downloader
|
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
# 29.06.24
|
|
2
|
-
|
|
3
|
-
import tempfile
|
|
4
|
-
import logging
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# External library
|
|
8
|
-
from bs4 import BeautifulSoup
|
|
9
|
-
from seleniumbase import Driver
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Internal utilities
|
|
13
|
-
from StreamingCommunity.Src.Util._jsonConfig import config_manager
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Config
|
|
17
|
-
USE_HEADLESS = config_manager.get_bool("BROWSER", "headless")
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class WebAutomation:
|
|
21
|
-
"""
|
|
22
|
-
A class for automating web interactions using SeleniumBase and BeautifulSoup.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self):
|
|
26
|
-
"""
|
|
27
|
-
Initializes the WebAutomation instance with SeleniumBase Driver.
|
|
28
|
-
|
|
29
|
-
Parameters:
|
|
30
|
-
headless (bool, optional): Whether to run the browser in headless mode. Default is True.
|
|
31
|
-
"""
|
|
32
|
-
logging.getLogger('seleniumbase').setLevel(logging.ERROR)
|
|
33
|
-
|
|
34
|
-
self.driver = Driver(
|
|
35
|
-
uc=True,
|
|
36
|
-
uc_cdp_events=True,
|
|
37
|
-
headless=USE_HEADLESS,
|
|
38
|
-
user_data_dir = tempfile.mkdtemp(),
|
|
39
|
-
chromium_arg="--disable-search-engine-choice-screen"
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
def quit(self):
|
|
43
|
-
"""
|
|
44
|
-
Quits the WebDriver instance.
|
|
45
|
-
"""
|
|
46
|
-
self.driver.quit()
|
|
47
|
-
|
|
48
|
-
def get_page(self, url):
|
|
49
|
-
"""
|
|
50
|
-
Navigates the browser to the specified URL.
|
|
51
|
-
|
|
52
|
-
Parameters:
|
|
53
|
-
url (str): The URL to navigate to.
|
|
54
|
-
"""
|
|
55
|
-
self.driver.get(url)
|
|
56
|
-
|
|
57
|
-
def retrieve_soup(self):
|
|
58
|
-
"""
|
|
59
|
-
Retrieves the BeautifulSoup object for the current page's HTML content.
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
BeautifulSoup object: Parsed HTML content of the current page.
|
|
63
|
-
"""
|
|
64
|
-
html_content = self.driver.page_source
|
|
65
|
-
soup = BeautifulSoup(html_content, 'html.parser')
|
|
66
|
-
return soup
|
|
67
|
-
|
|
68
|
-
def get_content(self):
|
|
69
|
-
"""
|
|
70
|
-
Returns the HTML content of the current page.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
str: The HTML content of the current page.
|
|
74
|
-
"""
|
|
75
|
-
return self.driver.page_source
|
|
76
|
-
|
|
1
|
+
# 29.06.24
|
|
2
|
+
|
|
3
|
+
import tempfile
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# External library
|
|
8
|
+
from bs4 import BeautifulSoup
|
|
9
|
+
from seleniumbase import Driver
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Internal utilities
|
|
13
|
+
from StreamingCommunity.Src.Util._jsonConfig import config_manager
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Config
|
|
17
|
+
USE_HEADLESS = config_manager.get_bool("BROWSER", "headless")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WebAutomation:
|
|
21
|
+
"""
|
|
22
|
+
A class for automating web interactions using SeleniumBase and BeautifulSoup.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
"""
|
|
27
|
+
Initializes the WebAutomation instance with SeleniumBase Driver.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
headless (bool, optional): Whether to run the browser in headless mode. Default is True.
|
|
31
|
+
"""
|
|
32
|
+
logging.getLogger('seleniumbase').setLevel(logging.ERROR)
|
|
33
|
+
|
|
34
|
+
self.driver = Driver(
|
|
35
|
+
uc=True,
|
|
36
|
+
uc_cdp_events=True,
|
|
37
|
+
headless=USE_HEADLESS,
|
|
38
|
+
user_data_dir = tempfile.mkdtemp(),
|
|
39
|
+
chromium_arg="--disable-search-engine-choice-screen"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def quit(self):
|
|
43
|
+
"""
|
|
44
|
+
Quits the WebDriver instance.
|
|
45
|
+
"""
|
|
46
|
+
self.driver.quit()
|
|
47
|
+
|
|
48
|
+
def get_page(self, url):
|
|
49
|
+
"""
|
|
50
|
+
Navigates the browser to the specified URL.
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
url (str): The URL to navigate to.
|
|
54
|
+
"""
|
|
55
|
+
self.driver.get(url)
|
|
56
|
+
|
|
57
|
+
def retrieve_soup(self):
|
|
58
|
+
"""
|
|
59
|
+
Retrieves the BeautifulSoup object for the current page's HTML content.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
BeautifulSoup object: Parsed HTML content of the current page.
|
|
63
|
+
"""
|
|
64
|
+
html_content = self.driver.page_source
|
|
65
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
|
66
|
+
return soup
|
|
67
|
+
|
|
68
|
+
def get_content(self):
|
|
69
|
+
"""
|
|
70
|
+
Returns the HTML content of the current page.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
str: The HTML content of the current page.
|
|
74
|
+
"""
|
|
75
|
+
return self.driver.page_source
|
|
76
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 18.04.24
|
|
2
|
-
|
|
3
|
-
from .command import join_video, join_audios, join_subtitle
|
|
4
|
-
from .util import print_duration_table, get_video_duration_s
|
|
1
|
+
# 18.04.24
|
|
2
|
+
|
|
3
|
+
from .command import join_video, join_audios, join_subtitle
|
|
4
|
+
from .util import print_duration_table, get_video_duration_s
|