From bba16b27b91b93b0d73d9222e062300c8207ac06 Mon Sep 17 00:00:00 2001 From: VineFeeder Date: Mon, 15 Sep 2025 10:57:01 +0100 Subject: [PATCH] Plex 1.0.3 --- .../src/envied/services/PLEX/__init__.py | 50 +++++++++++-------- .../src/vinefeeder/services/ITVX/__init__.py | 1 - .../src/vinefeeder/services/PLEX/__init__.py | 4 +- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/envied/src/envied/services/PLEX/__init__.py b/packages/envied/src/envied/services/PLEX/__init__.py index b1acfe7..60514a9 100644 --- a/packages/envied/src/envied/services/PLEX/__init__.py +++ b/packages/envied/src/envied/services/PLEX/__init__.py @@ -12,14 +12,23 @@ from concurrent.futures import ThreadPoolExecutor import click from click import Context - -from envied.core.credential import Credential -from envied.core.manifests import DASH, HLS -from envied.core.search_result import SearchResult -from envied.core.service import Service -from envied.core.titles import Episode, Movie, Movies, Series -from envied.core.tracks import Chapter, Chapters, Tracks - +try: + from devine.core.credential import Credential # type: ignore + from devine.core.manifests import DASH, HLS # type: ignore + from devine.core.search_result import SearchResult # type: ignore + from devine.core.service import Service # type: ignore + from devine.core.titles import Episode, Movie, Movies, Series # type: ignore + from devine.core.tracks import Chapter, Chapters, Tracks # type: ignore +except ImportError: + try: + from unshackle.core.credential import Credential + from unshackle.core.manifests import DASH, HLS + from unshackle.core.search_result import SearchResult + from unshackle.core.service import Service + from unshackle.core.titles import Episode, Movie, Movies, Series + from unshackle.core.tracks import Chapter, Chapters, Tracks + except ImportError: + raise ImportError("PLEX service requires devine or unshackle to be installed") from requests import Request @@ -30,7 +39,7 @@ class PLEX(Service): Service code for Plex's free streaming service (https://watch.plex.tv/). \b - Version: 1.0.0 + Version: 1.0.3 Author: stabbedbybrick Authorization: None Geofence: API and downloads are locked into whatever region the user is in @@ -108,12 +117,9 @@ class PLEX(Service): ) def get_titles(self) -> Movies | Series: - # check lang code and remove if exists - pattern = re.compile(r'^(https?://[^/]+)(?:/[a-z]{2}-[A-Z]{2})?(.*)$') - self.title = pattern.sub(r'\1\2', self.title) - url_pattern = re.compile( r"^https://watch.plex.tv/" + r"(?:[a-z]{2}(?:-[A-Z]{2})?/)??" r"(?Pmovie|show)/" r"(?P[\w-]+)" r"(?P(/season/\d+/episode/\d+))?" @@ -123,11 +129,13 @@ class PLEX(Service): if not match: raise ValueError(f"Could not parse ID from title: {self.title}") - kind, guid, path = (match.group(i) for i in ("type", "id", "url_path")) + kind, guid, url_path = (match.group(i) for i in ("type", "id", "url_path")) if kind == "show": - if path is not None: - episode = self._episode(urlparse(self.title).path) + if url_path is not None: + path = urlparse(self.title).path + url = re.sub(r"/[a-z]{2}(?:-[A-Z]{2})?/", "/", path) + episode = self._episode(url) return Series(episode) episodes = self._series(guid) @@ -175,7 +183,7 @@ class PLEX(Service): return tracks def get_chapters(self, title: Movie | Episode) -> Chapters: - '''if not (markers := title.data.get("Marker", [])): + if not (markers := title.data.get("Marker")): try: metadata = self._request( "POST", "/playQueues", @@ -191,15 +199,17 @@ class PLEX(Service): except Exception as e: self.log.debug("Failed to fetch markers: %s", e) - pass + return Chapters() + + if not markers: + return Chapters() chapters = [] for cue in markers: if cue.get("startTimeOffset", 0) > 0: chapters.append(Chapter(name=cue.get("type", "").title(), timestamp=cue.get("startTimeOffset"))) - return Chapters(chapters)''' - return [] + return Chapters(chapters) def get_widevine_service_certificate(self, **_: Any) -> str: return None diff --git a/packages/vinefeeder/src/vinefeeder/services/ITVX/__init__.py b/packages/vinefeeder/src/vinefeeder/services/ITVX/__init__.py index 0f0474e..5c357e9 100644 --- a/packages/vinefeeder/src/vinefeeder/services/ITVX/__init__.py +++ b/packages/vinefeeder/src/vinefeeder/services/ITVX/__init__.py @@ -73,7 +73,6 @@ class ItvxLoader(BaseLoader): # ALTERNATIVES BELOW FROM POP-UP MENU elif inx == 0: # from greedy-search OR selecting Browse-category - # example: https://www.channel4.com/programmes/the-great-british-bake-off/on-demand/75228-001 # need a search keyword(s) from url # split and select series name diff --git a/packages/vinefeeder/src/vinefeeder/services/PLEX/__init__.py b/packages/vinefeeder/src/vinefeeder/services/PLEX/__init__.py index b40ef5b..f31ece7 100644 --- a/packages/vinefeeder/src/vinefeeder/services/PLEX/__init__.py +++ b/packages/vinefeeder/src/vinefeeder/services/PLEX/__init__.py @@ -208,7 +208,7 @@ class PlexLoader(BaseLoader): return int(m.group()) if m else default seasons = sorted({p.strip().lower() for p in parts}, key=season_num) - self.clear_series_data() # safely remove any leftovers + self.clear_series_data() # safely remove any leftovers ready for building for item in seasons: url = f"https://watch.plex.tv/show/{selected.lower().replace(' ','-')}/season/{item.split(' ')[1]}" html_bytes = self.get_data(url=url, headers=headers) @@ -231,7 +231,7 @@ class PlexLoader(BaseLoader): "synopsis": rinse(synopsis) or None, } self.add_episode(selected, episode) - #print(selected, episode) + except Exception as e: print(f"No valid data at {url} found.\n Exiting {e}")