Unit3Dup 0.9.17__tar.gz → 0.9.20__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.
Files changed (105) hide show
  1. {unit3dup-0.9.17 → unit3dup-0.9.20}/PKG-INFO +1 -1
  2. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/PKG-INFO +1 -1
  3. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/SOURCES.txt +4 -0
  4. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/top_level.txt +2 -0
  5. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/settings.py +48 -273
  6. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/tags.py +93 -22
  7. unit3dup-0.9.20/common/trackers/ban_list.py +5 -0
  8. unit3dup-0.9.20/common/trackers/signs_list.py +252 -0
  9. unit3dup-0.9.20/common/trackers/tags_list.py +106 -0
  10. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/utility.py +37 -19
  11. unit3dup-0.9.20/docs_old/conf.py +10 -0
  12. {unit3dup-0.9.17 → unit3dup-0.9.20}/pyproject.toml +1 -1
  13. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/__main__.py +30 -20
  14. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/bot.py +3 -2
  15. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/TorrentManager.py +6 -6
  16. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/VideoManager.py +6 -2
  17. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/pvtVideo.py +2 -4
  18. {unit3dup-0.9.17 → unit3dup-0.9.20}/LICENSE +0 -0
  19. {unit3dup-0.9.17 → unit3dup-0.9.20}/README.rst +0 -0
  20. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/dependency_links.txt +0 -0
  21. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/entry_points.txt +0 -0
  22. {unit3dup-0.9.17 → unit3dup-0.9.20}/Unit3Dup.egg-info/requires.txt +0 -0
  23. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/__init__.py +0 -0
  24. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/bdinfo_string.py +0 -0
  25. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/bittorrent.py +0 -0
  26. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/command.py +0 -0
  27. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/constants.py +0 -0
  28. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/database.py +0 -0
  29. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/__init__.py +0 -0
  30. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/__init__.py +0 -0
  31. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/client.py +0 -0
  32. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/__init__.py +0 -0
  33. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/ftpx_service.py +0 -0
  34. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/ftpx_session.py +0 -0
  35. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/menu.py +0 -0
  36. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/models/__init__.py +0 -0
  37. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/ftpx/core/models/list.py +0 -0
  38. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/__init__.py +0 -0
  39. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/client.py +0 -0
  40. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/__init__.py +0 -0
  41. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/api.py +0 -0
  42. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/models/__init__.py +0 -0
  43. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/models/search.py +0 -0
  44. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/platformid.py +0 -0
  45. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/igdb/core/tags.py +0 -0
  46. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/imageHost.py +0 -0
  47. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/mediaresult.py +0 -0
  48. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/sessions/__init__.py +0 -0
  49. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/sessions/agents.py +0 -0
  50. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/sessions/exceptions.py +0 -0
  51. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/sessions/session.py +0 -0
  52. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/__init__.py +0 -0
  53. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/__init__.py +0 -0
  54. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/api.py +0 -0
  55. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/keywords.py +0 -0
  56. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/__init__.py +0 -0
  57. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/__init__.py +0 -0
  58. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/alternative_titles.py +0 -0
  59. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/details.py +0 -0
  60. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/movie.py +0 -0
  61. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/nowplaying.py +0 -0
  62. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/movie/release_info.py +0 -0
  63. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/__init__.py +0 -0
  64. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/alternative.py +0 -0
  65. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/details.py +0 -0
  66. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/on_the_air.py +0 -0
  67. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/translations.py +0 -0
  68. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/models/tvshow/tvshow.py +0 -0
  69. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/theMovieDB/core/videos.py +0 -0
  70. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/trailers/__init__.py +0 -0
  71. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/trailers/api.py +0 -0
  72. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/trailers/response.py +0 -0
  73. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/external_services/tvdb.py +0 -0
  74. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/extractor.py +0 -0
  75. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/frames.py +0 -0
  76. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/mediainfo.py +0 -0
  77. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/mediainfo_string.py +0 -0
  78. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/title.py +0 -0
  79. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/torrent_clients.py +0 -0
  80. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/trackers/__init__.py +0 -0
  81. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/trackers/data.py +0 -0
  82. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/trackers/itt.py +0 -0
  83. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/trackers/sis.py +0 -0
  84. {unit3dup-0.9.17 → unit3dup-0.9.20}/common/trackers/trackers.py +0 -0
  85. {unit3dup-0.9.17 → unit3dup-0.9.20}/requirements.txt +0 -0
  86. {unit3dup-0.9.17 → unit3dup-0.9.20}/setup.cfg +0 -0
  87. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/__init__.py +0 -0
  88. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/automode.py +0 -0
  89. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/duplicate.py +0 -0
  90. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/exceptions.py +0 -0
  91. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media.py +0 -0
  92. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/ContentManager.py +0 -0
  93. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/DocuManager.py +0 -0
  94. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/GameManager.py +0 -0
  95. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/MediaInfoManager.py +0 -0
  96. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/SeedManager.py +0 -0
  97. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/__init__.py +0 -0
  98. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/media_manager/common.py +0 -0
  99. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/pvtDocu.py +0 -0
  100. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/pvtTorrent.py +0 -0
  101. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/pvtTracker.py +0 -0
  102. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/torrent.py +0 -0
  103. {unit3dup-0.9.17 → unit3dup-0.9.20}/unit3dup/upload.py +0 -0
  104. {unit3dup-0.9.17 → unit3dup-0.9.20}/view/__init__.py +0 -0
  105. {unit3dup-0.9.17 → unit3dup-0.9.20}/view/custom_console.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Unit3Dup
