Unit3Dup 0.9.9__tar.gz → 0.9.11__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 (101) hide show
  1. {unit3dup-0.9.9 → unit3dup-0.9.11}/PKG-INFO +1 -1
  2. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/PKG-INFO +1 -1
  3. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/p2p_tags.py +113 -158
  4. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/settings.py +1 -1
  5. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/utility.py +45 -29
  6. {unit3dup-0.9.9 → unit3dup-0.9.11}/pyproject.toml +1 -1
  7. {unit3dup-0.9.9 → unit3dup-0.9.11}/LICENSE +0 -0
  8. {unit3dup-0.9.9 → unit3dup-0.9.11}/README.rst +0 -0
  9. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/SOURCES.txt +0 -0
  10. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/dependency_links.txt +0 -0
  11. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/entry_points.txt +0 -0
  12. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/requires.txt +0 -0
  13. {unit3dup-0.9.9 → unit3dup-0.9.11}/Unit3Dup.egg-info/top_level.txt +0 -0
  14. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/__init__.py +0 -0
  15. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/bdinfo_string.py +0 -0
  16. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/bittorrent.py +0 -0
  17. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/command.py +0 -0
  18. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/constants.py +0 -0
  19. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/database.py +0 -0
  20. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/__init__.py +0 -0
  21. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/__init__.py +0 -0
  22. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/client.py +0 -0
  23. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/__init__.py +0 -0
  24. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/ftpx_service.py +0 -0
  25. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/ftpx_session.py +0 -0
  26. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/menu.py +0 -0
  27. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/models/__init__.py +0 -0
  28. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/ftpx/core/models/list.py +0 -0
  29. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/__init__.py +0 -0
  30. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/client.py +0 -0
  31. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/__init__.py +0 -0
  32. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/api.py +0 -0
  33. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/models/__init__.py +0 -0
  34. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/models/search.py +0 -0
  35. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/platformid.py +0 -0
  36. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/igdb/core/tags.py +0 -0
  37. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/imageHost.py +0 -0
  38. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/mediaresult.py +0 -0
  39. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/sessions/__init__.py +0 -0
  40. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/sessions/agents.py +0 -0
  41. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/sessions/exceptions.py +0 -0
  42. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/sessions/session.py +0 -0
  43. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/__init__.py +0 -0
  44. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/__init__.py +0 -0
  45. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/api.py +0 -0
  46. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/keywords.py +0 -0
  47. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/__init__.py +0 -0
  48. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/__init__.py +0 -0
  49. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/alternative_titles.py +0 -0
  50. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/details.py +0 -0
  51. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/movie.py +0 -0
  52. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/nowplaying.py +0 -0
  53. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/movie/release_info.py +0 -0
  54. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/__init__.py +0 -0
  55. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/alternative.py +0 -0
  56. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/details.py +0 -0
  57. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/on_the_air.py +0 -0
  58. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/translations.py +0 -0
  59. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/models/tvshow/tvshow.py +0 -0
  60. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/theMovieDB/core/videos.py +0 -0
  61. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/trailers/__init__.py +0 -0
  62. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/trailers/api.py +0 -0
  63. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/trailers/response.py +0 -0
  64. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/external_services/tvdb.py +0 -0
  65. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/extractor.py +0 -0
  66. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/frames.py +0 -0
  67. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/mediainfo.py +0 -0
  68. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/mediainfo_string.py +0 -0
  69. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/title.py +0 -0
  70. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/torrent_clients.py +0 -0
  71. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/trackers/__init__.py +0 -0
  72. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/trackers/data.py +0 -0
  73. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/trackers/itt.py +0 -0
  74. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/trackers/sis.py +0 -0
  75. {unit3dup-0.9.9 → unit3dup-0.9.11}/common/trackers/trackers.py +0 -0
  76. {unit3dup-0.9.9 → unit3dup-0.9.11}/requirements.txt +0 -0
  77. {unit3dup-0.9.9 → unit3dup-0.9.11}/setup.cfg +0 -0
  78. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/__init__.py +0 -0
  79. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/__main__.py +0 -0
  80. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/automode.py +0 -0
  81. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/bot.py +0 -0
  82. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/duplicate.py +0 -0
  83. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/exceptions.py +0 -0
  84. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media.py +0 -0
  85. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/ContentManager.py +0 -0
  86. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/DocuManager.py +0 -0
  87. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/GameManager.py +0 -0
  88. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/MediaInfoManager.py +0 -0
  89. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/SeedManager.py +0 -0
  90. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/TorrentManager.py +0 -0
  91. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/VideoManager.py +0 -0
  92. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/__init__.py +0 -0
  93. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/media_manager/common.py +0 -0
  94. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/pvtDocu.py +0 -0
  95. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/pvtTorrent.py +0 -0
  96. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/pvtTracker.py +0 -0
  97. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/pvtVideo.py +0 -0
  98. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/torrent.py +0 -0
  99. {unit3dup-0.9.9 → unit3dup-0.9.11}/unit3dup/upload.py +0 -0
  100. {unit3dup-0.9.9 → unit3dup-0.9.11}/view/__init__.py +0 -0
  101. {unit3dup-0.9.9 → unit3dup-0.9.11}/view/custom_console.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Unit3Dup
