Unit3Dup 0.9.10__tar.gz → 0.9.12__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 (102) hide show
  1. {unit3dup-0.9.10 → unit3dup-0.9.12}/PKG-INFO +1 -1
  2. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/PKG-INFO +1 -1
  3. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/SOURCES.txt +1 -1
  4. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/command.py +8 -7
  5. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/settings.py +6 -4
  6. unit3dup-0.9.12/common/tags.py +357 -0
  7. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/utility.py +43 -23
  8. {unit3dup-0.9.10 → unit3dup-0.9.12}/pyproject.toml +1 -1
  9. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media.py +6 -20
  10. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/ContentManager.py +5 -6
  11. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/VideoManager.py +29 -13
  12. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/torrent.py +2 -2
  13. unit3dup-0.9.10/common/p2p_tags.py +0 -328
  14. {unit3dup-0.9.10 → unit3dup-0.9.12}/LICENSE +0 -0
  15. {unit3dup-0.9.10 → unit3dup-0.9.12}/README.rst +0 -0
  16. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/dependency_links.txt +0 -0
  17. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/entry_points.txt +0 -0
  18. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/requires.txt +0 -0
  19. {unit3dup-0.9.10 → unit3dup-0.9.12}/Unit3Dup.egg-info/top_level.txt +0 -0
  20. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/__init__.py +0 -0
  21. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/bdinfo_string.py +0 -0
  22. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/bittorrent.py +0 -0
  23. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/constants.py +0 -0
  24. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/database.py +0 -0
  25. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/__init__.py +0 -0
  26. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/__init__.py +0 -0
  27. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/client.py +0 -0
  28. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/__init__.py +0 -0
  29. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/ftpx_service.py +0 -0
  30. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/ftpx_session.py +0 -0
  31. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/menu.py +0 -0
  32. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/models/__init__.py +0 -0
  33. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/ftpx/core/models/list.py +0 -0
  34. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/__init__.py +0 -0
  35. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/client.py +0 -0
  36. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/__init__.py +0 -0
  37. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/api.py +0 -0
  38. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/models/__init__.py +0 -0
  39. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/models/search.py +0 -0
  40. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/platformid.py +0 -0
  41. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/igdb/core/tags.py +0 -0
  42. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/imageHost.py +0 -0
  43. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/mediaresult.py +0 -0
  44. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/sessions/__init__.py +0 -0
  45. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/sessions/agents.py +0 -0
  46. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/sessions/exceptions.py +0 -0
  47. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/sessions/session.py +0 -0
  48. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/__init__.py +0 -0
  49. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/__init__.py +0 -0
  50. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/api.py +0 -0
  51. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/keywords.py +0 -0
  52. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/__init__.py +0 -0
  53. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/__init__.py +0 -0
  54. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/alternative_titles.py +0 -0
  55. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/details.py +0 -0
  56. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/movie.py +0 -0
  57. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/nowplaying.py +0 -0
  58. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/movie/release_info.py +0 -0
  59. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/__init__.py +0 -0
  60. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/alternative.py +0 -0
  61. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/details.py +0 -0
  62. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/on_the_air.py +0 -0
  63. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/translations.py +0 -0
  64. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/models/tvshow/tvshow.py +0 -0
  65. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/theMovieDB/core/videos.py +0 -0
  66. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/trailers/__init__.py +0 -0
  67. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/trailers/api.py +0 -0
  68. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/trailers/response.py +0 -0
  69. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/external_services/tvdb.py +0 -0
  70. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/extractor.py +0 -0
  71. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/frames.py +0 -0
  72. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/mediainfo.py +0 -0
  73. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/mediainfo_string.py +0 -0
  74. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/title.py +0 -0
  75. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/torrent_clients.py +0 -0
  76. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/trackers/__init__.py +0 -0
  77. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/trackers/data.py +0 -0
  78. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/trackers/itt.py +0 -0
  79. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/trackers/sis.py +0 -0
  80. {unit3dup-0.9.10 → unit3dup-0.9.12}/common/trackers/trackers.py +0 -0
  81. {unit3dup-0.9.10 → unit3dup-0.9.12}/requirements.txt +0 -0
  82. {unit3dup-0.9.10 → unit3dup-0.9.12}/setup.cfg +0 -0
  83. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/__init__.py +0 -0
  84. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/__main__.py +0 -0
  85. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/automode.py +0 -0
  86. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/bot.py +0 -0
  87. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/duplicate.py +0 -0
  88. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/exceptions.py +0 -0
  89. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/DocuManager.py +0 -0
  90. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/GameManager.py +0 -0
  91. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/MediaInfoManager.py +0 -0
  92. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/SeedManager.py +0 -0
  93. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/TorrentManager.py +0 -0
  94. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/__init__.py +0 -0
  95. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/media_manager/common.py +0 -0
  96. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/pvtDocu.py +0 -0
  97. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/pvtTorrent.py +0 -0
  98. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/pvtTracker.py +0 -0
  99. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/pvtVideo.py +0 -0
  100. {unit3dup-0.9.10 → unit3dup-0.9.12}/unit3dup/upload.py +0 -0
  101. {unit3dup-0.9.10 → unit3dup-0.9.12}/view/__init__.py +0 -0
  102. {unit3dup-0.9.10 → unit3dup-0.9.12}/view/custom_console.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Unit3Dup
