plexflow 0.0.64__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/__init__.py +0 -0
- plexflow/__main__.py +15 -0
- plexflow/core/.DS_Store +0 -0
- plexflow/core/__init__.py +0 -0
- plexflow/core/context/__init__.py +0 -0
- plexflow/core/context/metadata/__init__.py +0 -0
- plexflow/core/context/metadata/context.py +32 -0
- plexflow/core/context/metadata/tmdb/__init__.py +0 -0
- plexflow/core/context/metadata/tmdb/context.py +45 -0
- plexflow/core/context/partial_context.py +46 -0
- plexflow/core/context/partials/__init__.py +8 -0
- plexflow/core/context/partials/cache.py +16 -0
- plexflow/core/context/partials/context.py +12 -0
- plexflow/core/context/partials/ids.py +37 -0
- plexflow/core/context/partials/movie.py +115 -0
- plexflow/core/context/partials/tgx_batch.py +33 -0
- plexflow/core/context/partials/tgx_context.py +34 -0
- plexflow/core/context/partials/torrents.py +23 -0
- plexflow/core/context/partials/watchlist.py +35 -0
- plexflow/core/context/plexflow_context.py +29 -0
- plexflow/core/context/plexflow_property.py +36 -0
- plexflow/core/context/root/__init__.py +0 -0
- plexflow/core/context/root/context.py +25 -0
- plexflow/core/context/select/__init__.py +0 -0
- plexflow/core/context/select/context.py +45 -0
- plexflow/core/context/torrent/__init__.py +0 -0
- plexflow/core/context/torrent/context.py +43 -0
- plexflow/core/context/torrent/tpb/__init__.py +0 -0
- plexflow/core/context/torrent/tpb/context.py +45 -0
- plexflow/core/context/torrent/yts/__init__.py +0 -0
- plexflow/core/context/torrent/yts/context.py +45 -0
- plexflow/core/context/watchlist/__init__.py +0 -0
- plexflow/core/context/watchlist/context.py +46 -0
- plexflow/core/downloads/__init__.py +0 -0
- plexflow/core/downloads/candidates/__init__.py +0 -0
- plexflow/core/downloads/candidates/download_candidate.py +210 -0
- plexflow/core/downloads/candidates/filtered.py +51 -0
- plexflow/core/downloads/candidates/utils.py +39 -0
- plexflow/core/env/__init__.py +0 -0
- plexflow/core/env/env.py +31 -0
- plexflow/core/genai/__init__.py +0 -0
- plexflow/core/genai/bot.py +9 -0
- plexflow/core/genai/plexa.py +54 -0
- plexflow/core/genai/torrent/imdb_verify.py +65 -0
- plexflow/core/genai/torrent/movie.py +25 -0
- plexflow/core/genai/utils/__init__.py +0 -0
- plexflow/core/genai/utils/loader.py +5 -0
- plexflow/core/metadata/__init__.py +0 -0
- plexflow/core/metadata/auto/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_meta.py +40 -0
- plexflow/core/metadata/auto/auto_providers/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/auto/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/auto/episode.py +49 -0
- plexflow/core/metadata/auto/auto_providers/auto/item.py +55 -0
- plexflow/core/metadata/auto/auto_providers/auto/movie.py +13 -0
- plexflow/core/metadata/auto/auto_providers/auto/season.py +43 -0
- plexflow/core/metadata/auto/auto_providers/auto/show.py +26 -0
- plexflow/core/metadata/auto/auto_providers/imdb/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/imdb/movie.py +36 -0
- plexflow/core/metadata/auto/auto_providers/imdb/show.py +45 -0
- plexflow/core/metadata/auto/auto_providers/moviemeter/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/moviemeter/movie.py +40 -0
- plexflow/core/metadata/auto/auto_providers/plex/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/plex/movie.py +39 -0
- plexflow/core/metadata/auto/auto_providers/tmdb/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/tmdb/episode.py +30 -0
- plexflow/core/metadata/auto/auto_providers/tmdb/movie.py +36 -0
- plexflow/core/metadata/auto/auto_providers/tmdb/season.py +23 -0
- plexflow/core/metadata/auto/auto_providers/tmdb/show.py +41 -0
- plexflow/core/metadata/auto/auto_providers/tmdb.py +92 -0
- plexflow/core/metadata/auto/auto_providers/tvdb/__init__.py +0 -0
- plexflow/core/metadata/auto/auto_providers/tvdb/episode.py +28 -0
- plexflow/core/metadata/auto/auto_providers/tvdb/movie.py +36 -0
- plexflow/core/metadata/auto/auto_providers/tvdb/season.py +25 -0
- plexflow/core/metadata/auto/auto_providers/tvdb/show.py +41 -0
- plexflow/core/metadata/providers/__init__.py +0 -0
- plexflow/core/metadata/providers/imdb/__init__.py +0 -0
- plexflow/core/metadata/providers/imdb/datatypes.py +53 -0
- plexflow/core/metadata/providers/imdb/imdb.py +112 -0
- plexflow/core/metadata/providers/moviemeter/__init__.py +0 -0
- plexflow/core/metadata/providers/moviemeter/datatypes.py +111 -0
- plexflow/core/metadata/providers/moviemeter/moviemeter.py +42 -0
- plexflow/core/metadata/providers/plex/__init__.py +0 -0
- plexflow/core/metadata/providers/plex/datatypes.py +693 -0
- plexflow/core/metadata/providers/plex/plex.py +167 -0
- plexflow/core/metadata/providers/tmdb/__init__.py +0 -0
- plexflow/core/metadata/providers/tmdb/datatypes.py +460 -0
- plexflow/core/metadata/providers/tmdb/tmdb.py +85 -0
- plexflow/core/metadata/providers/tvdb/__init__.py +0 -0
- plexflow/core/metadata/providers/tvdb/datatypes.py +257 -0
- plexflow/core/metadata/providers/tvdb/tv_datatypes.py +554 -0
- plexflow/core/metadata/providers/tvdb/tvdb.py +65 -0
- plexflow/core/metadata/providers/universal/__init__.py +0 -0
- plexflow/core/metadata/providers/universal/movie.py +130 -0
- plexflow/core/metadata/providers/universal/old.py +192 -0
- plexflow/core/metadata/providers/universal/show.py +107 -0
- plexflow/core/plex/__init__.py +0 -0
- plexflow/core/plex/api/context/authorized.py +15 -0
- plexflow/core/plex/api/context/discover.py +14 -0
- plexflow/core/plex/api/context/library.py +14 -0
- plexflow/core/plex/discover/__init__.py +0 -0
- plexflow/core/plex/discover/activity.py +448 -0
- plexflow/core/plex/discover/comment.py +89 -0
- plexflow/core/plex/discover/feed.py +11 -0
- plexflow/core/plex/hooks/__init__.py +0 -0
- plexflow/core/plex/hooks/plex_authorized.py +60 -0
- plexflow/core/plex/hooks/plexflow_database.py +6 -0
- plexflow/core/plex/library/__init__.py +0 -0
- plexflow/core/plex/library/library.py +103 -0
- plexflow/core/plex/token/__init__.py +0 -0
- plexflow/core/plex/token/auto_token.py +91 -0
- plexflow/core/plex/utils/__init__.py +0 -0
- plexflow/core/plex/utils/paginated.py +39 -0
- plexflow/core/plex/watchlist/__init__.py +0 -0
- plexflow/core/plex/watchlist/datatypes.py +124 -0
- plexflow/core/plex/watchlist/watchlist.py +23 -0
- plexflow/core/storage/__init__.py +0 -0
- plexflow/core/storage/object/__init__.py +0 -0
- plexflow/core/storage/object/plexflow_storage.py +143 -0
- plexflow/core/storage/object/redis_storage.py +169 -0
- plexflow/core/subtitles/__init__.py +0 -0
- plexflow/core/subtitles/providers/__init__.py +0 -0
- plexflow/core/subtitles/providers/auto_subtitles.py +48 -0
- plexflow/core/subtitles/providers/oss/__init__.py +0 -0
- plexflow/core/subtitles/providers/oss/datatypes.py +104 -0
- plexflow/core/subtitles/providers/oss/download.py +48 -0
- plexflow/core/subtitles/providers/oss/old.py +144 -0
- plexflow/core/subtitles/providers/oss/oss.py +400 -0
- plexflow/core/subtitles/providers/oss/oss_subtitle.py +32 -0
- plexflow/core/subtitles/providers/oss/search.py +52 -0
- plexflow/core/subtitles/providers/oss/unlimited_oss.py +231 -0
- plexflow/core/subtitles/providers/oss/utils/__init__.py +0 -0
- plexflow/core/subtitles/providers/oss/utils/config.py +63 -0
- plexflow/core/subtitles/providers/oss/utils/download_client.py +22 -0
- plexflow/core/subtitles/providers/oss/utils/exceptions.py +35 -0
- plexflow/core/subtitles/providers/oss/utils/file_utils.py +83 -0
- plexflow/core/subtitles/providers/oss/utils/languages.py +78 -0
- plexflow/core/subtitles/providers/oss/utils/response_base.py +221 -0
- plexflow/core/subtitles/providers/oss/utils/responses.py +176 -0
- plexflow/core/subtitles/providers/oss/utils/srt.py +561 -0
- plexflow/core/subtitles/results/__init__.py +0 -0
- plexflow/core/subtitles/results/subtitle.py +170 -0
- plexflow/core/torrents/__init__.py +0 -0
- plexflow/core/torrents/analyzers/analyzed_torrent.py +143 -0
- plexflow/core/torrents/analyzers/analyzer.py +45 -0
- plexflow/core/torrents/analyzers/torrentquest/analyzer.py +47 -0
- plexflow/core/torrents/auto/auto_providers/auto/__init__.py +0 -0
- plexflow/core/torrents/auto/auto_providers/auto/torrent.py +64 -0
- plexflow/core/torrents/auto/auto_providers/tpb/torrent.py +62 -0
- plexflow/core/torrents/auto/auto_torrents.py +29 -0
- plexflow/core/torrents/providers/__init__.py +0 -0
- plexflow/core/torrents/providers/ext/__init__.py +0 -0
- plexflow/core/torrents/providers/ext/ext.py +18 -0
- plexflow/core/torrents/providers/ext/utils.py +64 -0
- plexflow/core/torrents/providers/extratorrent/__init__.py +0 -0
- plexflow/core/torrents/providers/extratorrent/extratorrent.py +21 -0
- plexflow/core/torrents/providers/extratorrent/utils.py +66 -0
- plexflow/core/torrents/providers/eztv/__init__.py +0 -0
- plexflow/core/torrents/providers/eztv/eztv.py +47 -0
- plexflow/core/torrents/providers/eztv/utils.py +83 -0
- plexflow/core/torrents/providers/rarbg2/__init__.py +0 -0
- plexflow/core/torrents/providers/rarbg2/rarbg2.py +19 -0
- plexflow/core/torrents/providers/rarbg2/utils.py +76 -0
- plexflow/core/torrents/providers/snowfl/__init__.py +0 -0
- plexflow/core/torrents/providers/snowfl/snowfl.py +36 -0
- plexflow/core/torrents/providers/snowfl/utils.py +59 -0
- plexflow/core/torrents/providers/tgx/__init__.py +0 -0
- plexflow/core/torrents/providers/tgx/context.py +50 -0
- plexflow/core/torrents/providers/tgx/dump.py +40 -0
- plexflow/core/torrents/providers/tgx/tgx.py +22 -0
- plexflow/core/torrents/providers/tgx/utils.py +61 -0
- plexflow/core/torrents/providers/therarbg/__init__.py +0 -0
- plexflow/core/torrents/providers/therarbg/therarbg.py +17 -0
- plexflow/core/torrents/providers/therarbg/utils.py +61 -0
- plexflow/core/torrents/providers/torrentquest/__init__.py +0 -0
- plexflow/core/torrents/providers/torrentquest/torrentquest.py +20 -0
- plexflow/core/torrents/providers/torrentquest/utils.py +70 -0
- plexflow/core/torrents/providers/tpb/__init__.py +0 -0
- plexflow/core/torrents/providers/tpb/tpb.py +17 -0
- plexflow/core/torrents/providers/tpb/utils.py +139 -0
- plexflow/core/torrents/providers/yts/__init__.py +0 -0
- plexflow/core/torrents/providers/yts/utils.py +57 -0
- plexflow/core/torrents/providers/yts/yts.py +31 -0
- plexflow/core/torrents/results/__init__.py +0 -0
- plexflow/core/torrents/results/torrent.py +165 -0
- plexflow/core/torrents/results/universal.py +220 -0
- plexflow/core/torrents/results/utils.py +15 -0
- plexflow/events/__init__.py +0 -0
- plexflow/events/download/__init__.py +0 -0
- plexflow/events/download/torrent_events.py +96 -0
- plexflow/events/publish/__init__.py +0 -0
- plexflow/events/publish/publish.py +34 -0
- plexflow/logging/__init__.py +0 -0
- plexflow/logging/log_setup.py +8 -0
- plexflow/spiders/quiet_logger.py +9 -0
- plexflow/spiders/tgx/pipelines/dump_json_pipeline.py +30 -0
- plexflow/spiders/tgx/pipelines/meta_pipeline.py +13 -0
- plexflow/spiders/tgx/pipelines/publish_pipeline.py +14 -0
- plexflow/spiders/tgx/pipelines/torrent_info_pipeline.py +12 -0
- plexflow/spiders/tgx/pipelines/validation_pipeline.py +17 -0
- plexflow/spiders/tgx/settings.py +36 -0
- plexflow/spiders/tgx/spider.py +72 -0
- plexflow/utils/__init__.py +0 -0
- plexflow/utils/antibot/human_like_requests.py +122 -0
- plexflow/utils/api/__init__.py +0 -0
- plexflow/utils/api/context/http.py +62 -0
- plexflow/utils/api/rest/__init__.py +0 -0
- plexflow/utils/api/rest/antibot_restful.py +68 -0
- plexflow/utils/api/rest/restful.py +49 -0
- plexflow/utils/captcha/__init__.py +0 -0
- plexflow/utils/captcha/bypass/__init__.py +0 -0
- plexflow/utils/captcha/bypass/decode_audio.py +34 -0
- plexflow/utils/download/__init__.py +0 -0
- plexflow/utils/download/gz.py +26 -0
- plexflow/utils/filesystem/__init__.py +0 -0
- plexflow/utils/filesystem/search.py +129 -0
- plexflow/utils/gmail/__init__.py +0 -0
- plexflow/utils/gmail/mails.py +116 -0
- plexflow/utils/hooks/__init__.py +0 -0
- plexflow/utils/hooks/http.py +84 -0
- plexflow/utils/hooks/postgresql.py +93 -0
- plexflow/utils/hooks/redis.py +112 -0
- plexflow/utils/image/storage.py +36 -0
- plexflow/utils/imdb/__init__.py +0 -0
- plexflow/utils/imdb/imdb_codes.py +107 -0
- plexflow/utils/pubsub/consume.py +82 -0
- plexflow/utils/pubsub/produce.py +25 -0
- plexflow/utils/retry/__init__.py +0 -0
- plexflow/utils/retry/utils.py +38 -0
- plexflow/utils/strings/__init__.py +0 -0
- plexflow/utils/strings/filesize.py +55 -0
- plexflow/utils/strings/language.py +14 -0
- plexflow/utils/subtitle/search.py +76 -0
- plexflow/utils/tasks/decorators.py +78 -0
- plexflow/utils/tasks/k8s/task.py +70 -0
- plexflow/utils/thread_safe/safe_list.py +54 -0
- plexflow/utils/thread_safe/safe_set.py +69 -0
- plexflow/utils/torrent/__init__.py +0 -0
- plexflow/utils/torrent/analyze.py +118 -0
- plexflow/utils/torrent/extract/common.py +37 -0
- plexflow/utils/torrent/extract/ext.py +2391 -0
- plexflow/utils/torrent/extract/extratorrent.py +56 -0
- plexflow/utils/torrent/extract/kat.py +1581 -0
- plexflow/utils/torrent/extract/tgx.py +96 -0
- plexflow/utils/torrent/extract/therarbg.py +170 -0
- plexflow/utils/torrent/extract/torrentquest.py +171 -0
- plexflow/utils/torrent/files.py +36 -0
- plexflow/utils/torrent/hash.py +90 -0
- plexflow/utils/transcribe/__init__.py +0 -0
- plexflow/utils/transcribe/speech2text.py +40 -0
- plexflow/utils/video/__init__.py +0 -0
- plexflow/utils/video/subtitle.py +73 -0
- plexflow-0.0.64.dist-info/METADATA +71 -0
- plexflow-0.0.64.dist-info/RECORD +256 -0
- plexflow-0.0.64.dist-info/WHEEL +4 -0
- plexflow-0.0.64.dist-info/entry_points.txt +24 -0
plexflow/__init__.py
ADDED
File without changes
|
plexflow/__main__.py
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
from plexflow.core.subtitles.providers.oss.search import get_subtitles
|
2
|
+
from plexflow.core.subtitles.providers.oss.download import download_subtitles
|
3
|
+
from plexflow.core.subtitles.providers.auto_subtitles import AutoSubtitles
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import List
|
6
|
+
|
7
|
+
auto_subtitles = AutoSubtitles(
|
8
|
+
imdb_id="tt8367814",
|
9
|
+
languages=["nl", "en"],
|
10
|
+
credentials_path="config/credentials.yaml",
|
11
|
+
redis_host="localhost",
|
12
|
+
redis_port=6379,
|
13
|
+
)
|
14
|
+
|
15
|
+
download_subtitles(auto_subtitles)
|
plexflow/core/.DS_Store
ADDED
Binary file
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
from plexflow.core.context.plexflow_context import PlexflowContext
|
3
|
+
from plexflow.core.context.metadata.tmdb.context import TMDbMetadataContext
|
4
|
+
|
5
|
+
class MetadataContext(PlexflowContext):
|
6
|
+
"""A class used to represent a Select Context in Plexflow.
|
7
|
+
|
8
|
+
This class extends PlexflowContext and adds a selected item property.
|
9
|
+
|
10
|
+
Attributes:
|
11
|
+
selected_item (PlexflowObjectProperty): The selected item in the context.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self, store: PlexflowObjectStore, **kwargs):
|
15
|
+
"""Initializes the SelectContext with the given object store and keyword arguments.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
store (PlexflowObjectStore): The object store to be used.
|
19
|
+
**kwargs: Arbitrary keyword arguments.
|
20
|
+
"""
|
21
|
+
|
22
|
+
super().__init__(store=store, **kwargs)
|
23
|
+
|
24
|
+
@property
|
25
|
+
def tmdb(self) -> TMDbMetadataContext:
|
26
|
+
"""Gets the value of the selected item.
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
Any: The value of the selected item.
|
30
|
+
"""
|
31
|
+
|
32
|
+
return TMDbMetadataContext(store=self.object_store)
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
from plexflow.core.context.plexflow_context import PlexflowContext
|
3
|
+
from plexflow.core.context.plexflow_property import PlexflowObjectProperty
|
4
|
+
from plexflow.core.metadata.providers.tmdb.datatypes import TmdbMovie
|
5
|
+
from typing import Union
|
6
|
+
|
7
|
+
class TMDbMetadataContext(PlexflowContext):
|
8
|
+
"""A class used to represent a Select Context in Plexflow.
|
9
|
+
|
10
|
+
This class extends PlexflowContext and adds a selected item property.
|
11
|
+
|
12
|
+
Attributes:
|
13
|
+
selected_item (PlexflowObjectProperty): The selected item in the context.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def __init__(self, store: PlexflowObjectStore, **kwargs):
|
17
|
+
"""Initializes the SelectContext with the given object store and keyword arguments.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
store (PlexflowObjectStore): The object store to be used.
|
21
|
+
**kwargs: Arbitrary keyword arguments.
|
22
|
+
"""
|
23
|
+
|
24
|
+
super().__init__(store=store, **kwargs)
|
25
|
+
self.movie_details = PlexflowObjectProperty(self.object_store, "movie_details", local=True)
|
26
|
+
|
27
|
+
@property
|
28
|
+
def movie_data(self) -> Union[TmdbMovie, None]:
|
29
|
+
"""Gets the value of the selected item.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
Any: The value of the selected item.
|
33
|
+
"""
|
34
|
+
|
35
|
+
return self.movie_details.value
|
36
|
+
|
37
|
+
@movie_data.setter
|
38
|
+
def movie_data(self, val: TmdbMovie):
|
39
|
+
"""Sets the value of the selected item.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
val (Any): The value to be set.
|
43
|
+
"""
|
44
|
+
|
45
|
+
self.movie_details.value = val
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
from typing import Any
|
3
|
+
from ulid import ULID
|
4
|
+
|
5
|
+
class PartialContext:
|
6
|
+
@staticmethod
|
7
|
+
def create_universal_id(dag_run_id: str):
|
8
|
+
store = PlexflowObjectStore(dag_run_id)
|
9
|
+
try:
|
10
|
+
print("try retrieving universal id")
|
11
|
+
universal_id = store.retrieve(store.make_key(dag_run_id))
|
12
|
+
if isinstance(universal_id, str) and len(universal_id) > 0:
|
13
|
+
return universal_id
|
14
|
+
except Exception:
|
15
|
+
print("creating universal id")
|
16
|
+
|
17
|
+
universal_id = str(ULID())
|
18
|
+
store.store_temporarily(key=store.make_key(dag_run_id), obj=universal_id)
|
19
|
+
return universal_id
|
20
|
+
|
21
|
+
def __init__(self, context_id: str, dag_run_id: str, default_ttl: int, **kwargs) -> None:
|
22
|
+
self.context_id = context_id
|
23
|
+
self.dag_run_id = dag_run_id
|
24
|
+
self.default_ttl = default_ttl
|
25
|
+
self.store = PlexflowObjectStore(context_id, **kwargs)
|
26
|
+
|
27
|
+
def update_universal_id(self, value: str):
|
28
|
+
self.store.store_temporarily(key=self.store.make_key(self.dag_run_id), obj=value)
|
29
|
+
|
30
|
+
def set(self, key: str, value: Any, ttl: int = None) -> None:
|
31
|
+
self.store.store_temporarily(key=self.store.make_run_key(key), obj=value, ttl=ttl or self.default_ttl)
|
32
|
+
|
33
|
+
def set_global(self, key: str, value: Any, ttl: int = None) -> None:
|
34
|
+
self.store.store_temporarily(key=self.store.make_key(key), obj=value, ttl=ttl or self.default_ttl)
|
35
|
+
|
36
|
+
def get(self, key: str) -> Any:
|
37
|
+
return self.store.retrieve(key=self.store.make_run_key(key))
|
38
|
+
|
39
|
+
def get_global(self, key: str) -> Any:
|
40
|
+
return self.store.retrieve(key=self.store.make_key(key))
|
41
|
+
|
42
|
+
def get_keys(self, pattern: str):
|
43
|
+
return list(map(lambda key_bytes: key_bytes.decode('utf-8'), self.store.retrieve_keys(self.store.make_run_key(pattern))))
|
44
|
+
|
45
|
+
def get_by_pattern(self, pattern: str):
|
46
|
+
return self.store.retrieve_values(self.store.make_run_key(pattern))
|
@@ -0,0 +1,8 @@
|
|
1
|
+
from plexflow.core.context.partials.ids import Ids
|
2
|
+
from plexflow.core.context.partials.watchlist import Watchlist
|
3
|
+
from plexflow.core.context.partials.cache import LRUCache
|
4
|
+
from plexflow.core.context.partials.movie import Movie
|
5
|
+
from plexflow.core.context.partials.context import Context
|
6
|
+
from plexflow.core.context.partials.torrents import Torrents
|
7
|
+
from plexflow.core.context.partials.tgx_context import TgxRequestContext
|
8
|
+
from plexflow.core.context.partials.tgx_batch import TgxBatch
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
from datetime import datetime as dt
|
3
|
+
|
4
|
+
class LRUCache(PartialContext):
|
5
|
+
def __init__(self, **kwargs) -> None:
|
6
|
+
super().__init__(**kwargs)
|
7
|
+
|
8
|
+
def touch(self, media_id: str) -> None:
|
9
|
+
self.set_global(f"cache/processing/{media_id}", dt.now())
|
10
|
+
|
11
|
+
def last_used(self, media_id: str) -> dt:
|
12
|
+
try:
|
13
|
+
return self.get_global(f"cache/processing/{media_id}")
|
14
|
+
except Exception:
|
15
|
+
return None
|
16
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
|
3
|
+
class Context(PartialContext):
|
4
|
+
def __init__(self, **kwargs) -> None:
|
5
|
+
super().__init__(**kwargs)
|
6
|
+
|
7
|
+
def update(self, id: str):
|
8
|
+
self.update_universal_id(id)
|
9
|
+
|
10
|
+
@property
|
11
|
+
def id(self) -> str:
|
12
|
+
return self.context_id
|
@@ -0,0 +1,37 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
|
3
|
+
class Ids(PartialContext):
|
4
|
+
def __init__(self, **kwargs) -> None:
|
5
|
+
super().__init__(**kwargs)
|
6
|
+
|
7
|
+
@property
|
8
|
+
def imdb_id(self) -> str:
|
9
|
+
return self.get("imdb_id")
|
10
|
+
|
11
|
+
@imdb_id.setter
|
12
|
+
def imdb_id(self, value: str) -> None:
|
13
|
+
self.set("imdb_id", value)
|
14
|
+
|
15
|
+
@property
|
16
|
+
def tmdb_id(self) -> int:
|
17
|
+
return self.get("tmdb_id")
|
18
|
+
|
19
|
+
@tmdb_id.setter
|
20
|
+
def tmdb_id(self, value: int) -> None:
|
21
|
+
self.set("tmdb_id", value)
|
22
|
+
|
23
|
+
@property
|
24
|
+
def tvdb_id(self) -> int:
|
25
|
+
return self.get("tvdb_id")
|
26
|
+
|
27
|
+
@tvdb_id.setter
|
28
|
+
def tvdb_id(self, value: int) -> None:
|
29
|
+
self.set("tvdb_id", value)
|
30
|
+
|
31
|
+
@property
|
32
|
+
def plex_id(self) -> str:
|
33
|
+
return self.get("plex_id")
|
34
|
+
|
35
|
+
@plex_id.setter
|
36
|
+
def plex_id(self, value: str) -> None:
|
37
|
+
self.set("plex_id", value)
|
@@ -0,0 +1,115 @@
|
|
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.movie import AutoMovie
|
4
|
+
from plexflow.core.metadata.auto.auto_providers.tmdb.movie import AutoTmdbMovie
|
5
|
+
from plexflow.core.metadata.auto.auto_providers.tvdb.movie import AutoTvdbMovie
|
6
|
+
from plexflow.core.metadata.auto.auto_providers.moviemeter.movie import AutoMovieMeterMovie
|
7
|
+
from plexflow.core.metadata.auto.auto_providers.imdb.movie import AutoImdbMovie
|
8
|
+
from plexflow.core.metadata.auto.auto_providers.tmdb.show import AutoTmdbShow
|
9
|
+
from plexflow.core.metadata.auto.auto_providers.tvdb.show import AutoTvdbShow
|
10
|
+
from plexflow.core.metadata.auto.auto_providers.imdb.show import AutoImdbShow
|
11
|
+
from plexflow.core.metadata.auto.auto_providers.plex.movie import AutoPlexMovie
|
12
|
+
|
13
|
+
class Movie(PartialContext):
|
14
|
+
def __init__(self, **kwargs) -> None:
|
15
|
+
super().__init__(**kwargs)
|
16
|
+
|
17
|
+
@property
|
18
|
+
def sources(self) -> list:
|
19
|
+
keys = self.get_keys("movie/*")
|
20
|
+
# extract the source from the key
|
21
|
+
return [key.split("/")[-1] for key in keys]
|
22
|
+
|
23
|
+
def from_source(self, source: str) -> AutoMovie:
|
24
|
+
return self.get(f"movie/{source}")
|
25
|
+
|
26
|
+
@property
|
27
|
+
def title(self) -> str:
|
28
|
+
for source in self.sources:
|
29
|
+
details = self.from_source(source)
|
30
|
+
if details and details.title:
|
31
|
+
return details.title
|
32
|
+
|
33
|
+
@property
|
34
|
+
def year(self) -> int:
|
35
|
+
for source in self.sources:
|
36
|
+
details = self.from_source(source)
|
37
|
+
if details and details.year:
|
38
|
+
return details.year
|
39
|
+
|
40
|
+
@property
|
41
|
+
def release_date(self) -> dt:
|
42
|
+
for source in self.sources:
|
43
|
+
details = self.from_source(source)
|
44
|
+
if details and details.release_date:
|
45
|
+
return details.release_date
|
46
|
+
|
47
|
+
@property
|
48
|
+
def rank(self) -> int:
|
49
|
+
return self.plex.rank
|
50
|
+
|
51
|
+
@property
|
52
|
+
def released(self) -> bool:
|
53
|
+
dates = []
|
54
|
+
for source in self.sources:
|
55
|
+
details = self.from_source(source)
|
56
|
+
if details and details.release_date:
|
57
|
+
dates.append(details.release_date)
|
58
|
+
|
59
|
+
sorted_dates = sorted(dates)
|
60
|
+
now = dt.now()
|
61
|
+
return all([date < now for date in sorted_dates])
|
62
|
+
|
63
|
+
@property
|
64
|
+
def runtime(self) -> int:
|
65
|
+
for source in self.sources:
|
66
|
+
details = self.from_source(source)
|
67
|
+
if details and details.runtime:
|
68
|
+
return details.runtime
|
69
|
+
|
70
|
+
@property
|
71
|
+
def titles(self) -> set:
|
72
|
+
titles = set()
|
73
|
+
for source in self.sources:
|
74
|
+
details = self.from_source(source)
|
75
|
+
if details and details.title:
|
76
|
+
titles.add(details.title)
|
77
|
+
titles.update(details.titles)
|
78
|
+
return titles
|
79
|
+
|
80
|
+
@property
|
81
|
+
def summary(self) -> str:
|
82
|
+
for source in self.sources:
|
83
|
+
details = self.from_source(source)
|
84
|
+
if details and details.summary:
|
85
|
+
return details.summary
|
86
|
+
|
87
|
+
@property
|
88
|
+
def language(self) -> str:
|
89
|
+
for source in self.sources:
|
90
|
+
details = self.from_source(source)
|
91
|
+
if details and details.language:
|
92
|
+
return details.language
|
93
|
+
|
94
|
+
@property
|
95
|
+
def plex(self) -> AutoPlexMovie:
|
96
|
+
return self.from_source("plex")
|
97
|
+
|
98
|
+
@property
|
99
|
+
def tmdb(self) -> AutoTmdbMovie:
|
100
|
+
return self.from_source("tmdb")
|
101
|
+
|
102
|
+
@property
|
103
|
+
def imdb(self) -> AutoImdbMovie:
|
104
|
+
return self.from_source("imdb")
|
105
|
+
|
106
|
+
@property
|
107
|
+
def tvdb(self) -> AutoTvdbMovie:
|
108
|
+
return self.from_source("tvdb")
|
109
|
+
|
110
|
+
@property
|
111
|
+
def moviemeter(self) -> AutoMovieMeterMovie:
|
112
|
+
return self.from_source("moviemeter")
|
113
|
+
|
114
|
+
def update(self, movie: AutoMovie):
|
115
|
+
self.set(f"movie/{movie.source}", movie)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
|
3
|
+
class TgxBatch(PartialContext):
|
4
|
+
def __init__(self, **kwargs) -> None:
|
5
|
+
super().__init__(**kwargs)
|
6
|
+
|
7
|
+
def update(self, ids):
|
8
|
+
self.set("tgx/ids", ids)
|
9
|
+
|
10
|
+
def update_finished(self, ids):
|
11
|
+
self.set("tgx/finished", ids)
|
12
|
+
|
13
|
+
def update_unfinished(self, ids):
|
14
|
+
self.set("tgx/unfinished", ids)
|
15
|
+
|
16
|
+
def update_finished_items(self, items):
|
17
|
+
self.set("tgx/finished_items", items)
|
18
|
+
|
19
|
+
@property
|
20
|
+
def ids(self) -> set:
|
21
|
+
return self.get("tgx/ids")
|
22
|
+
|
23
|
+
@property
|
24
|
+
def finished(self) -> set:
|
25
|
+
return self.get("tgx/finished")
|
26
|
+
|
27
|
+
@property
|
28
|
+
def unfinished(self) -> set:
|
29
|
+
return self.get("tgx/unfinished")
|
30
|
+
|
31
|
+
@property
|
32
|
+
def finished_items(self) -> list:
|
33
|
+
return self.get("tgx/finished_items")
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
|
3
|
+
class TgxRequestContext(PartialContext):
|
4
|
+
def __init__(self, **kwargs) -> None:
|
5
|
+
super().__init__(**kwargs)
|
6
|
+
|
7
|
+
def update(self, cookies: dict):
|
8
|
+
self.set_global("tgx/cookies", cookies)
|
9
|
+
|
10
|
+
@property
|
11
|
+
def session_id(self) -> str:
|
12
|
+
"""
|
13
|
+
Cookies is a dictionary like below:
|
14
|
+
|
15
|
+
[{'name': 'PHPSESSID', 'value': 'a95el556bo30414fslulnbdi03', 'domain': 'torrentgalaxy.to', 'path': '/', 'expires': -1, 'httpOnly': False, 'secure': False, 'sameSite': 'Lax'}, {'name': 'AdskeeperStorage', 'value': '%7B%220%22%3A%7B%22svspr%22%3A%22https%3A%2F%2Ftorrentgalaxy.to%2Ftorrent%2F16100045%22%2C%22svsds%22%3A2%7D%2C%22C385455%22%3A%7B%22page%22%3A1%2C%22time%22%3A%221722597496754%22%7D%2C%22C1543068%22%3A%7B%22page%22%3A1%2C%22time%22%3A%221722597496757%22%7D%2C%22C1343686%22%3A%7B%22page%22%3A1%2C%22time%22%3A%221722597497305%22%7D%7D', 'domain': 'torrentgalaxy.to', 'path': '/', 'expires': -1, 'httpOnly': False, 'secure': False, 'sameSite': 'Lax'}]
|
16
|
+
"""
|
17
|
+
try:
|
18
|
+
cookies = self.get_global("tgx/cookies")
|
19
|
+
for cookie in cookies:
|
20
|
+
if cookie["name"] == "PHPSESSID":
|
21
|
+
return cookie["value"]
|
22
|
+
except Exception:
|
23
|
+
return None
|
24
|
+
|
25
|
+
@property
|
26
|
+
def cookies(self) -> dict:
|
27
|
+
try:
|
28
|
+
cookies = self.get_global("tgx/cookies")
|
29
|
+
simple_cookies = {}
|
30
|
+
for cookie in cookies:
|
31
|
+
simple_cookies[cookie["name"]] = cookie["value"]
|
32
|
+
return simple_cookies
|
33
|
+
except Exception:
|
34
|
+
return None
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
from datetime import datetime as dt
|
3
|
+
from plexflow.core.torrents.results.torrent import Torrent
|
4
|
+
from typing import List
|
5
|
+
|
6
|
+
class Torrents(PartialContext):
|
7
|
+
def __init__(self, **kwargs) -> None:
|
8
|
+
super().__init__(**kwargs)
|
9
|
+
|
10
|
+
@property
|
11
|
+
def sources(self) -> list[str]:
|
12
|
+
keys = self.get_keys("torrents/*")
|
13
|
+
# extract the source from the key
|
14
|
+
return [key.split("/")[-1] for key in keys]
|
15
|
+
|
16
|
+
def from_source(self, source: str) -> List[Torrent]:
|
17
|
+
return self.get(f"torrents/{source}")
|
18
|
+
|
19
|
+
def update(self, torrents: Torrent):
|
20
|
+
if len(torrents) == 0:
|
21
|
+
return
|
22
|
+
source = next(iter(torrents)).source
|
23
|
+
self.set(f"torrents/{source}", torrents)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from plexflow.core.context.partial_context import PartialContext
|
2
|
+
from plexflow.core.plex.watchlist.datatypes import MediaContainer, PlexMetadata
|
3
|
+
from ulid import ULID
|
4
|
+
from typing import Generator, Any
|
5
|
+
|
6
|
+
class Watchlist(PartialContext):
|
7
|
+
def __init__(self, **kwargs) -> None:
|
8
|
+
super().__init__(**kwargs)
|
9
|
+
|
10
|
+
@property
|
11
|
+
def selected(self) -> PlexMetadata:
|
12
|
+
try:
|
13
|
+
return self.get("watchlist/selected")
|
14
|
+
except Exception:
|
15
|
+
return None
|
16
|
+
|
17
|
+
def select(self, value: PlexMetadata) -> None:
|
18
|
+
self.set("watchlist/selected", value)
|
19
|
+
|
20
|
+
def update(self, container: MediaContainer) -> None:
|
21
|
+
tag = ULID()
|
22
|
+
self.set(f"watchlist/items/{tag}", container)
|
23
|
+
|
24
|
+
def __iter__(self):
|
25
|
+
return self.generator()
|
26
|
+
|
27
|
+
def raw(self):
|
28
|
+
return self.get_by_pattern("watchlist/items/*")
|
29
|
+
|
30
|
+
def generator(self) -> Generator[Any, Any, Any]:
|
31
|
+
items = self.get_by_pattern("watchlist/items/*")
|
32
|
+
for part in items:
|
33
|
+
part: MediaContainer = part
|
34
|
+
for item in part.Metadata:
|
35
|
+
yield item
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
|
3
|
+
class PlexflowContext:
|
4
|
+
"""A class used to represent the Plexflow Context.
|
5
|
+
|
6
|
+
This class provides a context for Plexflow computations, allowing access to an object store.
|
7
|
+
|
8
|
+
Attributes:
|
9
|
+
store (PlexflowObjectStore): The object store used in the Plexflow context.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __init__(self, store: PlexflowObjectStore):
|
13
|
+
"""Initializes the PlexflowContext with the given object store.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
store (PlexflowObjectStore): The object store to be used in the Plexflow context.
|
17
|
+
"""
|
18
|
+
|
19
|
+
self.store = store
|
20
|
+
|
21
|
+
@property
|
22
|
+
def object_store(self) -> PlexflowObjectStore:
|
23
|
+
"""Gets the object store used in the Plexflow context.
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
PlexflowObjectStore: The object store used in the Plexflow context.
|
27
|
+
"""
|
28
|
+
|
29
|
+
return self.store
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
|
3
|
+
class PlexflowObjectProperty:
|
4
|
+
"""A class used to represent a property of a Plexflow object."""
|
5
|
+
|
6
|
+
def __init__(self, store: PlexflowObjectStore, key: str, local: bool = True):
|
7
|
+
"""Initializes the PlexflowObjectProperty with the given object store, key, and locality.
|
8
|
+
|
9
|
+
Args:
|
10
|
+
store (PlexflowObjectStore): The object store to be used.
|
11
|
+
key (str): The key of the object.
|
12
|
+
local (bool, optional): Whether the key is local. Defaults to True.
|
13
|
+
"""
|
14
|
+
|
15
|
+
self.store = store
|
16
|
+
self.object_key = self.store.make_run_key(key) if local else self.store.make_key(key)
|
17
|
+
|
18
|
+
@property
|
19
|
+
def value(self):
|
20
|
+
"""Gets the value of the object from the object store.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
Any: The value of the object.
|
24
|
+
"""
|
25
|
+
|
26
|
+
return self.store.retrieve(self.object_key)
|
27
|
+
|
28
|
+
@value.setter
|
29
|
+
def value(self, val):
|
30
|
+
"""Sets the value of the object in the object store.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
val (Any): The value to be set.
|
34
|
+
"""
|
35
|
+
|
36
|
+
self.store.store_temporarily(self.object_key, val)
|
File without changes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from plexflow.core.context.plexflow_context import PlexflowContext
|
2
|
+
from plexflow.core.context.select.context import SelectContext
|
3
|
+
from plexflow.core.context.watchlist.context import WatchlistContext
|
4
|
+
from plexflow.core.context.metadata.context import MetadataContext
|
5
|
+
from plexflow.core.context.torrent.context import TorrentContext
|
6
|
+
|
7
|
+
class RootContext(PlexflowContext):
|
8
|
+
def __init__(self, **kwargs):
|
9
|
+
super().__init__(**kwargs)
|
10
|
+
|
11
|
+
@property
|
12
|
+
def select(self):
|
13
|
+
return SelectContext(self.object_store)
|
14
|
+
|
15
|
+
@property
|
16
|
+
def watchlist(self):
|
17
|
+
return WatchlistContext(self.object_store)
|
18
|
+
|
19
|
+
@property
|
20
|
+
def metadata(self):
|
21
|
+
return MetadataContext(self.object_store)
|
22
|
+
|
23
|
+
@property
|
24
|
+
def torrent(self):
|
25
|
+
return TorrentContext(self.object_store)
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
from plexflow.core.context.plexflow_context import PlexflowContext
|
3
|
+
from plexflow.core.context.plexflow_property import PlexflowObjectProperty
|
4
|
+
from plexflow.core.plex.watchlist.datatypes import PlexMetadata
|
5
|
+
from typing import Union
|
6
|
+
|
7
|
+
class SelectContext(PlexflowContext):
|
8
|
+
"""A class used to represent a Select Context in Plexflow.
|
9
|
+
|
10
|
+
This class extends PlexflowContext and adds a selected item property.
|
11
|
+
|
12
|
+
Attributes:
|
13
|
+
selected_item (PlexflowObjectProperty): The selected item in the context.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def __init__(self, store: PlexflowObjectStore, **kwargs):
|
17
|
+
"""Initializes the SelectContext with the given object store and keyword arguments.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
store (PlexflowObjectStore): The object store to be used.
|
21
|
+
**kwargs: Arbitrary keyword arguments.
|
22
|
+
"""
|
23
|
+
|
24
|
+
super().__init__(store=store, **kwargs)
|
25
|
+
self.selected_item = PlexflowObjectProperty(self.object_store, "selected", local=True)
|
26
|
+
|
27
|
+
@property
|
28
|
+
def item(self) -> Union[PlexMetadata, None]:
|
29
|
+
"""Gets the value of the selected item.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
Any: The value of the selected item.
|
33
|
+
"""
|
34
|
+
|
35
|
+
return self.selected_item.value
|
36
|
+
|
37
|
+
@item.setter
|
38
|
+
def item(self, val: PlexMetadata):
|
39
|
+
"""Sets the value of the selected item.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
val (Any): The value to be set.
|
43
|
+
"""
|
44
|
+
|
45
|
+
self.selected_item.value = val
|
File without changes
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from plexflow.core.storage.object.plexflow_storage import PlexflowObjectStore
|
2
|
+
from plexflow.core.context.plexflow_context import PlexflowContext
|
3
|
+
from plexflow.core.context.torrent.tpb.context import ThePirateBayTorrentContext
|
4
|
+
from plexflow.core.context.torrent.yts.context import YTSTorrentContext
|
5
|
+
|
6
|
+
class TorrentContext(PlexflowContext):
|
7
|
+
"""A class used to represent a Select Context in Plexflow.
|
8
|
+
|
9
|
+
This class extends PlexflowContext and adds a selected item property.
|
10
|
+
|
11
|
+
Attributes:
|
12
|
+
selected_item (PlexflowObjectProperty): The selected item in the context.
|
13
|
+
"""
|
14
|
+
|
15
|
+
def __init__(self, store: PlexflowObjectStore, **kwargs):
|
16
|
+
"""Initializes the SelectContext with the given object store and keyword arguments.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
store (PlexflowObjectStore): The object store to be used.
|
20
|
+
**kwargs: Arbitrary keyword arguments.
|
21
|
+
"""
|
22
|
+
|
23
|
+
super().__init__(store=store, **kwargs)
|
24
|
+
|
25
|
+
@property
|
26
|
+
def tpb(self) -> ThePirateBayTorrentContext:
|
27
|
+
"""Gets the value of the selected item.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
Any: The value of the selected item.
|
31
|
+
"""
|
32
|
+
|
33
|
+
return ThePirateBayTorrentContext(store=self.object_store)
|
34
|
+
|
35
|
+
@property
|
36
|
+
def yts(self) -> YTSTorrentContext:
|
37
|
+
"""Gets the value of the selected item.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
Any: The value of the selected item.
|
41
|
+
"""
|
42
|
+
|
43
|
+
return YTSTorrentContext(store=self.object_store)
|
File without changes
|