3
- Version: 0.9.17
3
+ Version: 0.9.20
4
4
  Summary: An uploader for the Unit3D torrent tracker
5
5
  Author: Parzival
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Unit3Dup
3
- Version: 0.9.17
3
+ Version: 0.9.20
4
4
  Summary: An uploader for the Unit3D torrent tracker
5
5
  Author: Parzival
6
6
  License-Expression: MIT
@@ -69,10 +69,14 @@ common/external_services/trailers/__init__.py
69
69
  common/external_services/trailers/api.py
70
70
  common/external_services/trailers/response.py
71
71
  common/trackers/__init__.py
72
+ common/trackers/ban_list.py
72
73
  common/trackers/data.py
73
74
  common/trackers/itt.py
75
+ common/trackers/signs_list.py
74
76
  common/trackers/sis.py
77
+ common/trackers/tags_list.py
75
78
  common/trackers/trackers.py
79
+ docs_old/conf.py
76
80
  unit3dup/__init__.py
77
81
  unit3dup/__main__.py
78
82
  unit3dup/automode.py
@@ -1,4 +1,6 @@
1
1
  common
2
2
  dist
3
+ docs
4
+ docs_old
3
5
  unit3dup
4
6
  view
@@ -1,5 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
-
3
2
  import ipaddress
4
3
  import json
5
4
  import os
@@ -8,17 +7,23 @@ import re
8
7
  import unicodedata
9
8
 
10
9
  from pydantic import BaseModel, model_validator
10
+ from pathvalidate import sanitize_filepath
11
11
  from urllib.parse import urlparse
12
12
  from pathlib import Path
13
- from pathvalidate import sanitize_filepath
13
+
14
+ from common.trackers.signs_list import SIGNS_LIST
15
+ from common.trackers.tags_list import TAGS_LIST
16
+ from common.trackers.ban_list import BAN_LIST
17
+
14
18
  from common.utility import ManageTitles
15
19
  from common import trackers
16
20
 
17
21
  config_file = "Unit3Dbot.json"
18
22
  user_tags_file = "tags_list.json"
19
23
  user_sign_file = "sign_list.json"
24
+ bane_file = "ban_list.json"
20
25
 
21
- version = "0.9.17"
26
+ version = "0.9.20"
22
27
 
23
28
  if os.name == "nt":