3
- Version: 0.9.10
3
+ Version: 0.9.12
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.10
3
+ Version: 0.9.12
4
4
  Summary: An uploader for the Unit3D torrent tracker
5
5
  Author: Parzival
6
6
  License-Expression: MIT
@@ -18,8 +18,8 @@ common/extractor.py
18
18
  common/frames.py
19
19
  common/mediainfo.py
20
20
  common/mediainfo_string.py
21
- common/p2p_tags.py
22
21
  common/settings.py
22
+ common/tags.py
23
23
  common/title.py
24
24
  common/torrent_clients.py
25
25
  common/utility.py
@@ -27,6 +27,7 @@ class CommandLine:
27
27
  parser.add_argument("-u", "--upload", type=str, help="Upload path")
28
28
  parser.add_argument("-f", "--folder", type=str, help="Upload folder")
29
29
  parser.add_argument("-scan", "--scan", type=str, help="Scan folder")
30
+ parser.add_argument("-b", "--buildtags", action="store_true", help="Auto build torrent name")
30
31
 
31
32
  parser.add_argument("-reseed", "--reseed", action="store_true", help="reseed folder")
32
33
  parser.add_argument("-gentitle", "--gentitle", action="store_true", help="")
@@ -40,19 +41,19 @@ class CommandLine:
40
41
  parser.add_argument('-force', nargs='?', const="movie", type=str, default=None)
41
42
  parser.add_argument("-noseed", "--noseed", action="store_true", help="No seeding after upload")
42
43
  parser.add_argument("-noup", "--noup", action="store_true", help="Torrent only. No upload")
43
- parser.add_argument("-duplicate", "--duplicate", action="store_true", help="Find duplicates")
44
+ parser.add_argument("-dup", "--duplicate", action="store_true", help="Find duplicates")
44
45
  parser.add_argument("-personal", "--personal", action="store_true", help="Set to personal release")
45
46
 
46
47
  parser.add_argument("-ftp", "--ftp", action="store_true", help="Connect to FTP")
47
48
 
48
49
  # optional
49
- parser.add_argument("-dump", "--dump", action="store_true", help="Download all torrent titles")
50
- parser.add_argument("-s", "--search", type=str, help="Search for torrent")
50
+ parser.add_argument("-dmp", "--dump", action="store_true", help="Download all torrent titles")
51
+ parser.add_argument("-sch", "--search", type=str, help="Search for torrent")
51
52
  parser.add_argument("-db", "--dbsave", action="store_true", help="Save the search results")
52
53
  parser.add_argument("-i", "--info", type=str, help="Get info on torrent")
53
54
  parser.add_argument("-up", "--uploader", type=str, help="Search by uploader")
54
- parser.add_argument("-desc", "--description", type=str, help="Search by description")
55
- parser.add_argument("-bdinfo", "--bdinfo", type=str, help="Show BDInfo")
55
+ parser.add_argument("-d", "--description", type=str, help="Search by description")
56
+ parser.add_argument("-bd", "--bdinfo", type=str, help="Show BDInfo")
56
57
  parser.add_argument("-m", "--mediainfo", type=str, help="Show MediaInfo")
57
58
  parser.add_argument("-st", "--startyear", type=str, help="Start year")
