plexflow 0.0.121__py3-none-any.whl → 0.0.123__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.
- plexflow/core/context/partials/show.py +107 -0
- plexflow/core/metadata/auto/__pycache__/auto_meta.cpython-312.pyc +0 -0
- plexflow/core/metadata/auto/auto_meta.py +4 -1
- plexflow/core/metadata/auto/auto_providers/auto/__pycache__/show.cpython-312.pyc +0 -0
- plexflow/core/metadata/auto/auto_providers/plex/__pycache__/episode.cpython-312.pyc +0 -0
- plexflow/core/metadata/auto/auto_providers/plex/__pycache__/season.cpython-312.pyc +0 -0
- plexflow/core/metadata/auto/auto_providers/plex/__pycache__/show.cpython-312.pyc +0 -0
- plexflow/core/metadata/auto/auto_providers/plex/episode.py +29 -0
- plexflow/core/metadata/auto/auto_providers/plex/season.py +25 -0
- plexflow/core/metadata/auto/auto_providers/plex/show.py +46 -0
- plexflow/core/metadata/providers/plex/__pycache__/datatypes.cpython-312.pyc +0 -0
- plexflow/core/metadata/providers/plex/datatypes.py +51 -11
- plexflow/utils/video/__pycache__/__init__.cpython-312.pyc +0 -0
- plexflow/utils/video/__pycache__/audio.cpython-312.pyc +0 -0
- plexflow/utils/video/audio.py +51 -1
- {plexflow-0.0.121.dist-info → plexflow-0.0.123.dist-info}/METADATA +2 -1
- {plexflow-0.0.121.dist-info → plexflow-0.0.123.dist-info}/RECORD +19 -12
- {plexflow-0.0.121.dist-info → plexflow-0.0.123.dist-info}/WHEEL +0 -0
- {plexflow-0.0.121.dist-info → plexflow-0.0.123.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
from datetime import datetime as dt
|
3
|
+
from plexflow.core.metadata.auto.auto_providers.auto.show import AutoShow
|
4
|
+
from plexflow.core.metadata.auto.auto_providers.tmdb.show import AutoTmdbShow
|
5
|
+
from plexflow.core.metadata.auto.auto_providers.tvdb.show import AutoTvdbShow
|
6
|
+
from plexflow.core.metadata.auto.auto_providers.imdb.show import AutoImdbShow
|
7
|
+
from plexflow.core.metadata.auto.auto_providers.plex.show import AutoPlexShow
|
8
|
+
|
9
|
+
class Show(PartialContext):
|
10
|
+
def __init__(self, **kwargs) -> None:
|
11
|
+
super().__init__(**kwargs)
|
12
|
+
|
13
|
+
@property
|
14
|
+
def sources(self) -> list:
|
15
|
+
keys = self.get_keys("show/*")
|
16
|
+
# extract the source from the key
|
17
|
+
return [key.split("/")[-1] for key in keys]
|
18
|
+
|
19
|
+
def from_source(self, source: str) -> AutoShow:
|
20
|
+
return self.get(f"show/{source}")
|
21
|
+
|
22
|
+
@property
|
23
|
+
def title(self) -> str:
|
24
|
+
for source in self.sources:
|
25
|
+
details = self.from_source(source)
|
26
|
+
if details and details.title:
|
27
|
+
return details.title
|
28
|
+
|
29
|
+
@property
|
30
|
+
def year(self) -> int:
|
31
|
+
for source in self.sources:
|
32
|
+
details = self.from_source(source)
|
33
|
+
if details and details.year:
|
34
|
+
return details.year
|
35
|
+
|
36
|
+
@property
|
37
|
+
def release_date(self) -> dt:
|
38
|
+
for source in self.sources:
|
39
|
+
details = self.from_source(source)
|
40
|
+
if details and details.release_date:
|
41
|
+
return details.release_date
|
42
|
+
|
43
|
+
@property
|
44
|
+
def rank(self) -> int:
|
45
|
+
return self.plex.rank
|
46
|
+
|
47
|
+
@property
|
48
|
+
def released(self) -> bool:
|
49
|
+
dates = []
|
50
|
+
for source in self.sources:
|
51
|
+
details = self.from_source(source)
|
52
|
+
if details and details.release_date:
|
53
|
+
dates.append(details.release_date)
|
54
|
+
|
55
|
+
sorted_dates = sorted(dates)
|
56
|
+
now = dt.now()
|
57
|
+
return all([date < now for date in sorted_dates])
|
58
|
+
|
59
|
+
@property
|
60
|
+
def runtime(self) -> int:
|
61
|
+
for source in self.sources:
|
62
|
+
details = self.from_source(source)
|
63
|
+
if details and details.runtime:
|
64
|
+
return details.runtime
|
65
|
+
|
66
|
+
@property
|
67
|
+
def titles(self) -> set:
|
68
|
+
titles = set()
|
69
|
+
for source in self.sources:
|
70
|
+
details = self.from_source(source)
|
71
|
+
if details and details.title:
|
72
|
+
titles.add(details.title)
|
73
|
+
titles.update(details.titles)
|
74
|
+
return titles
|
75
|
+
|
76
|
+
@property
|
77
|
+
def summary(self) -> str:
|
78
|
+
for source in self.sources:
|
79
|
+
details = self.from_source(source)
|
80
|
+
if details and details.summary:
|
81
|
+
return details.summary
|
82
|
+
|
83
|
+
@property
|
84
|
+
def language(self) -> str:
|
85
|
+
for source in self.sources:
|
86
|
+
details = self.from_source(source)
|
87
|
+
if details and details.language:
|
88
|
+
return details.language
|
89
|
+
|
90
|
+
@property
|
91
|
+
def plex(self) -> AutoPlexShow:
|
92
|
+
return self.from_source("plex")
|
93
|
+
|
94
|
+
@property
|
95
|
+
def tmdb(self) -> AutoTmdbShow:
|
96
|
+
return self.from_source("tmdb")
|
97
|
+
|
98
|
+
@property
|
99
|
+
def imdb(self) -> AutoImdbShow:
|
100
|
+
return self.from_source("imdb")
|
101
|
+
|
102
|
+
@property
|
103
|
+
def tvdb(self) -> AutoTvdbShow:
|
104
|
+
return self.from_source("tvdb")
|
105
|
+
|
106
|
+
def update(self, movie: AutoShow):
|
107
|
+
self.set(f"show/{movie.source}", movie)
|
Binary file
|
@@ -7,6 +7,7 @@ from plexflow.core.metadata.auto.auto_providers.imdb.movie import AutoImdbMovie
|
|
7
7
|
from plexflow.core.metadata.auto.auto_providers.tmdb.show import AutoTmdbShow
|
8
8
|
from plexflow.core.metadata.auto.auto_providers.tvdb.show import AutoTvdbShow
|
9
9
|
from plexflow.core.metadata.auto.auto_providers.imdb.show import AutoImdbShow
|
10
|
+
from plexflow.core.metadata.auto.auto_providers.plex.show import AutoPlexShow
|
10
11
|
from plexflow.core.metadata.auto.auto_providers.plex.movie import AutoPlexMovie
|
11
12
|
|
12
13
|
class AutoMeta:
|
@@ -29,12 +30,14 @@ class AutoMeta:
|
|
29
30
|
raise ValueError(f"Invalid source: {source}")
|
30
31
|
|
31
32
|
@staticmethod
|
32
|
-
def show(imdb_id: str, source: str = 'tmdb') -> AutoShow:
|
33
|
+
def show(imdb_id: str, source: str = 'tmdb', rating_key: str = None) -> AutoShow:
|
33
34
|
if source == 'tmdb':
|
34
35
|
return AutoTmdbShow(imdb_id)
|
35
36
|
elif source == 'tvdb':
|
36
37
|
return AutoTvdbShow(imdb_id)
|
37
38
|
elif source == 'imdb':
|
38
39
|
return AutoImdbShow(imdb_id)
|
40
|
+
elif source == 'plex':
|
41
|
+
return AutoPlexShow(rating_key=rating_key)
|
39
42
|
else:
|
40
43
|
raise ValueError(f"Invalid source: {source}")
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from plexflow.core.metadata.auto.auto_providers.auto.episode import AutoEpisode
|
3
|
+
from plexflow.core.metadata.auto.auto_providers.auto.season import AutoSeason
|
4
|
+
from plexflow.core.metadata.providers.plex.datatypes import PlexEpisodeMetadata
|
5
|
+
|
6
|
+
class AutoPlexEpisode(AutoEpisode):
|
7
|
+
def __init__(self, parent: AutoSeason, data: PlexEpisodeMetadata) -> None:
|
8
|
+
super().__init__(parent=parent)
|
9
|
+
self._episode = data
|
10
|
+
|
11
|
+
@property
|
12
|
+
def release_date(self) -> datetime:
|
13
|
+
return datetime.strptime(self._episode.originallyAvailableAt, '%Y-%m-%d') if self._episode.originallyAvailableAt else None
|
14
|
+
|
15
|
+
@property
|
16
|
+
def episode_number(self) -> int:
|
17
|
+
return self._episode.index
|
18
|
+
|
19
|
+
@property
|
20
|
+
def title(self) -> str:
|
21
|
+
return self._episode.title
|
22
|
+
|
23
|
+
@property
|
24
|
+
def runtime(self) -> int:
|
25
|
+
return self._episode.duration
|
26
|
+
|
27
|
+
@property
|
28
|
+
def summary(self) -> str:
|
29
|
+
return self._episode.summary
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from plexflow.core.metadata.auto.auto_providers.auto.season import AutoSeason
|
3
|
+
from plexflow.core.metadata.auto.auto_providers.auto.show import AutoShow
|
4
|
+
from plexflow.core.metadata.auto.auto_providers.auto.episode import AutoEpisode
|
5
|
+
from plexflow.core.metadata.providers.plex.datatypes import PlexSeasonMetadata
|
6
|
+
from plexflow.core.metadata.providers.plex.plex import search_episodes_by_season_rating_key
|
7
|
+
from plexflow.core.metadata.auto.auto_providers.plex.episode import AutoPlexEpisode
|
8
|
+
|
9
|
+
class AutoPlexSeason(AutoSeason):
|
10
|
+
def __init__(self, parent: AutoShow, data: PlexSeasonMetadata) -> None:
|
11
|
+
super().__init__(parent)
|
12
|
+
self._season = data
|
13
|
+
|
14
|
+
@property
|
15
|
+
def episodes(self) -> list[AutoEpisode]:
|
16
|
+
episodes = search_episodes_by_season_rating_key(key=self._season.ratingKey)
|
17
|
+
return [AutoPlexEpisode(self, episode) for episode in episodes]
|
18
|
+
|
19
|
+
@property
|
20
|
+
def release_date(self) -> datetime:
|
21
|
+
return datetime.strptime(self._season.originallyAvailableAt, '%Y-%m-%d')
|
22
|
+
|
23
|
+
@property
|
24
|
+
def season_number(self) -> int:
|
25
|
+
return self._season.index
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from plexflow.core.metadata.auto.auto_providers.auto.show import AutoShow
|
2
|
+
from plexflow.core.metadata.auto.auto_providers.auto.season import AutoSeason
|
3
|
+
from plexflow.core.metadata.providers.plex.plex import search_show_by_rating_key, search_seasons_by_show_rating_key
|
4
|
+
from datetime import datetime
|
5
|
+
from plexflow.utils.imdb.imdb_codes import extract_imdb_code
|
6
|
+
from plexflow.core.metadata.auto.auto_providers.plex.season import AutoPlexSeason
|
7
|
+
|
8
|
+
class AutoPlexShow(AutoShow):
|
9
|
+
def __init__(self, rating_key: str) -> None:
|
10
|
+
self._show = search_show_by_rating_key(rating_key)
|
11
|
+
imdb_id = next((next(extract_imdb_code(g.id), None) for g in self._show.Guid), None)
|
12
|
+
|
13
|
+
super().__init__(imdb_id, 'plex')
|
14
|
+
|
15
|
+
@property
|
16
|
+
def id(self) -> str:
|
17
|
+
return self._show.ratingKey
|
18
|
+
|
19
|
+
@property
|
20
|
+
def title(self) -> str:
|
21
|
+
return self._show.title
|
22
|
+
|
23
|
+
@property
|
24
|
+
def release_date(self) -> datetime:
|
25
|
+
return datetime.strptime(self._show.originallyAvailableAt, '%Y-%m-%d')
|
26
|
+
|
27
|
+
@property
|
28
|
+
def runtime(self) -> int:
|
29
|
+
return self._show.duration // 60000 if isinstance(self._show.duration, int) else None
|
30
|
+
|
31
|
+
@property
|
32
|
+
def titles(self) -> list:
|
33
|
+
return []
|
34
|
+
|
35
|
+
@property
|
36
|
+
def summary(self) -> str:
|
37
|
+
return self._show.summary
|
38
|
+
|
39
|
+
@property
|
40
|
+
def language(self) -> str:
|
41
|
+
return None
|
42
|
+
|
43
|
+
@property
|
44
|
+
def seasons(self) -> list[AutoSeason]:
|
45
|
+
seasons = search_seasons_by_show_rating_key(key=self.id)
|
46
|
+
return [AutoPlexSeason(self, season) for season in seasons]
|
Binary file
|
@@ -368,17 +368,57 @@ class PlexShowMetadata:
|
|
368
368
|
_catchall (dict): A catch-all dictionary for any additional attributes.
|
369
369
|
"""
|
370
370
|
|
371
|
+
art: Optional[str] = None,
|
372
|
+
guid: Optional[str] = None,
|
373
|
+
key: Optional[str] = None,
|
374
|
+
primaryExtraKey: Optional[str] = None,
|
375
|
+
rating: Optional[float] = None,
|
376
|
+
ratingKey: Optional[str] = None,
|
377
|
+
studio: Optional[str] = None,
|
378
|
+
subtype: Optional[str] = None,
|
379
|
+
summary: Optional[str] = None,
|
380
|
+
tagline: Optional[str] = None,
|
381
|
+
type: Optional[str] = None,
|
382
|
+
thumb: Optional[str] = None,
|
383
|
+
addedAt: Optional[int] = None,
|
384
|
+
duration: Optional[int] = None,
|
385
|
+
publicPagesURL: Optional[str] = None,
|
386
|
+
slug: Optional[str] = None,
|
387
|
+
userState: Optional[bool] = None,
|
388
|
+
title: Optional[str] = None,
|
389
|
+
leafCount: Optional[int] = None,
|
390
|
+
childCount: Optional[int] = None,
|
391
|
+
skipChildren: Optional[bool] = None,
|
392
|
+
isContinuingSeries: Optional[bool] = None,
|
393
|
+
contentRating: Optional[str] = None,
|
394
|
+
originallyAvailableAt: Optional[str] = None,
|
395
|
+
year: Optional[int] = None,
|
396
|
+
ratingImage: Optional[str] = None,
|
397
|
+
imdbRatingCount: Optional[int] = None,
|
398
|
+
source: Optional[str] = None
|
399
|
+
Image: Optional[List[PlexImage]] = None
|
400
|
+
Guid: Optional[List[PlexGuid]] = None
|
401
|
+
Role: Optional[List[PlexRole]] = None
|
402
|
+
Country: Optional[List[PlexCountry]] = None
|
403
|
+
Director: Optional[List[PlexDirector]] = None
|
404
|
+
Writer: Optional[List[PlexWriter]] = None
|
405
|
+
Rating: Optional[List[PlexRating]] = None
|
406
|
+
Studio: Optional[List[PlexStudio]] = None
|
407
|
+
Producer: Optional[List[PlexProducer]] = None
|
408
|
+
Genre: Optional[List[PlexGenre]] = None
|
409
|
+
_catchall: dict = field(default_factory=dict)
|
410
|
+
|
371
411
|
def __post_init__(self):
|
372
|
-
self.Image = [PlexImage(**image) if isinstance(image, dict) else image for image in self.Image]
|
373
|
-
self.Genre = [PlexGenre(**genre) if isinstance(genre, dict) else genre for genre in self.Genre]
|
374
|
-
self.Guid = [PlexGuid(**guid) if isinstance(guid, dict) else guid for guid in self.Guid]
|
375
|
-
self.Country = [PlexCountry(**country) if isinstance(country, dict) else country for country in self.Country]
|
376
|
-
self.Role = [PlexRole(**role) if isinstance(role, dict) else role for role in self.Role]
|
377
|
-
self.Director = [PlexDirector(**director) if isinstance(director, dict) else director for director in self.Director]
|
378
|
-
self.Producer = [PlexProducer(**producer) if isinstance(producer, dict) else producer for producer in self.Producer]
|
379
|
-
self.Writer = [PlexWriter(**writer) if isinstance(writer, dict) else writer for writer in self.Writer]
|
380
|
-
self.Rating = [PlexRating(**rating) if isinstance(rating, dict) else rating for rating in self.Rating]
|
381
|
-
self.Studio = [PlexStudio(**studio) if isinstance(studio, dict) else studio for studio in self.Studio]
|
412
|
+
self.Image = [PlexImage(**image) if isinstance(image, dict) else image for image in self.Image] if self.Image else []
|
413
|
+
self.Genre = [PlexGenre(**genre) if isinstance(genre, dict) else genre for genre in self.Genre] if self.Genre else []
|
414
|
+
self.Guid = [PlexGuid(**guid) if isinstance(guid, dict) else guid for guid in self.Guid] if self.Guid else []
|
415
|
+
self.Country = [PlexCountry(**country) if isinstance(country, dict) else country for country in self.Country] if self.Country else []
|
416
|
+
self.Role = [PlexRole(**role) if isinstance(role, dict) else role for role in self.Role] if self.Role else []
|
417
|
+
self.Director = [PlexDirector(**director) if isinstance(director, dict) else director for director in self.Director] if self.Director else []
|
418
|
+
self.Producer = [PlexProducer(**producer) if isinstance(producer, dict) else producer for producer in self.Producer] if self.Producer else []
|
419
|
+
self.Writer = [PlexWriter(**writer) if isinstance(writer, dict) else writer for writer in self.Writer] if self.Writer else []
|
420
|
+
self.Rating = [PlexRating(**rating) if isinstance(rating, dict) else rating for rating in self.Rating] if self.Rating else []
|
421
|
+
self.Studio = [PlexStudio(**studio) if isinstance(studio, dict) else studio for studio in self.Studio] if self.Studio else []
|
382
422
|
|
383
423
|
|
384
424
|
@dataclass_json(undefined=Undefined.EXCLUDE)
|
@@ -614,7 +654,7 @@ class PlexEpisodeMetadata:
|
|
614
654
|
_catchall: dict = field(default_factory=dict)
|
615
655
|
|
616
656
|
def __post_init__(self):
|
617
|
-
self.Image = [PlexImage(**image) if isinstance(image, dict) else image for image in self.Image]
|
657
|
+
self.Image = [PlexImage(**image) if isinstance(image, dict) else image for image in self.Image] if self.Image else []
|
618
658
|
self.Guid = [PlexGuid(**guid) if isinstance(guid, dict) else guid for guid in self.Guid]
|
619
659
|
self.Role = [PlexRole(**role) if isinstance(role, dict) else role for role in self.Role] if self.Role else []
|
620
660
|
self.Director = [PlexDirector(**director) if isinstance(director, dict) else director for director in self.Director] if self.Director else []
|
Binary file
|
Binary file
|
plexflow/utils/video/audio.py
CHANGED
@@ -2,6 +2,9 @@ import subprocess
|
|
2
2
|
from pathlib import Path
|
3
3
|
from typing import List, Optional
|
4
4
|
import re
|
5
|
+
import json
|
6
|
+
from typing import Tuple
|
7
|
+
|
5
8
|
|
6
9
|
class FFmpegError(Exception):
|
7
10
|
"""Custom exception for FFmpeg errors."""
|
@@ -74,6 +77,9 @@ def get_audio_stream_indices(video_path: Path) -> List[int]:
|
|
74
77
|
- FileNotFoundError: If the video file does not exist.
|
75
78
|
- FFmpegError: If ffmpeg encounters an error during processing.
|
76
79
|
"""
|
80
|
+
if isinstance(video_path, str):
|
81
|
+
video_path = Path(video_path)
|
82
|
+
|
77
83
|
if not video_path.exists():
|
78
84
|
raise FileNotFoundError(f"The video file {video_path} does not exist.")
|
79
85
|
|
@@ -95,4 +101,48 @@ def get_audio_stream_indices(video_path: Path) -> List[int]:
|
|
95
101
|
stream_index = int(match.group(1))
|
96
102
|
audio_indices.append(stream_index)
|
97
103
|
|
98
|
-
return audio_indices
|
104
|
+
return audio_indices
|
105
|
+
|
106
|
+
def get_audio_stream_info(video_path: Path) -> List[Tuple[int, Optional[str]]]:
|
107
|
+
"""
|
108
|
+
Retrieves the indices and language tags of audio streams in a video file using ffprobe.
|
109
|
+
|
110
|
+
Parameters:
|
111
|
+
- video_path (Path): Path to the input video file.
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
- List[Tuple[int, Optional[str]]]: A list of tuples, where each tuple contains
|
115
|
+
(stream_index, language_code). language_code will be None if not found.
|
116
|
+
|
117
|
+
Raises:
|
118
|
+
- FileNotFoundError: If the video file does not exist.
|
119
|
+
- FFmpegError: If ffprobe encounters an error during processing or JSON parsing.
|
120
|
+
"""
|
121
|
+
if isinstance(video_path, str):
|
122
|
+
video_path = Path(video_path)
|
123
|
+
|
124
|
+
if not video_path.exists():
|
125
|
+
raise FileNotFoundError(f"The video file {video_path} does not exist.")
|
126
|
+
|
127
|
+
command = [
|
128
|
+
'ffprobe',
|
129
|
+
'-v', 'error', # Suppress verbose output
|
130
|
+
'-select_streams', 'a', # Select only audio streams
|
131
|
+
'-show_entries', 'stream=index:stream_tags=language', # Show index and language tag
|
132
|
+
'-of', 'json', # Output in JSON format
|
133
|
+
str(video_path)
|
134
|
+
]
|
135
|
+
|
136
|
+
try:
|
137
|
+
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
138
|
+
data = json.loads(result.stdout)
|
139
|
+
|
140
|
+
audio_stream_info = []
|
141
|
+
for s in data.get('streams', []):
|
142
|
+
index = s.get('index')
|
143
|
+
language = s.get('tags', {}).get('language')
|
144
|
+
if index is not None:
|
145
|
+
audio_stream_info.append((index, language))
|
146
|
+
return audio_stream_info
|
147
|
+
except (subprocess.CalledProcessError, json.JSONDecodeError) as e:
|
148
|
+
raise FFmpegError(f"FFprobe error: {e.stderr if isinstance(e, subprocess.CalledProcessError) else e}")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: plexflow
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.123
|
4
4
|
Summary: A short description of the package.
|
5
5
|
License: MIT
|
6
6
|
Keywords: keyword1,keyword2,keyword3
|
@@ -58,6 +58,7 @@ Requires-Dist: scrapy (>=2.11.2,<3.0.0)
|
|
58
58
|
Requires-Dist: seleniumbase (>=4.28.4,<5.0.0)
|
59
59
|
Requires-Dist: tmdbsimple (>=2.9.1,<3.0.0)
|
60
60
|
Requires-Dist: tpblite (>=0.8.0,<0.9.0)
|
61
|
+
Requires-Dist: tqdm (>=4.67.1,<5.0.0)
|
61
62
|
Requires-Dist: tvdb-v4-official (>=1.1.0,<2.0.0)
|
62
63
|
Requires-Dist: tvdbsimple (>=1.0.6,<2.0.0)
|
63
64
|
Requires-Dist: uvicorn (>=0.29.0,<0.30.0)
|
@@ -32,6 +32,7 @@ plexflow/core/context/partials/ids.py,sha256=QoQ6FbX1OIWrE-iuz-G6kSzBlTt1_I1jyfl
|
|
32
32
|
plexflow/core/context/partials/movie.py,sha256=VXQ2SspFgGSRgDefg4VlHrH2fns3KRuKlU72ps6527o,3861
|
33
33
|
plexflow/core/context/partials/movie_assets.py,sha256=qjZTs-lpPfZkQQSKm6CB4aeECX5_YzOom51PxZzmnts,1913
|
34
34
|
plexflow/core/context/partials/reports.py,sha256=0W58RwK3VSsVHbF0rhvMNNlZZr01eutwermyvdeEZIs,810
|
35
|
+
plexflow/core/context/partials/show.py,sha256=BcGXISwnWYDbz_VhDkTmaZ98VDXoaF4wmM2b9wjxz3U,3389
|
35
36
|
plexflow/core/context/partials/subtitles.py,sha256=0NhKGkP-sArQswuSyA7puRSjjoobF-3Ah7Pd39QkgTU,535
|
36
37
|
plexflow/core/context/partials/tgx_batch.py,sha256=TduB09oBOQ8CtmPYsHIeNe7AI-ypKw21zQAX-7qktEs,859
|
37
38
|
plexflow/core/context/partials/tgx_context.py,sha256=_FuhOvKsFqi_uynHxgC9_QIR2CfYmz-uJCRFtGFJmXI,1641
|
@@ -103,8 +104,8 @@ plexflow/core/metadata/auto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
103
104
|
plexflow/core/metadata/auto/__pycache__/__init__.cpython-311.pyc,sha256=lH9qVMiMhT0beU3xsnhOgd0m2HXp8tnbVl85bwxYcLI,177
|
104
105
|
plexflow/core/metadata/auto/__pycache__/__init__.cpython-312.pyc,sha256=TBF2IS00BSmTn_t5LvTujeJbtXD5D1Wd-_K4vjqb2kE,163
|
105
106
|
plexflow/core/metadata/auto/__pycache__/auto_meta.cpython-311.pyc,sha256=fOZ525wZuT7oPzhUeLVrjCbVNil17f4HVVlpMYjTxec,2935
|
106
|
-
plexflow/core/metadata/auto/__pycache__/auto_meta.cpython-312.pyc,sha256=
|
107
|
-
plexflow/core/metadata/auto/auto_meta.py,sha256=
|
107
|
+
plexflow/core/metadata/auto/__pycache__/auto_meta.cpython-312.pyc,sha256=29bpuA-JSy19Ukt-dwIVN2A775ZO2cx3KLZ9V96s46E,2632
|
108
|
+
plexflow/core/metadata/auto/auto_meta.py,sha256=vuWnifrW000ls4LO3abhfzVNKAjcb4BXNzUXLrkmK1E,2075
|
108
109
|
plexflow/core/metadata/auto/auto_providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
109
110
|
plexflow/core/metadata/auto/auto_providers/__pycache__/__init__.cpython-311.pyc,sha256=IffYBef71LYioll3WjuKtsNDb5S7dUFd21v_vpqWKjo,192
|
110
111
|
plexflow/core/metadata/auto/auto_providers/__pycache__/__init__.cpython-312.pyc,sha256=Azc9iLSZ4fgwbEL8lRcdBqiiyGBQ_HU57ihUnCa3MVI,178
|
@@ -121,7 +122,7 @@ plexflow/core/metadata/auto/auto_providers/auto/__pycache__/movie.cpython-312.py
|
|
121
122
|
plexflow/core/metadata/auto/auto_providers/auto/__pycache__/season.cpython-311.pyc,sha256=4uxtPg7KE_Cut75mhjRjtnGVTgeinxbciJP3nlV1elY,2580
|
122
123
|
plexflow/core/metadata/auto/auto_providers/auto/__pycache__/season.cpython-312.pyc,sha256=L6uj3tL3H1ZkHVJkYYKL4bbsTpC2SSODL7-4hdUTYi8,2307
|
123
124
|
plexflow/core/metadata/auto/auto_providers/auto/__pycache__/show.cpython-311.pyc,sha256=3C_No5XMWNMuvHc7Vmlg_RKAFrTxcfFEhUskvW3CccE,2041
|
124
|
-
plexflow/core/metadata/auto/auto_providers/auto/__pycache__/show.cpython-312.pyc,sha256=
|
125
|
+
plexflow/core/metadata/auto/auto_providers/auto/__pycache__/show.cpython-312.pyc,sha256=nC5CoqomV_9sPzXIYegqQ4-sragZhFLr70Y2ADigAyA,1759
|
125
126
|
plexflow/core/metadata/auto/auto_providers/auto/episode.py,sha256=79QxeLpzaXp08wCS3VB3OboS0LoIsOUDfQ8uspfpBm4,1004
|
126
127
|
plexflow/core/metadata/auto/auto_providers/auto/item.py,sha256=zZV0ArqzdLyde28eI93WjSS4PQoz-9YZ0ep80BYEPA8,1047
|
127
128
|
plexflow/core/metadata/auto/auto_providers/auto/movie.py,sha256=ddiaLxlSsAuBHs14RUxW2xBDsfkc_LeEtu1GlP0uPLE,488
|
@@ -151,11 +152,17 @@ plexflow/core/metadata/auto/auto_providers/plex/__init__.py,sha256=47DEQpj8HBSa-
|
|
151
152
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/__init__.cpython-311.pyc,sha256=zhUOQ0VKGPvJIAViRNqPX7uawbiwevltDiXpJm-NizY,197
|
152
153
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/__init__.cpython-312.pyc,sha256=Mst-5xGQD5Xc_nqvW1-j7EJdEFMV4h16xsJptKOubFE,183
|
153
154
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/episode.cpython-311.pyc,sha256=giWCnLbrfYX5xIm9kRMhDOwJLhRtBv-NYE8bywjN-Ns,2602
|
155
|
+
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/episode.cpython-312.pyc,sha256=3CUlqkhIDO6qWiMYSG9NyNpu9WF7wl-OD6O9lV1MWis,2351
|
154
156
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/movie.cpython-311.pyc,sha256=Ou8VJS0aNVu9sJQrb4TXLdzu8Ysc0BYgi_tUXUll834,3337
|
155
157
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/movie.cpython-312.pyc,sha256=w5kTMqGYoI5zs1HJy_Tat4hienwP0cdfYTlp0EXS79E,3094
|
156
158
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/season.cpython-311.pyc,sha256=V8CHtjkpHNLZUaRCrzUVquPEXHnOGW5INQR_2mjQ1vI,2597
|
159
|
+
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/season.cpython-312.pyc,sha256=TaRq1jZQQ_djZRoewUioSj39j0XM4Mti8BJ9pgn3kE0,2288
|
157
160
|
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/show.cpython-311.pyc,sha256=BtLZsFDxLpnVOvhwHVHhsteQqrm7c4p7t0YUTqJEk4Y,3993
|
161
|
+
plexflow/core/metadata/auto/auto_providers/plex/__pycache__/show.cpython-312.pyc,sha256=HDQ18cj4qXVM-ESiEAqtw-GZs6-JBWYpOPwLyKBYIFU,3667
|
162
|
+
plexflow/core/metadata/auto/auto_providers/plex/episode.py,sha256=CoE2lJoJ-RcKTRYdcEUS-Lr6AXmKKsBbcG8beCMmkvs,985
|
158
163
|
plexflow/core/metadata/auto/auto_providers/plex/movie.py,sha256=SnIUD94wsSBpsEk5ER0xLtzn5WGgdlcKyDo9qjFUUEs,1199
|
164
|
+
plexflow/core/metadata/auto/auto_providers/plex/season.py,sha256=57dUBrM4Oo0fmX-vgg4j7Ssgznuiw6Cl-PjW-KaQxmY,1129
|
165
|
+
plexflow/core/metadata/auto/auto_providers/plex/show.py,sha256=ilyGlXoggzMwsM5fMK4Gi38NcIsTdn1mlekqT_RJaJs,1570
|
159
166
|
plexflow/core/metadata/auto/auto_providers/tmdb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
160
167
|
plexflow/core/metadata/auto/auto_providers/tmdb/__pycache__/__init__.cpython-311.pyc,sha256=u4k9dx-nYwwP84Wnd-MMEU9ySXazNIuZC-WCjvnDr8g,197
|
161
168
|
plexflow/core/metadata/auto/auto_providers/tmdb/__pycache__/__init__.cpython-312.pyc,sha256=m2uIdevu5Xl7qq5jYJT8UwIfrMzggkyn-YRFflzR5zY,183
|
@@ -215,13 +222,13 @@ plexflow/core/metadata/providers/plex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
215
222
|
plexflow/core/metadata/providers/plex/__pycache__/__init__.cpython-311.pyc,sha256=Dn0hfFPLViFaic_zPb69TzXE3CVgDayCBJbfj5GM6N8,187
|
216
223
|
plexflow/core/metadata/providers/plex/__pycache__/__init__.cpython-312.pyc,sha256=fwdj_MNjIInQSPXMhY9YiRSe9CJAwPElwbYa1fNbRvE,173
|
217
224
|
plexflow/core/metadata/providers/plex/__pycache__/datatypes.cpython-311.pyc,sha256=S6n0CREPam6rZ5qDl-iasX-yYLFAoQCwr3zAVU1OKMI,49762
|
218
|
-
plexflow/core/metadata/providers/plex/__pycache__/datatypes.cpython-312.pyc,sha256=
|
225
|
+
plexflow/core/metadata/providers/plex/__pycache__/datatypes.cpython-312.pyc,sha256=leELWfqr32G9VbGGawOESJYUtB2F_Ofd2__2wsIValA,45957
|
219
226
|
plexflow/core/metadata/providers/plex/__pycache__/imdb.cpython-311.pyc,sha256=N_uu32ljM0xa1Nn8NK43QtU9tYRw_LyBblq7FgbfCg0,4342
|
220
227
|
plexflow/core/metadata/providers/plex/__pycache__/moviemeter.cpython-311.pyc,sha256=P78PwQIcVFzjwQqjHRGHhoWx6XtHRqJKIWeeX_jId4s,2551
|
221
228
|
plexflow/core/metadata/providers/plex/__pycache__/plex.cpython-311.pyc,sha256=FgbspEc3m5Vkm_m9Ry7gVAavs_2-4Er4FIREdJgaDIQ,8182
|
222
229
|
plexflow/core/metadata/providers/plex/__pycache__/plex.cpython-312.pyc,sha256=GKjYqAdmiDSuAQ3HlsQJMRAHfi65sbw7maeLcuq6rbs,7334
|
223
230
|
plexflow/core/metadata/providers/plex/__pycache__/tmdb.cpython-311.pyc,sha256=vWlpw_-ldSWwFvz67kTwxK9XxZPy7iExyLgD6rTOf10,4200
|
224
|
-
plexflow/core/metadata/providers/plex/datatypes.py,sha256=-
|
231
|
+
plexflow/core/metadata/providers/plex/datatypes.py,sha256=-EWmoJkitlNLSNpyvWDZX1qPw9vjXenMnQZVrwwazOk,34235
|
225
232
|
plexflow/core/metadata/providers/plex/plex.py,sha256=KrOjSLzeZVIGDnLDC7dw87Yizq5h3Fbf9MtPv_tcET8,5918
|
226
233
|
plexflow/core/metadata/providers/tmdb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
227
234
|
plexflow/core/metadata/providers/tmdb/__pycache__/__init__.cpython-311.pyc,sha256=djXYmvhVt2MFuzdiZ7ojQCXMa9UffVv_j_hBl0bdIvM,187
|
@@ -699,12 +706,12 @@ plexflow/utils/transcribe/__pycache__/speech2text.cpython-311.pyc,sha256=WcYPF8J
|
|
699
706
|
plexflow/utils/transcribe/__pycache__/speech2text.cpython-312.pyc,sha256=dY538EbFsJXzZr3139_TrtuLytcmculX_yBhi9DeKaM,2842
|
700
707
|
plexflow/utils/transcribe/speech2text.py,sha256=ldcZqx18Yr8aa-y5sw7WaEKCci9mvBI0z06YQqJemnU,3547
|
701
708
|
plexflow/utils/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
702
|
-
plexflow/utils/video/__pycache__/__init__.cpython-312.pyc,sha256=
|
703
|
-
plexflow/utils/video/__pycache__/audio.cpython-312.pyc,sha256=
|
709
|
+
plexflow/utils/video/__pycache__/__init__.cpython-312.pyc,sha256=SA7I28R8t-m5Q4uA7laJCUz3JHqVgUtkvewvrAk1qVk,156
|
710
|
+
plexflow/utils/video/__pycache__/audio.cpython-312.pyc,sha256=kmzGDCHSC1hWyHwRutWunOWNKatY613d1gmhz5VILpw,6686
|
704
711
|
plexflow/utils/video/__pycache__/subtitle.cpython-312.pyc,sha256=PCjpCLydGXaRsQy6cikhgsEs8WlComfOoYPiLFqfVMA,2515
|
705
|
-
plexflow/utils/video/audio.py,sha256=
|
712
|
+
plexflow/utils/video/audio.py,sha256=Pd8OuQHX2QN-lc5iYkB0Vo1OEHmTcvDYH-uKud1f1q4,5262
|
706
713
|
plexflow/utils/video/subtitle.py,sha256=qPvvBjlPj0fynJJvGJgGeKt9ey26R-cF6EoLaYt9iXU,1333
|
707
|
-
plexflow-0.0.
|
708
|
-
plexflow-0.0.
|
709
|
-
plexflow-0.0.
|
710
|
-
plexflow-0.0.
|
714
|
+
plexflow-0.0.123.dist-info/METADATA,sha256=Z7UDvQ_ZclEi0KBFhCaWZkqsgU6mBZPzYyF0_fJoAPw,2971
|
715
|
+
plexflow-0.0.123.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
716
|
+
plexflow-0.0.123.dist-info/entry_points.txt,sha256=9RJC3ikOQORHNOn573EdwJOBUnFU_4EGHbtNUM5pjjY,1557
|
717
|
+
plexflow-0.0.123.dist-info/RECORD,,
|
File without changes
|
File without changes
|