Unit3DwebUp 0.0.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- config/__init__.py +4 -0
- config/api_data.py +28 -0
- config/constants.py +34 -0
- config/host_data.py +47 -0
- config/itt.py +154 -0
- config/logger.py +37 -0
- config/settings.py +212 -0
- config/sis.py +137 -0
- config/tags.py +395 -0
- config/trackers.py +47 -0
- external/__init__.py +0 -0
- external/async_http_client_service.py +48 -0
- external/websocket.py +41 -0
- models/__init__.py +0 -0
- models/interfaces.py +39 -0
- models/keywords.py +13 -0
- models/media.py +597 -0
- models/media_info.py +142 -0
- models/movie.py +287 -0
- models/tv.py +266 -0
- models/tvdb_search.py +102 -0
- models/videos.py +26 -0
- repositories/__init__.py +0 -0
- repositories/db_online.py +82 -0
- repositories/interfaces.py +59 -0
- repositories/job_repos.py +166 -0
- repositories/media_info_factory.py +28 -0
- services/__init__.py +0 -0
- services/auto_async_service.py +237 -0
- services/create_torrent_service.py +94 -0
- services/interfaces.py +72 -0
- services/itt_tracker_helper.py +463 -0
- services/itt_tracker_service.py +85 -0
- services/lifespan_service.py +58 -0
- services/media_service.py +114 -0
- services/tags_service.py +389 -0
- services/tmdb.py +246 -0
- services/torrent_client_service.py +92 -0
- services/torrent_service.py +107 -0
- services/tvdb.py +65 -0
- services/utility.py +433 -0
- services/video_service.py +356 -0
- unit3dwebup-0.0.14.dist-info/METADATA +191 -0
- unit3dwebup-0.0.14.dist-info/RECORD +53 -0
- unit3dwebup-0.0.14.dist-info/WHEEL +5 -0
- unit3dwebup-0.0.14.dist-info/entry_points.txt +2 -0
- unit3dwebup-0.0.14.dist-info/top_level.txt +6 -0
- use_case/__init__.py +0 -0
- use_case/make_torrent_usecase.py +67 -0
- use_case/process_all_usecase.py +43 -0
- use_case/scan_media_usecase.py +133 -0
- use_case/seed_usecase.py +117 -0
- use_case/upload_usecase.py +77 -0
models/media.py
ADDED
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# based on the old code unit3dup 08.21
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import hashlib
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
from config.tags import crew_patterns, platform_patterns
|
|
9
|
+
from services.utility import ManageTitles, System
|
|
10
|
+
from models.media_info import MediaFile
|
|
11
|
+
from config.constants import MediaStatus
|
|
12
|
+
from config.settings import get_settings
|
|
13
|
+
from config.tags import SIGNS_LIST, TAGS_LIST, BAN_LIST
|
|
14
|
+
from services import utility
|
|
15
|
+
|
|
16
|
+
settings = get_settings()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Media:
|
|
20
|
+
"""
|
|
21
|
+
AsyncMediaManager service uses this class to build for each file an object of type Media
|
|
22
|
+
Each Media has a job_id based on its path and filename. Many job_ids make up a job_list
|
|
23
|
+
As the Media object is processed by multiple classes,
|
|
24
|
+
it is gradually built until it is used to create the payload for the tracker
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, folder: str, subfolder: str, torrent_archive_path: str) -> None:
|
|
28
|
+
"""
|
|
29
|
+
:param folder: the main path
|
|
30
|
+
:param subfolder: file path or subfolder path
|
|
31
|
+
"""
|
|
32
|
+
self.folder: Path = Path(folder)
|
|
33
|
+
self.subfolder: str = subfolder
|
|
34
|
+
self.title: str = (Path(self.folder) / self.subfolder).name
|
|
35
|
+
self._torrent_file_path = Path(torrent_archive_path) / "ITT" / f"{self.title}.torrent"
|
|
36
|
+
|
|
37
|
+
# // Assign a job id
|
|
38
|
+
path = Path(self.folder) / self.subfolder
|
|
39
|
+
self.job_id: str = hashlib.sha256(str(path).encode()).hexdigest()
|
|
40
|
+
# // Media
|
|
41
|
+
self.cached: bool = False # non utilizzato
|
|
42
|
+
self._crew_list: list[str] | None = None
|
|
43
|
+
self._game_title: str | None = None
|
|
44
|
+
self._platform_list: list[str] | None = None
|
|
45
|
+
self._title_sanitized: str | None = None
|
|
46
|
+
self._guess_title: str | None = None
|
|
47
|
+
self._guess_filename: utility.Guessit | None = None
|
|
48
|
+
self._guess_season: int | None = None
|
|
49
|
+
self._episode: int | None = None
|
|
50
|
+
self._source: str | None = None
|
|
51
|
+
self._screen_size: str | None = None
|
|
52
|
+
self._audio_codec: str | None = None
|
|
53
|
+
self._subtitle: str | None = None
|
|
54
|
+
self._torrent_path: Path | None = None
|
|
55
|
+
self._media_to_string: str | None = None
|
|
56
|
+
self.signs_list: dict[str, str] = SIGNS_LIST
|
|
57
|
+
self.tags_list: dict[str, str] = TAGS_LIST
|
|
58
|
+
self.ban_list: dict[str, str] = BAN_LIST
|
|
59
|
+
self.releaser_sign: str = settings.prefs.RELEASER_SIGN
|
|
60
|
+
self._tag_position: list[str] = []
|
|
61
|
+
|
|
62
|
+
# // Contents
|
|
63
|
+
self._file_name: str | None = None
|
|
64
|
+
self._display_name: str | None = None
|
|
65
|
+
self._category: str | None = None
|
|
66
|
+
self._audio_languages: list[str] = []
|
|
67
|
+
self._media_file: MediaFile | None = None
|
|
68
|
+
self._languages: list[str] | None = None
|
|
69
|
+
self._resolution: str | None = None
|
|
70
|
+
self._tracker_name: str | None = None
|
|
71
|
+
|
|
72
|
+
# // Contents dall'esterno
|
|
73
|
+
self._torrent_name: str | None = None
|
|
74
|
+
self._size: int = 0
|
|
75
|
+
self._metainfo: str | None = None
|
|
76
|
+
self._torrent_pack: bool = False
|
|
77
|
+
self._doc_description: str | None = None
|
|
78
|
+
self._game_nfo: str | None = None
|
|
79
|
+
self._tmdb_id: int | None = None
|
|
80
|
+
self._imdb_id: int | None = None
|
|
81
|
+
self._tvdb_id: int | None = None
|
|
82
|
+
self._igdb_id: int | None = None
|
|
83
|
+
self._generate_title: str | None = None
|
|
84
|
+
self._keyword: str | None = None
|
|
85
|
+
self._trailer: str | None = None
|
|
86
|
+
self._description: str | None = None
|
|
87
|
+
self._is_hd: int = 0
|
|
88
|
+
self._is_folder: bool = False
|
|
89
|
+
self._extracted_frames: list[bytes] | None = None
|
|
90
|
+
self._backdrop_path: str | None = None
|
|
91
|
+
self._status: int | None = MediaStatus.INDEXED
|
|
92
|
+
self._error: str | None = None
|
|
93
|
+
self._screen_shots: list | None = None
|
|
94
|
+
self._job_id_list: str | None = None
|
|
95
|
+
self._imdb_from_tvdb: str | None = None
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def title_sanitized(self) -> str:
|
|
99
|
+
if not self._title_sanitized:
|
|
100
|
+
self._title_sanitized = ManageTitles.clean_text(self.title)
|
|
101
|
+
return self._title_sanitized
|
|
102
|
+
|
|
103
|
+
@title_sanitized.setter
|
|
104
|
+
def title_sanitized(self, value: str):
|
|
105
|
+
self._title_sanitized = value
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def crew_list(self) -> list[str]:
|
|
109
|
+
if not self._crew_list:
|
|
110
|
+
self._crew_list = self._crew(filename=self.title_sanitized)
|
|
111
|
+
return self._crew_list
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def platform_list(self) -> list[str]:
|
|
115
|
+
if not self._platform_list:
|
|
116
|
+
self._platform_list = self._platform(filename=self.title_sanitized)
|
|
117
|
+
return self._platform_list
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def game_nfo(self) -> str | None:
|
|
121
|
+
return self._game_nfo
|
|
122
|
+
|
|
123
|
+
@game_nfo.setter
|
|
124
|
+
def game_nfo(self, value: str | None):
|
|
125
|
+
self._game_nfo = value
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def game_title(self) -> str | None:
|
|
129
|
+
if not self._game_title:
|
|
130
|
+
_game_tmp = self.guess_filename.guessit_title
|
|
131
|
+
for crew in self.crew_list:
|
|
132
|
+
_game_tmp = _game_tmp.replace(crew, " ")
|
|
133
|
+
self._game_title = _game_tmp.strip()
|
|
134
|
+
return self._game_title
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def torrent_name(self) -> str | None:
|
|
138
|
+
return self._torrent_name
|
|
139
|
+
|
|
140
|
+
@torrent_name.setter
|
|
141
|
+
def torrent_name(self, value: str | None):
|
|
142
|
+
self._torrent_name = value
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def size(self) -> int:
|
|
146
|
+
return self._size
|
|
147
|
+
|
|
148
|
+
@size.setter
|
|
149
|
+
def size(self, value: int):
|
|
150
|
+
self._size = value
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def metainfo(self) -> str | None:
|
|
154
|
+
return self._metainfo
|
|
155
|
+
|
|
156
|
+
@metainfo.setter
|
|
157
|
+
def metainfo(self, value: str | None):
|
|
158
|
+
self._metainfo = value
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def doc_description(self) -> str | None:
|
|
162
|
+
return self._doc_description
|
|
163
|
+
|
|
164
|
+
@doc_description.setter
|
|
165
|
+
def doc_description(self, value: str | None):
|
|
166
|
+
self._doc_description = value
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def tracker_name(self) -> str | None:
|
|
170
|
+
return self._tracker_name
|
|
171
|
+
|
|
172
|
+
@tracker_name.setter
|
|
173
|
+
def tracker_name(self, value: str | None):
|
|
174
|
+
self._tracker_name = value
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def torrent_pack(self) -> bool:
|
|
178
|
+
return self._torrent_pack
|
|
179
|
+
|
|
180
|
+
@torrent_pack.setter
|
|
181
|
+
def torrent_pack(self, value: bool):
|
|
182
|
+
self._torrent_pack = value
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def tmdb_id(self) -> int | None:
|
|
186
|
+
return self._tmdb_id
|
|
187
|
+
|
|
188
|
+
@tmdb_id.setter
|
|
189
|
+
def tmdb_id(self, value: int | None):
|
|
190
|
+
self._tmdb_id = value
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def imdb_id(self) -> int | None:
|
|
194
|
+
return self._imdb_id
|
|
195
|
+
|
|
196
|
+
@imdb_id.setter
|
|
197
|
+
def imdb_id(self, value: int | None):
|
|
198
|
+
self._imdb_id = value
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def tvdb_id(self) -> int | None:
|
|
202
|
+
return self._tvdb_id
|
|
203
|
+
|
|
204
|
+
@tvdb_id.setter
|
|
205
|
+
def tvdb_id(self, value: int | None):
|
|
206
|
+
self._tvdb_id = value
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def igdb_id(self) -> int | None:
|
|
210
|
+
return self._igdb_id
|
|
211
|
+
|
|
212
|
+
@igdb_id.setter
|
|
213
|
+
def igdb_id(self, value: int | None):
|
|
214
|
+
self._igdb_id = value
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def generate_title(self) -> str | None:
|
|
218
|
+
if not self._generate_title and self.mediafile:
|
|
219
|
+
video_f = self.mediafile.video_format
|
|
220
|
+
audio_f = self.mediafile.audio_format
|
|
221
|
+
audio_lang = self.mediafile.audio_language
|
|
222
|
+
available_lang = ' '.join(
|
|
223
|
+
lang for lang in self.mediafile.available_languages if lang is not None
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
if System.category_list.get(System.TV_SHOW) in self.category:
|
|
227
|
+
serie = f"S{str(self.guess_season).zfill(2)}" if self.guess_season else ''
|
|
228
|
+
if not self.torrent_pack:
|
|
229
|
+
serie += f"E{str(self.guess_episode).zfill(2)}"
|
|
230
|
+
else:
|
|
231
|
+
serie = ''
|
|
232
|
+
|
|
233
|
+
self._generate_title = f"{self.guess_title} {serie} {self.resolution} {video_f} " \
|
|
234
|
+
f"{available_lang} {audio_f} {audio_lang.upper()}"
|
|
235
|
+
return self._generate_title
|
|
236
|
+
|
|
237
|
+
@generate_title.setter
|
|
238
|
+
def generate_title(self, value: str | None):
|
|
239
|
+
self._generate_title = value
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def guess_filename(self) -> utility.Guessit:
|
|
243
|
+
if not self._guess_filename:
|
|
244
|
+
self._guess_filename = utility.Guessit(self.title_sanitized)
|
|
245
|
+
return self._guess_filename
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def file_name(self) -> str | None:
|
|
249
|
+
return self._file_name
|
|
250
|
+
|
|
251
|
+
@file_name.setter
|
|
252
|
+
def file_name(self, value: str | None):
|
|
253
|
+
self._file_name = value
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def display_name(self) -> str | None:
|
|
257
|
+
return self._display_name
|
|
258
|
+
|
|
259
|
+
@display_name.setter
|
|
260
|
+
def display_name(self, value: str | None):
|
|
261
|
+
self._display_name = value
|
|
262
|
+
if self._display_name:
|
|
263
|
+
episode_title = self.guess_filename.guessit_episode_title
|
|
264
|
+
if episode_title:
|
|
265
|
+
self._display_name = " ".join(
|
|
266
|
+
self._display_name.replace(episode_title, "").split()
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def guess_title(self) -> str:
|
|
271
|
+
if not self._guess_title:
|
|
272
|
+
self._guess_title = self.guess_filename.guessit_title.strip()
|
|
273
|
+
return self._guess_title
|
|
274
|
+
|
|
275
|
+
@guess_title.setter
|
|
276
|
+
def guess_title(self, value: str):
|
|
277
|
+
self._guess_title = value
|
|
278
|
+
|
|
279
|
+
@property
|
|
280
|
+
def guess_season(self) -> int | None:
|
|
281
|
+
if not self._guess_season and System.category_list.get(System.TV_SHOW) in self.category:
|
|
282
|
+
self._guess_season = self.guess_filename.guessit_season
|
|
283
|
+
return self._guess_season
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def guess_episode(self) -> int | None:
|
|
287
|
+
if not self._episode and System.category_list.get(System.TV_SHOW) in self.category:
|
|
288
|
+
self._episode = self.guess_filename.guessit_episode
|
|
289
|
+
return self._episode
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def source(self) -> str | None:
|
|
293
|
+
if not self._source:
|
|
294
|
+
self._source = self.guess_filename.source
|
|
295
|
+
return self._source
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def screen_size(self) -> str | None:
|
|
299
|
+
if not self._screen_size:
|
|
300
|
+
for screen in self.title_sanitized.split():
|
|
301
|
+
if screen in System.RESOLUTION_labels:
|
|
302
|
+
self._screen_size = screen
|
|
303
|
+
return self._screen_size
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def audio_codec(self) -> str | None:
|
|
307
|
+
if not self._audio_codec:
|
|
308
|
+
self._audio_codec = self.guess_filename.audio_codec
|
|
309
|
+
return self._audio_codec
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def audio_languages(self):
|
|
313
|
+
if not self._audio_languages:
|
|
314
|
+
# Get languages from the title
|
|
315
|
+
filename_split = self.display_name.upper().split(" ")
|
|
316
|
+
|
|
317
|
+
for code in filename_split:
|
|
318
|
+
converted_code = ManageTitles.convert_iso(code)
|
|
319
|
+
if converted_code:
|
|
320
|
+
self._audio_languages.append(converted_code[0])
|
|
321
|
+
|
|
322
|
+
if not self._audio_languages:
|
|
323
|
+
# get from the audio track
|
|
324
|
+
self._audio_languages = self.languages
|
|
325
|
+
return self._audio_languages
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def subtitle(self) -> str | None:
|
|
329
|
+
if not self._subtitle:
|
|
330
|
+
self._subtitle = self.guess_filename.subtitle
|
|
331
|
+
return self._subtitle
|
|
332
|
+
|
|
333
|
+
@property
|
|
334
|
+
def torrent_file_path(self) -> Path:
|
|
335
|
+
return self._torrent_file_path
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def torrent_path(self) -> Path:
|
|
339
|
+
if not self._torrent_path:
|
|
340
|
+
if os.path.isfile(self.folder):
|
|
341
|
+
self._torrent_path = self.folder
|
|
342
|
+
if os.path.isdir(self.folder):
|
|
343
|
+
self._torrent_path = Path(self.folder) / self.subfolder
|
|
344
|
+
return self._torrent_path
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def category(self) -> str | None:
|
|
348
|
+
if self._category:
|
|
349
|
+
return self._category
|
|
350
|
+
|
|
351
|
+
if ManageTitles.media_docu_type(self.title):
|
|
352
|
+
self._category = System.category_list.get(System.DOCUMENTARY)
|
|
353
|
+
elif self.guess_filename.guessit_season:
|
|
354
|
+
self._category = System.category_list.get(System.TV_SHOW)
|
|
355
|
+
else:
|
|
356
|
+
self._category = System.category_list.get(System.MOVIE)
|
|
357
|
+
|
|
358
|
+
if self.crew_list or self.platform_list:
|
|
359
|
+
self._category = System.category_list.get(System.GAME)
|
|
360
|
+
|
|
361
|
+
return self._category
|
|
362
|
+
|
|
363
|
+
@category.setter
|
|
364
|
+
def category(self, value: str | None):
|
|
365
|
+
self._category = value
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def tag_position(self) -> list[str]:
|
|
369
|
+
self._tag_position = settings.prefs.TAG_POSITION_SERIE if self.category == 'series' \
|
|
370
|
+
else settings.prefs.TAG_POSITION_MOVIE
|
|
371
|
+
return self._tag_position
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def keyword(self) -> str | None:
|
|
375
|
+
return self._keyword
|
|
376
|
+
|
|
377
|
+
@keyword.setter
|
|
378
|
+
def keyword(self, value: str | None):
|
|
379
|
+
self._keyword = value
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def trailer(self) -> str | None:
|
|
383
|
+
return self._trailer
|
|
384
|
+
|
|
385
|
+
@trailer.setter
|
|
386
|
+
def trailer(self, value: str | None):
|
|
387
|
+
self._trailer = value
|
|
388
|
+
|
|
389
|
+
@property
|
|
390
|
+
def description(self) -> str | None:
|
|
391
|
+
return self._description
|
|
392
|
+
|
|
393
|
+
@description.setter
|
|
394
|
+
def description(self, value: str | None):
|
|
395
|
+
self._description = value
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
def extracted_frames(self) -> list[bytes] | None:
|
|
399
|
+
return self._extracted_frames
|
|
400
|
+
|
|
401
|
+
@extracted_frames.setter
|
|
402
|
+
def extracted_frames(self, value: list[bytes] | None):
|
|
403
|
+
self._extracted_frames = value
|
|
404
|
+
|
|
405
|
+
@property
|
|
406
|
+
def is_hd(self) -> int:
|
|
407
|
+
return self._is_hd
|
|
408
|
+
|
|
409
|
+
@is_hd.setter
|
|
410
|
+
def is_hd(self, value: int):
|
|
411
|
+
self._is_hd = value
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def mediafile(self) -> MediaFile | None:
|
|
415
|
+
return self._media_file
|
|
416
|
+
|
|
417
|
+
@mediafile.setter
|
|
418
|
+
def mediafile(self, value: MediaFile | None):
|
|
419
|
+
self._media_file = value
|
|
420
|
+
|
|
421
|
+
@property
|
|
422
|
+
def media_to_string(self) -> str | None:
|
|
423
|
+
return self._media_to_string
|
|
424
|
+
|
|
425
|
+
@media_to_string.setter
|
|
426
|
+
def media_to_string(self, value: str | None):
|
|
427
|
+
self._media_to_string = value
|
|
428
|
+
|
|
429
|
+
@property
|
|
430
|
+
def backdrop_path(self) -> str | None:
|
|
431
|
+
return self._backdrop_path
|
|
432
|
+
|
|
433
|
+
@backdrop_path.setter
|
|
434
|
+
def backdrop_path(self, value: str | None):
|
|
435
|
+
self._backdrop_path = value
|
|
436
|
+
|
|
437
|
+
@property
|
|
438
|
+
def status(self) -> int | None:
|
|
439
|
+
return self._status
|
|
440
|
+
|
|
441
|
+
@status.setter
|
|
442
|
+
def status(self, value: int | None):
|
|
443
|
+
self._status = value
|
|
444
|
+
|
|
445
|
+
@property
|
|
446
|
+
def error(self) -> str | None:
|
|
447
|
+
return self._error
|
|
448
|
+
|
|
449
|
+
@error.setter
|
|
450
|
+
def error(self, value: str | None):
|
|
451
|
+
self._error = value
|
|
452
|
+
|
|
453
|
+
@property
|
|
454
|
+
def is_folder(self) -> bool:
|
|
455
|
+
return self._is_folder
|
|
456
|
+
|
|
457
|
+
@is_folder.setter
|
|
458
|
+
def is_folder(self, value: bool):
|
|
459
|
+
self._is_folder = value
|
|
460
|
+
|
|
461
|
+
@property
|
|
462
|
+
def screen_shots(self) -> list[str]:
|
|
463
|
+
return self._screen_shots
|
|
464
|
+
|
|
465
|
+
@screen_shots.setter
|
|
466
|
+
def screen_shots(self, value: list[str]):
|
|
467
|
+
self._screen_shots = value or []
|
|
468
|
+
|
|
469
|
+
def add_screen_shot(self, value: str):
|
|
470
|
+
self._screen_shots.append(value)
|
|
471
|
+
|
|
472
|
+
@property
|
|
473
|
+
def job_id_list(self) -> str | None:
|
|
474
|
+
return self._job_id_list
|
|
475
|
+
|
|
476
|
+
@job_id_list.setter
|
|
477
|
+
def job_id_list(self, value: str):
|
|
478
|
+
self._job_id_list = value
|
|
479
|
+
|
|
480
|
+
@property
|
|
481
|
+
def imdb_id_from_tvdb(self) -> str:
|
|
482
|
+
return self._imdb_from_tvdb
|
|
483
|
+
|
|
484
|
+
@imdb_id_from_tvdb.setter
|
|
485
|
+
def imdb_id_from_tvdb(self, value: str):
|
|
486
|
+
self._imdb_from_tvdb = value
|
|
487
|
+
|
|
488
|
+
@property
|
|
489
|
+
def languages(self) -> list[str]:
|
|
490
|
+
if not self._languages and self.mediafile:
|
|
491
|
+
self._languages = self.mediafile.available_languages
|
|
492
|
+
return self._languages
|
|
493
|
+
|
|
494
|
+
@property
|
|
495
|
+
def resolution(self) -> str | None:
|
|
496
|
+
if not self._resolution:
|
|
497
|
+
if self.mediafile and self.mediafile.video_height:
|
|
498
|
+
closest_resolution = min(
|
|
499
|
+
System.RESOLUTIONS,
|
|
500
|
+
key=lambda x: abs(int(x) - int(self.mediafile.video_height))
|
|
501
|
+
)
|
|
502
|
+
scan_type = self.mediafile.video_scan_type
|
|
503
|
+
if scan_type:
|
|
504
|
+
closest_resolution = f"{closest_resolution}p" if scan_type.lower() == "progressive" else f"{closest_resolution}i"
|
|
505
|
+
else:
|
|
506
|
+
closest_resolution = f"{closest_resolution}i" if self.mediafile.is_interlaced else f"{closest_resolution}p"
|
|
507
|
+
self._resolution = closest_resolution
|
|
508
|
+
else:
|
|
509
|
+
self._resolution = System.NO_RESOLUTION
|
|
510
|
+
return self._resolution
|
|
511
|
+
|
|
512
|
+
@staticmethod
|
|
513
|
+
def _crew(filename: str) -> list[str]:
|
|
514
|
+
regex = r"\b(" + "|".join(re.escape(p) for p in crew_patterns) + r")\b$"
|
|
515
|
+
return re.findall(regex, filename, re.IGNORECASE)
|
|
516
|
+
|
|
517
|
+
@staticmethod
|
|
518
|
+
def _platform(filename: str) -> list[str]:
|
|
519
|
+
regex = r"\b(" + "|".join(re.escape(p) for p in platform_patterns) + r")\b"
|
|
520
|
+
return re.findall(regex, filename, re.IGNORECASE)
|
|
521
|
+
|
|
522
|
+
# Serialize
|
|
523
|
+
def to_dict(self) -> dict:
|
|
524
|
+
|
|
525
|
+
# /// PosixPath objects must be converted to strings to be serializable
|
|
526
|
+
return {
|
|
527
|
+
"folder": str(self.folder),
|
|
528
|
+
"subfolder": self.subfolder,
|
|
529
|
+
"title": self.title,
|
|
530
|
+
"job_id": self.job_id,
|
|
531
|
+
"status": self.status,
|
|
532
|
+
"error": self.error,
|
|
533
|
+
"title_sanitized": self.title_sanitized,
|
|
534
|
+
"guess_title": self.guess_title,
|
|
535
|
+
"generate_title": self.generate_title,
|
|
536
|
+
"category": self.category,
|
|
537
|
+
"backdrop_path": self.backdrop_path,
|
|
538
|
+
"media_to_string": self.media_to_string,
|
|
539
|
+
"description": self.description,
|
|
540
|
+
"mediafile": self.mediafile.to_dict() if self.mediafile else None,
|
|
541
|
+
"tmdb_id": self.tmdb_id,
|
|
542
|
+
"imdb_id": self.imdb_id,
|
|
543
|
+
"tvdb_id": self.tvdb_id,
|
|
544
|
+
"igdb_id": self.igdb_id,
|
|
545
|
+
"imdb_id_from_tvdb": self.imdb_id_from_tvdb,
|
|
546
|
+
"file_name": str(self.file_name),
|
|
547
|
+
"display_name": self.display_name,
|
|
548
|
+
"torrent_name": self.torrent_name,
|
|
549
|
+
"torrent_path": str(self.torrent_path),
|
|
550
|
+
"torrent_file_path": str(self.torrent_file_path),
|
|
551
|
+
"torrent_pack": self.torrent_pack,
|
|
552
|
+
"size": self.size,
|
|
553
|
+
"resolution": self.resolution,
|
|
554
|
+
"screen_size": self.screen_size,
|
|
555
|
+
"source": self.source,
|
|
556
|
+
"audio_codec": self.audio_codec,
|
|
557
|
+
"audio_languages": self.audio_languages,
|
|
558
|
+
"subtitle": self.subtitle,
|
|
559
|
+
"crew_list": self.crew_list,
|
|
560
|
+
"platform_list": self.platform_list,
|
|
561
|
+
"screen_shots": self.screen_shots,
|
|
562
|
+
"job_id_list": self.job_id_list,
|
|
563
|
+
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
@classmethod
|
|
567
|
+
# json to Media()
|
|
568
|
+
def from_dict(cls, data: dict) -> "Media":
|
|
569
|
+
torrent_archive_path = (
|
|
570
|
+
Path("/home/app/torrent_archive") if os.getenv("DOCKER") == "true"
|
|
571
|
+
else Path(settings.prefs.TORRENT_ARCHIVE_PATH)
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
m = cls(folder=data["folder"], subfolder=data["subfolder"], torrent_archive_path=str(torrent_archive_path))
|
|
575
|
+
m.file_name = data.get("file_name")
|
|
576
|
+
m.display_name = data.get("display_name")
|
|
577
|
+
m.torrent_name = data.get("torrent_name")
|
|
578
|
+
m.size = data.get("size", 0) # todo fare cast to int
|
|
579
|
+
m.torrent_pack = data.get("torrent_pack", False)
|
|
580
|
+
m.job_id = data.get("job_id")
|
|
581
|
+
m.status = int(data.get("status", 0))
|
|
582
|
+
m.error = data.get("error")
|
|
583
|
+
m.tmdb_id = data.get("tmdb_id")
|
|
584
|
+
m.imdb_id = data.get("imdb_id")
|
|
585
|
+
m.tvdb_id = data.get("tvdb_id")
|
|
586
|
+
m.igdb_id = data.get("igdb_id")
|
|
587
|
+
m.imdb_id_from_tvdb = data.get("imdb_id_from_tvdb")
|
|
588
|
+
m.backdrop_path = data.get("backdrop_path")
|
|
589
|
+
m.media_to_string = data.get("media_to_string")
|
|
590
|
+
m.description = data.get("description")
|
|
591
|
+
if data.get("mediafile"):
|
|
592
|
+
m.mediafile = MediaFile.dict_to_mediafile(data["mediafile"])
|
|
593
|
+
m.generate_title = data.get("generate_title")
|
|
594
|
+
m.category = data.get("category")
|
|
595
|
+
m.screen_shots = data.get("screen_shots")
|
|
596
|
+
m.job_id_list = data.get("job_id_list")
|
|
597
|
+
return m
|