ittup 1.2.2__tar.gz → 1.3.0__tar.gz
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.
- {ittup-1.2.2 → ittup-1.3.0}/PKG-INFO +1 -1
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/mediaresult.py +8 -4
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/api.py +13 -1
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/tags.py +68 -12
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/bot.py +10 -4
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/DocuManager.py +4 -4
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/GameManager.py +4 -5
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/VideoManager.py +7 -3
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/PKG-INFO +1 -1
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/SOURCES.txt +1 -0
- {ittup-1.2.2 → ittup-1.3.0}/pyproject.toml +1 -1
- ittup-1.3.0/tests/test_acodec.py +85 -0
- {ittup-1.2.2 → ittup-1.3.0}/LICENSE +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/README.rst +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/__main__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/about.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/bdinfo_string.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/bittorrent.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/command.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/constants.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/database.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/client.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/ftpx_service.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/ftpx_session.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/menu.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/models/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/ftpx/core/models/list.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/client.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/api.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/models/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/models/search.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/platformid.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/igdb/core/tags.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/imageHost.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/sessions/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/sessions/agents.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/sessions/exceptions.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/sessions/session.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/keywords.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/alternative.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/details.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/movie.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/nowplaying.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/release_info.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/translations.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/alternative.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/details.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/on_the_air.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/translations.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/tvshow.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/videos.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/trailers/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/trailers/api.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/trailers/response.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/tvdb.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/extractor.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/frames.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/mediainfo.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/mediainfo_string.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/settings.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/title.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/torrent_clients.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/ban_list.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/data.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/itt.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/signs_list.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/tags_list.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/trackers/trackers.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/common/utility.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/__main__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/automode.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/duplicate.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/exceptions.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/ContentManager.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/MediaInfoManager.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/SeedManager.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/TorrentManager.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/media_manager/common.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/pvtDocu.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/pvtTorrent.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/pvtTracker.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/pvtVideo.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/torrent.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/core/upload.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/view/__init__.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup/view/custom_console.py +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/dependency_links.txt +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/entry_points.txt +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/requires.txt +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/ittup.egg-info/top_level.txt +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/requirements.txt +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/setup.cfg +0 -0
- {ittup-1.2.2 → ittup-1.3.0}/tests/test_vcodec.py +0 -0
|
@@ -4,8 +4,9 @@ from datetime import datetime
|
|
|
4
4
|
|
|
5
5
|
class MediaResult:
|
|
6
6
|
def __init__(self, result=None, video_id: int = 0, imdb_id = None, tvdb_id = None, trailer_key: str = None,
|
|
7
|
-
keywords_list: str = None, season_title = None):
|
|
7
|
+
keywords_list: str = None, season_title = None, original_language: str = None):
|
|
8
8
|
self.result = result
|
|
9
|
+
self._original_language = original_language
|
|
9
10
|
self.trailer_key = trailer_key
|
|
10
11
|
self.keywords_list = keywords_list
|
|
11
12
|
self.video_id = video_id
|
|
@@ -20,6 +21,9 @@ class MediaResult:
|
|
|
20
21
|
except ValueError:
|
|
21
22
|
pass
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
@property
|
|
25
|
+
def original_language(self) -> str | None:
|
|
26
|
+
""" TMDB original language (ISO 639-1, es. 'en'), None when unknown """
|
|
27
|
+
# Results cached by older versions have no _original_language
|
|
28
|
+
return (getattr(self, '_original_language', None) or getattr(self.result, 'original_language', None)
|
|
29
|
+
or None)
|
|
@@ -235,6 +235,15 @@ class TmdbAPI(MyHttp):
|
|
|
235
235
|
return results[0].get('id')
|
|
236
236
|
return None
|
|
237
237
|
|
|
238
|
+
def original_language(self, video_id: int, category: str) -> str | None:
|
|
239
|
+
""" Original language (ISO 639-1) of the movie or tv show """
|
|
240
|
+
if endpoint_class := self.ENDPOINTS.get(category):
|
|
241
|
+
request = {**endpoint_class.details(video_id), 'datatype': dict}
|
|
242
|
+
response = self.request(endpoint=request)
|
|
243
|
+
if response:
|
|
244
|
+
return response[0].get('original_language') or None
|
|
245
|
+
return None
|
|
246
|
+
|
|
238
247
|
def external_ids(self, video_id: int, category: str) -> dict | None:
|
|
239
248
|
if endpoint_class := self.ENDPOINTS.get(category):
|
|
240
249
|
request = endpoint_class.external_ids(video_id)
|
|
@@ -406,7 +415,9 @@ class DbOnline(TmdbAPI):
|
|
|
406
415
|
if not tmdb_id:
|
|
407
416
|
custom_console.bot_warning_log(f"TMDB ID not found for IMDB ID '{imdb_id}'")
|
|
408
417
|
|
|
418
|
+
original_language = None
|
|
409
419
|
if tmdb_id > 0:
|
|
420
|
+
original_language = self.original_language(video_id=tmdb_id, category=self.category)
|
|
410
421
|
# Fill the IDs missing from the title string
|
|
411
422
|
self.add_external_ids(tmdb_id)
|
|
412
423
|
# Request trailer and keywords
|
|
@@ -414,7 +425,8 @@ class DbOnline(TmdbAPI):
|
|
|
414
425
|
keywords_list = self.keywords(tmdb_id) if trailer_key else ''
|
|
415
426
|
|
|
416
427
|
search_results = MediaResult(video_id=tmdb_id, imdb_id=self.imdb_id, tvdb_id=self.tvdb_id,
|
|
417
|
-
trailer_key=trailer_key, keywords_list=keywords_list
|
|
428
|
+
trailer_key=trailer_key, keywords_list=keywords_list,
|
|
429
|
+
original_language=original_language)
|
|
418
430
|
self.print_results(results=search_results)
|
|
419
431
|
return search_results
|
|
420
432
|
|
|
@@ -46,6 +46,14 @@ audio_translate = {
|
|
|
46
46
|
"MPEG Audio": "MPEG",
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
# Audio codecs from the best to the worst: only the best ones go in the title
|
|
50
|
+
audio_rank = ["TrueHD", "DTS-HD MA", "FLAC", "PCM", "DTS-ES", "DTS", "DD+", "DD", "AAC", "HE-AAC", "Opus", "MPEG"]
|
|
51
|
+
# The title keeps the best ITA codec and the best codec in the original language, then fills up to
|
|
52
|
+
# MAX_AUDIO_CODECS with the tracks with no language. Tracks in other languages only add their flag
|
|
53
|
+
MAX_AUDIO_CODECS = 2
|
|
54
|
+
# Original language (TMDB ISO 639-1) when it is not known yet
|
|
55
|
+
DEFAULT_ORIGINAL_LANGUAGE = "en"
|
|
56
|
+
|
|
49
57
|
# Codec family from the MediaInfo 'format' of the video track
|
|
50
58
|
video_family = {
|
|
51
59
|
"AVC": "264",
|
|
@@ -97,6 +105,7 @@ class SearchTags(object):
|
|
|
97
105
|
self.tags_dict = {}
|
|
98
106
|
self.release_type: str | None = None
|
|
99
107
|
self.name_family: str | None = None
|
|
108
|
+
self.original_language: str = DEFAULT_ORIGINAL_LANGUAGE
|
|
100
109
|
|
|
101
110
|
self.TAG_TYPES: dict = tags_list
|
|
102
111
|
self.SIGNS_LIST: dict = sign_list
|
|
@@ -267,6 +276,18 @@ class SearchTags(object):
|
|
|
267
276
|
# try to detect a known sign from SIGN_LIST
|
|
268
277
|
self.releaser_sign = self.detect_releaser(self.filename, self.SIGNS_LIST)
|
|
269
278
|
|
|
279
|
+
return self.ordered_title()
|
|
280
|
+
|
|
281
|
+
def set_original_language(self, original_language: str | None) -> tuple[str, dict]:
|
|
282
|
+
"""
|
|
283
|
+
Rebuild the audio tags of the title processed before with the original language from TMDB (es. 'ja')
|
|
284
|
+
"""
|
|
285
|
+
self.original_language = (original_language or DEFAULT_ORIGINAL_LANGUAGE).lower()
|
|
286
|
+
if "acodec" in self.tags_position:
|
|
287
|
+
self.tags_dict.update(self.mediainfo_audio(category="acodec"))
|
|
288
|
+
return self.ordered_title()
|
|
289
|
+
|
|
290
|
+
def ordered_title(self) -> tuple[str, dict]:
|
|
270
291
|
# /// Order according to tag position
|
|
271
292
|
tags_dict = {
|
|
272
293
|
k: self.tags_dict[k]
|
|
@@ -276,11 +297,38 @@ class SearchTags(object):
|
|
|
276
297
|
new_title = self.build_title(tags_dict)
|
|
277
298
|
return new_title, tags_dict
|
|
278
299
|
|
|
300
|
+
@staticmethod
|
|
301
|
+
def audio_language(audio: dict) -> str | None:
|
|
302
|
+
"""
|
|
303
|
+
ISO alpha-3 language of an audio track, None when it is not tagged
|
|
304
|
+
"""
|
|
305
|
+
for l in audio.get('other_language', []):
|
|
306
|
+
c = ManageTitles.convert_iso(l)
|
|
307
|
+
if c:
|
|
308
|
+
return c[0] if isinstance(c, list) else c
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
@staticmethod
|
|
312
|
+
def audio_score(codec: str, atmos: bool, channel_s: int) -> tuple:
|
|
313
|
+
"""
|
|
314
|
+
Sort key of an audio track: codec, then Atmos, then channels
|
|
315
|
+
"""
|
|
316
|
+
rank = len(audio_rank) - audio_rank.index(codec) if codec in audio_rank else 0
|
|
317
|
+
return rank, atmos, channel_s
|
|
318
|
+
|
|
319
|
+
def is_original_language(self, audio: dict) -> bool:
|
|
320
|
+
codes = [str(code).lower() for code in audio.get('other_language', []) + [audio.get('language') or '']]
|
|
321
|
+
return self.original_language in codes
|
|
322
|
+
|
|
279
323
|
def mediainfo_audio(self, category: str) -> dict:
|
|
280
324
|
languages = []
|
|
281
|
-
|
|
325
|
+
original_languages = []
|
|
326
|
+
# [(score, label, language, original language)]
|
|
327
|
+
tracks = []
|
|
282
328
|
if self.mediafile.audio_track:
|
|
283
329
|
for audio in self.mediafile.audio_track:
|
|
330
|
+
language = self.audio_language(audio)
|
|
331
|
+
original = self.is_original_language(audio)
|
|
284
332
|
other_format = audio.get('other_format', [])
|
|
285
333
|
if other_format:
|
|
286
334
|
codec_translated = audio_translate.get(other_format[0], '')
|
|
@@ -293,24 +341,32 @@ class SearchTags(object):
|
|
|
293
341
|
channel_s = audio.get('channel_s', 0)
|
|
294
342
|
# Add channels
|
|
295
343
|
ch = {2: "2.0", 6: "5.1", 8: "7.1"}.get(channel_s, "")
|
|
296
|
-
|
|
297
|
-
|
|
344
|
+
tracks.append((self.audio_score(codec_translated, bool(atmos), channel_s),
|
|
345
|
+
f"{codec_translated} {ch} {atmos}".strip(), language, original))
|
|
298
346
|
|
|
299
347
|
# Add flags
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if
|
|
303
|
-
|
|
304
|
-
languages.append(c[0])
|
|
305
|
-
else:
|
|
306
|
-
languages.append(c)
|
|
307
|
-
break
|
|
348
|
+
if language:
|
|
349
|
+
languages.append(language)
|
|
350
|
+
if original:
|
|
351
|
+
original_languages.append(language)
|
|
308
352
|
languages = list(dict.fromkeys(languages))
|
|
309
353
|
# Add multilanguage tag when languages > 2
|
|
310
354
|
if len(languages) > 2:
|
|
311
355
|
self.tags_dict.update({'multi': 'MULTI'})
|
|
312
356
|
|
|
313
|
-
|
|
357
|
+
# Best ITA codec + best original language codec, then the tracks with no language up to MAX_AUDIO_CODECS
|
|
358
|
+
best_first = sorted(tracks, key=lambda track: track[0], reverse=True)
|
|
359
|
+
picked = [track for track in best_first if track[2] == "ITA"][:1]
|
|
360
|
+
picked += [track for track in best_first if track[3]][:1]
|
|
361
|
+
picked += [track for track in best_first if track[2] is None]
|
|
362
|
+
audio_codecs = []
|
|
363
|
+
for _, label, _, _ in picked:
|
|
364
|
+
if label not in audio_codecs and len(audio_codecs) < MAX_AUDIO_CODECS:
|
|
365
|
+
audio_codecs.append(label)
|
|
366
|
+
|
|
367
|
+
# Flags: ITA, the original language, then the other languages with no codec
|
|
368
|
+
first = [language for language in ["ITA"] + original_languages[:1] if language in languages]
|
|
369
|
+
audio_codecs.extend(dict.fromkeys(first + languages))
|
|
314
370
|
return {category: audio_codecs}
|
|
315
371
|
|
|
316
372
|
@staticmethod
|
|
@@ -198,11 +198,10 @@ class Bot:
|
|
|
198
198
|
|
|
199
199
|
# Start uploading only the new files, one at a time
|
|
200
200
|
print()
|
|
201
|
-
self.run(include_paths=moved_paths)
|
|
202
|
-
print()
|
|
203
|
-
announce_idle = True
|
|
204
201
|
for moved_path in moved_paths:
|
|
205
202
|
self._run_isolated(include_path=moved_path, timeout=timeout)
|
|
203
|
+
print()
|
|
204
|
+
announce_idle = True
|
|
206
205
|
|
|
207
206
|
except KeyboardInterrupt:
|
|
208
207
|
custom_console.bot_log("Exiting...")
|
|
@@ -216,8 +215,15 @@ class Bot:
|
|
|
216
215
|
Returns:
|
|
217
216
|
True if the child process ended without errors
|
|
218
217
|
"""
|
|
218
|
+
# The child must be a fork of the watcher: it shares the loaded config and the console (the questions
|
|
219
|
+
# are answered on stdin), and the Bot can't be pickled for 'spawn' or 'forkserver' (the default
|
|
220
|
+
# since Python 3.14). Where fork isn't available or safe (Windows, macOS) the entry runs in the watcher
|
|
221
|
+
if "fork" not in multiprocessing.get_all_start_methods() or sys.platform == "darwin":
|
|
222
|
+
return self.run(include_paths=[include_path])
|
|
223
|
+
|
|
219
224
|
name = os.path.basename(include_path)
|
|
220
|
-
process = multiprocessing.Process(target=_run_worker, args=(self, include_path),
|
|
225
|
+
process = multiprocessing.get_context("fork").Process(target=_run_worker, args=(self, include_path),
|
|
226
|
+
daemon=True)
|
|
221
227
|
process.start()
|
|
222
228
|
try:
|
|
223
229
|
process.join(timeout if timeout > 0 else None)
|
|
@@ -38,14 +38,14 @@ class DocuManager:
|
|
|
38
38
|
custom_console.bot_log(f"Watcher Active.. skip the old upload '{content.file_name}'")
|
|
39
39
|
continue
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
43
|
-
|
|
44
|
-
# Skip if it is a duplicate
|
|
41
|
+
# Skip if it is a duplicate, before hashing the files
|
|
45
42
|
if ((self.cli.duplicate or config_settings.user_preferences.DUPLICATE_ON)
|
|
46
43
|
and UserContent.is_duplicate(content=content, tracker_name=selected_tracker, cli=self.cli)):
|
|
47
44
|
continue
|
|
48
45
|
|
|
46
|
+
torrent_response = UserContent.torrent(content=content, tracker_name_list=tracker_name_list,
|
|
47
|
+
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
48
|
+
|
|
49
49
|
# print the title will be shown on the torrent page
|
|
50
50
|
custom_console.bot_log(f"'DISPLAYNAME'...{{{content.display_name}}}\n")
|
|
51
51
|
|
|
@@ -61,15 +61,14 @@ class GameManager:
|
|
|
61
61
|
custom_console.bot_log(f"Watcher Active.. skip the old upload '{content.file_name}'")
|
|
62
62
|
continue
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# Skip if it is a duplicate
|
|
64
|
+
# Skip if it is a duplicate, before hashing the files
|
|
69
65
|
if ((self.cli.duplicate or config_settings.user_preferences.DUPLICATE_ON)
|
|
70
66
|
and UserContent.is_duplicate(content=content, tracker_name=selected_tracker, cli=self.cli)):
|
|
71
67
|
continue
|
|
72
68
|
|
|
69
|
+
torrent_response = UserContent.torrent(content=content, tracker_name_list=tracker_name_list,
|
|
70
|
+
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
71
|
+
|
|
73
72
|
# Login to IGDB only when the first game needs it
|
|
74
73
|
if not self.igdb_logged:
|
|
75
74
|
if not self.igdb.connect():
|
|
@@ -83,15 +83,16 @@ class VideoManager:
|
|
|
83
83
|
# Filter contents based on the preferred language or duplicates
|
|
84
84
|
if UserContent.is_preferred_language(content=content):
|
|
85
85
|
|
|
86
|
-
torrent_response = UserContent.torrent(content=content, tracker_name_list=tracker_name_list,
|
|
87
|
-
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
88
|
-
|
|
89
86
|
# Skip(S) if it is a duplicate or let the user choose to continue (C)
|
|
87
|
+
# Checked before hashing so a skipped duplicate doesn't cost a torrent file
|
|
90
88
|
if ((self.cli.duplicate or config_settings.user_preferences.DUPLICATE_ON)
|
|
91
89
|
and UserContent.is_duplicate(content=content, tracker_name=selected_tracker,
|
|
92
90
|
cli=self.cli)):
|
|
93
91
|
continue
|
|
94
92
|
|
|
93
|
+
torrent_response = UserContent.torrent(content=content, tracker_name_list=tracker_name_list,
|
|
94
|
+
selected_tracker=selected_tracker, this_path=torrent_filepath)
|
|
95
|
+
|
|
95
96
|
# Search for VIDEO ID
|
|
96
97
|
db_online = DbOnline(media=content, category=content.category, no_title=self.cli.notitle)
|
|
97
98
|
db = db_online.media_result
|
|
@@ -100,6 +101,9 @@ class VideoManager:
|
|
|
100
101
|
if not db:
|
|
101
102
|
continue
|
|
102
103
|
|
|
104
|
+
# The audio tags need the original language from TMDB
|
|
105
|
+
content.display_name, tags_dictionary = search_tags.set_original_language(db.original_language)
|
|
106
|
+
|
|
103
107
|
# Get meta from the media video
|
|
104
108
|
video_info = Video(media=content, tmdb_id=db.video_id, trailer_key=db.trailer_key)
|
|
105
109
|
video_info.build_info()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from types import SimpleNamespace
|
|
3
|
+
|
|
4
|
+
from ittup.common.tags import SearchTags
|
|
5
|
+
from ittup.common.trackers.tags_list import TAGS_LIST
|
|
6
|
+
|
|
7
|
+
LANGUAGES = {"ITA": ["Italian", "it", "ita"], "ENG": ["English", "en", "eng"], "FRA": ["French", "fr", "fra"],
|
|
8
|
+
"GER": ["German", "de", "deu"], "JPN": ["Japanese", "ja", "jpn"]}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def track(other_format: str, channel_s: int, language: str | None = None, commercial_name: str = "") -> dict:
|
|
12
|
+
return {"other_format": [other_format], "channel_s": channel_s, "commercial_name": commercial_name,
|
|
13
|
+
"other_language": LANGUAGES[language] if language else []}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def acodec(*audio_track: dict, original_language: str | None = None) -> list:
|
|
17
|
+
mediafile = SimpleNamespace(video_track=[], audio_track=list(audio_track), subtitle_track=[])
|
|
18
|
+
media = SimpleNamespace(mediafile=mediafile, torrent_pack=False, resolution="1080p", pack=None)
|
|
19
|
+
search = SearchTags(filename="Movie.2020.1080p.BluRay.REMUX-GRP.mkv", title="Movie", year="2020", season=None,
|
|
20
|
+
episode=None, media=media, tags_position=["title", "year", "acodec"], tags_list=TAGS_LIST,
|
|
21
|
+
sign_list={}, ban_list={"dummy": "banned"}, releaser_sign="")
|
|
22
|
+
search.process()
|
|
23
|
+
_, tags_dict = search.set_original_language(original_language)
|
|
24
|
+
return tags_dict["acodec"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_best_ita_and_best_eng():
|
|
28
|
+
assert acodec(track("MLP FBA 16-ch", 8, "ITA", "Dolby TrueHD with Dolby Atmos"), track("DTS XLL", 6, "ITA"),
|
|
29
|
+
track("AC-3", 6, "ENG"), track("E-AC-3", 6, "ENG"), original_language="en") == [
|
|
30
|
+
"TrueHD 7.1 Atmos", "DD+ 5.1", "ITA", "ENG"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_original_language_codec():
|
|
34
|
+
assert acodec(track("AC-3", 6, "ITA"), track("E-AC-3", 6, "ENG"), track("DTS XLL", 6, "JPN"),
|
|
35
|
+
original_language="ja") == ["DD 5.1", "DTS-HD MA 5.1", "ITA", "JPN", "ENG"]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_other_languages_only_add_the_flag():
|
|
39
|
+
assert acodec(track("AC-3", 6, "FRA"), track("MLP FBA 16-ch", 8, "GER"), track("AC-3", 6, "ITA"),
|
|
40
|
+
track("AAC LC", 2, "ENG"), original_language="en") == [
|
|
41
|
+
"DD 5.1", "AAC 2.0", "ITA", "ENG", "FRA", "GER"]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_unknown_original_language_is_english():
|
|
45
|
+
assert acodec(track("AC-3", 6, "ITA"), track("E-AC-3", 6, "ENG"), track("DTS XLL", 6, "JPN")) == [
|
|
46
|
+
"DD 5.1", "DD+ 5.1", "ITA", "ENG", "JPN"]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_italian_original_language():
|
|
50
|
+
assert acodec(track("AC-3", 6, "ITA"), track("DTS XLL", 6, "ITA"), track("E-AC-3", 6, "ENG"),
|
|
51
|
+
original_language="it") == ["DTS-HD MA 5.1", "ITA", "ENG"]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_channels_break_ties():
|
|
55
|
+
assert acodec(track("AC-3", 2, "ITA"), track("AC-3", 6, "ITA")) == ["DD 5.1", "ITA"]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_same_codec_is_written_once():
|
|
59
|
+
assert acodec(track("AC-3", 6, "ITA"), track("AC-3", 6, "ENG")) == ["DD 5.1", "ITA", "ENG"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_untagged_tracks_fill_up_to_two():
|
|
63
|
+
assert acodec(track("AC-3", 6, "ITA"), track("AAC LC", 2), track("DTS XLL", 6)) == [
|
|
64
|
+
"DD 5.1", "DTS-HD MA 5.1", "ITA"]
|
|
65
|
+
assert acodec(track("AC-3", 6, "ITA"), track("AAC LC", 2, "ENG"), track("DTS XLL", 6)) == [
|
|
66
|
+
"DD 5.1", "AAC 2.0", "ITA", "ENG"]
|
|
67
|
+
assert acodec(track("AC-3", 6, "ITA"), track("AC-3", 6, "ENG"), track("DTS XLL", 6)) == [
|
|
68
|
+
"DD 5.1", "DTS-HD MA 5.1", "ITA", "ENG"]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_untagged_tracks_only():
|
|
72
|
+
assert acodec(track("AC-3", 6), track("AAC LC", 2), track("E-AC-3", 6)) == ["DD+ 5.1", "DD 5.1"]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_title_is_rebuilt_with_the_original_language():
|
|
76
|
+
audio = [track("AC-3", 6, "ITA"), track("E-AC-3", 6, "ENG"), track("DTS XLL", 6, "JPN")]
|
|
77
|
+
mediafile = SimpleNamespace(video_track=[], audio_track=audio, subtitle_track=[])
|
|
78
|
+
media = SimpleNamespace(mediafile=mediafile, torrent_pack=False, resolution="1080p", pack=None)
|
|
79
|
+
search = SearchTags(filename="Movie.2020.1080p.BluRay.REMUX-GRP.mkv", title="Movie", year="2020", season=None,
|
|
80
|
+
episode=None, media=media, tags_position=["title", "year", "multi", "acodec"],
|
|
81
|
+
tags_list=TAGS_LIST, sign_list={}, ban_list={"dummy": "banned"}, releaser_sign="")
|
|
82
|
+
title, _ = search.process()
|
|
83
|
+
assert title == "Movie 2020 MULTI DD 5.1 DD+ 5.1 ITA ENG JPN"
|
|
84
|
+
title, _ = search.set_original_language("ja")
|
|
85
|
+
assert title == "Movie 2020 MULTI DD 5.1 DTS-HD MA 5.1 ITA JPN ENG"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/__init__.py
RENAMED
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/details.py
RENAMED
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/movie/movie.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/details.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ittup-1.2.2 → ittup-1.3.0}/ittup/common/external_services/theMovieDB/core/models/tvshow/tvshow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|