Skip to content

Commit 30fe00e

Browse files
authored
Merge pull request #3 from mov-cli/feat/plex
Feat/plex
2 parents 6f1fb21 + 6fa3347 commit 30fe00e

3 files changed

Lines changed: 79 additions & 12 deletions

File tree

mov_cli_ms/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
from mov_cli.plugins import PluginHookData
66

77
from .jellyfin.scraper import *
8+
from .plex.scraper import *
89

910
plugin: PluginHookData = {
1011
"version": 1, # plugin hook version
1112
"package_name": "mov-cli-ms", # pypi package name
1213
"scrapers": {
1314
"DEFAULT": JellyfinScraper,
14-
"jellyfin": JellyfinScraper
15+
"jellyfin": JellyfinScraper,
16+
"plex": PlexScraper
1517
}
1618
}
1719

mov_cli_ms/plex/scraper.py

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,89 @@
88
from mov_cli.http_client import HTTPClient
99
from mov_cli.scraper import ScraperOptionsT
1010

11-
from mov_cli import Single, Multi, Metadata
11+
from dataclasses import dataclass, field
12+
13+
from mov_cli import Single, Multi, Metadata, MetadataType
1214

1315
from mov_cli.scraper import Scraper
1416
from mov_cli.utils import EpisodeSelector
1517

16-
__all__ = ("PlexScraper", )
18+
from plexapi.myplex import MyPlexAccount
19+
from plexapi.server import PlexServer
20+
from plexapi.exceptions import TwoFactorRequired
21+
from plexapi.video import Movie, Show
22+
23+
__all__ = ("PlexScraper", "PlexMetadata",)
24+
25+
@dataclass
26+
class PlexMetadata(Metadata):
27+
id: int
28+
video: Movie | Show = field(default = None)
1729

1830
class PlexScraper(Scraper):
1931
def __init__(self, config: Config, http_client: HTTPClient, options: Optional[ScraperOptionsT] = None) -> None:
20-
self.base_url = ...
32+
env_config = config.get_env_config()
33+
34+
self.base_url = env_config("PLEX_SERVER_ID", default = None, cast = str)
35+
self.username = env_config("PLEX_USERNAME", default = None, cast = str)
36+
self.password = env_config("PLEX_PASSWORD", default = None, cast = str)
37+
38+
self.plex = self.__auth()
2139

2240
super().__init__(config, http_client, options)
2341

24-
def search(self, query: str, limit: int = 20) -> Generator[Metadata, Any, None]:
25-
...
2642

27-
def scrape_metadata_episodes(self, metadata: Metadata) -> Dict[int, int] | Dict[None, int]:
28-
...
29-
30-
def scrape(self, metadata: Metadata, episode: EpisodeSelector) -> Single | Multi:
31-
...
43+
def search(self, query: str, limit: int = 20) -> Generator[PlexMetadata, Any, None]:
44+
videos = self.plex.search(query, limit = limit)
45+
46+
for _, video in enumerate(videos):
47+
if video.TYPE in ["movie", "show"]:
48+
yield PlexMetadata(
49+
id = _,
50+
title = video.title,
51+
type = MetadataType.SINGLE if "movie" == video.TYPE else MetadataType.MULTI,
52+
year = video.year,
53+
video = video
54+
)
55+
56+
def scrape_episodes(self, metadata: PlexMetadata) -> Dict[int, int] | Dict[None, int]:
57+
scraped_episodes = {}
58+
59+
seasons = metadata.video.seasons()
60+
61+
for season in seasons:
62+
scraped_episodes[season.seasonNumber] = len(season.episodes())
63+
64+
return scraped_episodes
65+
66+
def scrape(self, metadata: PlexMetadata, episode: EpisodeSelector) -> Single | Multi:
67+
if metadata.type == MetadataType.MULTI:
68+
epi = metadata.video.episode(season = episode.season, episode = episode.episode)
69+
70+
return Multi(
71+
url = self.__make_url(epi),
72+
title = metadata.title,
73+
episode = episode
74+
)
75+
76+
return Single(
77+
url = self.__make_url(metadata.video),
78+
title = metadata.title,
79+
year = metadata.year
80+
)
81+
82+
def __make_url(self, item) -> str:
83+
key = next(item.iterParts()).key
84+
85+
return item._server.url(f"{key}?download=1&X-Plex-Token={self.plex.account().authToken}")
86+
87+
def __auth(self) -> PlexServer:
88+
try:
89+
account = MyPlexAccount(self.username, self.password)
90+
except TwoFactorRequired:
91+
code = self.options.get("2FA")
92+
account = MyPlexAccount(self.username, self.password, code=code)
93+
94+
plex = account.resource(self.base_url).connect()
95+
96+
return plex

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ dependencies = [
2626
"requests",
2727
"importlib-metadata; python_version<'3.8'",
2828

29-
"mov-cli>=4.3"
29+
"plexapi"
3030
]
3131

3232
dynamic = ["version"]

0 commit comments

Comments
 (0)