Unit3Dup 0.8.13__py3-none-any.whl → 0.8.15__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 -2
- common/database.py +7 -22
- common/settings.py +1 -1
- unit3dup/__main__.py +5 -12
- unit3dup/bot.py +0 -1
- unit3dup/media.py +7 -1
- unit3dup/media_manager/ContentManager.py +4 -0
- unit3dup/torrent.py +4 -3
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/METADATA +1 -1
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/RECORD +14 -23
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/WHEEL +1 -1
- common/external_services/Pw/__init__.py +0 -0
- common/external_services/Pw/core/__init__.py +0 -0
- common/external_services/Pw/core/models/__init__.py +0 -0
- common/external_services/Pw/core/models/indexers.py +0 -80
- common/external_services/Pw/core/models/search.py +0 -39
- common/external_services/Pw/core/models/torrent_client_config.py +0 -42
- common/external_services/Pw/core/pw_api.py +0 -96
- common/external_services/Pw/pw_manager.py +0 -63
- common/external_services/Pw/pw_service.py +0 -34
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/entry_points.txt +0 -0
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/licenses/LICENSE +0 -0
- {unit3dup-0.8.13.dist-info → unit3dup-0.8.15.dist-info}/top_level.txt +0 -0
common/command.py
CHANGED
|
@@ -43,11 +43,10 @@ class CommandLine:
|
|
|
43
43
|
parser.add_argument("-duplicate", "--duplicate", action="store_true", help="Find duplicates")
|
|
44
44
|
parser.add_argument("-personal", "--personal", action="store_true", help="Set to personal release")
|
|
45
45
|
|
|
46
|
-
parser.add_argument("-pw", "--pw", type=str, help="")
|
|
47
46
|
parser.add_argument("-ftp", "--ftp", action="store_true", help="Connect to FTP")
|
|
48
47
|
|
|
49
48
|
# optional
|
|
50
|
-
parser.add_argument("-dump", "--dump",
|
|
49
|
+
parser.add_argument("-dump", "--dump", action="store_true", help="Download all torrent titles")
|
|
51
50
|
parser.add_argument("-s", "--search", type=str, help="Search for torrent")
|
|
52
51
|
parser.add_argument("-i", "--info", type=str, help="Get info on torrent")
|
|
53
52
|
parser.add_argument("-up", "--uploader", type=str, help="Search by uploader")
|
common/database.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
2
3
|
import sqlite3
|
|
4
|
+
from unit3dup import config_settings
|
|
3
5
|
|
|
4
6
|
# Torrent attributes
|
|
5
7
|
create_table_sql = ('\n'
|
|
@@ -53,14 +55,17 @@ class Database:
|
|
|
53
55
|
|
|
54
56
|
def __init__(self, db_file):
|
|
55
57
|
self.filename = db_file
|
|
56
|
-
self.
|
|
58
|
+
self.CACHE_PATH = config_settings.user_preferences.CACHE_PATH
|
|
59
|
+
self.database = sqlite3.connect(os.path.join(self.CACHE_PATH,f"{db_file}.db"))
|
|
57
60
|
self.cursor = self.database.cursor()
|
|
58
61
|
self.build()
|
|
59
62
|
|
|
60
63
|
def build(self):
|
|
64
|
+
self.cursor.execute("DROP TABLE IF EXISTS torrents")
|
|
61
65
|
self.cursor.execute(create_table_sql)
|
|
62
66
|
self.database.commit()
|
|
63
67
|
|
|
68
|
+
|
|
64
69
|
def write(self, data: dict):
|
|
65
70
|
for key, value in data.items():
|
|
66
71
|
if isinstance(value, (dict,list)):
|
|
@@ -69,26 +74,6 @@ class Database:
|
|
|
69
74
|
keys = ', '.join(data.keys())
|
|
70
75
|
placeholders = ', '.join(['?'] * len(data))
|
|
71
76
|
values = tuple(data.values())
|
|
72
|
-
|
|
73
77
|
sql = f'''INSERT INTO torrents ({keys}) VALUES ({placeholders})'''
|
|
74
78
|
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
|
-
|
|
79
|
+
self.database.commit()
|
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.15"
|
|
17
17
|
|
|
18
18
|
if os.name == "nt":
|
|
19
19
|
PW_TORRENT_ARCHIVE_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "pw_torrent_archive"
|
unit3dup/__main__.py
CHANGED
|
@@ -119,20 +119,12 @@ def main():
|
|
|
119
119
|
|
|
120
120
|
# Watcher
|
|
121
121
|
if cli.args.watcher:
|
|
122
|
-
bot = Bot(path=
|
|
122
|
+
bot = Bot(path='', cli=cli.args, mode="auto", trackers_name_list=tracker_name_list,
|
|
123
123
|
torrent_archive_path=tracker_archive)
|
|
124
124
|
|
|
125
125
|
bot.watcher(duration=config.user_preferences.WATCHER_INTERVAL, watcher_path=config.user_preferences.WATCHER_PATH,
|
|
126
126
|
destination_path = config.user_preferences.WATCHER_DESTINATION_PATH)
|
|
127
127
|
|
|
128
|
-
# Pw
|
|
129
|
-
if cli.args.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
|
|
134
|
-
|
|
135
|
-
|
|
136
128
|
# ftp and upload
|
|
137
129
|
if cli.args.ftp:
|
|
138
130
|
bot = Bot(path='', cli=cli.args, mode="folder", trackers_name_list=tracker_name_list)
|
|
@@ -153,13 +145,14 @@ def main():
|
|
|
153
145
|
|
|
154
146
|
# Search by different criteria
|
|
155
147
|
if cli.args.search:
|
|
156
|
-
|
|
148
|
+
print("NOT YET IMPLEMENTED")
|
|
149
|
+
# torrent_info.view_search(cli.args.search)
|
|
157
150
|
return
|
|
158
151
|
|
|
159
152
|
# Dump
|
|
160
153
|
if cli.args.dump:
|
|
161
|
-
print("
|
|
162
|
-
# torrent_info.view_search(
|
|
154
|
+
print("NOT YET IMPLEMENTED")
|
|
155
|
+
# torrent_info.view_search(" ", inkey=False)
|
|
163
156
|
return
|
|
164
157
|
|
|
165
158
|
if cli.args.info:
|
unit3dup/bot.py
CHANGED
|
@@ -11,7 +11,6 @@ from unit3dup.media_manager.ContentManager import ContentManager
|
|
|
11
11
|
from unit3dup.media_manager.TorrentManager import TorrentManager
|
|
12
12
|
|
|
13
13
|
from common.external_services.ftpx.core.models.list import FTPDirectory
|
|
14
|
-
from common.external_services.Pw.pw_manager import PwManager
|
|
15
14
|
from common.external_services.ftpx.core.menu import Menu
|
|
16
15
|
from common.external_services.ftpx.client import Client
|
|
17
16
|
from common.extractor import Extractor
|
unit3dup/media.py
CHANGED
|
@@ -14,7 +14,7 @@ class Media:
|
|
|
14
14
|
self.folder: str = folder
|
|
15
15
|
self.subfolder: str = subfolder
|
|
16
16
|
self.title: str = os.path.basename(os.path.join(self.folder, self.subfolder))
|
|
17
|
-
self.
|
|
17
|
+
self._not_title_lang = False
|
|
18
18
|
|
|
19
19
|
# // Media
|
|
20
20
|
self._crew_list: list[str] | None = None
|
|
@@ -53,6 +53,10 @@ class Media:
|
|
|
53
53
|
self._igdb_id: int | None = None
|
|
54
54
|
self._generate_title: str | None = None
|
|
55
55
|
|
|
56
|
+
@property
|
|
57
|
+
def no_title_lang(self) -> bool:
|
|
58
|
+
return self._not_title_lang
|
|
59
|
+
|
|
56
60
|
@property
|
|
57
61
|
def title_sanitized(self)-> str:
|
|
58
62
|
if not self._title_sanitized:
|
|
@@ -279,6 +283,8 @@ class Media:
|
|
|
279
283
|
if converted_code := ManageTitles.convert_iso(code):
|
|
280
284
|
self._audio_languages = converted_code
|
|
281
285
|
return self._audio_languages
|
|
286
|
+
# no language found in title
|
|
287
|
+
self._not_title_lang = True
|
|
282
288
|
# get from the audio track
|
|
283
289
|
self._audio_languages = self.languages
|
|
284
290
|
return self._audio_languages
|
|
@@ -51,6 +51,10 @@ class ContentManager:
|
|
|
51
51
|
content = self.get_data(media=media)
|
|
52
52
|
if content:
|
|
53
53
|
contents.append(content)
|
|
54
|
+
|
|
55
|
+
# Add language to the title from the media file when it's absent
|
|
56
|
+
if not media._not_title_lang:
|
|
57
|
+
media.display_name = " ".join([media.display_name] + media.audio_languages)
|
|
54
58
|
return contents
|
|
55
59
|
|
|
56
60
|
def get_data(self, media: Media) -> Media | bool:
|
unit3dup/torrent.py
CHANGED
|
@@ -147,6 +147,7 @@ class View(Torrent):
|
|
|
147
147
|
|
|
148
148
|
# Load the constant tracker
|
|
149
149
|
self.tracker_data = TRACKData.load_from_module(tracker_name=tracker_name)
|
|
150
|
+
self.tracker_name = tracker_name
|
|
150
151
|
print()
|
|
151
152
|
|
|
152
153
|
def get_unique_id(self, media_info: str) -> str:
|
|
@@ -182,12 +183,12 @@ class View(Torrent):
|
|
|
182
183
|
else:
|
|
183
184
|
release_year = item['attributes']['release_year']
|
|
184
185
|
|
|
185
|
-
media = f"
|
|
186
|
+
media = f"{self.tracker_name} - TMDB: {item['attributes']['tmdb_id']} - {release_year}"
|
|
186
187
|
|
|
187
188
|
elif item['attributes']['igdb_id'] !=0:
|
|
188
|
-
media = f"
|
|
189
|
+
media = f"{self.tracker_name} IGDB: {item['attributes']['igdb_id']}"
|
|
189
190
|
else:
|
|
190
|
-
media = f"
|
|
191
|
+
media = f"{self.tracker_name} DOC:"
|
|
191
192
|
|
|
192
193
|
# Print a data to the console
|
|
193
194
|
custom_console.bot_log(f"\n {media} - {item['attributes']['name']}")
|
|
@@ -1,14 +1,14 @@
|
|
|
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=BJNOdnfS5FQpZdCib-q0Tq9S9IoPtHlOEF9kxDQCzls,5978
|
|
5
5
|
common/constants.py,sha256=tdflS7ZJwAcI1ZYUhBBb60QybVT7TmVS-EYxS4bNFp0,352
|
|
6
|
-
common/database.py,sha256=
|
|
6
|
+
common/database.py,sha256=XOjh-X3XZBHjln9scRgzArpTlfgfR7P3ZlwahPbeUSU,3056
|
|
7
7
|
common/extractor.py,sha256=WKZwt2kQfKO2VJ1rtwE_j6Zl84zICnowZq_Ql16wmRc,4564
|
|
8
8
|
common/frames.py,sha256=p_jsaXII5tZTVt5ymu-w1hk2c_UMeOn3PZeuVR-wXWY,7973
|
|
9
9
|
common/mediainfo.py,sha256=U2r1jJejBsV8GP3iPk4O8_NkHO5RQ9Kkh2bKwVNUBmg,6229
|
|
10
10
|
common/mediainfo_string.py,sha256=8vuWlF2bqWRKpDbn81bV2fPA7hbl7RwOnxN2i4E3zNE,3958
|
|
11
|
-
common/settings.py,sha256=
|
|
11
|
+
common/settings.py,sha256=pGdw3qAC_fqSncyxqRNRYec3N75EhiUWTS5wy8JV8CE,32782
|
|
12
12
|
common/title.py,sha256=nFainfUBTYW9ML4Y-CB9ZFD_Es-OZXcAMPUo6D09u3k,3793
|
|
13
13
|
common/torrent_clients.py,sha256=NOIpYtLG_bA19HwcH9ahGFmGNtRkoMO6nAjma-JzDfs,12040
|
|
14
14
|
common/utility.py,sha256=r5MuFrafAzSJbe7DLx8uMKSG1qQi8k6oA43Y_qJhH7A,8647
|
|
@@ -16,15 +16,6 @@ common/external_services/__init__.py,sha256=rU7HPEcZ7WQFD8eqDzuye2xHPBjxXPwPqpt7
|
|
|
16
16
|
common/external_services/imageHost.py,sha256=BpdtGZUtZHl4QJwFKyJs_BI6z4gHI4wu_Beu-fnfkDw,9588
|
|
17
17
|
common/external_services/imdb.py,sha256=AIo8CO-SfP_uNocDeNY08hpvCAnuotoI7hYUytDiMQA,579
|
|
18
18
|
common/external_services/mediaresult.py,sha256=Yz-h7QROkfNHwaSSXZ1JRDSmG2YIZkmtQO5vmpkYWZ4,677
|
|
19
|
-
common/external_services/Pw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
common/external_services/Pw/pw_manager.py,sha256=a8s3YgzHf0iw45Fh5BeMRSX5aGlatBJbOYamSrWFj2U,2225
|
|
21
|
-
common/external_services/Pw/pw_service.py,sha256=_-AQgffqiuoS0xcHc7sEgQBuXidU9RdJZyZnRa-ATZc,1151
|
|
22
|
-
common/external_services/Pw/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
common/external_services/Pw/core/pw_api.py,sha256=C1XzN-hJwJvzjZwiNTL39mu4gJGiEKKZYjt9JAStIHk,3234
|
|
24
|
-
common/external_services/Pw/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
common/external_services/Pw/core/models/indexers.py,sha256=7nVqZd-_nbwL40HLGEFauI8zNeC-w66py2tK7h9rGV4,1947
|
|
26
|
-
common/external_services/Pw/core/models/search.py,sha256=fmoEccxgRDG26nmEcpJR0e5twBLTOEzDzaeQFG2TAc4,969
|
|
27
|
-
common/external_services/Pw/core/models/torrent_client_config.py,sha256=zmPqcYoRSIeXoxLvK0Q5wAj_gkSd1y1u1oEj5g6BvGM,1025
|
|
28
19
|
common/external_services/ftpx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
20
|
common/external_services/ftpx/client.py,sha256=D_23Cw9zeQQIiVhUIUE13ENXNVyP4-MMx_Rgqg67U7Y,10713
|
|
30
21
|
common/external_services/ftpx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -72,19 +63,19 @@ common/trackers/itt.py,sha256=cB0D5ZpMbGgEOAKloET9dS_fAFclhzwPPwRFt-LStX0,4019
|
|
|
72
63
|
common/trackers/sis.py,sha256=AahQH-FxAqS19vgEFylOJzeY0_SHr27_Tibs7lraSdI,3480
|
|
73
64
|
common/trackers/trackers.py,sha256=sts5l_x27V2Op1Y6Au5FoQujspSkWMPWyEYMfcmVYLA,1467
|
|
74
65
|
unit3dup/__init__.py,sha256=seXz3lHgdrUBiOnhC6Je47npS66UZ0c62VFuoH3z5Mk,78
|
|
75
|
-
unit3dup/__main__.py,sha256=
|
|
66
|
+
unit3dup/__main__.py,sha256=DBhzZdUi19N1-WTBQJbps9wQKNcNhwreaXwXQtFORHs,9088
|
|
76
67
|
unit3dup/automode.py,sha256=HIJrE8qEHp7DZQbppNtB_8jHY3Q94d6frp7BXnZuEac,4387
|
|
77
|
-
unit3dup/bot.py,sha256=
|
|
68
|
+
unit3dup/bot.py,sha256=dgmFaXHb_F992EF67tvXqHJ0nvfhpE2CwIjrGT-O9wo,9188
|
|
78
69
|
unit3dup/duplicate.py,sha256=Ji1Y9vVLmhFQ5rgkUU-s7uXl-jC8akAa8OiQOfjFa9g,10428
|
|
79
70
|
unit3dup/exceptions.py,sha256=DhlcbbZEuvEYk5VSZTnle8oRg5I8Pq6Y6fxXTdOOOfo,4078
|
|
80
|
-
unit3dup/media.py,sha256=
|
|
71
|
+
unit3dup/media.py,sha256=5suH2XeekB80zNoIAM8PERZBO746JDlpcIvHz-4jY9E,13888
|
|
81
72
|
unit3dup/pvtDocu.py,sha256=ZLMaal2fn6ZcFPLtET0LTmYEPjhJmLitEjkICHrm9CQ,4594
|
|
82
73
|
unit3dup/pvtTorrent.py,sha256=cItlsCpcUJL23iXQHy0YzrrvV3JSl54UlBgm8_UROAs,2559
|
|
83
74
|
unit3dup/pvtTracker.py,sha256=U4xMmhiqMNZaIOgEi3pnP-3H75e7Gagndh8GDFEP7Cs,18647
|
|
84
75
|
unit3dup/pvtVideo.py,sha256=w_T6wEeGrsHkuR3KObJc4mNpJgg9hhHh_9LoxFlaqjM,3900
|
|
85
|
-
unit3dup/torrent.py,sha256=
|
|
76
|
+
unit3dup/torrent.py,sha256=tWnAxZjPKGr_ktqfVmimnSgdnWU0efNbB-FIsLUMmY8,19957
|
|
86
77
|
unit3dup/upload.py,sha256=gjB8u2oP2FPXZ8t9SMIzkUEr52hKRy_zSR8OWJlW2xc,6075
|
|
87
|
-
unit3dup/media_manager/ContentManager.py,sha256=
|
|
78
|
+
unit3dup/media_manager/ContentManager.py,sha256=68k8sqJgL1a2ir_rpQhkB1ntePp01IpblJYcQCdev2Y,7358
|
|
88
79
|
unit3dup/media_manager/DocuManager.py,sha256=oFt7jlxj-gIUty9PADBQV5a24bsv3yhjKhwI6niOhf4,3116
|
|
89
80
|
unit3dup/media_manager/GameManager.py,sha256=9EmPeNrirOwaVOj-vkLr29Xo7daIA4ssqrrt0WyMl30,4090
|
|
90
81
|
unit3dup/media_manager/MediaInfoManager.py,sha256=0NO9dgD7seJM67B3DRnwvRIdoy7bfquBUox-PnHInK8,1081
|
|
@@ -95,11 +86,11 @@ unit3dup/media_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
95
86
|
unit3dup/media_manager/common.py,sha256=hG2zOw7ocQfZyI1dhusbehxswpIrZK7T2aAbCNwULqA,10138
|
|
96
87
|
unit3dup/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
97
88
|
unit3dup/web/main.py,sha256=BzjKDgAjKZMnoQwx7nDDbs_64kCrFO1VYpbHmsGiFVc,1267
|
|
98
|
-
unit3dup-0.8.
|
|
89
|
+
unit3dup-0.8.15.dist-info/licenses/LICENSE,sha256=GNAZDLhU0xz8QPbIyHAOYlVnQYDvKWk2N9fZJMhqaG8,1090
|
|
99
90
|
view/__init__.py,sha256=XIzb6rl58HmYPnksD73cYMFF88dn6FHa3u7bOHFbChk,81
|
|
100
91
|
view/custom_console.py,sha256=OITmkEoQH9N_uE5ElPaSdc8XvaLzE9wcwTbOHtcMvrI,5629
|
|
101
|
-
unit3dup-0.8.
|
|
102
|
-
unit3dup-0.8.
|
|
103
|
-
unit3dup-0.8.
|
|
104
|
-
unit3dup-0.8.
|
|
105
|
-
unit3dup-0.8.
|
|
92
|
+
unit3dup-0.8.15.dist-info/METADATA,sha256=wWNaUq7iZ_jCVHSHMNBDdQMaCSwlwORirOzhSi69nUg,4864
|
|
93
|
+
unit3dup-0.8.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
94
|
+
unit3dup-0.8.15.dist-info/entry_points.txt,sha256=fxXSyI6-r6jy9_v-C5ZHm03q1aC3tE9EvCQZxC1NQnI,52
|
|
95
|
+
unit3dup-0.8.15.dist-info/top_level.txt,sha256=19NVMnQNkJxBUKebRNaYCRs56A5CO4U1L67GMQCPiLU,21
|
|
96
|
+
unit3dup-0.8.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@dataclass
|
|
7
|
-
class SubCategory:
|
|
8
|
-
id: int = 0
|
|
9
|
-
name: str = ''
|
|
10
|
-
subCategories: list[any] = field(default_factory=list)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@dataclass
|
|
14
|
-
class Category:
|
|
15
|
-
id: int = 0
|
|
16
|
-
name: str = ''
|
|
17
|
-
subCategories: list[SubCategory] = field(default_factory=list)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@dataclass
|
|
21
|
-
class Capability:
|
|
22
|
-
bookSearchParams: list[str] = field(default_factory=list)
|
|
23
|
-
categories: list[Category] = field(default_factory=list)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@dataclass
|
|
27
|
-
class FieldOption:
|
|
28
|
-
hint: str = ''
|
|
29
|
-
name: str = ''
|
|
30
|
-
order: int = 0
|
|
31
|
-
value: int = 0
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@dataclass
|
|
35
|
-
class Field:
|
|
36
|
-
advanced: bool = False
|
|
37
|
-
hidden: str = ''
|
|
38
|
-
isFloat: bool = False
|
|
39
|
-
name: str = ''
|
|
40
|
-
order: int = 0
|
|
41
|
-
privacy: str = ''
|
|
42
|
-
type: str = ''
|
|
43
|
-
value: str = ''
|
|
44
|
-
helpText: str = ''
|
|
45
|
-
label: str = ''
|
|
46
|
-
selectOptionsProviderAction: str = ''
|
|
47
|
-
selectOptions: list[FieldOption] = field(default_factory=list)
|
|
48
|
-
unit: str = ''
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass
|
|
52
|
-
class Indexer:
|
|
53
|
-
added: str = ''
|
|
54
|
-
appProfileId: int = 0
|
|
55
|
-
capabilities: Capability = field(default_factory=Capability)
|
|
56
|
-
configContract: str = ''
|
|
57
|
-
definitionName: str = ''
|
|
58
|
-
description: str = ''
|
|
59
|
-
downloadClientId: int = 0
|
|
60
|
-
enable: bool = True
|
|
61
|
-
encoding: str = ''
|
|
62
|
-
fields: list[Field] = field(default_factory=list)
|
|
63
|
-
id: int = 0
|
|
64
|
-
implementation: str = ''
|
|
65
|
-
implementationName: str = ''
|
|
66
|
-
indexerUrls: list[str] = field(default_factory=list)
|
|
67
|
-
infoLink: str = ''
|
|
68
|
-
language: str = ''
|
|
69
|
-
legacyUrls: list[str] = field(default_factory=list)
|
|
70
|
-
name: str = ''
|
|
71
|
-
priority: int = 0
|
|
72
|
-
privacy: str = ''
|
|
73
|
-
protocol: str = ''
|
|
74
|
-
redirect: bool = False
|
|
75
|
-
sortName: str = ''
|
|
76
|
-
supportsPagination: bool = False
|
|
77
|
-
supportsRedirect: bool = False
|
|
78
|
-
supportsRss: bool = False
|
|
79
|
-
supportsSearch: bool = False
|
|
80
|
-
tags: list[int] = field(default_factory=list)
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@dataclass
|
|
7
|
-
class Search:
|
|
8
|
-
"""
|
|
9
|
-
Get a result from the endpoint /search?query
|
|
10
|
-
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
age: int = 0
|
|
14
|
-
ageHours: float = 0.0
|
|
15
|
-
ageMinutes: float = 0.0
|
|
16
|
-
categories: list[dict[str, any]] = field(default_factory=list)
|
|
17
|
-
downloadUrl: None | str = None
|
|
18
|
-
fileName: None | str = None
|
|
19
|
-
guid: None | str = None
|
|
20
|
-
imdbId: int = 0
|
|
21
|
-
indexer: None | str = None
|
|
22
|
-
indexerFlags: list[str] = field(default_factory=list)
|
|
23
|
-
indexerId: int = 0
|
|
24
|
-
infoUrl: None | str = None
|
|
25
|
-
leechers: int = 0
|
|
26
|
-
protocol: str = "torrent"
|
|
27
|
-
publishDate: None | str = None
|
|
28
|
-
seeders: int = 0
|
|
29
|
-
size: int = 0
|
|
30
|
-
sortTitle: None | str = None
|
|
31
|
-
title: None | str = None
|
|
32
|
-
tmdbId: int = 0
|
|
33
|
-
tvMazeId: int = 0
|
|
34
|
-
tvdbId: int = 0
|
|
35
|
-
files: int | None = None
|
|
36
|
-
grabs: int | None = None
|
|
37
|
-
posterUrl: str | None = None
|
|
38
|
-
infoHash: str | None = None
|
|
39
|
-
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@dataclass
|
|
7
|
-
class SelectOption:
|
|
8
|
-
hint: str
|
|
9
|
-
name: str
|
|
10
|
-
order: int
|
|
11
|
-
value: int
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class Field:
|
|
16
|
-
advanced: bool = False
|
|
17
|
-
isFloat: bool = False
|
|
18
|
-
label: str = ""
|
|
19
|
-
name: str = ""
|
|
20
|
-
order: int = 0
|
|
21
|
-
privacy: str = "normal"
|
|
22
|
-
type: str = "textbox"
|
|
23
|
-
value: str | int | bool | None = None
|
|
24
|
-
helpText: str | None = None
|
|
25
|
-
selectOptions: list[SelectOption] | None = None
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class TorrentClientConfig:
|
|
30
|
-
categories: list[str] = field(default_factory=list)
|
|
31
|
-
configContract: str | None = None
|
|
32
|
-
enable: bool = True
|
|
33
|
-
fields: list[Field] = field(default_factory=list)
|
|
34
|
-
id: int = 0
|
|
35
|
-
implementation: str | None = None
|
|
36
|
-
implementationName: str | None = None
|
|
37
|
-
infoLink: str | None = None
|
|
38
|
-
name: str | None = None
|
|
39
|
-
priority: int = 0
|
|
40
|
-
protocol: str | None = None
|
|
41
|
-
supportsCategories: bool = False
|
|
42
|
-
tags: list[str] = field(default_factory=list)
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import os.path
|
|
3
|
-
|
|
4
|
-
import httpx
|
|
5
|
-
|
|
6
|
-
from common.external_services.Pw.core.models.torrent_client_config import (
|
|
7
|
-
TorrentClientConfig,
|
|
8
|
-
)
|
|
9
|
-
from common.external_services.Pw.core.models.indexers import Indexer
|
|
10
|
-
from common.external_services.Pw.core.models.search import Search
|
|
11
|
-
from common.external_services.sessions.session import MyHttp
|
|
12
|
-
from common.external_services.sessions.agents import Agent
|
|
13
|
-
from common import config_settings
|
|
14
|
-
|
|
15
|
-
from view import custom_console
|
|
16
|
-
|
|
17
|
-
class PwAPI(MyHttp):
|
|
18
|
-
|
|
19
|
-
def __init__(self):
|
|
20
|
-
"""
|
|
21
|
-
Initialize the PwApi instance
|
|
22
|
-
"""
|
|
23
|
-
headers = Agent.headers()
|
|
24
|
-
headers.update(
|
|
25
|
-
{"X-Api-Key": config_settings.options.PW_API_KEY, "Content-Type": "application/json"}
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
super().__init__(headers)
|
|
29
|
-
self.http_client = self.session
|
|
30
|
-
self.base_url = config_settings.options.PW_URL
|
|
31
|
-
self.api_key = config_settings.options.PW_API_KEY
|
|
32
|
-
self.dataclass = {f"{self.base_url}/indexer": Indexer}
|
|
33
|
-
|
|
34
|
-
if not config_settings.options.PW_URL:
|
|
35
|
-
custom_console.bot_question_log("No PW_URL provided\n")
|
|
36
|
-
exit(1)
|
|
37
|
-
|
|
38
|
-
if not config_settings.options.PW_API_KEY:
|
|
39
|
-
custom_console.bot_question_log("No PW_API_KEY provided\n")
|
|
40
|
-
exit(1)
|
|
41
|
-
|
|
42
|
-
def get_indexers(self) -> list[type[[Indexer]]]:
|
|
43
|
-
"""Get all indexers."""
|
|
44
|
-
|
|
45
|
-
response = self.get_url(url=f"{self.base_url}/indexer", params={})
|
|
46
|
-
|
|
47
|
-
if response.status_code == 200:
|
|
48
|
-
indexers_list = response.json()
|
|
49
|
-
return [Indexer(**indexer) for indexer in indexers_list]
|
|
50
|
-
else:
|
|
51
|
-
return [Indexer]
|
|
52
|
-
|
|
53
|
-
def get_torrent_url(self, url: str, filename: str)-> httpx.Response :
|
|
54
|
-
return self.get_url(url=url)
|
|
55
|
-
|
|
56
|
-
def search(self, query: str) -> list[Search] | None:
|
|
57
|
-
"""Get search queue."""
|
|
58
|
-
|
|
59
|
-
params = {"query": query}
|
|
60
|
-
url = f"{self.base_url}/search?"
|
|
61
|
-
|
|
62
|
-
response = self.get_url(url=url, params=params)
|
|
63
|
-
if response:
|
|
64
|
-
if response.status_code == 200:
|
|
65
|
-
results_list = response.json()
|
|
66
|
-
return [Search(**result) for result in results_list]
|
|
67
|
-
else:
|
|
68
|
-
return []
|
|
69
|
-
return None
|
|
70
|
-
|
|
71
|
-
def get_torrent_client_ids(self) -> list["TorrentClientConfig"]:
|
|
72
|
-
"""Get a list of torrent client configurations"""
|
|
73
|
-
|
|
74
|
-
url = f"{self.base_url}/downloadclient"
|
|
75
|
-
response = self.get_url(url=url, params={})
|
|
76
|
-
|
|
77
|
-
if response.status_code == 200:
|
|
78
|
-
configurations_list = response.json()
|
|
79
|
-
return [
|
|
80
|
-
TorrentClientConfig(**client_config)
|
|
81
|
-
for client_config in configurations_list
|
|
82
|
-
]
|
|
83
|
-
else:
|
|
84
|
-
return []
|
|
85
|
-
|
|
86
|
-
def send_torrent_to_client(self, payload):
|
|
87
|
-
"""send torrent to client"""
|
|
88
|
-
|
|
89
|
-
url = f"{self.base_url}/downloadclient/1"
|
|
90
|
-
response = self.get_url(url=url, body=payload, get_method=False)
|
|
91
|
-
|
|
92
|
-
# TODO: Test again - get_url() updated 21/09/2024
|
|
93
|
-
if response.status_code == 202 or response.status_code == 200:
|
|
94
|
-
result = response.json()
|
|
95
|
-
else:
|
|
96
|
-
return []
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
from common.external_services.Pw.pw_service import PwService
|
|
7
|
-
from common.utility import ManageTitles
|
|
8
|
-
from common.database import Database
|
|
9
|
-
from common import config_settings
|
|
10
|
-
from unit3dup.media import Media
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from qbittorrent import Client
|
|
14
|
-
from view import custom_console
|
|
15
|
-
|
|
16
|
-
class PwManager:
|
|
17
|
-
|
|
18
|
-
def __init__(self,cli: argparse.Namespace):
|
|
19
|
-
# Keyword
|
|
20
|
-
self.search = cli.pw
|
|
21
|
-
|
|
22
|
-
# filename for the new download
|
|
23
|
-
self.filename = ManageTitles.normalize_filename(self.search)
|
|
24
|
-
|
|
25
|
-
# Select the tracker database
|
|
26
|
-
self.database = Database(db_file=cli.tracker)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def process(self):
|
|
30
|
-
|
|
31
|
-
# a new qbittorrent instance
|
|
32
|
-
qb = Client(f"http://{config_settings.torrent_client_config.QBIT_HOST}:{config_settings.torrent_client_config.QBIT_PORT}/")
|
|
33
|
-
# a new pw instance
|
|
34
|
-
pw_service = PwService()
|
|
35
|
-
# Query the indexers
|
|
36
|
-
search = pw_service.search(query=self.search)
|
|
37
|
-
|
|
38
|
-
content = []
|
|
39
|
-
if search:
|
|
40
|
-
for index, s in enumerate(search):
|
|
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
|
-
"""
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from common.external_services.Pw.core.pw_api import PwAPI
|
|
4
|
-
from common.external_services.Pw.core.models.indexers import Indexer
|
|
5
|
-
from common.external_services.Pw.core.models.search import Search
|
|
6
|
-
from common.external_services.Pw.core.models.torrent_client_config import TorrentClientConfig
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class PwService:
|
|
10
|
-
|
|
11
|
-
def __init__(self):
|
|
12
|
-
self.pw_api = PwAPI()
|
|
13
|
-
|
|
14
|
-
def get_indexers(self) -> [Indexer]:
|
|
15
|
-
return self.pw_api.get_indexers()
|
|
16
|
-
|
|
17
|
-
def search(self, query: str) -> list[Search]:
|
|
18
|
-
return self.pw_api.search(query=query)
|
|
19
|
-
|
|
20
|
-
def get_torrent_client_ids(self) -> list[TorrentClientConfig]:
|
|
21
|
-
return self.pw_api.get_torrent_client_ids()
|
|
22
|
-
|
|
23
|
-
def send_torrent_to_client(self, payload):
|
|
24
|
-
return self.pw_api.send_torrent_to_client(payload)
|
|
25
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|