mirror of
https://github.com/vinefeeder/TwinVine.git
synced 2026-07-15 18:10:04 +02:00
Plex 1.0.3
This commit is contained in:
@@ -12,14 +12,23 @@ from concurrent.futures import ThreadPoolExecutor
|
|||||||
import click
|
import click
|
||||||
from click import Context
|
from click import Context
|
||||||
|
|
||||||
|
try:
|
||||||
from envied.core.credential import Credential
|
from devine.core.credential import Credential # type: ignore
|
||||||
from envied.core.manifests import DASH, HLS
|
from devine.core.manifests import DASH, HLS # type: ignore
|
||||||
from envied.core.search_result import SearchResult
|
from devine.core.search_result import SearchResult # type: ignore
|
||||||
from envied.core.service import Service
|
from devine.core.service import Service # type: ignore
|
||||||
from envied.core.titles import Episode, Movie, Movies, Series
|
from devine.core.titles import Episode, Movie, Movies, Series # type: ignore
|
||||||
from envied.core.tracks import Chapter, Chapters, Tracks
|
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
|
from requests import Request
|
||||||
|
|
||||||
@@ -30,7 +39,7 @@ class PLEX(Service):
|
|||||||
Service code for Plex's free streaming service (https://watch.plex.tv/).
|
Service code for Plex's free streaming service (https://watch.plex.tv/).
|
||||||
|
|
||||||
\b
|
\b
|
||||||
Version: 1.0.0
|
Version: 1.0.3
|
||||||
Author: stabbedbybrick
|
Author: stabbedbybrick
|
||||||
Authorization: None
|
Authorization: None
|
||||||
Geofence: API and downloads are locked into whatever region the user is in
|
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:
|
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(
|
url_pattern = re.compile(
|
||||||
r"^https://watch.plex.tv/"
|
r"^https://watch.plex.tv/"
|
||||||
|
r"(?:[a-z]{2}(?:-[A-Z]{2})?/)??"
|
||||||
r"(?P<type>movie|show)/"
|
r"(?P<type>movie|show)/"
|
||||||
r"(?P<id>[\w-]+)"
|
r"(?P<id>[\w-]+)"
|
||||||
r"(?P<url_path>(/season/\d+/episode/\d+))?"
|
r"(?P<url_path>(/season/\d+/episode/\d+))?"
|
||||||
@@ -123,11 +129,13 @@ class PLEX(Service):
|
|||||||
if not match:
|
if not match:
|
||||||
raise ValueError(f"Could not parse ID from title: {self.title}")
|
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 kind == "show":
|
||||||
if path is not None:
|
if url_path is not None:
|
||||||
episode = self._episode(urlparse(self.title).path)
|
path = urlparse(self.title).path
|
||||||
|
url = re.sub(r"/[a-z]{2}(?:-[A-Z]{2})?/", "/", path)
|
||||||
|
episode = self._episode(url)
|
||||||
return Series(episode)
|
return Series(episode)
|
||||||
|
|
||||||
episodes = self._series(guid)
|
episodes = self._series(guid)
|
||||||
@@ -175,7 +183,7 @@ class PLEX(Service):
|
|||||||
return tracks
|
return tracks
|
||||||
|
|
||||||
def get_chapters(self, title: Movie | Episode) -> Chapters:
|
def get_chapters(self, title: Movie | Episode) -> Chapters:
|
||||||
'''if not (markers := title.data.get("Marker", [])):
|
if not (markers := title.data.get("Marker")):
|
||||||
try:
|
try:
|
||||||
metadata = self._request(
|
metadata = self._request(
|
||||||
"POST", "/playQueues",
|
"POST", "/playQueues",
|
||||||
@@ -191,15 +199,17 @@ class PLEX(Service):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.debug("Failed to fetch markers: %s", e)
|
self.log.debug("Failed to fetch markers: %s", e)
|
||||||
pass
|
return Chapters()
|
||||||
|
|
||||||
|
if not markers:
|
||||||
|
return Chapters()
|
||||||
|
|
||||||
chapters = []
|
chapters = []
|
||||||
for cue in markers:
|
for cue in markers:
|
||||||
if cue.get("startTimeOffset", 0) > 0:
|
if cue.get("startTimeOffset", 0) > 0:
|
||||||
chapters.append(Chapter(name=cue.get("type", "").title(), timestamp=cue.get("startTimeOffset")))
|
chapters.append(Chapter(name=cue.get("type", "").title(), timestamp=cue.get("startTimeOffset")))
|
||||||
|
|
||||||
return Chapters(chapters)'''
|
return Chapters(chapters)
|
||||||
return []
|
|
||||||
|
|
||||||
def get_widevine_service_certificate(self, **_: Any) -> str:
|
def get_widevine_service_certificate(self, **_: Any) -> str:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ class ItvxLoader(BaseLoader):
|
|||||||
# ALTERNATIVES BELOW FROM POP-UP MENU
|
# ALTERNATIVES BELOW FROM POP-UP MENU
|
||||||
elif inx == 0:
|
elif inx == 0:
|
||||||
# from greedy-search OR selecting Browse-category
|
# 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
|
# need a search keyword(s) from url
|
||||||
# split and select series name
|
# split and select series name
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ class PlexLoader(BaseLoader):
|
|||||||
return int(m.group()) if m else default
|
return int(m.group()) if m else default
|
||||||
|
|
||||||
seasons = sorted({p.strip().lower() for p in parts}, key=season_num)
|
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:
|
for item in seasons:
|
||||||
url = f"https://watch.plex.tv/show/{selected.lower().replace(' ','-')}/season/{item.split(' ')[1]}"
|
url = f"https://watch.plex.tv/show/{selected.lower().replace(' ','-')}/season/{item.split(' ')[1]}"
|
||||||
html_bytes = self.get_data(url=url, headers=headers)
|
html_bytes = self.get_data(url=url, headers=headers)
|
||||||
@@ -231,7 +231,7 @@ class PlexLoader(BaseLoader):
|
|||||||
"synopsis": rinse(synopsis) or None,
|
"synopsis": rinse(synopsis) or None,
|
||||||
}
|
}
|
||||||
self.add_episode(selected, episode)
|
self.add_episode(selected, episode)
|
||||||
#print(selected, episode)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"No valid data at {url} found.\n Exiting {e}")
|
print(f"No valid data at {url} found.\n Exiting {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user