58
59
  parser.add_argument("-en", "--endyear", type=str, help="End year")
@@ -68,8 +69,8 @@ class CommandLine:
68
69
  parser.add_argument("-playid", "--playlist_id", type=str, help="Playlist ID")
69
70
  parser.add_argument("-coll", "--collection_id", type=str, help="Collection ID")
70
71
  parser.add_argument("-free", "--freelech", type=str, help="Freelech discount")
71
- parser.add_argument("-a", "--alive", action="store_true", help="Alive torrent")
72
- parser.add_argument("-d", "--dead", action="store_true", help="Dead torrent")
72
+ parser.add_argument("-al", "--alive", action="store_true", help="Alive torrent")
73
+ parser.add_argument("-dd", "--dead", action="store_true", help="Dead torrent")
73
74
  parser.add_argument("-dy", "--dying", action="store_true", help="Dying torrent")
74
75
 
75
76
  parser.add_argument(
@@ -15,7 +15,7 @@ from common.utility import ManageTitles
15
15
  from common import trackers
16
16
 
17
17
  config_file = "Unit3Dbot.json"
18
- version = "0.9.10"
18
+ version = "0.9.12"
19
19
 
20
20
  if os.name == "nt":
21
21
  WATCHER_DESTINATION_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "watcher_destination_path"
@@ -250,12 +250,13 @@ class Validate:
250
250
  print(f"-> Invalid TAG position. The list is empty !")
251
251
  exit(1)
252
252
 
253
- if len(position_list) != 9:
253
+ if len(position_list) > 17 or len(position_list) < 5:
254
254
  print(f"-> Invalid TAG position list. Wrong number of elements !")
255
255
  exit(1)
256
256
 
257
257
  for tag in position_list:
258
- if tag.lower() not in ["version","resolution", "platform","source", "audio", "channels", "flag", "subtitle", "video"]:
258
+ if tag.lower() not in ["title", "year", "season", "version", "resolution", "uhd", "platform", "source", "remux",
259
+ "multi", "acodec", "channels", "flag", "subtitle", "vcodec", "hdr", "video_encoder"]:
259
260
  print(f"-> Invalid TAG position '{tag}'. Please fix your configuration file")
260
261
  exit(1)
261
262
 
@@ -578,7 +579,8 @@ class Load:
578
579
  "PASSIMA_PRIORITY": 5,
579
580
  "IMARIDE_PRIORITY": 6,
580
581
  "NUMBER_OF_SCREENSHOTS": 4,
581
- "TAGS_POSITION": ["version","resolution", "platform", "source", "audio", "channels", "flag", "subtitle", "video"],
582
+ "TAGS_POSITION": ["title", "year", "season", "version", "resolution", "uhd", "platform", "source", "remux",
583
+ "multi", "acodec", "channels", "flag", "subtitle", "vcodec", "hdr", "video_encoder"],
582
584
  "YOUTUBE_FAV_CHANNEL_ID": "UCGCbxpnt25hWPFLSbvwfg_w",
583
585
  "YOUTUBE_CHANNEL_ENABLE": "False",
584
586
  "DUPLICATE_ON": "true",
@@ -0,0 +1,357 @@
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import re
4
+ from common.mediainfo import MediaFile
5
+ from common.utility import ManageTitles
6
+
7
+ TAG_TYPES = {
8
+ "REMUX": "remux",
9
+ "WEB-DL": "source",
10
+ "WEB-DLMUX": "source",
11
+ "WEBMUX": "source",
12
+ "WEBRIP": "source",
13
+ "BD-UNTOUCHED": "source",
14
+ "TS": "source",
15
+ "CAM": "source",
16
+ "HDTS": "source",
17
+ "MD": "source",
18
+ "UHDRIP": "source",
19
+ "BLURAY": "source",
20
+ "BRRIP": "source",
21
+ "BDRIP": "source",
22
+ "FHDRIP": "source",
23
+
24
+ "ATVP": "platform",
25
+ "AMZN": "platform",
26
+ "AMC": "platform",
27
+ "CN": "platform",
28
+ "CR": "platform",
29
+ "DCU": "platform",
30
+ "DISC": "platform",
31
+ "DSCP": "platform",
32
+ "DSNY": "platform",
33
+ "DSNP": "platform",
34
+ "DPLY": "platform",
35
+ "ESPN": "platform",
36
+ "FOOD": "platform",
37
+ "FOX": "platform",
38
+ "PLAY": "platform",
39
+ "HBO": "platform",
40
+ "HMAX": "platform",
41
+ "HGTV": "platform",
42
+ "HIST": "platform",
43
+ "HULU": "platform",
44
+ "MTOD": "platform",
45
+ "NATG": "platform",
46
+ "NF": "platform",
47
+ "NICK": "platform",
48
+ "NOW": "platform",
49
+ "PMNT": "platform",
50
+ "PMTP": "platform",
51
+ "PCOK": "platform",
52
+ "RKTN": "platform",
53
+ "SHO": "platform",
54
+ "SKST": "platform",
55
+ "STAN": "platform",
56
+ "STRP": "platform",
57
+ "STZ": "platform",
58
+ "TIMV": "platform",
59
+
60
+ "REPACK": "version",
61
+ "EXTENDED": "version",
62
+ "SUBBED": "version",
63
+ "MUX": "version",
64
+ "REMASTERED": "version",
65
+ "READNFO": "version",
66
+ "UNRATED": "version",
67
+ "LIMITED": "version",
68
+ "VU": "version",
69
+ "STV": "version",
70
+ "RECODE": "version",
71
+ "INTERNAL": "version",
72
+ "PROPER": "version",
73
+ "DUAL": "version",
74
+ "UNTOUCHED": "version",
75
+ "COMPLETE": "version",
76
+ "COMPLETA": "version",
77
+
78
+ "X264": "video_encoder",
79
+ "X265": "video_encoder",
80
+ }
81
+
82
+ # From hdr format
83
+ hdr_map = {
84
+ "DOLBY VISION": "DV",
85
+ "DOLBY VISION HDR": "DV HDR",
86
+ "DOLBY VISION HDR10": "DV HDR10",
87
+ "HDR10PLUS": "HDR10+",
88
+ "HDRPLUS+": "HDR10+",
89
+ "HDR10+": "HDR10+",
90
+ "HDR10": "HDR10",
91
+ "HDR10 / HDR10": "HDR10",
92
+ "DOVI": "DV",
93
+ "HDR": "HDR",
94
+ }
95
+
96
+ audio_translate = {
97
+ "AC3": "DD",
98
+ "AAC LC": "AAC",
99
+ "AC-3": "DD",
100
+ "EAC3": "DD+",
101
+ "E-AC3": "DD+",
102
+ "E-AC-3": "DD+",
103
+ "E-AC-3 JOC": "DD+",
104
+ "DTS": "DTS",
105
+ "DTS ES": "DTS-ES",
106
+ "DTS ES XLL": "DTS-HD MA",
107
+ "DTS XLL": "DTS-HD MA",
108
+ "MLP FBA 16-ch": "TrueHD",
109
+ "MPEG Audio": "MPEG",
110
+ }
111
+
112
+ video_translate = {
113
+ "AVC": "H.264",
114
+ "HEVC": "H.265",
115
+ "H265": "H.265",
116
+ "H264": "H.264",
117
+ }
118
+
119
+ video_encoder_translate = {
120
+ "X265": "x.265",
121
+ "X264": "x.264",
122
+ }
123
+
124
+
125
+ class SearchTags(object):
126
+ def __init__(self, filename, title: str, year: str, season: int, episode: int,
127
+ mediafile: MediaFile, tags_position: list, releaser_sign: str):
128
+
129
+ self.tags_position = tags_position
130
+ self.releaser_sign = releaser_sign
131
+ self.mediafile = mediafile
132
+ self.filename = filename
133
+ self.episode = episode
134
+ self.season = season
135
+ self.title = title
136
+ self.year = year
137
+ self.tags_dict = {}
138
+ self.tags_position = tags_position
139
+
140
+ def normalize_version_tag(self, tag: str) -> str:
141
+ tag_esc = re.escape(tag)
142
+ # Filter hyphenated,space compounds
143
+ tag_esc = tag_esc.replace(r'\ ', r'[.\s_-]*')
144
+ return tag_esc
145
+
146
+ def normalize_platform_tag(self, tag: str) -> str:
147
+ # escape
148
+ tag_esc = re.escape(tag)
149
+ return tag_esc
150
+
151
+ def normalize_sources(self, tag: str) -> str:
152
+ tag_esc = re.escape(tag)
153
+ # Filter hyphenated,space compounds
154
+ tag_esc = tag_esc.replace(r'\ ', r'[.\s_-]*')
155
+ return tag_esc
156
+
157
+ def normalize_video_encoder(self, tag: str) -> str:
158
+ tag_esc = re.escape(tag)
159
+ tag_esc = re.sub(r'([A-Z])(\d+)', r'\1[._-]?\2', tag_esc)
160
+ return tag_esc
161
+
162
+ def process(self) -> str:
163
+ patterns = []
164
+
165
+ # loop sorted TAG_TYPES dictionary
166
+ for i, (tag, category) in enumerate(
167
+ sorted(TAG_TYPES.items(), key=lambda x: len(x[0]), reverse=True)
168
+ ):
169
+ if category == "version":
170
+ norm = self.normalize_version_tag(tag)
171
+ elif category == "platform":
172
+ norm = self.normalize_platform_tag(tag)
173
+ elif category == "source":
174
+ norm = self.normalize_sources(tag)
175
+ elif category == "video_encoder":
176
+ norm = self.normalize_video_encoder(tag)
177
+ else:
178
+ norm = re.escape(tag)
179
+ # Save a regex pattern for each category
180
+ patterns.append([norm, category])
181
+
182
+ # Run regex
183
+ for p, category in patterns:
184
+ regex = re.compile(r'(?<!\w)' + p + r'(?!\w)', re.IGNORECASE)
185
+ matches = regex.findall(self.filename)
186
+ if matches:
187
+ self.tags_dict.setdefault(category, []).append(matches[0])
188
+
189
+ # /// Read from mediainfo
190
+ updated_category = {}
191
+ for category in self.tags_position:
192
+ if category == "acodec":
193
+ updated_category = self.mediainfo_audio(category=category)
194
+
195
+ elif category == "vcodec":
196
+ updated_category = self.mediainfo_video(category=category)
197
+
198
+ elif category == "hdr":
199
+ updated_category = self.mediainfo_hdr(category=category)
200
+
201
+ elif category == "uhd":
202
+ updated_category = self.mediainfo_uhd(category=category)
203
+
204
+ elif category == "subtitle":
205
+ updated_category = {'subtitle': "SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB"}
206
+
207
+ if updated_category:
208
+ self.tags_dict.update(updated_category)
209
+
210
+ # /// Add S#E#, title, Year
211
+ se_str = ''
212
+ if self.season is not None and self.episode is not None:
213
+ se_str = f"S{self.season:02d}E{self.episode:02d}"
214
+ elif self.season is not None:
215
+ se_str = f"S{self.season:02d}"
216
+ elif self.episode is not None:
217
+ se_str = f"E{self.episode:02d}"
218
+
219
+ self.tags_dict.update({'title': self.title})
220
+ if self.year:
221
+ self.tags_dict.update({'year': self.year})
222
+ if se_str:
223
+ self.tags_dict.update({'season': se_str})
224
+
225
+ # /// Add Sign
226
+ if not self.releaser_sign:
227
+ filename, _ = os.path.splitext(os.path.basename(self.filename))
228
+ m = re.search(r'-([A-Za-z0-9]+)$', filename)
229
+ self.releaser_sign = f"-{m.group(1)}" if m and m.group(1) not in TAG_TYPES else ""
230
+ else:
231
+ self.releaser_sign = f"-{self.releaser_sign}"
232
+
233
+ # /// Order according to tag position
234
+ tags_dict = {
235
+ k: self.tags_dict[k]
236
+ for k in self.tags_position
237
+ if k in self.tags_dict
238
+ }
239
+
240
+ # /// Build the title
241
+ build = []
242
+ for k, v in tags_dict.items():
243
+ if isinstance(v, list):
244
+ build.append(' '.join(v))
245
+ else:
246
+ build.append(str(v))
247
+
248
+ refactored = ' '.join(build) + self.releaser_sign
249
+ return refactored
250
+
251
+ def mediainfo_audio(self, category: str) -> dict:
252
+ langs = set()
253
+ audio_codecs = []
254
+ if self.mediafile.audio_track:
255
+ for audio in self.mediafile.audio_track:
256
+ other_format = audio.get('other_format', [])
257
+ if other_format:
258
+ codec_translated = audio_translate.get(other_format[0], '')
259
+ if not codec_translated:
260
+ codec_translated = other_format[0]
261
+ # Check Atmos
262
+ dolby = audio.get('commercial_name', "").lower()
263
+ atmos = 'Atmos' if 'atmos' in dolby else ''
264
+ # Add audio codec
265
+ channel_s = audio.get('channel_s', 0)
266
+ # Add channels
267
+ ch = {2: "2.0", 6: "5.1", 8: "7.1"}.get(channel_s, "")
268
+ if f"{codec_translated} {ch} {atmos}".strip() not in audio_codecs:
269
+ audio_codecs.append(f"{codec_translated} {ch} {atmos}".strip())
270
+ print(f"Mediainfo {other_format} -> {codec_translated} {ch} {atmos}")
271
+
272
+ # Add flags
273
+ for l in audio.get('other_language', []):
274
+ c = ManageTitles.convert_iso(l)
275
+ if c:
276
+ if isinstance(c, list):
277
+ langs.update(c)
278
+ else:
279
+ langs.add(c)
280
+ break
281
+ # Add multilanguage tag when languages > 2
282
+ if len(langs) > 2:
283
+ self.tags_dict.update({'multi': 'MULTI'})
284
+
285
+ audio_codecs.extend(list(langs))
286
+ return {category: audio_codecs}
287
+
288
+ def mediainfo_video(self, category: str) -> dict:
289
+ codec_translated = {}
290
+ if self.mediafile.video_track:
291
+ for video in self.mediafile.video_track:
292
+ video_format = video.get('format', "")
293
+ codec_translated = video_translate.get(video_format, video_format)
294
+ if codec_translated:
295
+ return {category: codec_translated}
296
+ return codec_translated
297
+
298
+ def mediainfo_hdr(self, category: str) -> dict:
299
+ if self.mediafile.video_track:
300
+ for video in self.mediafile.video_track:
301
+ hdr_format_commercial = video.get('hdr_format_commercial', "")
302
+ hdr_format = video.get('hdr_format', "")
303
+ # Check hdr
304
+ if hdr_format_commercial:
305
+ print(f"hdr_format_commercial: {hdr_format_commercial}")
306
+ print(f"hdr_format: {hdr_format}")
307
+ hdr = ''
308
+ if hdr_format_commercial in hdr_map:
309
+ print(f"hdr_format_commercial: {hdr_format_commercial} -> Tag: {hdr_map[hdr_format_commercial]}")
310
+ hdr = hdr_map[hdr_format_commercial]
311
+ # Check dolby vision
312
+ if 'DOLBY VISION' in hdr_format_commercial.upper() or 'DOLBY VISION' in hdr_format.upper():
313
+ hdr = f"DOLBY VISION {hdr}"
314
+ print(hdr)
315
+ return {category: hdr_map[hdr]}
316
+ return {}
317
+
318
+ def mediainfo_uhd(self, category: str) -> dict:
319
+ """
320
+ identify resolution based on Height and Width tolerance 5%
321
+ """
322
+ result = {}
323
+ if self.mediafile.video_track:
324
+ video_height = int(self.mediafile.video_track[0].get('height', 0))
325
+ video_width = int(self.mediafile.video_track[0].get('width', 0))
326
+ print(f"VideoTrack : W{video_width} x H{video_height}")
327
+
328
+ # Calculate range 5%
329
+ def in_range(value, standard):
330
+ tol = standard * 0.05
331
+ return standard - tol <= value <= standard + tol
332
+
333
+ # /// UHD
334
+ if video_height >= 2000 or video_width >= 3840:
335
+ result[category] = 'UHD'
336
+ result['resolution'] = '2160p'
337
+ # /// Full HD
338
+ elif in_range(video_height, 1080) or in_range(video_width, 1920):
339
+ result[category] = 'FullHD'
340
+ result['resolution'] = '1080p'
341
+ # /// HD
342
+ elif in_range(video_height, 720) or in_range(video_width, 1280):
343
+ result[category] = 'HD'
344
+ result['resolution'] = '720p'
345
+ # /// SD 576p
346
+ elif in_range(video_height, 576) or in_range(video_width, 768):
347
+ result[category] = 'SD'
348
+ result['resolution'] = '576p'
349
+ # /// SD 480p
350
+ elif in_range(video_height, 480) or in_range(video_width, 640):
351
+ result[category] = 'SD'
352
+ result['resolution'] = '480p'
353
+ else:
354
+ result[category] = 'unknown'
355
+ result['resolution'] = f'{video_width}x{video_height}'
356
+
357
+ return result
@@ -171,8 +171,39 @@ class ManageTitles:
171
171
 
172
172
  return filename
173
173
 
174
+ @staticmethod
175
+ def recover_tag(filename_sanitized: str) -> str:
176
+
177
+ # Add the tag
178
+ replacements = [
179
+ (r'\b7 \b1\b', '7.1'),
180
+ (r'\b5 \b1\b', '5.1'),
181
+ (r'\bDDP5 \b1\b', 'DDP5.1'),
182
+ (r'\bDDP2 \b0\b', 'DDP2.0'),
183
+ (r'\bDD5 \b1\b', 'DD5.1'),
184
+ (r'\bDD2 \b0\b', 'DD2.0'),
185
+ (r'\b2 \b0\b', '2.0'),
186
+ (r'\bWEB \bDL\b', 'WEB-DL'),
187
+ (r'\bWEB \bDLMUX\b', 'WEB-DLMUX'),
188
+ (r'\bBD \bUNTOUCHED\b', 'BD-UNTOUCHED'),
189
+ (r'\bCINEMA \bMD\b', 'CINEMA-MD'),
190
+ (r'\bHEVC \bFHC\b', 'HEVC-FHC'),
191
+ (r'\bCBR \bCBZ\b', 'CBR-CBZ'),
192
+ (r'\bH \b264\b', 'H.264'),
193
+ (r'\bH \b265\b', 'H.265'),
194
+ (r'\bAAC2 \b0\b', 'AAC2.0'),
195
+ (r'\bAAC5 \b1\b', 'AAC5.1'),
196
+ ]
197
+
198
+ for tag, replacement in replacements:
199
+ filename_sanitized = re.sub(tag, replacement, filename_sanitized, flags=re.IGNORECASE)
200
+ return filename_sanitized
201
+
174
202
  @staticmethod
175
203
  def clean_text(filename: str) -> str:
204
+ """
205
+ Clean filename
206
+ """
176
207
 
177
208
  # Remove each addition from the string
178
209
  filename_sanitized = filename
@@ -193,34 +224,23 @@ class ManageTitles:
193
224
 
194
225
  # remove double space
195
226
  filename_sanitized = re.sub(r"\s+", " ", filename_sanitized).strip()
196
-
197
227
  return filename_sanitized
198
228
 
199
229
  @staticmethod
200
- def recover_tag(filename_sanitized: str) -> str:
230
+ def clean_tags(filename: str) -> str:
231
+ """
232
+ Clean filename for title generation
233
+ """
201
234
 
202
- # Add the tag
203
- replacements = [
204
- (r'\b7 \b1\b', '7.1'),
205
- (r'\b5 \b1\b', '5.1'),
206
- (r'\bDDP5 \b1\b', 'DDP5.1'),
207
- (r'\bDDP2 \b0\b', 'DDP2.0'),
208
- (r'\bDD5 \b1\b', 'DD5.1'),
209
- (r'\bDD2 \b0\b', 'DD2.0'),
210
- (r'\b2 \b0\b', '2.0'),
211
- (r'\bWEB \bDL\b', 'WEB-DL'),
212
- (r'\bWEB \bDLMUX\b', 'WEB-DLMUX'),
213
- (r'\bBD \bUNTOUCHED\b', 'BD-UNTOUCHED'),
214
- (r'\bCINEMA \bMD\b', 'CINEMA-MD'),
215
- (r'\bHEVC \bFHC\b', 'HEVC-FHC'),
216
- (r'\bCBR \bCBZ\b', 'CBR-CBZ'),
217
- (r'\bH \b264\b', 'H.264'),
218
- (r'\bH \b265\b', 'H.265'),
219
- (r'\bAAC2 \b0\b', 'AAC2.0'),
220
- ]
235
+ filename_sanitized = filename
236
+ # Remove v version
237
+ filename_sanitized = re.sub(r"v\d+(?:[ .]\d+)*", "", filename_sanitized).strip()
221
238
 
222
- for tag, replacement in replacements:
223
- filename_sanitized = re.sub(tag, replacement, filename_sanitized, flags=re.IGNORECASE)
239
+ # remove spaces, tab, newline
240
+ filename_sanitized = re.sub(r"\s+", " ", filename_sanitized)
241
+
242
+ # remove double space
243
+ filename_sanitized = re.sub(r"\s+", " ", filename_sanitized).strip()
224
244
  return filename_sanitized
225
245
 
226
246
 
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  dynamic = ["dependencies"]
7
7
  name = "Unit3Dup"
8
- version = "0.9.10"
8
+ version = "0.9.12"
9
9
  description = "An uploader for the Unit3D torrent tracker"
10
10
  readme = "README.rst"
11
11
  requires-python = ">=3.10"
@@ -6,9 +6,7 @@ from common.external_services.igdb.core.tags import crew_patterns, platform_patt
6
6
  from common.title import Guessit
7
7
  from common.utility import ManageTitles, System
8
8
  from common.mediainfo import MediaFile
9
- from common.p2p_tags import P2pTags
10
9
  from common import title
11
- from unit3dup import config_settings
12
10
  from view import custom_console
13
11
 
14
12
 
@@ -62,9 +60,12 @@ class Media:
62
60
  self._title_sanitized = ManageTitles.clean_text(self.title)
63
61
  return self._title_sanitized
64
62
 
65
- @title_sanitized.setter
66
- def title_sanitized(self, value):
67
- self.title_sanitized = value
63
+ @property
64
+ def title_sanitize_tags(self) -> str:
65
+ if not self._title_sanitized:
66
+ self._title_sanitized = ManageTitles.clean_tags(self.title)
67
+ return self._title_sanitized
68
+
68
69
 
69
70
  @property
70
71
  def crew_list(self) -> list['str']:
@@ -219,21 +220,6 @@ class Media:
219
220
 
220
221
  @property
221
222
  def display_name(self):
222
- if not self._display_name:
223
- self._guess_filename = title.Guessit(self.title_sanitized)
224
- guess = self._guess_filename.guessit
225
- p2p_tags = P2pTags(filename=self.title_sanitized,
226
- title=guess.get("title", None),
227
- year=guess.get("year", ""),
228
- episode_title=guess.get("episode_title", None),
229
- mediafile_resolution=self.resolution,
230
- season=self.guess_season,
231
- episode=self.guess_episode,
232
- releaser_sign=config_settings.user_preferences.RELEASER_SIGN,
233
- tags_position=config_settings.user_preferences.TAGS_POSITION,
234
- mediafile=self.mediafile
235
- )
236
- self._display_name = p2p_tags.process()
237
223
  return self._display_name
238
224
 
239
225
  @display_name.setter
@@ -135,10 +135,9 @@ class ContentManager:
135
135
  self.file_name = self.path
136
136
 
137
137
  # # Display name on webpage
138
-
139
- # self.display_name, _ = os.path.splitext(os.path.basename(self.file_name))
140
- # self.display_name = ManageTitles.clean_text(self.display_name)
141
- # self.display_name = re.sub(r'[\[\]()]', '', self.display_name)
138
+ self.display_name, _ = os.path.splitext(os.path.basename(self.file_name))
139
+ self.display_name = ManageTitles.clean_text(self.display_name)
140
+ self.display_name = re.sub(r'[\[\]()]', '', self.display_name)
142
141
 
143
142
  # current media path
144
143
  self.torrent_path = self.path
@@ -164,8 +163,8 @@ class ContentManager:
164
163
  self.file_name = os.path.join(self.path, files_list[0])
165
164
 
166
165
  # # Display name on webpage
167
- # self.display_name = ManageTitles.clean_text(os.path.basename(self.path))
168
- # self.display_name = re.sub(r'[\[\]()]', '', self.display_name)
166
+ self.display_name = ManageTitles.clean_text(os.path.basename(self.path))
167
+ self.display_name = re.sub(r'[\[\]()]', '', self.display_name)
169
168
 
170
169
  # current media path
171
170
  self.torrent_path = self.path