Unit3Dup 0.8.7__py3-none-any.whl → 0.8.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.
- common/command.py +1 -0
- common/database.py +94 -0
- common/external_services/Pw/core/pw_api.py +6 -9
- common/external_services/Pw/pw_manager.py +32 -15
- common/external_services/Pw/pw_service.py +7 -2
- common/external_services/imageHost.py +23 -3
- common/settings.py +73 -11
- unit3dup/__main__.py +10 -2
- unit3dup/torrent.py +24 -15
- unit3dup/web/__init__.py +0 -0
- unit3dup/web/main.py +46 -0
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/METADATA +6 -17
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/RECORD +18 -15
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/WHEEL +1 -1
- view/custom_console.py +25 -0
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/entry_points.txt +0 -0
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/licenses/LICENSE +0 -0
- {unit3dup-0.8.7.dist-info → unit3dup-0.8.9.dist-info}/top_level.txt +0 -0
common/command.py
CHANGED
|
@@ -47,6 +47,7 @@ class CommandLine:
|
|
|
47
47
|
parser.add_argument("-ftp", "--ftp", action="store_true", help="Connect to FTP")
|
|
48
48
|
|
|
49
49
|
# optional
|
|
50
|
+
parser.add_argument("-dump", "--dump", type=str, help="Download all torrent files")
|
|
50
51
|
parser.add_argument("-s", "--search", type=str, help="Search for torrent")
|
|
51
52
|
parser.add_argument("-i", "--info", type=str, help="Get info on torrent")
|
|
52
53
|
parser.add_argument("-up", "--uploader", type=str, help="Search by uploader")
|
common/database.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sqlite3
|
|
3
|
+
|
|
4
|
+
# Torrent attributes
|
|
5
|
+
create_table_sql = ('\n'
|
|
6
|
+
'CREATE TABLE IF NOT EXISTS torrents (\n'
|
|
7
|
+
' id INTEGER PRIMARY KEY AUTOINCREMENT,\n'
|
|
8
|
+
' name TEXT,\n'
|
|
9
|
+
' category TEXT,\n'
|
|
10
|
+
' category_id INTEGER,\n'
|
|
11
|
+
' created_at TEXT,\n'
|
|
12
|
+
' description TEXT,\n'
|
|
13
|
+
' details_link TEXT,\n'
|
|
14
|
+
' download_link TEXT,\n'
|
|
15
|
+
' double_upload BOOLEAN,\n'
|
|
16
|
+
' featured BOOLEAN,\n'
|
|
17
|
+
' freeleech TEXT,\n'
|
|
18
|
+
' igdb_id INTEGER,\n'
|
|
19
|
+
' imdb_id TEXT,\n'
|
|
20
|
+
' info_hash TEXT,\n'
|
|
21
|
+
' internal BOOLEAN,\n'
|
|
22
|
+
' leechers INTEGER,\n'
|
|
23
|
+
' magnet_link TEXT,\n'
|
|
24
|
+
' mal_id INTEGER,\n'
|
|
25
|
+
' media_info TEXT,\n'
|
|
26
|
+
' release_year INTEGER,\n'
|
|
27
|
+
' resolution TEXT,\n'
|
|
28
|
+
' resolution_id INTEGER,\n'
|
|
29
|
+
' seeders INTEGER,\n'
|
|
30
|
+
' size INTEGER,\n'
|
|
31
|
+
' times_completed INTEGER,\n'
|
|
32
|
+
' tmdb_id INTEGER,\n'
|
|
33
|
+
' tvdb_id INTEGER,\n'
|
|
34
|
+
' type TEXT,\n'
|
|
35
|
+
' type_id INTEGER,\n'
|
|
36
|
+
' uploader TEXT,\n'
|
|
37
|
+
' personal_release BOOLEAN,\n'
|
|
38
|
+
' refundable BOOLEAN,\n'
|
|
39
|
+
' num_file INTEGER,\n'
|
|
40
|
+
' bd_info TEXT,\n'
|
|
41
|
+
' genres TEXT,\n'
|
|
42
|
+
' poster TEXT,\n'
|
|
43
|
+
' meta TEXT,\n'
|
|
44
|
+
' files TEXT\n'
|
|
45
|
+
')\n')
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Database:
|
|
49
|
+
"""
|
|
50
|
+
Create a new database and populate it with torrents attributes
|
|
51
|
+
Search torrents based on attributes
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, db_file):
|
|
55
|
+
self.filename = db_file
|
|
56
|
+
self.database = sqlite3.connect(f"{db_file}.db")
|
|
57
|
+
self.cursor = self.database.cursor()
|
|
58
|
+
self.build()
|
|
59
|
+
|
|
60
|
+
def build(self):
|
|
61
|
+
self.cursor.execute(create_table_sql)
|
|
62
|
+
self.database.commit()
|
|
63
|
+
|
|
64
|
+
def write(self, data: dict):
|
|
65
|
+
for key, value in data.items():
|
|
66
|
+
if isinstance(value, (dict,list)):
|
|
67
|
+
data[key] = json.dumps(value)
|
|
68
|
+
|
|
69
|
+
keys = ', '.join(data.keys())
|
|
70
|
+
placeholders = ', '.join(['?'] * len(data))
|
|
71
|
+
values = tuple(data.values())
|
|
72
|
+
|
|
73
|
+
sql = f'''INSERT INTO torrents ({keys}) VALUES ({placeholders})'''
|
|
74
|
+
self.cursor.execute(sql, values)
|
|
75
|
+
self.database.commit()
|
|
76
|
+
|
|
77
|
+
def search(self, query: str):
|
|
78
|
+
# Search a substring in 'name'
|
|
79
|
+
self.cursor.execute("SELECT name FROM torrents WHERE name LIKE ?", ('%' + query + '%',))
|
|
80
|
+
results = self.cursor.fetchall()
|
|
81
|
+
# print the results
|
|
82
|
+
for r in results:
|
|
83
|
+
print(f"[database]{r}")
|
|
84
|
+
input("[DATABASE] Press Enter to continue...")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import os.path
|
|
3
3
|
|
|
4
|
+
import httpx
|
|
5
|
+
|
|
4
6
|
from common.external_services.Pw.core.models.torrent_client_config import (
|
|
5
7
|
TorrentClientConfig,
|
|
6
8
|
)
|
|
@@ -37,7 +39,7 @@ class PwAPI(MyHttp):
|
|
|
37
39
|
custom_console.bot_question_log("No PW_API_KEY provided\n")
|
|
38
40
|
exit(1)
|
|
39
41
|
|
|
40
|
-
def get_indexers(self) -> [
|
|
42
|
+
def get_indexers(self) -> list[type[[Indexer]]]:
|
|
41
43
|
"""Get all indexers."""
|
|
42
44
|
|
|
43
45
|
response = self.get_url(url=f"{self.base_url}/indexer", params={})
|
|
@@ -46,15 +48,10 @@ class PwAPI(MyHttp):
|
|
|
46
48
|
indexers_list = response.json()
|
|
47
49
|
return [Indexer(**indexer) for indexer in indexers_list]
|
|
48
50
|
else:
|
|
49
|
-
return []
|
|
51
|
+
return [Indexer]
|
|
50
52
|
|
|
51
|
-
def get_torrent_url(self, url: str, filename: str):
|
|
52
|
-
|
|
53
|
-
response = self.get_url(url=url)
|
|
54
|
-
if response.status_code == 200:
|
|
55
|
-
# Write the torrent to file
|
|
56
|
-
with open(os.path.join(config_settings.options.PW_TORRENT_ARCHIVE_PATH,f"{filename}.torrent"), 'wb') as f:
|
|
57
|
-
f.write(response.content)
|
|
53
|
+
def get_torrent_url(self, url: str, filename: str)-> httpx.Response :
|
|
54
|
+
return self.get_url(url=url)
|
|
58
55
|
|
|
59
56
|
def search(self, query: str) -> list[Search] | None:
|
|
60
57
|
"""Get search queue."""
|
|
@@ -5,7 +5,10 @@ import os
|
|
|
5
5
|
|
|
6
6
|
from common.external_services.Pw.pw_service import PwService
|
|
7
7
|
from common.utility import ManageTitles
|
|
8
|
+
from common.database import Database
|
|
8
9
|
from common import config_settings
|
|
10
|
+
from unit3dup.media import Media
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
from qbittorrent import Client
|
|
11
14
|
from view import custom_console
|
|
@@ -19,28 +22,42 @@ class PwManager:
|
|
|
19
22
|
# filename for the new download
|
|
20
23
|
self.filename = ManageTitles.normalize_filename(self.search)
|
|
21
24
|
|
|
25
|
+
# Select the tracker database
|
|
26
|
+
self.database = Database(db_file=cli.tracker)
|
|
27
|
+
|
|
22
28
|
|
|
23
29
|
def process(self):
|
|
24
30
|
|
|
25
|
-
# a new
|
|
26
|
-
qb = Client(f"http://{config_settings.
|
|
31
|
+
# a new qbittorrent instance
|
|
32
|
+
qb = Client(f"http://{config_settings.torrent_client_config.QBIT_HOST}:{config_settings.torrent_client_config.QBIT_PORT}/")
|
|
27
33
|
# a new pw instance
|
|
28
34
|
pw_service = PwService()
|
|
29
35
|
# Query the indexers
|
|
30
36
|
search = pw_service.search(query=self.search)
|
|
31
37
|
|
|
38
|
+
content = []
|
|
32
39
|
if search:
|
|
33
40
|
for index, s in enumerate(search):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if s.seeders > 0:
|
|
42
|
+
category = s.categories[0]['name']
|
|
43
|
+
if category in ['Movies','TV','TV/HD']:
|
|
44
|
+
content.append(s)
|
|
45
|
+
custom_console.bot_process_table_pw(content=content)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
for c in content:
|
|
49
|
+
test = Media(folder=f"c:\\test\\{c.fileName}", subfolder=f"c:\\test\\{c.fileName}")
|
|
50
|
+
print(f"[Prowlarr] {c.fileName}")
|
|
51
|
+
self.database.search(test.guess_title)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
""""
|
|
55
|
+
qb.login(username=config_settings.torrent_client_config.QBIT_USER,
|
|
56
|
+
password=config_settings.torrent_client_config.QBIT_PASS)
|
|
57
|
+
|
|
58
|
+
for torrent in content:
|
|
59
|
+
filename = str(os.path.join(config_settings.options.PW_TORRENT_ARCHIVE_PATH,torrent.fileName))
|
|
60
|
+
print(filename)
|
|
61
|
+
magnet = pw_service.get_torrent_from_pw(torrent_url=torrent.downloadUrl,download_filename=filename)
|
|
62
|
+
qb.download_from_link(magnet, savepath=config_settings.options.PW_DOWNLOAD_PATH)
|
|
63
|
+
"""
|
|
@@ -23,7 +23,12 @@ class PwService:
|
|
|
23
23
|
def send_torrent_to_client(self, payload):
|
|
24
24
|
return self.pw_api.send_torrent_to_client(payload)
|
|
25
25
|
|
|
26
|
-
def get_torrent_from_pw(self, torrent_url: str, download_filename: str):
|
|
27
|
-
|
|
26
|
+
def get_torrent_from_pw(self, torrent_url: str, download_filename: str)-> str | None:
|
|
27
|
+
response = self.pw_api.get_torrent_url(url=torrent_url, filename=download_filename)
|
|
28
|
+
# Redirect (PW)
|
|
29
|
+
if response.status_code == 301:
|
|
30
|
+
return response.headers.get('Location')
|
|
31
|
+
return None
|
|
32
|
+
|
|
28
33
|
|
|
29
34
|
|
|
@@ -5,7 +5,6 @@ import json
|
|
|
5
5
|
import time
|
|
6
6
|
import requests
|
|
7
7
|
|
|
8
|
-
from PIL import Image
|
|
9
8
|
from abc import ABC, abstractmethod
|
|
10
9
|
from common import config_settings
|
|
11
10
|
from view import custom_console
|
|
@@ -16,6 +15,7 @@ class ImageUploader(ABC):
|
|
|
16
15
|
self.image = base64.b64encode(image)
|
|
17
16
|
self.key = key
|
|
18
17
|
self.image_name = image_name
|
|
18
|
+
self.timeout = 30
|
|
19
19
|
|
|
20
20
|
@abstractmethod
|
|
21
21
|
def get_endpoint(self):
|
|
@@ -40,7 +40,7 @@ class ImageUploader(ABC):
|
|
|
40
40
|
try:
|
|
41
41
|
upload_n += 1
|
|
42
42
|
response = requests.post(
|
|
43
|
-
self.get_endpoint(), data = data, files = files, timeout =
|
|
43
|
+
self.get_endpoint(), data = data, files = files, timeout = self.timeout
|
|
44
44
|
)
|
|
45
45
|
response.raise_for_status()
|
|
46
46
|
return response.json()
|
|
@@ -61,7 +61,7 @@ class ImageUploader(ABC):
|
|
|
61
61
|
except requests.exceptions.Timeout:
|
|
62
62
|
custom_console.bot_log(
|
|
63
63
|
f"[{self.__class__.__name__}] We did not receive a response from the server"
|
|
64
|
-
f" within the
|
|
64
|
+
f" within the {self.timeout} second limit"
|
|
65
65
|
)
|
|
66
66
|
break
|
|
67
67
|
|
|
@@ -163,6 +163,20 @@ class ImgFi(ImageUploader):
|
|
|
163
163
|
def get_field_name(self) -> str:
|
|
164
164
|
return 'source'
|
|
165
165
|
|
|
166
|
+
class PassIMA(ImageUploader):
|
|
167
|
+
|
|
168
|
+
priority= config_settings.user_preferences.PASSIMA_PRIORITY
|
|
169
|
+
def get_endpoint(self) -> str:
|
|
170
|
+
return "https://passtheima.ge/api/1/upload"
|
|
171
|
+
|
|
172
|
+
def get_data(self) -> dict:
|
|
173
|
+
return {
|
|
174
|
+
"key": self.key,
|
|
175
|
+
"title": self.image_name,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
def get_field_name(self) -> str:
|
|
179
|
+
return 'source'
|
|
166
180
|
|
|
167
181
|
|
|
168
182
|
class ImageUploaderFallback:
|
|
@@ -213,6 +227,10 @@ class ImageUploaderFallback:
|
|
|
213
227
|
|
|
214
228
|
if uploader_host == "ImgFi":
|
|
215
229
|
return response['image']['url']
|
|
230
|
+
|
|
231
|
+
if uploader_host == "PassIMA":
|
|
232
|
+
return response['image']['url']
|
|
233
|
+
|
|
216
234
|
return None
|
|
217
235
|
|
|
218
236
|
class Build:
|
|
@@ -232,6 +250,7 @@ class Build:
|
|
|
232
250
|
self.LENSDUMP_KEY= config_settings.tracker_config.LENSDUMP_KEY
|
|
233
251
|
self.PTSCREENS_KEY= config_settings.tracker_config.PTSCREENS_KEY
|
|
234
252
|
self.IMGFI_KEY = config_settings.tracker_config.IMGFI_KEY
|
|
253
|
+
self.PASSIMA_KEY = config_settings.tracker_config.PASSIMA_KEY
|
|
235
254
|
self.extracted_frames = extracted_frames
|
|
236
255
|
|
|
237
256
|
|
|
@@ -251,6 +270,7 @@ class Build:
|
|
|
251
270
|
PtScreens(img_bytes, self.PTSCREENS_KEY,image_name=image_name),
|
|
252
271
|
LensDump(img_bytes, self.LENSDUMP_KEY,image_name=image_name),
|
|
253
272
|
ImgFi(img_bytes, self.IMGFI_KEY,image_name=image_name),
|
|
273
|
+
PassIMA(img_bytes, self.PASSIMA_KEY, image_name=image_name),
|
|
254
274
|
]
|
|
255
275
|
|
|
256
276
|
# Sorting list based on priority
|
common/settings.py
CHANGED
|
@@ -13,7 +13,7 @@ from common.utility import ManageTitles
|
|
|
13
13
|
from common import trackers
|
|
14
14
|
|
|
15
15
|
config_file = "Unit3Dbot.json"
|
|
16
|
-
version = "0.8.
|
|
16
|
+
version = "0.8.9"
|
|
17
17
|
|
|
18
18
|
if os.name == "nt":
|
|
19
19
|
PW_TORRENT_ARCHIVE_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "pw_torrent_archive"
|
|
@@ -40,12 +40,20 @@ def get_default_path(field: str)-> str:
|
|
|
40
40
|
"CACHE_PATH": CACHE_PATH,
|
|
41
41
|
"WATCHER_DESTINATION_PATH": WATCHER_DESTINATION_PATH,
|
|
42
42
|
"WATCHER_PATH": WATCHER_PATH,
|
|
43
|
-
"
|
|
43
|
+
"PW_DOWNLOAD_PATH": PW_DOWNLOAD_PATH,
|
|
44
44
|
"PW_TORRENT_ARCHIVE_PATH": PW_TORRENT_ARCHIVE_PATH
|
|
45
45
|
}
|
|
46
46
|
return str(default_paths[field])
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
class Ccolors:
|
|
51
|
+
OKCYAN = '\033[96m'
|
|
52
|
+
OKGREEN = '\033[92m'
|
|
53
|
+
WARNING = '\033[93m'
|
|
54
|
+
FAIL = '\033[91m'
|
|
55
|
+
ENDC = '\033[0m'
|
|
56
|
+
|
|
49
57
|
class TrackerConfig(BaseModel):
|
|
50
58
|
ITT_URL: str
|
|
51
59
|
ITT_APIKEY: str | None = None
|
|
@@ -60,6 +68,7 @@ class TrackerConfig(BaseModel):
|
|
|
60
68
|
LENSDUMP_KEY: str | None = None
|
|
61
69
|
PTSCREENS_KEY: str | None = None
|
|
62
70
|
IMGFI_KEY: str | None = None
|
|
71
|
+
PASSIMA_KEY: str | None = None
|
|
63
72
|
YOUTUBE_KEY: str | None = None
|
|
64
73
|
IGDB_CLIENT_ID: str | None = None
|
|
65
74
|
IGDB_ID_SECRET: str | None = None
|
|
@@ -92,6 +101,7 @@ class UserPreferences(BaseModel):
|
|
|
92
101
|
FREE_IMAGE_PRIORITY: int = 2
|
|
93
102
|
IMGBB_PRIORITY: int = 3
|
|
94
103
|
IMGFI_PRIORITY: int = 4
|
|
104
|
+
PASSIMA_PRIORITY: int = 5
|
|
95
105
|
NUMBER_OF_SCREENSHOTS: int = 4
|
|
96
106
|
YOUTUBE_FAV_CHANNEL_ID: str | None = None
|
|
97
107
|
YOUTUBE_CHANNEL_ENABLE: bool = False
|
|
@@ -120,7 +130,7 @@ class Options(BaseModel):
|
|
|
120
130
|
PW_API_KEY: str | None = None
|
|
121
131
|
PW_URL: str = "http://localhost:9696/api/v1"
|
|
122
132
|
PW_TORRENT_ARCHIVE_PATH: str | None = None
|
|
123
|
-
|
|
133
|
+
PW_DOWNLOAD_PATH: str | None = None
|
|
124
134
|
FTPX_USER: str = "user"
|
|
125
135
|
FTPX_PASS: str = "pass"
|
|
126
136
|
FTPX_IP: str = "127.0.0.1"
|
|
@@ -415,11 +425,11 @@ class Config(BaseModel):
|
|
|
415
425
|
'CACHE_SCR','CACHE_DBONLINE', 'PERSONAL_RELEASE']:
|
|
416
426
|
section[field] = Validate.boolean(value=section[field], field_name=field)
|
|
417
427
|
|
|
418
|
-
if field in ['TORRENT_COMMENT','
|
|
428
|
+
if field in ['TORRENT_COMMENT','WATCHER_PATH','DEFAULT_TRACKER']:
|
|
419
429
|
section[field] = Validate.string(value=section[field], field_name=field)
|
|
420
430
|
|
|
421
431
|
if field in ['NUMBER_OF_SCREENSHOTS','COMPRESS_SCSHOT','IMGBB_PRIORITY','FREE_IMAGE_PRIORITY',
|
|
422
|
-
'LENSDUMP_PRIORITY','WATCHER_INTERVAL','SIZE_TH', 'FAST_LOAD']:
|
|
432
|
+
'LENSDUMP_PRIORITY','PASSIMA_PRIORITY','WATCHER_INTERVAL','SIZE_TH', 'FAST_LOAD']:
|
|
423
433
|
section[field] = Validate.integer(value=section[field], field_name=field)
|
|
424
434
|
|
|
425
435
|
if field == 'PREFERRED_LANG':
|
|
@@ -441,11 +451,29 @@ class Config(BaseModel):
|
|
|
441
451
|
section[field] =Validate.unit3dup_path(path=section[field],field_name=field,
|
|
442
452
|
default_path=get_default_path(field=field))
|
|
443
453
|
|
|
454
|
+
|
|
444
455
|
return v
|
|
445
456
|
|
|
446
457
|
@model_validator(mode='before')
|
|
447
458
|
def set_default_options(cls, v):
|
|
448
|
-
|
|
459
|
+
section = v['options']
|
|
460
|
+
|
|
461
|
+
for field, value in section.items():
|
|
462
|
+
if value is None:
|
|
463
|
+
print(f"Please fix the '{field}' value")
|
|
464
|
+
exit(1)
|
|
465
|
+
else:
|
|
466
|
+
field = field.upper()
|
|
467
|
+
|
|
468
|
+
if field == 'PW_TORRENT_ARCHIVE_PATH':
|
|
469
|
+
section[field] = Validate.unit3dup_path(path=section[field], field_name=field,
|
|
470
|
+
default_path=get_default_path(field=field))
|
|
471
|
+
|
|
472
|
+
if field == 'PW_DOWNLOAD_PATH':
|
|
473
|
+
section[field] = Validate.unit3dup_path(path=section[field], field_name=field,
|
|
474
|
+
default_path=get_default_path(field=field))
|
|
475
|
+
|
|
476
|
+
return v
|
|
449
477
|
|
|
450
478
|
@model_validator(mode='before')
|
|
451
479
|
def set_default_console_options(cls, v):
|
|
@@ -502,6 +530,7 @@ class Load:
|
|
|
502
530
|
"LENSDUMP_KEY": "no_key",
|
|
503
531
|
"PTSCREENS_KEY": "no_key",
|
|
504
532
|
"IMGFI_KEY": "no_key",
|
|
533
|
+
"PASSIMA_KEY": "no_key",
|
|
505
534
|
"YOUTUBE_KEY": "no_key",
|
|
506
535
|
"IGDB_CLIENT_ID": "no_key",
|
|
507
536
|
"IGDB_ID_SECRET": "no_key",
|
|
@@ -532,6 +561,7 @@ class Load:
|
|
|
532
561
|
"FREE_IMAGE_PRIORITY": 2,
|
|
533
562
|
"IMGBB_PRIORITY": 3,
|
|
534
563
|
"IMGFI_PRIORITY": 4,
|
|
564
|
+
"PASSIMA_PRIORITY": 5,
|
|
535
565
|
"NUMBER_OF_SCREENSHOTS": 4,
|
|
536
566
|
"YOUTUBE_FAV_CHANNEL_ID": "UCGCbxpnt25hWPFLSbvwfg_w",
|
|
537
567
|
"YOUTUBE_CHANNEL_ENABLE": "False",
|
|
@@ -558,7 +588,7 @@ class Load:
|
|
|
558
588
|
"PW_API_KEY": "no_key",
|
|
559
589
|
"PW_URL": "http://localhost:9696/api/v1",
|
|
560
590
|
"PW_TORRENT_ARCHIVE_PATH": ".",
|
|
561
|
-
"
|
|
591
|
+
"PW_DOWNLOAD_PATH": ".",
|
|
562
592
|
"FTPX_USER": "user",
|
|
563
593
|
"FTPX_PASS": "pass",
|
|
564
594
|
"FTPX_IP": "127.0.0.1",
|
|
@@ -741,10 +771,11 @@ class JsonConfig:
|
|
|
741
771
|
return json.loads(json_data)
|
|
742
772
|
|
|
743
773
|
except json.JSONDecodeError as e:
|
|
744
|
-
print(f"
|
|
745
|
-
|
|
746
|
-
print(
|
|
747
|
-
|
|
774
|
+
print(f"* Please fix the error{Ccolors.WARNING} near Line {e.lineno}{Ccolors.ENDC}"
|
|
775
|
+
f" and {Ccolors.WARNING}Column {e.colno}{Ccolors.ENDC} in the config file: *\n")
|
|
776
|
+
print(f"{e.msg}\n")
|
|
777
|
+
# Seek And...
|
|
778
|
+
self.aim(line=e.lineno,col=e.colno)
|
|
748
779
|
exit(1)
|
|
749
780
|
except FileNotFoundError:
|
|
750
781
|
print(f"Configuration '{self.default_json_path}' not found")
|
|
@@ -797,3 +828,34 @@ class JsonConfig:
|
|
|
797
828
|
|
|
798
829
|
print(message)
|
|
799
830
|
|
|
831
|
+
def aim(self, line: int, col: int):
|
|
832
|
+
"""
|
|
833
|
+
Try to identify the exact location of json error
|
|
834
|
+
Args:
|
|
835
|
+
line: Error line from the try block
|
|
836
|
+
col: Error line from the try block
|
|
837
|
+
Returns:
|
|
838
|
+
None
|
|
839
|
+
"""
|
|
840
|
+
|
|
841
|
+
# Open the configuration file
|
|
842
|
+
with open(self.default_json_path, 'r') as file:
|
|
843
|
+
lines = file.readlines()
|
|
844
|
+
|
|
845
|
+
# Test the line value
|
|
846
|
+
if line <= len(lines):
|
|
847
|
+
# Create a "context" around the error....
|
|
848
|
+
line_context1 = lines[line -2].rstrip('\n')
|
|
849
|
+
line_context2 = lines[line + 1].rstrip('\n')
|
|
850
|
+
|
|
851
|
+
# Try to identify the position
|
|
852
|
+
line_text = lines[line - 1].rstrip('\n')
|
|
853
|
+
print(f"{line_context1}")
|
|
854
|
+
print(f"{Ccolors.WARNING}>>> {line_text}{Ccolors.ENDC}")
|
|
855
|
+
|
|
856
|
+
# Put the cursor under the error
|
|
857
|
+
cursor = ' ' * (col-1) + '^'
|
|
858
|
+
print(f"{Ccolors.WARNING} {cursor}{Ccolors.ENDC}")
|
|
859
|
+
print(f"{line_context2}")
|
|
860
|
+
else:
|
|
861
|
+
print("Line number is out of range !")
|
unit3dup/__main__.py
CHANGED
|
@@ -127,8 +127,10 @@ def main():
|
|
|
127
127
|
|
|
128
128
|
# Pw
|
|
129
129
|
if cli.args.pw:
|
|
130
|
-
|
|
131
|
-
bot.pw
|
|
130
|
+
print("Not yet implemented")
|
|
131
|
+
# bot = Bot(path=cli.args.pw,cli=cli.args, trackers_name_list=tracker_name_list)
|
|
132
|
+
# bot.pw()
|
|
133
|
+
return
|
|
132
134
|
|
|
133
135
|
|
|
134
136
|
# ftp and upload
|
|
@@ -154,6 +156,12 @@ def main():
|
|
|
154
156
|
torrent_info.view_search(cli.args.search)
|
|
155
157
|
return
|
|
156
158
|
|
|
159
|
+
# Dump
|
|
160
|
+
if cli.args.dump:
|
|
161
|
+
print("Not yet implemented")
|
|
162
|
+
# torrent_info.view_search(cli.args.dump,inkey=False)
|
|
163
|
+
return
|
|
164
|
+
|
|
157
165
|
if cli.args.info:
|
|
158
166
|
torrent_info.view_search(cli.args.info, info=True)
|
|
159
167
|
return
|
unit3dup/torrent.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import re
|
|
3
|
+
import time
|
|
3
4
|
import requests
|
|
4
5
|
|
|
5
6
|
from common.trackers.trackers import TRACKData
|
|
7
|
+
from common.database import Database
|
|
6
8
|
from unit3dup import pvtTracker
|
|
7
9
|
from view import custom_console
|
|
8
10
|
|
|
@@ -10,8 +12,9 @@ class Torrent:
|
|
|
10
12
|
|
|
11
13
|
def __init__(self, tracker_name: str):
|
|
12
14
|
|
|
13
|
-
self.perPage =
|
|
15
|
+
self.perPage = 100
|
|
14
16
|
self.tracker = pvtTracker.Unit3d(tracker_name=tracker_name)
|
|
17
|
+
self.database = Database(db_file=tracker_name)
|
|
15
18
|
|
|
16
19
|
def get_unique_id(self, media_info: str) -> str:
|
|
17
20
|
# Divido per campi
|
|
@@ -142,7 +145,6 @@ class View(Torrent):
|
|
|
142
145
|
def __init__(self, tracker_name: str):
|
|
143
146
|
super().__init__(tracker_name=tracker_name)
|
|
144
147
|
|
|
145
|
-
self.perPage = 130
|
|
146
148
|
# Load the constant tracker
|
|
147
149
|
self.tracker_data = TRACKData.load_from_module(tracker_name=tracker_name)
|
|
148
150
|
print()
|
|
@@ -171,10 +173,8 @@ class View(Torrent):
|
|
|
171
173
|
f" -> {item['attributes']['name']}"
|
|
172
174
|
)
|
|
173
175
|
|
|
174
|
-
|
|
175
|
-
def print_normal(tracker_data: dict):
|
|
176
|
+
def print_normal(self, tracker_data: dict):
|
|
176
177
|
data = [item for item in tracker_data["data"]]
|
|
177
|
-
|
|
178
178
|
for item in data:
|
|
179
179
|
if item['attributes']['tmdb_id'] != 0:
|
|
180
180
|
if not item['attributes']['release_year']:
|
|
@@ -184,14 +184,18 @@ class View(Torrent):
|
|
|
184
184
|
|
|
185
185
|
media = f"[TRACKER] TMDB: {item['attributes']['tmdb_id']} - {release_year}"
|
|
186
186
|
|
|
187
|
+
elif item['attributes']['igdb_id'] !=0:
|
|
188
|
+
media = f"[TRACKER] IGDB: {item['attributes']['igdb_id']}"
|
|
187
189
|
else:
|
|
188
|
-
media = f"[TRACKER]
|
|
190
|
+
media = f"[TRACKER] DOC:"
|
|
189
191
|
|
|
192
|
+
# Print a data to the console
|
|
190
193
|
custom_console.bot_log(f"\n {media} - {item['attributes']['name']}")
|
|
194
|
+
# Save torrent data into database
|
|
195
|
+
self.database.write(item['attributes'])
|
|
191
196
|
|
|
192
197
|
|
|
193
|
-
|
|
194
|
-
def page_view(self, tracker_data: dict, tracker: pvtTracker, info=False):
|
|
198
|
+
def page_view(self, tracker_data: dict, tracker: pvtTracker, info=False, inkey=True):
|
|
195
199
|
|
|
196
200
|
self.print_normal(tracker_data) if not info else self.print_info(tracker_data)
|
|
197
201
|
page = 0
|
|
@@ -199,12 +203,17 @@ class View(Torrent):
|
|
|
199
203
|
if not tracker_data["links"]["next"]:
|
|
200
204
|
break
|
|
201
205
|
|
|
206
|
+
# Wait for user input if inkey is True
|
|
202
207
|
page += 1
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
if inkey:
|
|
209
|
+
custom_console.bot_question_log(
|
|
210
|
+
f"\n Prossima Pagina '{page}' - Premi un tasto per continuare, Q(quit) - "
|
|
211
|
+
)
|
|
212
|
+
if input().lower() == "q":
|
|
213
|
+
break
|
|
214
|
+
else:
|
|
215
|
+
# otherwise wait for 2 seconds ( 30 request/ 60sec max) dirty
|
|
216
|
+
time.sleep(2)
|
|
208
217
|
print()
|
|
209
218
|
custom_console.rule(f"\n[bold blue]'Page -> {page}'", style="#ea00d9")
|
|
210
219
|
tracker_data = tracker.next(url=tracker_data["links"]["next"])
|
|
@@ -214,11 +223,11 @@ class View(Torrent):
|
|
|
214
223
|
else self.print_info(tracker_data)
|
|
215
224
|
)
|
|
216
225
|
|
|
217
|
-
def view_search(self, keyword: str, info=False):
|
|
226
|
+
def view_search(self, keyword: str, info=False, inkey=True):
|
|
218
227
|
tracker_data = self.search(keyword=keyword)
|
|
219
228
|
custom_console.log(f"Searching.. '{keyword}'")
|
|
220
229
|
(
|
|
221
|
-
self.page_view(tracker_data=tracker_data, tracker=self.tracker)
|
|
230
|
+
self.page_view(tracker_data=tracker_data, tracker=self.tracker,inkey=inkey)
|
|
222
231
|
if not info
|
|
223
232
|
else self.page_view(
|
|
224
233
|
tracker_data=tracker_data, tracker=self.tracker, info=True
|
unit3dup/web/__init__.py
ADDED
|
File without changes
|
unit3dup/web/main.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from fastapi import FastAPI, APIRouter
|
|
2
|
+
from random import randint
|
|
3
|
+
from common.torrent_clients import TransmissionClient, QbittorrentClient, RTorrentClient
|
|
4
|
+
from common.command import CommandLine
|
|
5
|
+
from common.settings import Load,DEFAULT_JSON_PATH
|
|
6
|
+
|
|
7
|
+
from unit3dup.torrent import View
|
|
8
|
+
from unit3dup import pvtTracker
|
|
9
|
+
from unit3dup.bot import Bot
|
|
10
|
+
from view import custom_console
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import uvicorn
|
|
14
|
+
import argparse
|
|
15
|
+
from random import randint
|
|
16
|
+
|
|
17
|
+
app = FastAPI()
|
|
18
|
+
|
|
19
|
+
# Classe che gestisce gli endpoint
|
|
20
|
+
class WebApp:
|
|
21
|
+
def __init__(self, config: Load):
|
|
22
|
+
self.router = APIRouter()
|
|
23
|
+
self.numb = randint(0, 100)
|
|
24
|
+
self._setup_routes()
|
|
25
|
+
|
|
26
|
+
def _setup_routes(self):
|
|
27
|
+
# Add the endpoints
|
|
28
|
+
self.router.add_api_route("/", self.root, methods=["GET"])
|
|
29
|
+
self.router.add_api_route("/upload/{name}", self.upload, methods=["GET"])
|
|
30
|
+
|
|
31
|
+
async def root(self):
|
|
32
|
+
return {"message": f"Hello World {self.numb}"}
|
|
33
|
+
|
|
34
|
+
async def upload(self, name: str):
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
return {"message": f"Hello {name}, numb is {self.numb}"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def web():
|
|
42
|
+
web_app = WebApp(config=Load().load_config())
|
|
43
|
+
app.include_router(web_app.router)
|
|
44
|
+
uvicorn.run("unit3dup.web.main:app", host="127.0.0.1", port=8000, reload=True)
|
|
45
|
+
|
|
46
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Unit3Dup
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.9
|
|
4
4
|
Summary: An uploader for the Unit3D torrent tracker
|
|
5
5
|
Author: Parzival
|
|
6
6
|
License-Expression: MIT
|
|
@@ -66,24 +66,19 @@ It performs the following tasks:
|
|
|
66
66
|
unit3dup can grab the first page, convert it to an image (using xpdf),
|
|
67
67
|
and then the bot can upload it to an image host, then add the link to the torrent page description.
|
|
68
68
|
|
|
69
|
-
.. image:: https://img.shields.io/badge/INSTALL-gr
|
|
70
|
-
:alt: install
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
pip install unit3dup
|
|
70
|
+
Install and Upgrade
|
|
71
|
+
===================
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
-------
|
|
78
|
-
pip install --upgrade unit3dup
|
|
73
|
+
- pip install unit3dup --upgrade
|
|
79
74
|
|
|
80
75
|
Ubuntu/Debian Dependencies
|
|
81
76
|
--------------------------
|
|
82
|
-
sudo apt install ffmpeg
|
|
77
|
+
- sudo apt install ffmpeg
|
|
83
78
|
|
|
84
79
|
Only for pdf
|
|
85
80
|
------------
|
|
86
|
-
sudo apt install poppler-utils
|
|
81
|
+
- sudo apt install poppler-utils
|
|
87
82
|
|
|
88
83
|
|
|
89
84
|
Windows Dependencies
|
|
@@ -110,12 +105,6 @@ Alternative method
|
|
|
110
105
|
4. unit3dup
|
|
111
106
|
|
|
112
107
|
|
|
113
|
-
.. image:: https://img.shields.io/badge/Bot_UPDATE-gr
|
|
114
|
-
:alt: Bot Update
|
|
115
|
-
|
|
116
|
-
1. pip install unit3dup --upgrade
|
|
117
|
-
|
|
118
|
-
|
|
119
108
|
|
|
120
109
|
RUN
|
|
121
110
|
======
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
common/__init__.py,sha256=M82CDZm5KKWf8V3a10FKCy1wtFrJd1TMEhBib1Xtk1g,76
|
|
2
2
|
common/bdinfo_string.py,sha256=dfrU5T90fvkO_fklvVNWSoCgd5qvrVvqEZ_HKEsHAU8,3457
|
|
3
3
|
common/bittorrent.py,sha256=MPgMykWjmhGox7jf1MQn53Ew4NxpjzEc4FCF6oA2oYs,315
|
|
4
|
-
common/command.py,sha256=
|
|
4
|
+
common/command.py,sha256=7QmtTFdawq2S70p9JP2dr2bGbAUdiTVnGFiNrBcz3R4,6029
|
|
5
5
|
common/constants.py,sha256=tdflS7ZJwAcI1ZYUhBBb60QybVT7TmVS-EYxS4bNFp0,352
|
|
6
|
+
common/database.py,sha256=Lp6i3Wu5vza87atWD2NGQRCchVLBcY-k8E0AAuAQxls,3232
|
|
6
7
|
common/extractor.py,sha256=WKZwt2kQfKO2VJ1rtwE_j6Zl84zICnowZq_Ql16wmRc,4564
|
|
7
8
|
common/frames.py,sha256=p_jsaXII5tZTVt5ymu-w1hk2c_UMeOn3PZeuVR-wXWY,7973
|
|
8
9
|
common/mediainfo.py,sha256=U2r1jJejBsV8GP3iPk4O8_NkHO5RQ9Kkh2bKwVNUBmg,6229
|
|
9
10
|
common/mediainfo_string.py,sha256=8vuWlF2bqWRKpDbn81bV2fPA7hbl7RwOnxN2i4E3zNE,3958
|
|
10
|
-
common/settings.py,sha256=
|
|
11
|
+
common/settings.py,sha256=RPzMlRiYlqiuPd2hJO4w348R8GVERHhiA7V43t_pPug,32781
|
|
11
12
|
common/title.py,sha256=nFainfUBTYW9ML4Y-CB9ZFD_Es-OZXcAMPUo6D09u3k,3793
|
|
12
13
|
common/torrent_clients.py,sha256=NOIpYtLG_bA19HwcH9ahGFmGNtRkoMO6nAjma-JzDfs,12040
|
|
13
14
|
common/utility.py,sha256=6VLhN4K8W9oJfYiHKK_nq5LGtbwHaSMjeojstoyqYfU,8575
|
|
14
15
|
common/external_services/__init__.py,sha256=rU7HPEcZ7WQFD8eqDzuye2xHPBjxXPwPqpt7IT08mkM,178
|
|
15
|
-
common/external_services/imageHost.py,sha256
|
|
16
|
+
common/external_services/imageHost.py,sha256=BpdtGZUtZHl4QJwFKyJs_BI6z4gHI4wu_Beu-fnfkDw,9588
|
|
16
17
|
common/external_services/imdb.py,sha256=AIo8CO-SfP_uNocDeNY08hpvCAnuotoI7hYUytDiMQA,579
|
|
17
18
|
common/external_services/mediaresult.py,sha256=Yz-h7QROkfNHwaSSXZ1JRDSmG2YIZkmtQO5vmpkYWZ4,677
|
|
18
19
|
common/external_services/Pw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
common/external_services/Pw/pw_manager.py,sha256=
|
|
20
|
-
common/external_services/Pw/pw_service.py,sha256=
|
|
20
|
+
common/external_services/Pw/pw_manager.py,sha256=a8s3YgzHf0iw45Fh5BeMRSX5aGlatBJbOYamSrWFj2U,2225
|
|
21
|
+
common/external_services/Pw/pw_service.py,sha256=_-AQgffqiuoS0xcHc7sEgQBuXidU9RdJZyZnRa-ATZc,1151
|
|
21
22
|
common/external_services/Pw/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
common/external_services/Pw/core/pw_api.py,sha256=
|
|
23
|
+
common/external_services/Pw/core/pw_api.py,sha256=C1XzN-hJwJvzjZwiNTL39mu4gJGiEKKZYjt9JAStIHk,3234
|
|
23
24
|
common/external_services/Pw/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
25
|
common/external_services/Pw/core/models/indexers.py,sha256=7nVqZd-_nbwL40HLGEFauI8zNeC-w66py2tK7h9rGV4,1947
|
|
25
26
|
common/external_services/Pw/core/models/search.py,sha256=fmoEccxgRDG26nmEcpJR0e5twBLTOEzDzaeQFG2TAc4,969
|
|
@@ -71,7 +72,7 @@ common/trackers/itt.py,sha256=DFXxrFX9i19kwGHfA1guswlBOueIHU00K-HvoperstA,4019
|
|
|
71
72
|
common/trackers/sis.py,sha256=AahQH-FxAqS19vgEFylOJzeY0_SHr27_Tibs7lraSdI,3480
|
|
72
73
|
common/trackers/trackers.py,sha256=uQgqmkJBoud4h8CWrc73yAURtkVU630sk1ZqLXJud7s,1384
|
|
73
74
|
unit3dup/__init__.py,sha256=seXz3lHgdrUBiOnhC6Je47npS66UZ0c62VFuoH3z5Mk,78
|
|
74
|
-
unit3dup/__main__.py,sha256=
|
|
75
|
+
unit3dup/__main__.py,sha256=CDazL8WFGv_Y6y875s3Ej-0QK5MPytbTJm_vsPHWB-A,9270
|
|
75
76
|
unit3dup/automode.py,sha256=HIJrE8qEHp7DZQbppNtB_8jHY3Q94d6frp7BXnZuEac,4387
|
|
76
77
|
unit3dup/bot.py,sha256=TM8Htnq-udJDnN-7TwaPP6CiwWX0wb_Nud9p8ej8GRo,9250
|
|
77
78
|
unit3dup/duplicate.py,sha256=Ji1Y9vVLmhFQ5rgkUU-s7uXl-jC8akAa8OiQOfjFa9g,10428
|
|
@@ -81,7 +82,7 @@ unit3dup/pvtDocu.py,sha256=ZLMaal2fn6ZcFPLtET0LTmYEPjhJmLitEjkICHrm9CQ,4594
|
|
|
81
82
|
unit3dup/pvtTorrent.py,sha256=cItlsCpcUJL23iXQHy0YzrrvV3JSl54UlBgm8_UROAs,2559
|
|
82
83
|
unit3dup/pvtTracker.py,sha256=U4xMmhiqMNZaIOgEi3pnP-3H75e7Gagndh8GDFEP7Cs,18647
|
|
83
84
|
unit3dup/pvtVideo.py,sha256=w_T6wEeGrsHkuR3KObJc4mNpJgg9hhHh_9LoxFlaqjM,3900
|
|
84
|
-
unit3dup/torrent.py,sha256=
|
|
85
|
+
unit3dup/torrent.py,sha256=JEcrVG8dlYASBvL51GldU1ouKlfieKccKX2KZ_4UKBY,19883
|
|
85
86
|
unit3dup/upload.py,sha256=gjB8u2oP2FPXZ8t9SMIzkUEr52hKRy_zSR8OWJlW2xc,6075
|
|
86
87
|
unit3dup/media_manager/ContentManager.py,sha256=X0nepb-PgBzTasnw-Z_Vz11oq8-66kg_5Q0Eddn964g,7123
|
|
87
88
|
unit3dup/media_manager/DocuManager.py,sha256=oFt7jlxj-gIUty9PADBQV5a24bsv3yhjKhwI6niOhf4,3116
|
|
@@ -92,11 +93,13 @@ unit3dup/media_manager/TorrentManager.py,sha256=qqM1d1TyfBuruXtKLRbQ8gFk3_2JNH9d
|
|
|
92
93
|
unit3dup/media_manager/VideoManager.py,sha256=O1NzGnWiWPfMgjyV6h9_b9b8M5tzFtpje9cvI2g6Nc0,5437
|
|
93
94
|
unit3dup/media_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
94
95
|
unit3dup/media_manager/common.py,sha256=hG2zOw7ocQfZyI1dhusbehxswpIrZK7T2aAbCNwULqA,10138
|
|
95
|
-
unit3dup
|
|
96
|
+
unit3dup/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
97
|
+
unit3dup/web/main.py,sha256=BzjKDgAjKZMnoQwx7nDDbs_64kCrFO1VYpbHmsGiFVc,1267
|
|
98
|
+
unit3dup-0.8.9.dist-info/licenses/LICENSE,sha256=GNAZDLhU0xz8QPbIyHAOYlVnQYDvKWk2N9fZJMhqaG8,1090
|
|
96
99
|
view/__init__.py,sha256=XIzb6rl58HmYPnksD73cYMFF88dn6FHa3u7bOHFbChk,81
|
|
97
|
-
view/custom_console.py,sha256=
|
|
98
|
-
unit3dup-0.8.
|
|
99
|
-
unit3dup-0.8.
|
|
100
|
-
unit3dup-0.8.
|
|
101
|
-
unit3dup-0.8.
|
|
102
|
-
unit3dup-0.8.
|
|
100
|
+
view/custom_console.py,sha256=OITmkEoQH9N_uE5ElPaSdc8XvaLzE9wcwTbOHtcMvrI,5629
|
|
101
|
+
unit3dup-0.8.9.dist-info/METADATA,sha256=fTipWVLGNyAyrtT48e7V-1jcFl-UORYn4oUzXzzszL4,5015
|
|
102
|
+
unit3dup-0.8.9.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
103
|
+
unit3dup-0.8.9.dist-info/entry_points.txt,sha256=fxXSyI6-r6jy9_v-C5ZHm03q1aC3tE9EvCQZxC1NQnI,52
|
|
104
|
+
unit3dup-0.8.9.dist-info/top_level.txt,sha256=19NVMnQNkJxBUKebRNaYCRs56A5CO4U1L67GMQCPiLU,21
|
|
105
|
+
unit3dup-0.8.9.dist-info/RECORD,,
|
view/custom_console.py
CHANGED
|
@@ -69,6 +69,31 @@ class CustomConsole(Console):
|
|
|
69
69
|
|
|
70
70
|
self.print(Align.center(table))
|
|
71
71
|
|
|
72
|
+
def bot_process_table_pw(self, content: list):
|
|
73
|
+
|
|
74
|
+
table = Table(
|
|
75
|
+
title="Here is your files list" if content else "There are no files here",
|
|
76
|
+
border_style="bold blue",
|
|
77
|
+
header_style="red blue",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
table.add_column("Category", style="dim")
|
|
81
|
+
table.add_column("Indexer", justify="left", style="bold green")
|
|
82
|
+
table.add_column("Title", justify="left", style="bold green")
|
|
83
|
+
table.add_column("Size", justify="left", style="bold green")
|
|
84
|
+
table.add_column("Seeders", justify="left", style="bold green")
|
|
85
|
+
|
|
86
|
+
for item in content:
|
|
87
|
+
table.add_row(
|
|
88
|
+
item.categories[0]['name'],
|
|
89
|
+
item.indexer,
|
|
90
|
+
item.title,
|
|
91
|
+
str(item.size),
|
|
92
|
+
str(item.seeders),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
self.print(Align.center(table))
|
|
96
|
+
|
|
72
97
|
def bot_tmdb_table_log(self, result, title: str, media_info_language: str):
|
|
73
98
|
|
|
74
99
|
self.print("\n")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|