Unit3Dup 0.8.21__py3-none-any.whl → 0.8.24__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/external_services/imdb.py +3 -7
- common/external_services/mediaresult.py +2 -1
- common/external_services/theMovieDB/core/api.py +57 -61
- common/external_services/tvdb.py +27 -0
- common/settings.py +5 -3
- common/utility.py +3 -1
- unit3dup/media.py +11 -1
- unit3dup/media_manager/ContentManager.py +7 -1
- unit3dup/media_manager/VideoManager.py +4 -3
- unit3dup/pvtTracker.py +4 -5
- unit3dup/upload.py +3 -1
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/METADATA +176 -176
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/RECORD +17 -16
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/WHEEL +1 -1
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/licenses/LICENSE +0 -0
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/entry_points.txt +0 -0
- {unit3dup-0.8.21.dist-info → unit3dup-0.8.24.dist-info}/top_level.txt +0 -0
common/external_services/imdb.py
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from imdb import Cinemagoer
|
|
4
|
-
from view import custom_console
|
|
5
|
-
from rich.table import Table
|
|
6
|
-
from rich.align import Align
|
|
7
|
-
|
|
3
|
+
from imdb import Cinemagoer # Installato da github , su pipy non ancora disponibile la versione 2025
|
|
8
4
|
from common.utility import ManageTitles
|
|
9
|
-
from
|
|
5
|
+
from unit3dup import config_settings
|
|
10
6
|
|
|
11
7
|
|
|
12
8
|
class IMDB:
|
|
@@ -20,4 +16,4 @@ class IMDB:
|
|
|
20
16
|
for movie in movies:
|
|
21
17
|
if ManageTitles.fuzzyit(str1=query, str2=movie.data['title']) > 95:
|
|
22
18
|
return movie.movieID
|
|
23
|
-
|
|
19
|
+
return None
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
|
|
5
5
|
class MediaResult:
|
|
6
|
-
def __init__(self, result=None, video_id: int = 0, imdb_id = None, trailer_key: str = None,
|
|
6
|
+
def __init__(self, result=None, video_id: int = 0, imdb_id = None, tvdb_id = None, trailer_key: str = None,
|
|
7
7
|
keywords_list: str = None, season_title = None):
|
|
8
8
|
self.result = result
|
|
9
9
|
self.trailer_key = trailer_key
|
|
10
10
|
self.keywords_list = keywords_list
|
|
11
11
|
self.video_id = video_id
|
|
12
12
|
self.imdb_id = imdb_id
|
|
13
|
+
self.tvdb_id = tvdb_id
|
|
13
14
|
self.season_title = season_title
|
|
14
15
|
self.year = None
|
|
15
16
|
|
|
@@ -20,7 +20,7 @@ from common.external_services.sessions.session import MyHttp
|
|
|
20
20
|
from common.external_services.trailers.api import YtTrailer
|
|
21
21
|
from common.external_services.sessions.agents import Agent
|
|
22
22
|
from common.external_services.theMovieDB import config
|
|
23
|
-
from common.external_services.
|
|
23
|
+
from common.external_services.tvdb import TVDB
|
|
24
24
|
from common.utility import ManageTitles
|
|
25
25
|
|
|
26
26
|
from unit3dup.media import Media
|
|
@@ -35,33 +35,29 @@ T = TypeVar('T')
|
|
|
35
35
|
|
|
36
36
|
class MovieEndpoint:
|
|
37
37
|
@staticmethod
|
|
38
|
-
def search(query: str)-> dict:
|
|
39
|
-
return {'url': f'{base_url}/search/movie', 'datatype': Movie, 'query': query, 'results': 'results'
|
|
40
|
-
|
|
38
|
+
def search(query: str) -> dict:
|
|
39
|
+
return {'url': f'{base_url}/search/movie', 'datatype': Movie, 'query': query, 'results': 'results'}
|
|
41
40
|
|
|
42
41
|
@staticmethod
|
|
43
|
-
def playing()-> dict:
|
|
42
|
+
def playing() -> dict:
|
|
44
43
|
return {'url': f'{base_url}/movie/now_playing', 'datatype': NowPlaying, 'query': '', 'results': 'results'}
|
|
45
44
|
|
|
46
|
-
|
|
47
45
|
@staticmethod
|
|
48
|
-
def alternative(movie_id: int)-> dict:
|
|
46
|
+
def alternative(movie_id: int) -> dict:
|
|
49
47
|
return {'url': f'{base_url}/movie/{movie_id}/alternative_titles', 'datatype': Alternative, 'query': '',
|
|
50
48
|
'results': 'titles'}
|
|
51
49
|
|
|
52
|
-
|
|
53
50
|
@staticmethod
|
|
54
|
-
def videos(movie_id: int)-> dict:
|
|
51
|
+
def videos(movie_id: int) -> dict:
|
|
55
52
|
return {'url': f'{base_url}/movie/{movie_id}/videos', 'datatype': Videos, 'query': '',
|
|
56
53
|
'results': 'results'}
|
|
57
54
|
|
|
58
55
|
@staticmethod
|
|
59
|
-
def details(movie_id: int)-> dict:
|
|
56
|
+
def details(movie_id: int) -> dict:
|
|
60
57
|
return {'url': f'{base_url}/movie/{movie_id}', 'datatype': MovieDetails, 'query': ''}
|
|
61
58
|
|
|
62
|
-
|
|
63
59
|
@staticmethod
|
|
64
|
-
def keywords(movie_id: int)-> dict:
|
|
60
|
+
def keywords(movie_id: int) -> dict:
|
|
65
61
|
return {'url': f'{base_url}/movie/{movie_id}/keywords', 'datatype': Keyword, 'query': '',
|
|
66
62
|
'results': 'keywords'}
|
|
67
63
|
|
|
@@ -71,38 +67,31 @@ class TvEndpoint:
|
|
|
71
67
|
def search(query: str):
|
|
72
68
|
return {'url': f'{base_url}/search/tv', 'datatype': TvShow, 'query': query, 'results': 'results'}
|
|
73
69
|
|
|
74
|
-
|
|
75
70
|
@staticmethod
|
|
76
71
|
def playing():
|
|
77
72
|
return {'url': f'{base_url}/tv/on_the_air', 'datatype': OnTheAir, 'query': '', 'results': 'results'}
|
|
78
73
|
|
|
79
|
-
|
|
80
74
|
@staticmethod
|
|
81
75
|
def alternative(serie_id: int) -> dict:
|
|
82
76
|
return {'url': f'{base_url}/tv/{serie_id}/alternative_titles', 'datatype': Alternative, 'query': '',
|
|
83
77
|
'results': 'results'}
|
|
84
78
|
|
|
85
|
-
|
|
86
79
|
@staticmethod
|
|
87
|
-
def videos(serie_id: int)-> dict:
|
|
80
|
+
def videos(serie_id: int) -> dict:
|
|
88
81
|
return {'url': f'{base_url}/tv/{serie_id}/videos', 'datatype': Videos, 'query': '',
|
|
89
82
|
'results': 'results'}
|
|
90
83
|
|
|
91
84
|
@staticmethod
|
|
92
|
-
def details(serie_id: int)-> dict:
|
|
85
|
+
def details(serie_id: int) -> dict:
|
|
93
86
|
return {'url': f'{base_url}/tv/{serie_id}', 'datatype': TVShowDetails, 'query': ''}
|
|
94
87
|
|
|
95
|
-
|
|
96
|
-
|
|
97
88
|
@staticmethod
|
|
98
|
-
def keywords(serie_id: int)-> dict:
|
|
89
|
+
def keywords(serie_id: int) -> dict:
|
|
99
90
|
return {'url': f'{base_url}/tv/{serie_id}/keywords', 'datatype': Keyword, 'query': '',
|
|
100
91
|
'results': 'results'}
|
|
101
92
|
|
|
102
93
|
|
|
103
|
-
|
|
104
94
|
class TmdbAPI(MyHttp):
|
|
105
|
-
|
|
106
95
|
params = {
|
|
107
96
|
"api_key": config.TMDB_APIKEY,
|
|
108
97
|
"language": "it-IT",
|
|
@@ -147,7 +136,7 @@ class TmdbAPI(MyHttp):
|
|
|
147
136
|
:return: list of T or None
|
|
148
137
|
"""
|
|
149
138
|
|
|
150
|
-
if endpoint_class:=self.ENDPOINTS.get(category):
|
|
139
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
151
140
|
request = endpoint_class.playing()
|
|
152
141
|
return self.request(endpoint=request)
|
|
153
142
|
else:
|
|
@@ -161,7 +150,7 @@ class TmdbAPI(MyHttp):
|
|
|
161
150
|
:param category: category of the search query, e.g., 'movie' or 'tv'
|
|
162
151
|
:return: list of T or None
|
|
163
152
|
"""
|
|
164
|
-
if endpoint_class:=self.ENDPOINTS.get(category):
|
|
153
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
165
154
|
request = endpoint_class.alternative(media_id)
|
|
166
155
|
return self.request(endpoint=request)
|
|
167
156
|
else:
|
|
@@ -169,7 +158,7 @@ class TmdbAPI(MyHttp):
|
|
|
169
158
|
return []
|
|
170
159
|
|
|
171
160
|
def _videos(self, video_id: int, category: str) -> list[T] | None:
|
|
172
|
-
if endpoint_class:=self.ENDPOINTS.get(category):
|
|
161
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
173
162
|
request = endpoint_class.videos(video_id)
|
|
174
163
|
return self.request(endpoint=request)
|
|
175
164
|
else:
|
|
@@ -177,23 +166,21 @@ class TmdbAPI(MyHttp):
|
|
|
177
166
|
return []
|
|
178
167
|
|
|
179
168
|
def details(self, video_id: int, category: str) -> list[T] | None:
|
|
180
|
-
if endpoint_class:=self.ENDPOINTS.get(category):
|
|
169
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
181
170
|
request = endpoint_class.details(video_id)
|
|
182
171
|
return self.request(endpoint=request)
|
|
183
172
|
else:
|
|
184
173
|
print(f"Endpoint for category '{category}' not found.")
|
|
185
174
|
return []
|
|
186
175
|
|
|
187
|
-
|
|
188
176
|
def _keywords(self, video_id: int, category: str) -> list[T] | None:
|
|
189
|
-
if endpoint_class:=self.ENDPOINTS.get(category):
|
|
177
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
190
178
|
request = endpoint_class.keywords(video_id)
|
|
191
179
|
return self.request(endpoint=request)
|
|
192
180
|
else:
|
|
193
181
|
print(f"Endpoint for category '{category}' not found.")
|
|
194
182
|
return []
|
|
195
183
|
|
|
196
|
-
|
|
197
184
|
def request(self, endpoint: dict) -> list[T] | None:
|
|
198
185
|
"""
|
|
199
186
|
Sends a request to the API and returns a list of instances of the specified 'datatype'.
|
|
@@ -215,20 +202,24 @@ class TmdbAPI(MyHttp):
|
|
|
215
202
|
return []
|
|
216
203
|
return None
|
|
217
204
|
|
|
205
|
+
|
|
218
206
|
class DbOnline(TmdbAPI):
|
|
219
207
|
def __init__(self, media: Media, category: str, no_title: str) -> None:
|
|
220
208
|
super().__init__()
|
|
221
209
|
self.media = media
|
|
222
210
|
self.query = media.guess_title
|
|
223
211
|
self.category = category
|
|
212
|
+
self.imdb_id = None
|
|
213
|
+
self.tvdb_id = None
|
|
224
214
|
|
|
225
215
|
# Load the cache file
|
|
226
216
|
if config_settings.user_preferences.CACHE_DBONLINE:
|
|
227
217
|
self.cache = diskcache.Cache(str(os.path.join(config_settings.user_preferences.CACHE_PATH, "tmdb.cache")))
|
|
228
218
|
|
|
229
|
-
if media.tmdb_id or media.imdb_id:
|
|
219
|
+
if media.tmdb_id or media.imdb_id or media.tmdb_id:
|
|
230
220
|
# Skip cache if there is a tmdb id or imdb in the title string
|
|
231
|
-
self.media_result = self.
|
|
221
|
+
self.media_result = self.results_in_string(tmdb_id=int(media.tmdb_id), imdb_id=int(media.imdb_id),
|
|
222
|
+
tvdb_id=int(media.tvdb_id))
|
|
232
223
|
else:
|
|
233
224
|
# Load from the cache or search online for a tmdb id or imdb
|
|
234
225
|
# Search for a video based on the filename or the title from the -notitle flag in the CLI
|
|
@@ -247,8 +238,9 @@ class DbOnline(TmdbAPI):
|
|
|
247
238
|
for result in results:
|
|
248
239
|
# check date
|
|
249
240
|
if result.get_date() and self.media.guess_filename.guessit_year:
|
|
250
|
-
if not datetime.strptime(result.get_date(),
|
|
251
|
-
|
|
241
|
+
if not datetime.strptime(result.get_date(),
|
|
242
|
+
'%Y-%m-%d').year == self.media.guess_filename.guessit_year:
|
|
243
|
+
continue
|
|
252
244
|
|
|
253
245
|
# Search for title
|
|
254
246
|
if ManageTitles.fuzzyit(str1=self.query, str2=ManageTitles.clean_text(result.get_title())) > 95:
|
|
@@ -265,7 +257,7 @@ class DbOnline(TmdbAPI):
|
|
|
265
257
|
return result
|
|
266
258
|
return False
|
|
267
259
|
|
|
268
|
-
def results_in_string(self, tmdb_id:int, imdb_id:int)-> MediaResult:
|
|
260
|
+
def results_in_string(self, tmdb_id: int, imdb_id: int, tvdb_id: int) -> MediaResult:
|
|
269
261
|
"""
|
|
270
262
|
Use id from the string filename or name folder
|
|
271
263
|
Cache disabled
|
|
@@ -281,12 +273,11 @@ class DbOnline(TmdbAPI):
|
|
|
281
273
|
else:
|
|
282
274
|
tmdb_id = 0
|
|
283
275
|
|
|
284
|
-
search_results = MediaResult(video_id=tmdb_id, imdb_id=imdb_id, trailer_key=trailer_key,
|
|
276
|
+
search_results = MediaResult(video_id=tmdb_id, imdb_id=self.imdb_id, tvdb_id=tvdb_id, trailer_key=trailer_key,
|
|
285
277
|
keywords_list=keywords_list)
|
|
286
278
|
self.print_results(results=search_results)
|
|
287
279
|
return search_results
|
|
288
280
|
|
|
289
|
-
|
|
290
281
|
def search(self) -> MediaResult | None:
|
|
291
282
|
"""
|
|
292
283
|
Search for results based on a tmdb query
|
|
@@ -303,13 +294,19 @@ class DbOnline(TmdbAPI):
|
|
|
303
294
|
# or start an on-line search
|
|
304
295
|
results = self._search(self.query, self.category)
|
|
305
296
|
# Use imdb_id when tmdb_id is not available
|
|
306
|
-
|
|
297
|
+
|
|
298
|
+
if 'tv' in self.category:
|
|
299
|
+
result = self.tvdb_search()
|
|
300
|
+
if result:
|
|
301
|
+
self.tvdb_id = result.get('tvdb_id', None)
|
|
302
|
+
self.imdb_id = result.get('imdb_id', None)
|
|
303
|
+
|
|
307
304
|
if results:
|
|
308
|
-
if result:=self.is_like(results):
|
|
305
|
+
if result := self.is_like(results):
|
|
309
306
|
# Get the trailer
|
|
310
307
|
trailer_key = self.trailer(result.id)
|
|
311
308
|
keywords_list = self.keywords(result.id)
|
|
312
|
-
search_results = MediaResult(result, video_id=result.id, imdb_id=imdb_id,
|
|
309
|
+
search_results = MediaResult(result, video_id=result.id, imdb_id=self.imdb_id, tvdb_id=self.tvdb_id,
|
|
313
310
|
trailer_key=trailer_key, keywords_list=keywords_list)
|
|
314
311
|
|
|
315
312
|
self.print_results(results=search_results)
|
|
@@ -340,6 +337,9 @@ class DbOnline(TmdbAPI):
|
|
|
340
337
|
self.cache[self.hash_key(self.query)] = search_results
|
|
341
338
|
return search_results
|
|
342
339
|
|
|
340
|
+
def tvdb_search(self) -> dict | None:
|
|
341
|
+
tvdb = TVDB(category=self.category)
|
|
342
|
+
return tvdb.search(query=self.query)
|
|
343
343
|
|
|
344
344
|
def manual_search(self) -> MediaResult | None:
|
|
345
345
|
"""
|
|
@@ -348,8 +348,6 @@ class DbOnline(TmdbAPI):
|
|
|
348
348
|
Returns:
|
|
349
349
|
MediaResult
|
|
350
350
|
"""
|
|
351
|
-
imdb = IMDB()
|
|
352
|
-
imdb_id = 0
|
|
353
351
|
user_id = 0
|
|
354
352
|
while True:
|
|
355
353
|
# Check if user wants to skip
|
|
@@ -363,11 +361,10 @@ class DbOnline(TmdbAPI):
|
|
|
363
361
|
custom_console.bot_warning_log(f"\n ** Auto skip TMDB ID **\n")
|
|
364
362
|
|
|
365
363
|
# Try to add IMDB ID if tmdb is not available
|
|
366
|
-
if user_id==0:
|
|
367
|
-
imdb_id = imdb.search(query=self.query)
|
|
364
|
+
if user_id == 0:
|
|
368
365
|
# try searching for a YouTube video anyway
|
|
369
366
|
trailer_key = self.youtube_trailer()
|
|
370
|
-
search_results = MediaResult(video_id=user_id, imdb_id=imdb_id, trailer_key=trailer_key,
|
|
367
|
+
search_results = MediaResult(video_id=user_id, imdb_id=self.imdb_id, trailer_key=trailer_key,
|
|
371
368
|
keywords_list='not available')
|
|
372
369
|
self.print_results(results=search_results)
|
|
373
370
|
return search_results
|
|
@@ -377,15 +374,15 @@ class DbOnline(TmdbAPI):
|
|
|
377
374
|
# Request trailer and keywords
|
|
378
375
|
trailer_key = self.trailer(user_id)
|
|
379
376
|
keywords_list = self.keywords(user_id) if trailer_key else ''
|
|
380
|
-
search_results = MediaResult(result=result, video_id=user_id, imdb_id=imdb_id,
|
|
377
|
+
search_results = MediaResult(result=result, video_id=user_id, imdb_id=self.imdb_id,
|
|
378
|
+
trailer_key=trailer_key,
|
|
381
379
|
keywords_list=keywords_list)
|
|
382
380
|
self.print_results(results=search_results)
|
|
383
381
|
return search_results
|
|
384
382
|
|
|
385
|
-
|
|
386
383
|
def youtube_trailer(self) -> str | None:
|
|
387
384
|
# Search trailer on YouTube
|
|
388
|
-
if 'no_key'
|
|
385
|
+
if 'no_key' in config_settings.tracker_config.YOUTUBE_KEY:
|
|
389
386
|
return "not available"
|
|
390
387
|
|
|
391
388
|
yt_trailer = YtTrailer(self.query)
|
|
@@ -398,7 +395,7 @@ class DbOnline(TmdbAPI):
|
|
|
398
395
|
if not config_settings.user_preferences.SKIP_YOUTUBE:
|
|
399
396
|
user_youtube_id = custom_console.user_input_str(message="Title not found."
|
|
400
397
|
" Please digit a valid Youtube ID (0=skip)->")
|
|
401
|
-
if user_youtube_id==0:
|
|
398
|
+
if user_youtube_id == 0:
|
|
402
399
|
return "not available"
|
|
403
400
|
return user_youtube_id
|
|
404
401
|
return None
|
|
@@ -424,17 +421,17 @@ class DbOnline(TmdbAPI):
|
|
|
424
421
|
else:
|
|
425
422
|
return "not available"
|
|
426
423
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
custom_console.
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
def load_cache(self, query: str)-> MediaResult | None:
|
|
424
|
+
def print_results(self, results: MediaResult) -> None:
|
|
425
|
+
custom_console.bot_log(f"'TMDB TITLE'..... {self.query}")
|
|
426
|
+
custom_console.bot_log(f"'TMDB ID'........ {results.video_id}")
|
|
427
|
+
if results.imdb_id:
|
|
428
|
+
custom_console.bot_warning_log(f"'IMDB ID'........ '{results.imdb_id}'")
|
|
429
|
+
if results.tvdb_id:
|
|
430
|
+
custom_console.bot_warning_log(f"'TVDB ID'........ '{results.tvdb_id}'")
|
|
431
|
+
custom_console.bot_log(f"'TMDB KEYWORDS'.. {results.keywords_list}")
|
|
432
|
+
custom_console.bot_log(f"'TRAILER CODE' .. {results.trailer_key}")
|
|
433
|
+
|
|
434
|
+
def load_cache(self, query: str) -> MediaResult | None:
|
|
438
435
|
# Check if the item is in the cache
|
|
439
436
|
if query not in self.cache:
|
|
440
437
|
return None
|
|
@@ -449,7 +446,6 @@ class DbOnline(TmdbAPI):
|
|
|
449
446
|
custom_console.bot_error_log("Proceed to extract the screenshot again. Please wait..")
|
|
450
447
|
return None
|
|
451
448
|
|
|
452
|
-
|
|
453
449
|
def search_id(self, video_id: int) -> list[T] | None:
|
|
454
450
|
"""
|
|
455
451
|
Search Movie or Tvshow based on ID
|
|
@@ -460,4 +456,4 @@ class DbOnline(TmdbAPI):
|
|
|
460
456
|
result = self.details(video_id=video_id, category=self.category)
|
|
461
457
|
if result:
|
|
462
458
|
return result[0]
|
|
463
|
-
return None
|
|
459
|
+
return None
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import tvdb_v4_official
|
|
2
|
+
from common.utility import ManageTitles
|
|
3
|
+
from unit3dup import config_settings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TVDB:
|
|
7
|
+
|
|
8
|
+
def __init__(self, category: str):
|
|
9
|
+
self.api = tvdb_v4_official.TVDB(config_settings.tracker_config.TVDB_APIKEY)
|
|
10
|
+
self.category = category
|
|
11
|
+
self.filtered_results = []
|
|
12
|
+
|
|
13
|
+
def search(self, query: str) -> dict | None:
|
|
14
|
+
results = self.api.search(query=query, type='series')
|
|
15
|
+
self.filtered_results = [item for item in results]
|
|
16
|
+
|
|
17
|
+
for item in self.filtered_results:
|
|
18
|
+
title = item.get('name', '') or item.get('extended_title', '')
|
|
19
|
+
remote_ids = item.get('remote_ids', [])
|
|
20
|
+
imdb_id = None
|
|
21
|
+
for remote_id in remote_ids:
|
|
22
|
+
if 'IMDB' in remote_id.get('sourceName').upper():
|
|
23
|
+
imdb_id = remote_id.get('id').lower().replace('tt', '')
|
|
24
|
+
score = ManageTitles.fuzzyit(str1=query, str2=title)
|
|
25
|
+
if score > 95:
|
|
26
|
+
return {'tvdb_id' : item.get('tvdb_id'), 'imdb_id': imdb_id}
|
|
27
|
+
return None
|
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.24"
|
|
17
17
|
|
|
18
18
|
if os.name == "nt":
|
|
19
19
|
PW_TORRENT_ARCHIVE_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "pw_torrent_archive"
|
|
@@ -63,6 +63,7 @@ class TrackerConfig(BaseModel):
|
|
|
63
63
|
SIS_PID: str | None = None
|
|
64
64
|
MULTI_TRACKER: list[str] | None = None
|
|
65
65
|
TMDB_APIKEY: str | None = None
|
|
66
|
+
TVDB_APIKEY: str | None = None
|
|
66
67
|
IMGBB_KEY: str | None = None
|
|
67
68
|
FREE_IMAGE_KEY: str | None = None
|
|
68
69
|
LENSDUMP_KEY: str | None = None
|
|
@@ -530,6 +531,7 @@ class Load:
|
|
|
530
531
|
"SIS_PID": "no_key",
|
|
531
532
|
"MULTI_TRACKER" : ["itt"],
|
|
532
533
|
"TMDB_APIKEY": "no_key",
|
|
534
|
+
"TVDB_APIKEY": "no_key",
|
|
533
535
|
"IMGBB_KEY": "no_key",
|
|
534
536
|
"FREE_IMAGE_KEY": "no_key",
|
|
535
537
|
"LENSDUMP_KEY": "no_key",
|
|
@@ -558,8 +560,7 @@ class Load:
|
|
|
558
560
|
"RTORR_PORT": "9091",
|
|
559
561
|
"SHARED_RTORR_PATH": "no_path",
|
|
560
562
|
"TORRENT_CLIENT": "qbittorrent",
|
|
561
|
-
"TAG": "ADDED TORRENTS"
|
|
562
|
-
"FAST_LOAD": "0",
|
|
563
|
+
"TAG": "ADDED TORRENTS"
|
|
563
564
|
},
|
|
564
565
|
"user_preferences": {
|
|
565
566
|
"PTSCREENS_PRIORITY": 0,
|
|
@@ -591,6 +592,7 @@ class Load:
|
|
|
591
592
|
"CACHE_SCR": "False",
|
|
592
593
|
"CACHE_DBONLINE": "False",
|
|
593
594
|
"PERSONAL_RELEASE": "False",
|
|
595
|
+
"FAST_LOAD": "0"
|
|
594
596
|
},
|
|
595
597
|
"options": {
|
|
596
598
|
"PW_API_KEY": "no_key",
|
common/utility.py
CHANGED
|
@@ -107,7 +107,9 @@ class ManageTitles:
|
|
|
107
107
|
"""
|
|
108
108
|
Replaces hyphens with dots and removes video resolutions
|
|
109
109
|
"""
|
|
110
|
-
resolutions = ["4320", "2160", "1080", "720", "576", "480"]
|
|
110
|
+
# resolutions = ["4320", "2160", "1080", "720", "576", "480"]
|
|
111
|
+
resolutions = ["4320p", "2160p", "1080p", "720p", "576p", "480p"]
|
|
112
|
+
|
|
111
113
|
subdir = subdir.replace("-", ".")
|
|
112
114
|
for res in resolutions:
|
|
113
115
|
subdir = subdir.replace(res, " ")
|
unit3dup/media.py
CHANGED
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
import re
|
|
4
4
|
|
|
5
5
|
from common.external_services.igdb.core.tags import crew_patterns, platform_patterns
|
|
6
|
+
from common.title import Guessit
|
|
6
7
|
from common.utility import ManageTitles, System
|
|
7
8
|
from common.mediainfo import MediaFile
|
|
8
9
|
from common import title
|
|
@@ -21,7 +22,7 @@ class Media:
|
|
|
21
22
|
self._platform_list: list[str] | None = None
|
|
22
23
|
self._title_sanitized: str | None = None
|
|
23
24
|
self._guess_title: str | None = None
|
|
24
|
-
self._guess_filename:
|
|
25
|
+
self._guess_filename: Guessit | None = None
|
|
25
26
|
self._guess_season: int | None = None
|
|
26
27
|
self._episode: str | None = None
|
|
27
28
|
self._source: str | None = None
|
|
@@ -49,6 +50,7 @@ class Media:
|
|
|
49
50
|
self._game_nfo: str | None = None
|
|
50
51
|
self._tmdb_id: int | None = None
|
|
51
52
|
self._imdb_id: int | None = None
|
|
53
|
+
self._tvdb_id: int | None = None
|
|
52
54
|
self._igdb_id: int | None = None
|
|
53
55
|
self._generate_title: str | None = None
|
|
54
56
|
|
|
@@ -158,6 +160,14 @@ class Media:
|
|
|
158
160
|
def imdb_id(self, value):
|
|
159
161
|
self._imdb_id = value
|
|
160
162
|
|
|
163
|
+
@property
|
|
164
|
+
def tvdb_id(self) -> int:
|
|
165
|
+
return self._tvdb_id
|
|
166
|
+
|
|
167
|
+
@tvdb_id.setter
|
|
168
|
+
def tvdb_id(self, value):
|
|
169
|
+
self._tvdb_id = value
|
|
170
|
+
|
|
161
171
|
@property
|
|
162
172
|
def igdb_id(self) -> int:
|
|
163
173
|
return self._igdb_id
|
|
@@ -34,6 +34,7 @@ class ContentManager:
|
|
|
34
34
|
self.doc_description: str | None = None
|
|
35
35
|
self.tmdb_id: int = 0
|
|
36
36
|
self.imdb_id: int = 0
|
|
37
|
+
self.tvdb_id: int = 0
|
|
37
38
|
self.igdb_id: int = 0
|
|
38
39
|
self.generate_title: str | None = None
|
|
39
40
|
|
|
@@ -85,6 +86,7 @@ class ContentManager:
|
|
|
85
86
|
|
|
86
87
|
# Add ID if there are one in the title
|
|
87
88
|
media.imdb_id = self.imdb_id
|
|
89
|
+
media.tvdb_id = self.tvdb_id
|
|
88
90
|
media.tmdb_id = self.tmdb_id
|
|
89
91
|
media.igdb_id = self.igdb_id
|
|
90
92
|
media.display_name = self.display_name
|
|
@@ -112,7 +114,10 @@ class ContentManager:
|
|
|
112
114
|
self.tmdb_id = id.replace('tmdb-', '')
|
|
113
115
|
self.tmdb_id = self.tmdb_id if self.tmdb_id.isdigit() else None
|
|
114
116
|
self.display_name = self.display_name.replace(f"tmdb-{self.tmdb_id}", '')
|
|
115
|
-
|
|
117
|
+
elif 'tvdb-' in id:
|
|
118
|
+
self.tvdb_id = id.replace('tvdb-', '')
|
|
119
|
+
self.tvdb_id = self.tvdb_id if self.tvdb_id.isdigit() else None
|
|
120
|
+
self.display_name = self.display_name.replace(f"tvdb-{self.tvdb_id}", '')
|
|
116
121
|
elif 'igdb-' in id:
|
|
117
122
|
self.igdb_id = id.replace('igdb-', '')
|
|
118
123
|
self.igdb_id = self.igdb_id if self.igdb_id.isdigit() else None
|
|
@@ -121,6 +126,7 @@ class ContentManager:
|
|
|
121
126
|
else:
|
|
122
127
|
self.imdb_id = 0
|
|
123
128
|
self.tmdb_id = 0
|
|
129
|
+
self.tvdb_id = 0
|
|
124
130
|
self.igdb_id = 0
|
|
125
131
|
|
|
126
132
|
def process_file(self) -> bool:
|
|
@@ -26,7 +26,7 @@ class VideoManager:
|
|
|
26
26
|
|
|
27
27
|
self.torrent_found:bool = False
|
|
28
28
|
self.contents: list[Media] = contents
|
|
29
|
-
self.cli: argparse = cli
|
|
29
|
+
self.cli: argparse.Namespace = cli
|
|
30
30
|
|
|
31
31
|
def process(self, selected_tracker: str, tracker_name_list: list, tracker_archive: str) -> list[BittorrentData]:
|
|
32
32
|
"""
|
|
@@ -90,6 +90,7 @@ class VideoManager:
|
|
|
90
90
|
# Get meta from the media video
|
|
91
91
|
video_info = Video(media=content, tmdb_id=db.video_id, trailer_key=db.trailer_key)
|
|
92
92
|
video_info.build_info()
|
|
93
|
+
|
|
93
94
|
# print the title will be shown on the torrent page
|
|
94
95
|
custom_console.bot_log(f"'DISPLAYNAME'...{{{content.display_name}}}\n")
|
|
95
96
|
|
|
@@ -97,8 +98,8 @@ class VideoManager:
|
|
|
97
98
|
unit3d_up = UploadBot(content=content, tracker_name=selected_tracker, cli = self.cli)
|
|
98
99
|
|
|
99
100
|
# Get the data
|
|
100
|
-
unit3d_up.data(show_id=db.video_id, imdb_id=db.imdb_id,
|
|
101
|
-
video_info=video_info)
|
|
101
|
+
unit3d_up.data(show_id=db.video_id, imdb_id=db.imdb_id, tvdb_id = db.tvdb_id,
|
|
102
|
+
show_keywords_list=db.keywords_list, video_info=video_info)
|
|
102
103
|
|
|
103
104
|
# Don't upload if -noup is set to True
|
|
104
105
|
if self.cli.noup:
|
unit3dup/pvtTracker.py
CHANGED
|
@@ -29,10 +29,10 @@ class Myhttp:
|
|
|
29
29
|
self.headers = {
|
|
30
30
|
"User-Agent": "Unit3D-up/0.0 (Linux 5.10.0-23-amd64)",
|
|
31
31
|
"Accept": "application/json",
|
|
32
|
+
"Authorization": f"Bearer {self.api_token}"
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
34
|
+
|
|
35
|
+
self.params = {}
|
|
36
36
|
|
|
37
37
|
self.data = {
|
|
38
38
|
"name": "TEST.torrent",
|
|
@@ -43,7 +43,7 @@ class Myhttp:
|
|
|
43
43
|
"resolution_id": 10, # mandatory
|
|
44
44
|
"tmdb": "", # mandatory
|
|
45
45
|
"imdb": "0",
|
|
46
|
-
"tvdb": "0",
|
|
46
|
+
"tvdb": "0",
|
|
47
47
|
"mal": "0", # no ancora implementato
|
|
48
48
|
"igdb": "0",
|
|
49
49
|
"anonymous": 0,
|
|
@@ -56,7 +56,6 @@ class Myhttp:
|
|
|
56
56
|
"free": 0,
|
|
57
57
|
"doubleup": 0,
|
|
58
58
|
"sticky": 0,
|
|
59
|
-
"torrent-cover": "", # no ancora implementato
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
|
unit3dup/upload.py
CHANGED
|
@@ -62,11 +62,13 @@ class UploadBot:
|
|
|
62
62
|
custom_console.rule()
|
|
63
63
|
return {}, error_message
|
|
64
64
|
|
|
65
|
-
def data(self,show_id: int , imdb_id: int, show_keywords_list: str, video_info: Video) -> Unit3d | None:
|
|
65
|
+
def data(self,show_id: int , imdb_id: int, tvdb_id: int, show_keywords_list: str, video_info: Video) -> Unit3d | None:
|
|
66
66
|
|
|
67
67
|
self.tracker.data["name"] = self.content.display_name
|
|
68
68
|
self.tracker.data["tmdb"] = show_id
|
|
69
69
|
self.tracker.data["imdb"] = imdb_id if imdb_id else 0
|
|
70
|
+
self.tracker.data["tvdb"] = tvdb_id if tvdb_id else None
|
|
71
|
+
|
|
70
72
|
self.tracker.data["keywords"] = show_keywords_list
|
|
71
73
|
self.tracker.data["category_id"] = self.tracker_data.category.get(self.content.category)
|
|
72
74
|
self.tracker.data["anonymous"] = int(config_settings.user_preferences.ANON)
|
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: Unit3Dup
|
|
3
|
-
Version: 0.8.
|
|
4
|
-
Summary: An uploader for the Unit3D torrent tracker
|
|
5
|
-
Author: Parzival
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/31December99/Unit3Dup
|
|
8
|
-
Requires-Python: >=3.10
|
|
9
|
-
Description-Content-Type: text/x-rst
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Requires-Dist: guessit==3.8.0
|
|
12
|
-
Requires-Dist: pymediainfo==6.1.0
|
|
13
|
-
Requires-Dist: python-qbittorrent==0.4.3
|
|
14
|
-
Requires-Dist: pydantic==2.10.6
|
|
15
|
-
Requires-Dist: requests==2.32.3
|
|
16
|
-
Requires-Dist: rich==13.7.1
|
|
17
|
-
Requires-Dist: torf==4.2.7
|
|
18
|
-
Requires-Dist: tqdm==4.66.5
|
|
19
|
-
Requires-Dist: thefuzz==0.22.1
|
|
20
|
-
Requires-Dist: unidecode==1.3.8
|
|
21
|
-
Requires-Dist: pillow==10.4.0
|
|
22
|
-
Requires-Dist: patool==2.4.0
|
|
23
|
-
Requires-Dist: diskcache==5.6.3
|
|
24
|
-
Requires-Dist: httpx==0.27.2
|
|
25
|
-
Requires-Dist: transmission-rpc==7.0.11
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Dynamic: license-file
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**Hi !**
|
|
34
|
-
===============================================
|
|
35
|
-
|version| |online| |status| |python| |ubuntu| |debian| |windows|
|
|
36
|
-
|
|
37
|
-
.. |version| image:: https://img.shields.io/pypi/v/unit3dup.svg
|
|
38
|
-
.. |online| image:: https://img.shields.io/badge/Online-green
|
|
39
|
-
.. |status| image:: https://img.shields.io/badge/Status-Active-brightgreen
|
|
40
|
-
.. |python| image:: https://img.shields.io/badge/Python-3.10+-blue
|
|
41
|
-
.. |ubuntu| image:: https://img.shields.io/badge/Ubuntu-22-blue
|
|
42
|
-
.. |debian| image:: https://img.shields.io/badge/Debian-12-blue
|
|
43
|
-
.. |windows| image:: https://img.shields.io/badge/Windows-10-blue
|
|
44
|
-
|
|
45
|
-
Auto Torrent Generator and Uploader
|
|
46
|
-
===================================
|
|
47
|
-
|
|
48
|
-
This Python script generates and uploads torrents based on input provided for movies or TV series and Games.
|
|
49
|
-
|
|
50
|
-
It performs the following tasks:
|
|
51
|
-
|
|
52
|
-
- Scan folder and subfolders
|
|
53
|
-
- Compiles various metadata information to create a torrent
|
|
54
|
-
- Extracts a series of screenshots directly from the video
|
|
55
|
-
- Add webp to your torrent description page
|
|
56
|
-
- Extracts cover from the PDF documents
|
|
57
|
-
- Generates meta-info derived from the video or game
|
|
58
|
-
- Searches for the corresponding ID on TMDB, IGDB
|
|
59
|
-
- Add trailer from TMDB or YouTube
|
|
60
|
-
- Seeding in qBittorrent, Transmission or rTorrent
|
|
61
|
-
- Reseeding one or more torrents at a time
|
|
62
|
-
- Seed your torrents across different OS
|
|
63
|
-
- Add a custom title to your seasons
|
|
64
|
-
- Generate info for a title using MediaInfo
|
|
65
|
-
|
|
66
|
-
unit3dup can grab the first page, convert it to an image (using xpdf),
|
|
67
|
-
and then the bot can upload it to an image host, then add the link to the torrent page description.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Install and Upgrade
|
|
71
|
-
===================
|
|
72
|
-
|
|
73
|
-
- pip install unit3dup --upgrade
|
|
74
|
-
|
|
75
|
-
Windows Dependencies
|
|
76
|
-
--------------------
|
|
77
|
-
1. Download and unzip https://www.ffmpeg.org/download.html and add its folder to
|
|
78
|
-
PATH environment user variable
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Only for pdf
|
|
82
|
-
~~~~~~~~~~~~
|
|
83
|
-
1. Download and unzip poppler for Windows from https://github.com/oschwartz10612/poppler-windows/releases
|
|
84
|
-
2. Put the folder 'bin' in the system path (e.g. ``C:\poppler-24.08.0\Library\bin``)
|
|
85
|
-
3. *Close and reopen a new console window*
|
|
86
|
-
4. Test it: Run ``pdftocairo`` in the terminal
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Ubuntu/Debian Dependencies
|
|
90
|
-
--------------------------
|
|
91
|
-
- sudo apt install ffmpeg
|
|
92
|
-
|
|
93
|
-
Only for pdf
|
|
94
|
-
~~~~~~~~~~~~
|
|
95
|
-
- sudo apt install poppler-utils
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
RUN
|
|
99
|
-
======
|
|
100
|
-
|
|
101
|
-
.. code-block:: python
|
|
102
|
-
|
|
103
|
-
unit3dup -u <filepath>
|
|
104
|
-
unit3dup -f <folderpath>
|
|
105
|
-
unit3dup -scan <folderpath>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
DOC
|
|
110
|
-
===
|
|
111
|
-
|
|
112
|
-
Link `Unit3DUP <https://unit3dup.readthedocs.io/en/latest/index.html#>`_
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
ImageHost
|
|
116
|
-
=========
|
|
117
|
-
|
|
118
|
-
The bot can upload images to the following image hosting platforms:
|
|
119
|
-
|
|
120
|
-
+------------------+----------------------------+
|
|
121
|
-
| **Image Host** | **URL** |
|
|
122
|
-
+==================+============================+
|
|
123
|
-
| ``ImgBB`` | https://imgbb.com |
|
|
124
|
-
+------------------+----------------------------+
|
|
125
|
-
| ``FreeImage`` | https://freeimage.host |
|
|
126
|
-
+------------------+----------------------------+
|
|
127
|
-
| ``PtScreens`` | https://ptscreens.com |
|
|
128
|
-
+------------------+----------------------------+
|
|
129
|
-
| ``LensDump`` | https://lensdump.com |
|
|
130
|
-
+------------------+----------------------------+
|
|
131
|
-
| ``ImgFI`` | https://imgfi.com |
|
|
132
|
-
+------------------+----------------------------+
|
|
133
|
-
| ``PassIMA`` | https://passtheima.ge |
|
|
134
|
-
+------------------+----------------------------+
|
|
135
|
-
| ``ImaRide`` | https://www.imageride.net |
|
|
136
|
-
+------------------+----------------------------+
|
|
137
|
-
|
|
138
|
-
Trackers
|
|
139
|
-
========
|
|
140
|
-
|
|
141
|
-
The Italian tracker: a multitude of people from diverse technical and social backgrounds,
|
|
142
|
-
united by a shared passion for torrents and more
|
|
143
|
-
|
|
144
|
-
+------------------+----------------------------+
|
|
145
|
-
| **Trackers** | **Description** |
|
|
146
|
-
+==================+============================+
|
|
147
|
-
| ``ITT`` | https://itatorrents.xyz/ |
|
|
148
|
-
+------------------+----------------------------+
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
.. image:: https://img.shields.io/badge/Telegram-Join-blue?logo=telegram
|
|
152
|
-
:target: https://t.me/+hj294GabGWJlMDI8
|
|
153
|
-
:alt: Unisciti su Telegram
|
|
154
|
-
|
|
155
|
-
.. image:: https://img.shields.io/discord/1214696147600408698?label=Discord&logo=discord&style=flat
|
|
156
|
-
:target: https://discord.gg/Skvune9P
|
|
157
|
-
:alt: Discord Server
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
🎯 Streaming Community
|
|
162
|
-
======================
|
|
163
|
-
|
|
164
|
-
`goto GitHub Project <https://github.com/Arrowar/StreamingCommunity>`_
|
|
165
|
-
|
|
166
|
-
An open-source script for downloading movies, TV shows, and anime from various websites,
|
|
167
|
-
built by a community of people with a shared interest in programming.
|
|
168
|
-
|
|
169
|
-
.. image:: https://img.shields.io/badge/Telegram-Join-blue?logo=telegram
|
|
170
|
-
:target: https://t.me/+hj294GabGWJlMDI8
|
|
171
|
-
:alt: Unisciti su Telegram
|
|
172
|
-
|
|
173
|
-
.. image:: https://img.shields.io/badge/StreamingCommunity-blue.svg
|
|
174
|
-
:target: https://github.com/Arrowar/StreamingCommunity
|
|
175
|
-
:alt: StreamingCommunity Badge
|
|
176
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: Unit3Dup
|
|
3
|
+
Version: 0.8.24
|
|
4
|
+
Summary: An uploader for the Unit3D torrent tracker
|
|
5
|
+
Author: Parzival
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/31December99/Unit3Dup
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/x-rst
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: guessit==3.8.0
|
|
12
|
+
Requires-Dist: pymediainfo==6.1.0
|
|
13
|
+
Requires-Dist: python-qbittorrent==0.4.3
|
|
14
|
+
Requires-Dist: pydantic==2.10.6
|
|
15
|
+
Requires-Dist: requests==2.32.3
|
|
16
|
+
Requires-Dist: rich==13.7.1
|
|
17
|
+
Requires-Dist: torf==4.2.7
|
|
18
|
+
Requires-Dist: tqdm==4.66.5
|
|
19
|
+
Requires-Dist: thefuzz==0.22.1
|
|
20
|
+
Requires-Dist: unidecode==1.3.8
|
|
21
|
+
Requires-Dist: pillow==10.4.0
|
|
22
|
+
Requires-Dist: patool==2.4.0
|
|
23
|
+
Requires-Dist: diskcache==5.6.3
|
|
24
|
+
Requires-Dist: httpx==0.27.2
|
|
25
|
+
Requires-Dist: transmission-rpc==7.0.11
|
|
26
|
+
Requires-Dist: pathvalidate==3.2.3
|
|
27
|
+
Requires-Dist: bencode2==0.3.24
|
|
28
|
+
Requires-Dist: rtorrent-rpc==0.9.4
|
|
29
|
+
Requires-Dist: tvdb_v4_official==1.1.0
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
**Hi !**
|
|
34
|
+
===============================================
|
|
35
|
+
|version| |online| |status| |python| |ubuntu| |debian| |windows|
|
|
36
|
+
|
|
37
|
+
.. |version| image:: https://img.shields.io/pypi/v/unit3dup.svg
|
|
38
|
+
.. |online| image:: https://img.shields.io/badge/Online-green
|
|
39
|
+
.. |status| image:: https://img.shields.io/badge/Status-Active-brightgreen
|
|
40
|
+
.. |python| image:: https://img.shields.io/badge/Python-3.10+-blue
|
|
41
|
+
.. |ubuntu| image:: https://img.shields.io/badge/Ubuntu-22-blue
|
|
42
|
+
.. |debian| image:: https://img.shields.io/badge/Debian-12-blue
|
|
43
|
+
.. |windows| image:: https://img.shields.io/badge/Windows-10-blue
|
|
44
|
+
|
|
45
|
+
Auto Torrent Generator and Uploader
|
|
46
|
+
===================================
|
|
47
|
+
|
|
48
|
+
This Python script generates and uploads torrents based on input provided for movies or TV series and Games.
|
|
49
|
+
|
|
50
|
+
It performs the following tasks:
|
|
51
|
+
|
|
52
|
+
- Scan folder and subfolders
|
|
53
|
+
- Compiles various metadata information to create a torrent
|
|
54
|
+
- Extracts a series of screenshots directly from the video
|
|
55
|
+
- Add webp to your torrent description page
|
|
56
|
+
- Extracts cover from the PDF documents
|
|
57
|
+
- Generates meta-info derived from the video or game
|
|
58
|
+
- Searches for the corresponding ID on TMDB, IGDB, IMDB,TVDB
|
|
59
|
+
- Add trailer from TMDB or YouTube
|
|
60
|
+
- Seeding in qBittorrent, Transmission or rTorrent
|
|
61
|
+
- Reseeding one or more torrents at a time
|
|
62
|
+
- Seed your torrents across different OS
|
|
63
|
+
- Add a custom title to your seasons
|
|
64
|
+
- Generate info for a title using MediaInfo
|
|
65
|
+
|
|
66
|
+
unit3dup can grab the first page, convert it to an image (using xpdf),
|
|
67
|
+
and then the bot can upload it to an image host, then add the link to the torrent page description.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Install and Upgrade
|
|
71
|
+
===================
|
|
72
|
+
|
|
73
|
+
- pip install unit3dup --upgrade
|
|
74
|
+
|
|
75
|
+
Windows Dependencies
|
|
76
|
+
--------------------
|
|
77
|
+
1. Download and unzip https://www.ffmpeg.org/download.html and add its folder to
|
|
78
|
+
PATH environment user variable
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
Only for pdf
|
|
82
|
+
~~~~~~~~~~~~
|
|
83
|
+
1. Download and unzip poppler for Windows from https://github.com/oschwartz10612/poppler-windows/releases
|
|
84
|
+
2. Put the folder 'bin' in the system path (e.g. ``C:\poppler-24.08.0\Library\bin``)
|
|
85
|
+
3. *Close and reopen a new console window*
|
|
86
|
+
4. Test it: Run ``pdftocairo`` in the terminal
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
Ubuntu/Debian Dependencies
|
|
90
|
+
--------------------------
|
|
91
|
+
- sudo apt install ffmpeg
|
|
92
|
+
|
|
93
|
+
Only for pdf
|
|
94
|
+
~~~~~~~~~~~~
|
|
95
|
+
- sudo apt install poppler-utils
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
RUN
|
|
99
|
+
======
|
|
100
|
+
|
|
101
|
+
.. code-block:: python
|
|
102
|
+
|
|
103
|
+
unit3dup -u <filepath>
|
|
104
|
+
unit3dup -f <folderpath>
|
|
105
|
+
unit3dup -scan <folderpath>
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
DOC
|
|
110
|
+
===
|
|
111
|
+
|
|
112
|
+
Link `Unit3DUP <https://unit3dup.readthedocs.io/en/latest/index.html#>`_
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
ImageHost
|
|
116
|
+
=========
|
|
117
|
+
|
|
118
|
+
The bot can upload images to the following image hosting platforms:
|
|
119
|
+
|
|
120
|
+
+------------------+----------------------------+
|
|
121
|
+
| **Image Host** | **URL** |
|
|
122
|
+
+==================+============================+
|
|
123
|
+
| ``ImgBB`` | https://imgbb.com |
|
|
124
|
+
+------------------+----------------------------+
|
|
125
|
+
| ``FreeImage`` | https://freeimage.host |
|
|
126
|
+
+------------------+----------------------------+
|
|
127
|
+
| ``PtScreens`` | https://ptscreens.com |
|
|
128
|
+
+------------------+----------------------------+
|
|
129
|
+
| ``LensDump`` | https://lensdump.com |
|
|
130
|
+
+------------------+----------------------------+
|
|
131
|
+
| ``ImgFI`` | https://imgfi.com |
|
|
132
|
+
+------------------+----------------------------+
|
|
133
|
+
| ``PassIMA`` | https://passtheima.ge |
|
|
134
|
+
+------------------+----------------------------+
|
|
135
|
+
| ``ImaRide`` | https://www.imageride.net |
|
|
136
|
+
+------------------+----------------------------+
|
|
137
|
+
|
|
138
|
+
Trackers
|
|
139
|
+
========
|
|
140
|
+
|
|
141
|
+
The Italian tracker: a multitude of people from diverse technical and social backgrounds,
|
|
142
|
+
united by a shared passion for torrents and more
|
|
143
|
+
|
|
144
|
+
+------------------+----------------------------+
|
|
145
|
+
| **Trackers** | **Description** |
|
|
146
|
+
+==================+============================+
|
|
147
|
+
| ``ITT`` | https://itatorrents.xyz/ |
|
|
148
|
+
+------------------+----------------------------+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
.. image:: https://img.shields.io/badge/Telegram-Join-blue?logo=telegram
|
|
152
|
+
:target: https://t.me/+hj294GabGWJlMDI8
|
|
153
|
+
:alt: Unisciti su Telegram
|
|
154
|
+
|
|
155
|
+
.. image:: https://img.shields.io/discord/1214696147600408698?label=Discord&logo=discord&style=flat
|
|
156
|
+
:target: https://discord.gg/Skvune9P
|
|
157
|
+
:alt: Discord Server
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
🎯 Streaming Community
|
|
162
|
+
======================
|
|
163
|
+
|
|
164
|
+
`goto GitHub Project <https://github.com/Arrowar/StreamingCommunity>`_
|
|
165
|
+
|
|
166
|
+
An open-source script for downloading movies, TV shows, and anime from various websites,
|
|
167
|
+
built by a community of people with a shared interest in programming.
|
|
168
|
+
|
|
169
|
+
.. image:: https://img.shields.io/badge/Telegram-Join-blue?logo=telegram
|
|
170
|
+
:target: https://t.me/+hj294GabGWJlMDI8
|
|
171
|
+
:alt: Unisciti su Telegram
|
|
172
|
+
|
|
173
|
+
.. image:: https://img.shields.io/badge/StreamingCommunity-blue.svg
|
|
174
|
+
:target: https://github.com/Arrowar/StreamingCommunity
|
|
175
|
+
:alt: StreamingCommunity Badge
|
|
176
|
+
|
|
@@ -8,14 +8,15 @@ 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=IJ1Mh2zTZDdcF4bs5H8dnGlTAwuIDTJdnNVE25xZXvY,33148
|
|
12
12
|
common/title.py,sha256=nFainfUBTYW9ML4Y-CB9ZFD_Es-OZXcAMPUo6D09u3k,3793
|
|
13
13
|
common/torrent_clients.py,sha256=NOIpYtLG_bA19HwcH9ahGFmGNtRkoMO6nAjma-JzDfs,12040
|
|
14
|
-
common/utility.py,sha256=
|
|
14
|
+
common/utility.py,sha256=QV_kVjUJ1GQ67fH3UB-zwqh6_5aHhinqLVMR0kaPG1w,9050
|
|
15
15
|
common/external_services/__init__.py,sha256=rU7HPEcZ7WQFD8eqDzuye2xHPBjxXPwPqpt7IT08mkM,178
|
|
16
16
|
common/external_services/imageHost.py,sha256=00sVVmSFQD0AE1I8batCJQUxNn734NpNz8p1qDWyzHc,10215
|
|
17
|
-
common/external_services/imdb.py,sha256=
|
|
18
|
-
common/external_services/mediaresult.py,sha256=
|
|
17
|
+
common/external_services/imdb.py,sha256=oqD2qKJVUjUDkhL2gT8kie_8St1_UMe5YpDixpzpXTM,588
|
|
18
|
+
common/external_services/mediaresult.py,sha256=x5Kb6dCZKACV-xkQ7un8cuTU7-3EyKreS32MGhFnj5s,725
|
|
19
|
+
common/external_services/tvdb.py,sha256=qnlAG6Snbln80fXlaRl3dDuvGA5fS7x_luJksQFHvZA,1076
|
|
19
20
|
common/external_services/ftpx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
21
|
common/external_services/ftpx/client.py,sha256=D_23Cw9zeQQIiVhUIUE13ENXNVyP4-MMx_Rgqg67U7Y,10713
|
|
21
22
|
common/external_services/ftpx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -38,7 +39,7 @@ common/external_services/sessions/exceptions.py,sha256=s3jpm-LiIJvGFa-Vr9cU09qJ9
|
|
|
38
39
|
common/external_services/sessions/session.py,sha256=DFqcIKQAEJrJ5bOEBxbnxbDrxEx31nmS_NjCYMmJ7EQ,4877
|
|
39
40
|
common/external_services/theMovieDB/__init__.py,sha256=uBRzseXxb-L4XS6Np548FlWrSwVTQcTwLkOca9cuDyc,82
|
|
40
41
|
common/external_services/theMovieDB/core/__init__.py,sha256=37I0EaaHJEfnVUHmswZwJtEOvI929Cel9p15VJjhF_k,16
|
|
41
|
-
common/external_services/theMovieDB/core/api.py,sha256=
|
|
42
|
+
common/external_services/theMovieDB/core/api.py,sha256=UN6kZ4WJKDmoGGqJ9_P1EElzRYJf-wi05HLt-a7MT8Y,19412
|
|
42
43
|
common/external_services/theMovieDB/core/keywords.py,sha256=hGm4-iUU32LlrTlNO4DnUl3a0lknaMYVymcuk8k38G0,118
|
|
43
44
|
common/external_services/theMovieDB/core/videos.py,sha256=K3unERRMTKpSJTwhvboRHUQHhxTdreTWIxJOrfzDnTs,329
|
|
44
45
|
common/external_services/theMovieDB/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -68,30 +69,30 @@ unit3dup/automode.py,sha256=JbHIvK5mHbNxpq_m5o26FEpqEUlL9XbTyUUPvKD6EqQ,4412
|
|
|
68
69
|
unit3dup/bot.py,sha256=2P24z_8UM58binKqrM0eIXxPTiWEduyK2bdfVkmxPEQ,8759
|
|
69
70
|
unit3dup/duplicate.py,sha256=0soPxYGTB6P5tb-iIUbZTdcI0-8CJntzoG5PnKNJ1vg,10437
|
|
70
71
|
unit3dup/exceptions.py,sha256=DhlcbbZEuvEYk5VSZTnle8oRg5I8Pq6Y6fxXTdOOOfo,4078
|
|
71
|
-
unit3dup/media.py,sha256=
|
|
72
|
+
unit3dup/media.py,sha256=nd2Wf78EN-eyoK6-OugvCcdDw6KtSkTU7MEpM4QR8qw,13920
|
|
72
73
|
unit3dup/pvtDocu.py,sha256=ZLMaal2fn6ZcFPLtET0LTmYEPjhJmLitEjkICHrm9CQ,4594
|
|
73
74
|
unit3dup/pvtTorrent.py,sha256=cItlsCpcUJL23iXQHy0YzrrvV3JSl54UlBgm8_UROAs,2559
|
|
74
|
-
unit3dup/pvtTracker.py,sha256=
|
|
75
|
+
unit3dup/pvtTracker.py,sha256=p5a1GoYcWqDQ1iiaFwVwAchRSXGbGaycm4QGHhw35fI,18611
|
|
75
76
|
unit3dup/pvtVideo.py,sha256=HZbkk1GiCFe6g7e0UPoOc5VGzRaTsViNnU1SCuijkIs,3944
|
|
76
77
|
unit3dup/torrent.py,sha256=surV0royo_GCEvdlPIP1S9gvFvJb1u26XM11rZOGVEg,20064
|
|
77
|
-
unit3dup/upload.py,sha256=
|
|
78
|
-
unit3dup/media_manager/ContentManager.py,sha256
|
|
78
|
+
unit3dup/upload.py,sha256=cXK1yXOH73wz62ghy7OEeDsp4dtxf_bYR69QmQn9NpM,6694
|
|
79
|
+
unit3dup/media_manager/ContentManager.py,sha256=fj0ftb64LkI7yZQ4L9S4AW76Vf28vk8RoEV3eI4h_qc,8012
|
|
79
80
|
unit3dup/media_manager/DocuManager.py,sha256=oFt7jlxj-gIUty9PADBQV5a24bsv3yhjKhwI6niOhf4,3116
|
|
80
81
|
unit3dup/media_manager/GameManager.py,sha256=9EmPeNrirOwaVOj-vkLr29Xo7daIA4ssqrrt0WyMl30,4090
|
|
81
82
|
unit3dup/media_manager/MediaInfoManager.py,sha256=0NO9dgD7seJM67B3DRnwvRIdoy7bfquBUox-PnHInK8,1081
|
|
82
83
|
unit3dup/media_manager/SeedManager.py,sha256=Vqpf_xpGbxsJHg0C3-kL0_tdF4f2FRPlZH7UpnmAE3g,1912
|
|
83
84
|
unit3dup/media_manager/TorrentManager.py,sha256=qqM1d1TyfBuruXtKLRbQ8gFk3_2JNH9dOa6Yg-QnDCw,6507
|
|
84
|
-
unit3dup/media_manager/VideoManager.py,sha256=
|
|
85
|
+
unit3dup/media_manager/VideoManager.py,sha256=SHhchcVoID2JnCP7oXp8TcDFJDFDUk_CQylW2YLy31c,5471
|
|
85
86
|
unit3dup/media_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
87
|
unit3dup/media_manager/common.py,sha256=EDsD1FVNiWPS9teHs5vyGkYkC92gzFdSanMyMAR5vpU,10147
|
|
87
88
|
unit3dup/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
89
|
unit3dup/web/main.py,sha256=BzjKDgAjKZMnoQwx7nDDbs_64kCrFO1VYpbHmsGiFVc,1267
|
|
89
|
-
unit3dup-0.8.
|
|
90
|
+
unit3dup-0.8.24.dist-info/licenses/LICENSE,sha256=GNAZDLhU0xz8QPbIyHAOYlVnQYDvKWk2N9fZJMhqaG8,1090
|
|
90
91
|
view/__init__.py,sha256=XIzb6rl58HmYPnksD73cYMFF88dn6FHa3u7bOHFbChk,81
|
|
91
92
|
view/custom_console.py,sha256=OITmkEoQH9N_uE5ElPaSdc8XvaLzE9wcwTbOHtcMvrI,5629
|
|
92
93
|
view/web_console.py,sha256=YkxutJK5GqswMKEF77EllphPYQW0eb8OIBlplucHhvM,7697
|
|
93
|
-
unit3dup-0.8.
|
|
94
|
-
unit3dup-0.8.
|
|
95
|
-
unit3dup-0.8.
|
|
96
|
-
unit3dup-0.8.
|
|
97
|
-
unit3dup-0.8.
|
|
94
|
+
unit3dup-0.8.24.dist-info/METADATA,sha256=nWDki-S6GSthm4FV3867IQ__e-HyLbLafr-Nu15-6EE,5656
|
|
95
|
+
unit3dup-0.8.24.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
96
|
+
unit3dup-0.8.24.dist-info/entry_points.txt,sha256=fxXSyI6-r6jy9_v-C5ZHm03q1aC3tE9EvCQZxC1NQnI,52
|
|
97
|
+
unit3dup-0.8.24.dist-info/top_level.txt,sha256=19NVMnQNkJxBUKebRNaYCRs56A5CO4U1L67GMQCPiLU,21
|
|
98
|
+
unit3dup-0.8.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|