3
- Version: 0.9.9
3
+ Version: 0.9.11
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.9
3
+ Version: 0.9.11
4
4
  Summary: An uploader for the Unit3D torrent tracker
5
5
  Author: Parzival
6
6
  License-Expression: MIT
@@ -1,9 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import os
3
3
  import re
4
+ from collections import deque
4
5
  from common.utility import ManageTitles
5
6
  from common.mediainfo import MediaFile
6
- from collections import deque
7
7
 
8
8
  TAG_TYPES = {
9
9
  "WEB-DL": "source",
@@ -16,8 +16,10 @@ TAG_TYPES = {
16
16
  "REMUX": "source",
17
17
  "VU": "source",
18
18
  "UHD": "source",
19
+ "UHDRIP": "source",
19
20
  "BLURAY": "source",
20
21
 
22
+ "ATVP": "platform",
21
23
  "AMZN": "platform",
22
24
  "AMC": "platform",
23
25
  "CN": "platform",
@@ -53,8 +55,6 @@ TAG_TYPES = {
53
55
  "STZ": "platform",
54
56
  "TIMV": "platform",
55
57
 
56
- "SUB": "subtitle",
57
- "SUBS": "subtitle",
58
58
  "ITA": "flag",
59
59
  "ENG": "flag",
60
60
  "FRA": "flag",
@@ -65,6 +65,9 @@ TAG_TYPES = {
65
65
  "POR": "flag",
66
66
  "PRT": "flag",
67
67
 
68
+ "SUB": "subtitle",
69
+ "SUBS": "subtitle",
70
+
68
71
  "ATMOS": "audio",
69
72
  "TRUEHD": "audio",
70
73
  "DTSHD": "audio",
@@ -74,19 +77,19 @@ TAG_TYPES = {
74
77
  "DDP5.1": "audio",
75
78
  "DDP2.0": "audio",
76
79
  "DTS": "audio",
77
-
80
+ "XLL": "audio",
78
81
  "DD7.1": "audio",
79
82
  "DD5.1": "audio",
80
83
  "DD2.0": "audio",
81
-
82
84
  "DD+ 7.1": "audio",
83
85
  "DD+ 5.1": "audio",
84
86
  "DD+ 2.0": "audio",
85
-
87
+ "DTS-HD MA 7.1": "audio",
88
+ "DTS-HD MA 5.1": "audio",
89
+ "DTS-HD MA 2.0": "audio",
86
90
  "DD 7.1": "audio",
87
91
  "DD 5.1": "audio",
88
92
  "DD 2.0": "audio",
89
-
90
93
  "AAC2.0": "audio",
91
94
  "AAC5.1": "audio",
92
95
  "AC3": "audio",
@@ -94,22 +97,25 @@ TAG_TYPES = {
94
97
  "DD+": "audio",
95
98
  "DDP": "audio",
96
99
  "E-AC3": "audio",
100
+ "E-AC-3": "audio",
97
101
  "EAC3": "audio",
98
102
  "AC-3": "audio",
99
103
  "AAC": "audio",
104
+ "AAC LC": "audio",
100
105
  "AVC": "audio",
101
106
 
102
107
  "7.1": "channels",
103
108
  "5.1": "channels",
104
109
  "2.0": "channels",
105
110
 
111
+ "X.264": "video_encoder",
112
+ "X264": "video_encoder",
113
+ "X.265": "video_encoder",
114
+ "X265": "video_encoder",
115
+
106
116
  "H.264": "video",
107
- "X.264": "video",
108
- "X264": "video",
109
- "H264": "video",
110
117
  "H.265": "video",
111
- "X.265": "video",
112
- "X265": "video",
118
+ "H264": "video",
113
119
  "H265": "video",
114
120
  "HEVC": "video",
115
121
  "DV": "video",
@@ -121,7 +127,6 @@ TAG_TYPES = {
121
127
  "HDR": "video",
122
128
  "HDR10+": "video",
123
129
  "FHDRIP": "video",
124
- "UHDRIP": "video",
125
130
  "FULL HD": "video",
126
131
  "FULLHD": "video",
127
132
  "HD": "video",
@@ -136,14 +141,15 @@ TAG_TYPES = {
136
141
  "720P": "resolution",
137
142
  "576P": "resolution",
138
143
  "480P": "resolution",
139
-
140
144
  }
141
145
 
142
146
 
143
147
  class P2pTags:
144
- def __init__(self, filename: str, title: str, year: str, mediafile_resolution: str, season: int, episode: int,
145
- episode_title: str, releaser_sign: str, tags_position: list, mediafile: MediaFile):
146
-
148
+ def __init__(
149
+ self, filename: str, title: str, year: str, mediafile_resolution: str,
150
+ season: int, episode: int, episode_title: str, releaser_sign: str,
151
+ tags_position: list, mediafile: MediaFile
152
+ ):
147
153
  self.filename = filename
148
154
  self.title = title
149
155
  self.year = year
@@ -156,55 +162,65 @@ class P2pTags:
156
162
  self.tags_position = tags_position
157
163
  self.sign_in_title: str | None = None
158
164
 
165
+ self.tags_sorted = self._extract_tags()
166
+
167
+ def _extract_tags(self) -> list:
159
168
  search_tags = sorted(TAG_TYPES.keys(), key=len, reverse=True)
160
- pattern = re.compile(
161
- r'\b(?:' + '|'.join(map(re.escape, search_tags)) + r')\b',
162
- re.IGNORECASE
163
- )
169
+ pattern = re.compile(r'\b(?:' + '|'.join(map(re.escape, search_tags)) + r')\b', re.IGNORECASE)
164
170
 
165
171
  # Search for tags in the title
166
- tags_match = pattern.findall(filename.upper())
167
- # remove dope
168
- tags_match = list(dict.fromkeys(tags_match))
169
-
172
+ tags_match = list(dict.fromkeys(pattern.findall(self.filename)))
170
173
  # Search for channels
171
- channel_s = self.mediafile.audio_track[0].get('channel_s', None)
172
- ch: str = ''
173
- # map channels
174
- if channel_s == 6:
175
- ch = "5.1"
176
- elif channel_s == 8:
177
- ch = "7.1"
178
- elif channel_s == 2:
179
- ch = "2.0"
180
-
181
- # extract categories results
182
- categories = [TAG_TYPES.get(tag) for tag in tags_match]
174
+ ch = ''
175
+ if self.mediafile.audio_track:
176
+ channel_s = self.mediafile.audio_track[0].get('channel_s', 0)
177
+ ch = {2: "2.0", 6: "5.1", 8: "7.1"}.get(channel_s, "")
183
178
 
179
+ # Categories of found tags
180
+ categories = [TAG_TYPES.get(tag.upper()) for tag in tags_match]
184
181
  # Add video codec only if there is no video categories
185
- if 'video' not in categories:
186
- video_codec = self.mediafile.video_track[0].get('format', "") if self.mediafile.video_track else ""
187
- tags_match.append(video_codec)
188
-
189
- # Add audio codec only if there is no audio categories
190
- if 'audio' not in categories:
191
- audio_format = self.mediafile.audio_track[0].get('format', "") if self.mediafile.audio_track else ""
192
- tags_match.append(audio_format)
182
+ if 'video' not in categories and self.mediafile.video_track:
183
+ video_codec = self.mediafile.video_track[0].get('format', "")
184
+ if video_codec:
185
+ tags_match.append(video_codec)
186
+
187
+ # Add audio codec only if there is no video categories
188
+ if 'audio' not in categories and self.mediafile.audio_track:
189
+ for audio in self.mediafile.audio_track:
190
+ # Other_format https://github.com/sbraz/pymediainfo/discussions/119#discussioncomment-2330673
191
+ # con format mi restituisce solo DTS
192
+ # Use other_format per format che hanno uno o piu tag
193
+ other_format = audio.get('other_format', [])
194
+ if other_format:
195
+ tags_match.append(other_format[0])
193
196
 
194
197
  # Add tag language if there is no tag
195
198
  flags = self._audio_lang()
196
- # are all the language tags from mediaInfo available in the title?
197
- if len(flags) != tags_match.count('flag'):
198
- missing_flags = [tag for tag in flags if tag not in tags_match]
199
- tags_match.extend(missing_flags)
199
+ missing_flags = [tag for tag in flags if tag not in tags_match]
200
+ tags_match.extend(missing_flags)
200
201
 
201
202
  # Add subtitle tag if subtitle_track exist and there is no 'sub' in the title
202
- if 'subtitle' not in categories:
203
- sub_tag = "SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB"
204
- if self.mediafile.subtitle_track:
205
- tags_match.append(sub_tag)
203
+ if 'subtitle' not in categories and self.mediafile.subtitle_track:
204
+ tags_match.append("SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB")
206
205
 
207
- # Translate audio codec
206
+ return self._normalize_tags(tags_match, ch)
207
+
208
+ def _audio_lang(self) -> set:
209
+ if not self.mediafile:
210
+ return set()
211
+ langs = set()
212
+ for track in self.mediafile.audio_track:
213
+ for l in track.get('other_language', []):
214
+ c = ManageTitles.convert_iso(l)
215
+ if c:
216
+ if isinstance(c, list):
217
+ langs.update(c)
218
+ else:
219
+ langs.update(c)
220
+ break
221
+ return langs
222
+
223
+ def _normalize_tags(self, tags_match: list, channel_tag: str) -> list:
208
224
  audio_translate = {
209
225
  "AC3": "DD",
210
226
  "AC-3": "DD",
@@ -214,139 +230,85 @@ class P2pTags:
214
230
  "DDP5.1": "DD+",
215
231
  "DDP7.1": "DD+",
216
232
  "DDP": "DD+",
233
+ "DTS XLL": "DTS-HD MA",
217
234
  }
218
235
 
219
- # Translate video codec
220
236
  video_translate = {
221
- "H.264": "x264",
222
- "X.264": "x264",
223
- "X264": "x264",
224
- "AVC": "x264",
225
- "H.265": "x265",
226
- "H265": "x265",
227
- "X.265": "x265",
228
- "X265": "x265",
229
- "HEVC": "x265",
237
+ "AVC": "H.264",
238
+ "X265": "x.265",
239
+ "X264": "x.264",
240
+ "HEVC": "H.265",
241
+ "H265": "H.265",
242
+ "H264": "H.264",
230
243
  }
231
244
 
232
- # lower the res..
233
245
  resolution_lower = {"4320P", "2160P", "1080P", "720P", "576P", "480P"}
234
- codec_lower = {'X.264', 'X265', 'X.265', 'X264'}
235
-
236
- has_channel_tag = ch in tags_match
237
- new_tags = []
246
+ codec_lower = {"X.264", "X265", "X.265", "X264"}
238
247
 
239
248
  # verify the tags found in the title
249
+ normalized = []
240
250
  for tag in tags_match:
241
251
  t = tag.upper()
242
252
  if t in audio_translate:
243
253
  codec = audio_translate[t]
244
- # Add channels only if it does not exist
245
- if ch and not has_channel_tag:
246
- tag = f"{codec} {ch}"
247
- else:
248
- tag = codec
249
-
254
+ tag = f"{codec} {channel_tag}" if channel_tag else codec
250
255
  elif t in video_translate:
251
256
  tag = video_translate[t]
252
-
253
- # Lower the res
254
- elif t in resolution_lower:
257
+ elif t in resolution_lower or t in codec_lower:
255
258
  tag = t.lower()
256
-
257
- # Fix the 'sub' word
258
259
  elif t == "SUB":
259
- sub_tag = "SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB"
260
- tag = sub_tag
261
-
262
- elif t in codec_lower:
263
- tag = t.lower()
264
-
265
- new_tags.append(tag)
266
-
267
- tags_match = new_tags
260
+ tag = "SUBS" if len(self.mediafile.subtitle_track) > 1 else "SUB"
261
+ normalized.append(tag)
268
262
 
269
263
  # Check if a 'resolution' tag exists and add mediafile resolution if it doesn't
270
- if not any(TAG_TYPES.get(tag.upper()) == "resolution" for tag in tags_match):
271
- tags_match.append(self.mediafile_resolution)
264
+ if not any(TAG_TYPES.get(tag.upper()) == "resolution" for tag in normalized):
265
+ normalized.append(self.mediafile_resolution)
272
266
 
267
+ # Sort and alternate audio/flag tags
268
+ return self._sort_tags(normalized, channel_tag)
269
+
270
+ def _sort_tags(self, tags: list, channel_tag: str) -> list:
273
271
  # /// Sort tags based on 2 rules:
274
272
  # 1) Order by tag_positions
275
273
  # 2) For audio and flag categories alternate them (audio/flag/audio/flag)
276
274
  # We can't sort each tags so we create dedicated list
277
- audio_q = deque()
278
- flag_q = deque()
279
- channel_q = deque()
280
-
281
- # This dict is for other categories
275
+ audio_q, flag_q, channel_q = deque(), deque(), deque()
282
276
  other_groups = {}
283
277
 
284
- # Isolate audio and flag tags
285
- # All other tags will follow the normal precedence order
286
- for tag in tags_match:
278
+ for tag in tags:
287
279
  cat = TAG_TYPES.get(tag.upper(), "unknown")
288
280
  if cat == "audio":
289
- # Add audio tag to its queue
290
- audio_q.append(tag)
281
+ audio_q.append(tag.upper())
291
282
  elif cat == "channels":
292
283
  channel_q.append(tag)
293
284
  elif cat == "flag":
294
- # Add flag tag to its queue
295
- flag_q.append(tag)
285
+ flag_q.append(tag.upper())
286
+ elif cat == "video":
287
+ other_groups.setdefault(cat, []).append(tag.upper())
288
+ elif cat == "video_encoder":
289
+ # Skip video encoder
290
+ continue
296
291
  else:
297
- # Add the other tags to other_groups
298
292
  other_groups.setdefault(cat, []).append(tag)
299
293
 
300
294
  # Alternate only if we have at least 2 audio and 2 flag tags
295
+ mixed = []
301
296
  if len(audio_q) >= 2 and len(flag_q) >= 2:
302
- mixed_audio_ch_flag = []
303
- # Alternate
304
297
  while audio_q or flag_q:
305
- if audio_q:
306
- # get the first left audio and append to new list
307
- mixed_audio_ch_flag.append(audio_q.popleft())
308
- if channel_q:
309
- mixed_audio_ch_flag.append(channel_q.popleft())
310
- if flag_q:
311
- # get the first right flag and append to new list
312
- mixed_audio_ch_flag.append(flag_q.popleft())
298
+ if audio_q: mixed.append(audio_q.popleft())
299
+ if channel_q: mixed.append(channel_q.popleft())
300
+ if flag_q: mixed.append(flag_q.popleft())
313
301
  else:
314
- # otherwise goes for normal precedence
315
- mixed_audio_ch_flag = list(audio_q) + list(channel_q) + list(flag_q)
302
+ mixed = list(audio_q) + list(channel_q) + list(flag_q)
316
303
 
317
- # Rebuild the title ordering each tag+ audio/flag by tag_position
318
304
  result = []
319
-
320
305
  for cat in self.tags_position:
321
- if cat in ("audio", "channels", "flag"):
322
- # Insert the audio/flag processed tags
323
- if mixed_audio_ch_flag:
324
- result.extend(mixed_audio_ch_flag)
325
- # clear
326
- mixed_audio_ch_flag = []
306
+ if cat in ("audio", "channels", "flag") and mixed:
307
+ result.extend(mixed)
308
+ mixed = []
327
309
  elif cat in other_groups:
328
310
  result.extend(other_groups[cat])
329
- self.tags_sorted = result
330
-
331
- def _audio_lang(self) -> list:
332
-
333
- if not self.mediafile:
334
- return []
335
-
336
- lang: list = []
337
- for track in self.mediafile.audio_track:
338
- l = track.get('other_language', None)
339
- if l:
340
- for t in l:
341
- c = ManageTitles.convert_iso(t)
342
- if c:
343
- if isinstance(c, list):
344
- lang.extend(c)
345
- break
346
- else:
347
- lang.append(c)
348
- break
349
- return lang
311
+ return result
350
312
 
351
313
  def process(self) -> str:
352
314
  se_str = ''
@@ -357,21 +319,14 @@ class P2pTags:
357
319
  elif self.episode is not None:
358
320
  se_str = f"E{self.episode:02d}"
359
321
 
322
+ # Detect releaser sign in filename if not provided
360
323
  if not self.releaser_sign:
361
- # Search for a sign in the title
362
- base_name = os.path.basename(self.filename)
363
- filename, file_ext = os.path.splitext(base_name)
324
+ filename, _ = os.path.splitext(os.path.basename(self.filename))
364
325
  m = re.search(r'-([A-Za-z0-9]+)$', filename)
365
-
366
- if m and m.group(1) not in TAG_TYPES:
367
- self.sign_in_title = f"-{m.group(1)}"
368
- else:
369
- self.sign_in_title = ""
326
+ self.sign_in_title = f"-{m.group(1)}" if m and m.group(1) not in TAG_TYPES else ""
370
327
  else:
371
328
  self.sign_in_title = f"-{self.releaser_sign}"
372
329
 
373
- parts = [self.title, str(self.year), se_str, self.episode_title]
374
- filtered_parts = [part for part in parts if part]
375
- title = ' '.join(filtered_parts)
376
-
377
- return f"{title} {' '.join(self.tags_sorted)}{self.sign_in_title}"
330
+ parts = [self.title, str(self.year), se_str]
331
+ filtered_parts = [p for p in parts if p]
332
+ return f"{' '.join(filtered_parts)} {' '.join(self.tags_sorted)}{self.sign_in_title}"
@@ -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.9"
18
+ version = "0.9.11"
19
19
 
20
20
  if os.name == "nt":
21
21
  WATCHER_DESTINATION_PATH: Path = Path(os.getenv("LOCALAPPDATA", ".")) / "Unit3Dup_config" / "watcher_destination_path"
@@ -43,17 +43,33 @@ class ManageTitles:
43
43
  "ES-MX": "ESP"
44
44
  }
45
45
 
46
+ # From mediainfo
47
+ long_name = {
48
+ "ENGLISH": "ENG",
49
+ "ITALIAN": "ITA",
50
+ "GERMAN": "DEU",
51
+ "FRENCH": "FRA",
52
+ "SPANISH": "ESP",
53
+ "JAPANESE": "JPN",
54
+ "BRAZILIAN": "BRA",
55
+ "RUSSIAN": "RUS",
56
+ "CHINESE": "CHN",
57
+ "AMERICAN": "USA",
58
+ "BRITISH": "GBR"
59
+ }
46
60
  @staticmethod
47
61
  def convert_iso(code) -> list | str | None:
48
62
  """ Convert iso 2 to 3 """
49
63
  code = code.upper()
50
-
51
64
  # if it's 'multilang'
52
65
  if '-' in code:
53
66
  codes = code.split('-')
54
67
  else:
55
68
  codes = [code]
56
69
 
70
+ if code in ManageTitles.long_name:
71
+ codes = [ManageTitles.long_name[code]]
72
+
57
73
  result = []
58
74
  for part in codes:
59
75
  # Capture the 2 or 3 letter code followed by '-' or end string
@@ -167,45 +183,45 @@ class ManageTitles:
167
183
  filename_sanitized = re.sub(r"v\d+(?:[ .]\d+)*", "", filename_sanitized).strip()
168
184
 
169
185
  # Remove dots, extra spaces
170
- filename_sanitized = re.sub(r"[._]", " ", filename_sanitized)
186
+ # filename_sanitized = re.sub(r"[._]", " ", filename_sanitized)
171
187
 
172
188
  # remove spaces, tab, newline
173
189
  filename_sanitized = re.sub(r"\s+", " ", filename_sanitized)
174
190
 
175
191
  # Recover tag
176
- filename_sanitized = ManageTitles.recover_tag(filename_sanitized)
192
+ # filename_sanitized = ManageTitles.recover_tag(filename_sanitized)
177
193
 
178
194
  # remove double space
179
195
  filename_sanitized = re.sub(r"\s+", " ", filename_sanitized).strip()
180
196
 
181
197
  return filename_sanitized
182
198
 
183
- @staticmethod
184
- def recover_tag(filename_sanitized: str) -> str:
185
-
186
- # Add the tag
187
- replacements = [
188
- (r'\b7 \b1\b', '7.1'),
189
- (r'\b5 \b1\b', '5.1'),
190
- (r'\bDDP5 \b1\b', 'DDP5.1'),
191
- (r'\bDDP2 \b0\b', 'DDP2.0'),
192
- (r'\bDD5 \b1\b', 'DD5.1'),
193
- (r'\bDD2 \b0\b', 'DD2.0'),
194
- (r'\b2 \b0\b', '2.0'),
195
- (r'\bWEB \bDL\b', 'WEB-DL'),
196
- (r'\bWEB \bDLMUX\b', 'WEB-DLMUX'),
197
- (r'\bBD \bUNTOUCHED\b', 'BD-UNTOUCHED'),
198
- (r'\bCINEMA \bMD\b', 'CINEMA-MD'),
199
- (r'\bHEVC \bFHC\b', 'HEVC-FHC'),
200
- (r'\bCBR \bCBZ\b', 'CBR-CBZ'),
201
- (r'\bH \b264\b', 'H.264'),
202
- (r'\bH \b265\b', 'H.265'),
203
- (r'\bAAC2 \b0\b', 'AAC2.0'),
204
- ]
205
-
206
- for tag, replacement in replacements:
207
- filename_sanitized = re.sub(tag, replacement, filename_sanitized, flags=re.IGNORECASE)
208
- return filename_sanitized
199
+ # @staticmethod
200
+ # def recover_tag(filename_sanitized: str) -> str:
201
+ #
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
+ # ]
221
+ #
222
+ # for tag, replacement in replacements:
223
+ # filename_sanitized = re.sub(tag, replacement, filename_sanitized, flags=re.IGNORECASE)
224
+ # return filename_sanitized
209
225
 
210
226
 
211
227
  class MyString:
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  dynamic = ["dependencies"]
7
7
  name = "Unit3Dup"
8
- version = "0.9.9"
8
+ version = "0.9.11"
9
9
  description = "An uploader for the Unit3D torrent tracker"
10
10
  readme = "README.rst"
11
11
  requires-python = ">=3.10"
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