24
29
  WATCHER_DESTINATION_PATH: Path = Path(
@@ -29,7 +34,7 @@ if os.name == "nt":
29
34
  DEFAULT_JSON_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / f"{config_file}"
30
35
  USER_TAGS_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / f"{user_tags_file}"
31
36
  USER_SIGN_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / f"{user_sign_file}"
32
-
37
+ BAN_TAGS_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / f"{bane_file}"
33
38
 
34
39
  else:
35
40
  WATCHER_DESTINATION_PATH: Path = Path.home() / "Unit3Dup_config" / "watcher_destination_path"
@@ -39,6 +44,7 @@ else:
39
44
  DEFAULT_JSON_PATH: Path = Path.home() / "Unit3Dup_config" / f"{config_file}"
40
45
  USER_TAGS_PATH: Path = Path.home() / "Unit3Dup_config" / f"{user_tags_file}"
41
46
  USER_SIGN_PATH: Path = Path.home() / "Unit3Dup_config" / f"{user_sign_file}"
47
+ BAN_TAGS_PATH: Path = Path.home() / "Unit3Dup_config" / f"{bane_file}"
42
48
 
43
49
 
44
50
  def get_default_path(field: str) -> str:
@@ -109,7 +115,8 @@ class UserPreferences(BaseModel):
109
115
  IMGFI_PRIORITY: int = 4
110
116
  PASSIMA_PRIORITY: int = 5
111
117
  IMARIDE_PRIORITY: int = 6
112
- TAGS_POSITION: list[str] | None = None
118
+ TAGS_POSITION_MOVIE: list[str] | None = None
119
+ TAGS_POSITION_SERIE: list[str] | None = None
113
120
 
114
121
  NUMBER_OF_SCREENSHOTS: int = 4
115
122
  YOUTUBE_FAV_CHANNEL_ID: str | None = None
@@ -253,18 +260,19 @@ class Validate:
253
260
  def validate_tags_position(position_list: list) -> list | None:
254
261
 
255
262
  if not position_list:
256
- print(f"-> Invalid TAG position. The list is empty !")
263
+ print(f"-> Invalid TAG POSITION list. The list is empty !")
257
264
  exit(1)
258
265
 
259
266
  if len(position_list) > 17 or len(position_list) < 5:
260
- print(f"-> Invalid TAG position list. Wrong number of elements !")
267
+ print(f"-> Invalid Tag list: number of elements exceeds the maximum allowed tags!")
261
268
  exit(1)
262
269
 
263
270
  for tag in position_list:
264
- if tag.lower() not in ["title", "year", "season", "version", "resolution", "uhd", "platform", "source",
271
+ if tag.lower() not in ["title", "part", "year", "season", "version", "resolution", "uhd", "platform",
272
+ "source",
265
273
  "remux",
266
274
  "multi", "acodec", "channels", "flag", "subtitle", "vcodec", "hdr", "video_encoder"]:
267
- print(f"-> Invalid TAG position '{tag}'. Please fix your configuration file")
275
+ print(f"-> Invalid TAG '{tag}'. Please fix your configuration file")
268
276
  exit(1)
269
277
 
270
278
  return position_list
@@ -485,7 +493,10 @@ class Config(BaseModel):
485
493
  if field == 'RELEASER_SIGN':
486
494
  section[field] = Validate.sign(sign=section[field])
487
495
 
488
- if field in ['TAGS_POSITION']:
496
+ if field in ['TAGS_POSITION_MOVIE']:
497
+ section[field] = Validate.validate_tags_position(position_list=section[field])
498
+
499
+ if field in ['TAGS_POSITION_SERIE']:
489
500
  section[field] = Validate.validate_tags_position(position_list=section[field])
490
501
 
491
502
  return v
@@ -526,274 +537,27 @@ class Load:
526
537
  """
527
538
  Creates a tags list file
528
539
  """
529
- TAG_TYPES = {
530
- "REMUX": "remux",
531
- "WEB-DL": "source",
532
- "WEBDL": "source",
533
- "WEB-DLRIP": "source",
534
- "WEBDLRIP": "source",
535
- "WEB-DLMUX": "source",
536
- "WEBDLMUX": "source",
537
- "WEBMUX": "source",
538
- "WEBRIP": "source",
539
- "BD-UNTOUCHED": "source",
540
- "UNTOUCHED": "source",
541
-
542
- "TS": "source",
543
- "CAM": "source",
544
- "HDTS": "source",
545
- "MD": "source",
546
- "UHDRIP": "source",
547
- "BLURAY": "source",
548
- "BRRIP": "source",
549
- "BDRIP": "source",
550
- "FHDRIP": "source",
551
- "PDTV": "source",
552
- "SATRIP": "source",
553
- "DVBRIP": "source",
554
- "DVB-S": "source",
555
- "DTTRIP": "source",
556
- "WP": "source",
557
- "DVDSCR": "source",
558
- "TVRIP": "source",
559
- "VHSRIP": "source",
560
- "DVDRIP": "source",
561
- "HDTV": "source",
562
- "DVD5": "source",
563
- "DVD9": "source",
564
- "VU": "source",
565
-
566
- "ATVP": "platform",
567
- "AMZN": "platform",
568
- "AMC": "platform",
569
- "CN": "platform",
570
- "CR": "platform",
571
- "DCU": "platform",
572
- "DISC": "platform",
573
- "DSCP": "platform",
574
- "DSNY": "platform",
575
- "DSNP": "platform",
576
- "DPLY": "platform",
577
- "ESPN": "platform",
578
- "FOOD": "platform",
579
- "FOX": "platform",
580
- "PLAY": "platform",
581
- "HBO": "platform",
582
- "HMAX": "platform",
583
- "HGTV": "platform",
584
- "HIST": "platform",
585
- "HULU": "platform",
586
- "MTOD": "platform",
587
- "NATG": "platform",
588
- "NF": "platform",
589
- "NICK": "platform",
590
- "NOW": "platform",
591
- "PMNT": "platform",
592
- "PMTP": "platform",
593
- "PCOK": "platform",
594
- "RKTN": "platform",
595
- "SHO": "platform",
596
- "SKST": "platform",
597
- "STAN": "platform",
598
- "STRP": "platform",
599
- "STZ": "platform",
600
- "TIMV": "platform",
601
-
602
- "SPECIAL": "version",
603
- "REPACK": "version",
604
- "EXTENDED": "version",
605
- "EDITION": "version",
606
- "DIRECTOR'S": "version",
607
- "CUT": "version",
608
-
609
- "SUBBED": "version",
610
- "MUX": "version",
611
- "REMASTERED": "version",
612
- "READNFO": "version",
613
- "UNRATED": "version",
614
- "UNCUT": "version",
615
- "LIMITED": "version",
616
- "ANNIVERSARY": "version",
617
- "4k RESTORATION": "version",
618
- "IMAX": "version",
619
- "OPEN MATTE": "version",
620
- "2IN1": "version",
621
-
622
- "STV": "version",
623
- "RECODE": "version",
624
- "INTERNAL": "version",
625
- "PROPER": "version",
626
- "DUAL": "version",
627
- "COMPLETE": "version",
628
- "COMPLETA": "version",
629
-
630
- "X264": "video_encoder",
631
- "X265": "video_encoder",
632
- }
633
-
634
540
  path.parent.mkdir(parents=True, exist_ok=True)
635
541
  with open(path, "w", encoding="utf-8") as tags_list_file:
636
- json.dump(TAG_TYPES, tags_list_file, ensure_ascii=False, indent=4)
542
+ json.dump(TAGS_LIST, tags_list_file, ensure_ascii=False, indent=4)
637
543
 
638
544
  @staticmethod
639
545
  def create_sign_list_file(path: Path):
640
546
  """
641
- Creates a tags list file
547
+ Creates a sign list file
642
548
  """
643
- TAG_TYPES = {
644
- "21APRILE": "releaser",
645
- "ALE88SERMETE": "releaser",
646
- "ARRANCAR": "releaser",
647
- "ASTOR": "releaser",
648
- "AV1MERR": "releaser",
649
- "BADGUY": "releaser",
650
- "BITSHIFT": "releaser",
651
- "BLACKBIT": "releaser",
652
- "BUMBLEBEE1982": "releaser",
653
- "CAPPYO": "releaser",
654
- "CAVALLONZI": "releaser",
655
- "CB01HD": "releaser",
656
- "CHD": "releaser",
657
- "CHDWEB": "releaser",
658
- "CIAME": "releaser",
659
- "CLOCLONE": "releaser",
660
- "COMIX21": "releaser",
661
- "CREW": "releaser",
662
- "CSS": "releaser",
663
- "CSS2": "releaser",
664
- "CSS7896": "releaser",
665
- "CYBER": "releaser",
666
- "D3VELOPER": "releaser",
667
- "DAICHISO": "releaser",
668
- "DANGUARD": "releaser",
669
- "DARKCOMPANY": "releaser",
670
- "DARKPARANOR": "releaser",
671
- "DAYMON64": "releaser",
672
- "DDN": "releaser",
673
- "DEDO1911": "releaser",
674
- "DEMN": "releaser",
675
- "DMAN": "releaser",
676
- "DOCH74": "releaser",
677
- "DRIIP": "releaser",
678
- "DYNUX": "releaser",
679
- "ELGHOTO": "releaser",
680
- "ENCRYPTED": "releaser",
681
- "EVN": "releaser",
682
- "EZTV": "releaser",
683
- "FAINO1310": "releaser",
684
- "FEDECAS89": "releaser",
685
- "FGT": "releaser",
686
- "FHC": "releaser",
687
- "FLORIN993": "releaser",
688
- "FLUX": "releaser",
689
- "FREZEEN": "releaser",
690
- "FUSION": "releaser",
691
- "G66": "releaser",
692
- "GABIACAS": "releaser",
693
- "GIUSEPPETNT": "releaser",
694
- "GOLDENTORRENT": "releaser",
695
- "GRYM": "releaser",
696
- "HAPPITEAM-YNK": "releaser",
697
- "HASHDEV": "releaser",
698
- "HDCHINA": "releaser",
699
- "HENRYDIRTY": "releaser",
700
- "HONE": "releaser",
701
- "HHNN": "releaser",
702
- "HYRULE": "releaser",
703
- "I3AM": "releaser",
704
- "IBANEZ89": "releaser",
705
- "IDIB": "releaser",
706
- "IDN": "releaser",
707
- "ILGANZO": "releaser",
708
- "ILPADRINO": "releaser",
709
- "ILSAGGIO": "releaser",
710
- "ILSOMMO": "releaser",
711
- "IPDR01": "releaser",
712
- "ITT": "releaser",
713
- "JOHNSEED": "releaser",
714
- "KINGOFROME": "releaser",
715
- "KRIKK": "releaser",
716
- "LAZY-SUBS": "releaser",
717
- "LEPORE": "releaser",
718
- "LFI": "releaser",
719
- "LULLOZZO": "releaser",
720
- "MATT3O": "releaser",
721
- "MATT_BROWN4": "releaser",
722
- "MAX2014": "releaser",
723
- "MIRCREW": "releaser",
724
- "MISTERNED": "releaser",
725
- "MRBLONDE": "releaser",
726
- "MRROBOT": "releaser",
727
- "MUETTO": "releaser",
728
- "MUWATTALI": "releaser",
729
- "NAHOM": "releaser",
730
- "NARSETE": "releaser",
731
- "NEOSTARK": "releaser",
732
- "NEUROSIS": "releaser",
733
- "NIMOUEH": "releaser",
734
- "NOGROUP": "releaser",
735
- "NOVARIP": "releaser",
736
- "NTROPIC": "releaser",
737
- "ODS": "releaser",
738
- "ONGOIA": "releaser",
739
- "PEPPE": "releaser",
740
- "PENNYWISE": "releaser",
741
- "PETE321": "releaser",
742
- "PICOPOCO": "releaser",
743
- "PING": "releaser",
744
- "PINKER": "releaser",
745
- "PIR8": "releaser",
746
- "PLAYWEB": "releaser",
747
- "PRIME": "releaser",
748
- "PROMETHEUS": "releaser",
749
- "PROSCIUTTO": "releaser",
750
- "RADESE": "releaser",
751
- "RAWR": "releaser",
752
- "RARBG": "releaser",
753
- "RIDDICKK": "releaser",
754
- "ROGELIOBYNIGHT": "releaser",
755
- "ROMEO": "releaser",
756
- "RYUKXX": "releaser",
757
- "S-K": "releaser",
758
- "SANDWORM": "releaser",
759
- "SEEDBOX": "releaser",
760
- "SEEDBOX2": "releaser",
761
- "SERCIUS": "releaser",
762
- "SIMO01": "releaser",
763
- "SIXTEEN8664": "releaser",
764
- "SK4TTO": "releaser",
765
- "SMURFADMIN": "releaser",
766
- "SPYRO1989": "releaser",
767
- "STEVEJOHNNEE": "releaser",
768
- "STINGUAJT": "releaser",
769
- "TAHTAKALECI": "releaser",
770
- "TELESTO": "releaser",
771
- "TERMINAL": "releaser",
772
- "THEBLACKKING": "releaser",
773
- "THEEMOJICREW": "releaser",
774
- "THUDARA": "releaser",
775
- "TIGRE67": "releaser",
776
- "TORRENT10": "releaser",
777
- "TOTAL_SHARE88": "releaser",
778
- "TREE7458": "releaser",
779
- "TRIVIAL99": "releaser",
780
- "UBI": "releaser",
781
- "V3SP4EV3R": "releaser",
782
- "VIOLENT96": "releaser",
783
- "VOLVIC": "releaser",
784
- "WHEELIE": "releaser",
785
- "WHITERHINO": "releaser",
786
- "WIZARDS2K": "releaser",
787
- "WRS": "releaser",
788
- "XVID": "releaser",
789
- "YIFY": "releaser",
790
- "YTS": "releaser",
791
- "ZIORIP": "releaser"
792
- }
793
-
794
549
  path.parent.mkdir(parents=True, exist_ok=True)
795
550
  with open(path, "w", encoding="utf-8") as tags_sign_file:
796
- json.dump(TAG_TYPES, tags_sign_file, ensure_ascii=False, indent=4)
551
+ json.dump(SIGNS_LIST, tags_sign_file, ensure_ascii=False, indent=4)
552
+
553
+ @staticmethod
554
+ def create_ban_list_file(path: Path):
555
+ """
556
+ Creates a ban list file
557
+ """
558
+ path.parent.mkdir(parents=True, exist_ok=True)
559
+ with open(path, "w", encoding="utf-8") as ban_list_file:
560
+ json.dump(BAN_LIST, ban_list_file, ensure_ascii=False, indent=4)
797
561
 
798
562
  @staticmethod
799
563
  def create_default_json_file(path: Path):
@@ -851,9 +615,16 @@ class Load:
851
615
  "PASSIMA_PRIORITY": 5,
852
616
  "IMARIDE_PRIORITY": 6,
853
617
  "NUMBER_OF_SCREENSHOTS": 4,
854
- "TAGS_POSITION": ["title", "year", "season", "version", "resolution", "uhd", "platform", "source",
855
- "remux",
856
- "multi", "acodec", "channels", "flag", "subtitle", "hdr", "vcodec", "video_encoder"],
618
+ "TAGS_POSITION_MOVIE": ["title", "year", "part", "version", "resolution", "uhd", "platform", "source",
619
+ "remux",
620
+ "multi", "acodec", "channels", "flag", "subtitle", "hdr", "vcodec",
621
+ "video_encoder"],
622
+
623
+ "TAGS_POSITION_SERIE": ["title", "year", "season", "version", "resolution", "uhd", "platform", "source",
624
+ "remux",
625
+ "multi", "acodec", "channels", "flag", "subtitle", "hdr", "vcodec",
626
+ "video_encoder"],
627
+
857
628
  "YOUTUBE_FAV_CHANNEL_ID": "UCGCbxpnt25hWPFLSbvwfg_w",
858
629
  "YOUTUBE_CHANNEL_ENABLE": "False",
859
630
  "DUPLICATE_ON": "true",
@@ -935,6 +706,10 @@ class Load:
935
706
  print(f"Create default Sign_list file: {USER_SIGN_PATH}")
936
707
  Load.create_sign_list_file(USER_SIGN_PATH)
937
708
 
709
+ if not BAN_TAGS_PATH.exists():
710
+ print(f"Create default Ban_list file: {BAN_TAGS_PATH}")
711
+ Load.create_ban_list_file(BAN_TAGS_PATH)
712
+
938
713
  # Since the last bot version there might are new attributes
939
714
  # Load the json file, find the difference between json file and the code. Update the user's json file
940
715
  update_config = JsonConfig(default_json_path=DEFAULT_JSON_PATH)
@@ -1090,7 +865,7 @@ class JsonConfig:
1090
865
 
1091
866
  def json_message_new_attributes(self):
1092
867
 
1093
- print("-- ** Since the last bot version there are new attributes ** --")
868
+ print("-- ** New attributes have been added since the last bot version ** --")
1094
869
  message = ''
1095
870
  if self.tracker_diff_keys:
1096
871
  message += f"New Tracker Configuration attribute: {self.tracker_diff_keys}\n"
@@ -1,5 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- import os
3
2
  import re
4
3
  from common.mediainfo import MediaFile
5
4
  from common.utility import ManageTitles
@@ -10,12 +9,14 @@ hdr_map = {
10
9
  "DOLBY VISION": "DV",
11
10
  "DOLBY VISION HDR": "DV HDR",
12
11
  "DOLBY VISION HDR10": "DV HDR10",
13
- "DOLBY VISION HDR10+": "DV HDR",
12
+ "DOLBY VISION HDR10+": "DV HDR10+",
14
13
  "HDR10PLUS": "HDR10+",
15
14
  "HDRPLUS+": "HDR10+",
16
15
  "HDR10+": "HDR10+",
17
16
  "HDR10": "HDR10",
17
+ "BLU-RAY / HDR10": "HDR10",
18
18
  "HDR10 / HDR10": "HDR10",
19
+ "HDR10 / HDR10+": "HDR10+",
19
20
  "HDR10 / HDR10 / HDR10+": "HDR10+",
20
21
  "SMPTE ST 2086": "HDR10",
21
22
  "SMPTE ST 2094": "HDR10+",
@@ -56,7 +57,8 @@ video_encoder_translate = {
56
57
 
57
58
  class SearchTags(object):
58
59
  def __init__(self, filename, title: str, year: str, season: int, episode: int,
59
- mediafile: MediaFile, tags_position: list, tags_list: dict, sign_list: dict, releaser_sign: str):
60
+ mediafile: MediaFile, tags_position: list, tags_list: dict, sign_list: dict, ban_list: dict,
61
+ releaser_sign: str):
60
62
 
61
63
  self.tags_position = tags_position
62
64
  self.releaser_sign = releaser_sign
@@ -68,14 +70,29 @@ class SearchTags(object):
68
70
  self.year = year
69
71
  self.tags_dict = {}
70
72
  self.tags_position = tags_position
71
- self.TAG_TYPES = tags_list
72
- self.SIGNS_LIST = sign_list
73
+ self.TAG_TYPES: dict = tags_list
74
+ self.SIGNS_LIST: dict = sign_list
75
+ self.BAN_LIST: dict = ban_list
73
76
 
74
77
  @staticmethod
75
78
  def normalize_version_tag(tag: str) -> str:
76
79
  tag_esc = re.escape(tag)
77
80
  return tag_esc
78
81
 
82
+ @staticmethod
83
+ def normalize_part_tag(title: str) -> str | None:
84
+ """
85
+ Extract substring PartX
86
+ Try to remove noisy chars and return a normalized tag
87
+ Part1, Part 1, Part.1, [Part 1], Parte1, Pt1, Prt 2,
88
+ """
89
+ pattern = r'[\[\(]?\b(?:Part|Parte|Pt|Prt)[\s\.-]*?(\d+)\b[\]\)]?'
90
+ match = re.search(pattern, title, re.IGNORECASE)
91
+ if match:
92
+ part_number = match.group(1)
93
+ return f"Part {part_number}"
94
+ return None
95
+
79
96
  @staticmethod
80
97
  def normalize_platform_tag(tag: str) -> str:
81
98
  tag_esc = re.escape(tag)
@@ -86,7 +103,6 @@ class SearchTags(object):
86
103
  tag_esc = re.escape(tag)
87
104
  return tag_esc
88
105
 
89
-
90
106
  @staticmethod
91
107
  def normalize_video_encoder(tag: str) -> str:
92
108
  tag_esc = re.escape(tag)
@@ -101,12 +117,16 @@ class SearchTags(object):
101
117
  build.append(' '.join(v))
102
118
  else:
103
119
  build.append(str(v))
120
+
104
121
  refactored = ' '.join(build) + self.releaser_sign
105
122
  return refactored
106
123
 
107
124
  def process(self) -> str:
108
125
  patterns = []
109
126
 
127
+ # Remove banned items from categories
128
+ self.tags_position = [x for x in self.tags_position if x not in self.BAN_LIST]
129
+
110
130
  # loop sorted TAG_TYPES dictionary
111
131
  for i, (tag, category) in enumerate(
112
132
  sorted(self.TAG_TYPES.items(), key=lambda x: len(x[0]), reverse=True)
@@ -131,6 +151,14 @@ class SearchTags(object):
131
151
  if matches:
132
152
  self.tags_dict.setdefault(category, []).append(matches[0])
133
153
 
154
+ # /// Tags with no categories
155
+ # Identify PartX
156
+ norm = self.normalize_part_tag(self.filename)
157
+ if norm:
158
+ # Skip if it is part of title es: "Wicked.Parte.2.2025.iTA" Title = Wicked Parte 2
159
+ if not any(t in self.title.lower() for t in ['part', 'parte']):
160
+ self.tags_dict.update({'part': norm})
161
+
134
162
  # /// Read from mediainfo
135
163
  updated_category = {}
136
164
  for category in self.tags_position:
@@ -146,10 +174,13 @@ class SearchTags(object):
146
174
 
147
175
  elif category == "hdr":
148
176
  updated_category = self.mediainfo_hdr(category=category)
177
+ if not updated_category:
178
+ updated_category = {category: 'SDR'}
149
179
 
150
180
  elif category == "uhd":
151
181
  updated_category = self.mediainfo_uhd(category=category)
152
182
 
183
+
153
184
  elif category == "subtitle":
154
185
  if self.mediafile.subtitle_track:
155
186
  updated_category = {'subtitle': "SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB"}
@@ -175,22 +206,7 @@ class SearchTags(object):
175
206
  if not self.releaser_sign:
176
207
  # If releaser_sign is not defined in the configuration file,
177
208
  # try to detect a known sign from SIGN_LIST
178
- pattern = "|".join(
179
- sorted((re.escape(k) for k in self.SIGNS_LIST.keys()), key=len, reverse=True)
180
- )
181
- self.filename = os.path.splitext(self.filename)[0]
182
- regex = re.compile(
183
- r'(?:^|[\s._-])(' + pattern + r')(?=$|[\s._-]*$)',
184
- re.IGNORECASE
185
- )
186
- matches = regex.findall(self.filename)
187
- if matches:
188
- self.releaser_sign = f"-{matches[0]}" if matches[0].upper() in self.SIGNS_LIST else ""
189
- else:
190
- self.releaser_sign = ""
191
- else:
192
- # Add releaser_sign from the configuration file
193
- self.releaser_sign = f"-{self.releaser_sign}"
209
+ self.releaser_sign = self.detect_releaser(self.filename, self.SIGNS_LIST)
194
210
 
195
211
  # /// Order according to tag position
196
212
  tags_dict = {
@@ -255,6 +271,11 @@ class SearchTags(object):
255
271
  for video in self.mediafile.video_track:
256
272
  hdr_format_commercial = video.get('hdr_format_commercial', "")
257
273
  hdr_format = video.get('hdr_format', "")
274
+ colour_primaries = video.get('color_primaries', "")
275
+ matrix_coefficients = video.get('matrix_coefficients', "")
276
+ bit_depth = video.get('bit_depth', "")
277
+ transfer_characteristics = video.get('transfer_characteristics', "")
278
+
258
279
  # Check hdr
259
280
  if hdr_format_commercial:
260
281
  # print(f"hdr_format_commercial: {hdr_format_commercial}")
@@ -271,6 +292,17 @@ class SearchTags(object):
271
292
  if 'DOLBY VISION' in hdr_format_commercial.upper() or 'DOLBY VISION' in hdr_format.upper():
272
293
  hdr = f"DOLBY VISION {hdr}"
273
294
  return {category: hdr_map.get(hdr, '*HDR')}
295
+ else:
296
+ if "2020" in colour_primaries and "2020" in matrix_coefficients:
297
+ if bit_depth == 10 and transfer_characteristics.strip() == 'PQ':
298
+ return {category: 'PQ10'}
299
+ else:
300
+ custom_console.bot_warning_log(f"<> PQ10 Warning:")
301
+ custom_console.bot_log(f"colour_primaries: {colour_primaries}")
302
+ custom_console.bot_log(f"matrix_coefficients: {matrix_coefficients}")
303
+ custom_console.bot_log(f"bit_depth: |{bit_depth}|")
304
+ custom_console.bot_log(f"transfer_characteristics: |{transfer_characteristics}|")
305
+
274
306
  return {}
275
307
 
276
308
  def mediainfo_uhd(self, category: str) -> dict:
@@ -314,3 +346,42 @@ class SearchTags(object):
314
346
  result['resolution'] = f'{video_width}x{video_height}'
315
347
 
316
348
  return result
349
+
350
+ @staticmethod
351
+ def detect_releaser(name: str, signs_list: dict) -> str:
352
+ """
353
+ normalize both signs_list and base_name
354
+ find the start/end position of the matched sign
355
+ extract the substring from the original base_name
356
+ """
357
+ # Strip the title
358
+ base_name = str(name).strip()
359
+
360
+ # sort dictionary from the longest to shortest to avoid partial result (es. 'crew' instead di 'mircrew')
361
+ tokens_signs_list_sorted = sorted(signs_list.keys(), key=len, reverse=True)
362
+
363
+ video_exts = [
364
+ "mp4", "mkv", "avi", "mov", "wmv", "flv", "webm", "mpeg", "mpg", "m4v", "ts", "3gp"
365
+ ]
366
+
367
+ # Regex per catturare l'estensione alla fine (case insensitive)
368
+ pattern = rf"\.({'|'.join(video_exts)})$"
369
+
370
+ # # Search for signs in the base_name only at the end of the string
371
+ base_name = re.sub(pattern, "", base_name, flags=re.IGNORECASE)
372
+
373
+ # Search for signs in the base_name_normalized
374
+ for token in tokens_signs_list_sorted:
375
+ token = str(token)
376
+ pattern = re.escape(token)
377
+ match = re.search(pattern, base_name, re.IGNORECASE)
378
+
379
+ if match:
380
+ # Sign must be the last words
381
+ base_name_len = len(base_name)
382
+ match_len = match.end() - base_name_len
383
+ if match_len == 0:
384
+ # Capture any characters from the start to the end of base_name
385
+ sign = base_name[match.start(): match.end()]
386
+ return f"-{sign}"
387
+ return ""
@@ -0,0 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ BAN_LIST = {
4
+ "dummy" : "banned"
5
+ }