mirror of
https://github.com/vinefeeder/TwinVine.git
synced 2026-07-15 18:10:04 +02:00
updates and additions
This commit is contained in:
@@ -34,7 +34,7 @@ class NINE(Service):
|
|||||||
\b
|
\b
|
||||||
Tips:
|
Tips:
|
||||||
- Search by show name:
|
- Search by show name:
|
||||||
envied.dl NINE "Travel Guides"
|
unshackle dl NINE "Travel Guides"
|
||||||
- Use complete URLs:
|
- Use complete URLs:
|
||||||
SERIES: https://www.9now.com.au/travel-guides
|
SERIES: https://www.9now.com.au/travel-guides
|
||||||
EPISODE: https://www.9now.com.au/travel-guides/season-9/episode-2
|
EPISODE: https://www.9now.com.au/travel-guides/season-9/episode-2
|
||||||
@@ -386,40 +386,36 @@ class NINE(Service):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _best_source(sources: list[dict]) -> dict | None:
|
def _best_source(sources: list[dict]) -> dict | None:
|
||||||
dash_drm = next(
|
dash_drm = NINE._first_source(
|
||||||
(
|
sources,
|
||||||
source for source in sources
|
lambda source: (
|
||||||
if source.get("type") == "application/dash+xml"
|
source.get("type") == "application/dash+xml"
|
||||||
and (source.get("key_systems") or {}).get("com.widevine.alpha")
|
and (source.get("key_systems") or {}).get("com.widevine.alpha")
|
||||||
and source.get("src")
|
|
||||||
),
|
),
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
if dash_drm:
|
if dash_drm:
|
||||||
return dash_drm
|
return dash_drm
|
||||||
|
|
||||||
dash_clear = next(
|
dash_clear = NINE._first_source(sources, lambda source: source.get("type") == "application/dash+xml")
|
||||||
(
|
|
||||||
source for source in sources
|
|
||||||
if source.get("type") == "application/dash+xml" and source.get("src")
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
if dash_clear:
|
if dash_clear:
|
||||||
return dash_clear
|
return dash_clear
|
||||||
|
|
||||||
return next(
|
return NINE._first_source(sources, lambda source: source.get("type") == "application/x-mpegURL")
|
||||||
(
|
|
||||||
source for source in sources
|
@staticmethod
|
||||||
if source.get("type") == "application/x-mpegURL"
|
def _first_source(sources: list[dict], predicate: Any) -> dict | None:
|
||||||
and source.get("src", "").startswith("https://")
|
matches = [source for source in sources if predicate(source) and source.get("src")]
|
||||||
),
|
return next((source for source in matches if source["src"].startswith("https://")), None) or next(
|
||||||
|
iter(matches),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _add_subtitles(tracks: Tracks, text_tracks: list[dict]) -> None:
|
def _add_subtitles(tracks: Tracks, text_tracks: list[dict]) -> None:
|
||||||
for text_track in text_tracks:
|
for text_track in text_tracks:
|
||||||
|
if not NINE._is_caption_track(text_track):
|
||||||
|
continue
|
||||||
|
|
||||||
source_url = text_track.get("src")
|
source_url = text_track.get("src")
|
||||||
if not source_url and text_track.get("sources"):
|
if not source_url and text_track.get("sources"):
|
||||||
source_url = next(
|
source_url = next(
|
||||||
@@ -442,6 +438,19 @@ class NINE(Service):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_caption_track(text_track: dict) -> bool:
|
||||||
|
kind = (text_track.get("kind") or "").lower()
|
||||||
|
label = (text_track.get("label") or "").lower()
|
||||||
|
source_url = (text_track.get("src") or "").lower()
|
||||||
|
|
||||||
|
if kind in ("metadata", "thumbnail", "thumbnails") or label in ("thumbnail", "thumbnails"):
|
||||||
|
return False
|
||||||
|
if "/thumbnail/" in source_url or "thumbnail.webvtt" in source_url:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return kind in ("captions", "subtitles") or bool(text_track.get("srclang"))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _subtitle_codec(text_track: dict, source_url: str) -> str:
|
def _subtitle_codec(text_track: dict, source_url: str) -> str:
|
||||||
mime_type = (text_track.get("mime_type") or "").lower()
|
mime_type = (text_track.get("mime_type") or "").lower()
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
from vinefeeder.base_loader import BaseLoader
|
from vinefeeder.base_loader import BaseLoader
|
||||||
from vinefeeder.parsing_utils import extract_script_with_id_json, parse_json, split_options
|
from vinefeeder.parsing_utils import extract_script_with_id_json, parse_json, split_options
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
@@ -101,53 +103,21 @@ class StvLoader(BaseLoader):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def fetch_videos(self, search_term):
|
def fetch_videos(self, search_term):
|
||||||
headers = {
|
|
||||||
"Accept": "*/*",
|
|
||||||
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
|
|
||||||
"Connection": "keep-alive",
|
|
||||||
"Origin": "https://player.stv.tv",
|
|
||||||
"Referer": "https://player.stv.tv/",
|
|
||||||
"Host": "search-api.swiftype.com",
|
|
||||||
"Access-Control-Request-Method": "POST",
|
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
|
|
||||||
}
|
|
||||||
url = "https://search-api.swiftype.com/api/v1/public/engines/search.json"
|
|
||||||
|
|
||||||
response = self.get_options(url, headers=headers)
|
url = f"https://v4.api.stv.tv/v4/discovery/search?query={search_term}&indexUid=programme_index&limit=20&offset=0&facets="
|
||||||
|
|
||||||
xdata = response["x-request-id"]
|
response = self.get_data(url)
|
||||||
headers = {
|
parsed_data = json.loads(response)
|
||||||
"Accept": "*/*",
|
mydata = parsed_data["data"]
|
||||||
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
|
|
||||||
"Connection": "keep-alive",
|
|
||||||
"Origin": "https://player.stv.tv",
|
|
||||||
"Referer": "https://player.stv.tv/",
|
|
||||||
"Host": "search-api.swiftype.com",
|
|
||||||
"Access-Control-Request-Method": "POST",
|
|
||||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
|
|
||||||
"x-request-id": f"{xdata}",
|
|
||||||
}
|
|
||||||
json = {
|
|
||||||
"engine_key": "S1jgssBHdk8ZtMWngK_y",
|
|
||||||
"per_page": 100,
|
|
||||||
"page": 1,
|
|
||||||
"fetch_fields": {"page": ["title", "body", "resultDescriptionTx", "url"]},
|
|
||||||
"highlight_fields": {"page": {"title": {"size": 100, "fallback": True}}},
|
|
||||||
"search_fields": {"page": ["title^3", "body", "category", "sections"]},
|
|
||||||
"q": search_term,
|
|
||||||
"spelling": "strict",
|
|
||||||
}
|
|
||||||
|
|
||||||
response = self.post_data(url, headers=headers, json=json)
|
|
||||||
parsed_data = response.json() #
|
|
||||||
mydata = parsed_data["records"]["page"]
|
|
||||||
|
|
||||||
for item in mydata:
|
for item in mydata:
|
||||||
title = item["title"]
|
title = item['attributes']["title"]
|
||||||
|
url = item['attributes']["permalink"]
|
||||||
|
synopsis = item['attributes']["long_description"]
|
||||||
episode = {
|
episode = {
|
||||||
"title": item["title"],
|
"title": title,
|
||||||
"url": item["url"],
|
"url": "https://player.stv.tv/" + url.strip('/'),
|
||||||
"synopsis": item["resultDescriptionTx"],
|
"synopsis": synopsis,
|
||||||
}
|
}
|
||||||
self.add_episode(title, episode)
|
self.add_episode(title, episode)
|
||||||
|
|
||||||
@@ -179,13 +149,11 @@ class StvLoader(BaseLoader):
|
|||||||
self.clear_series_data() # Clear existing series data
|
self.clear_series_data() # Clear existing series data
|
||||||
|
|
||||||
'''console.print_json(data=parsed_data) # for debugging
|
'''console.print_json(data=parsed_data) # for debugging
|
||||||
f = open("1stv.json",'w')
|
f = open("stv.json",'w')
|
||||||
f.write(json.dumps(parsed_data))
|
f.write(json.dumps(parsed_data))
|
||||||
f.close()'''
|
f.close()'''
|
||||||
|
|
||||||
series_data = parsed_data["props"]["pageProps"]["data"]["programmeHeader"][
|
series_data = parsed_data["props"]["pageProps"]["data"]["programmeHeader"]["name"]
|
||||||
"name"
|
|
||||||
]
|
|
||||||
tabs = len(parsed_data["props"]["pageProps"]["data"]["tabs"])
|
tabs = len(parsed_data["props"]["pageProps"]["data"]["tabs"])
|
||||||
headers = {
|
headers = {
|
||||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0',
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0',
|
||||||
@@ -223,8 +191,14 @@ class StvLoader(BaseLoader):
|
|||||||
series_no = parsed_data["props"]["pageProps"]["data"]["tabs"][0]["title"]
|
series_no = parsed_data["props"]["pageProps"]["data"]["tabs"][0]["title"]
|
||||||
if "Episode" in series_no:
|
if "Episode" in series_no:
|
||||||
series_no = 100
|
series_no = 100
|
||||||
|
else:
|
||||||
|
if "-" in series_no:
|
||||||
|
series_no = int(series_no.split("-")[0])
|
||||||
else:
|
else:
|
||||||
series_no = int(series_no.split(" ")[1])
|
series_no = int(series_no.split(" ")[1])
|
||||||
|
old_series_no = series_no
|
||||||
|
except KeyError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
title = item["title"]
|
title = item["title"]
|
||||||
url = f"https://player.stv.tv{item['link']}" # https://player.stv.tv/episode/4nlk/loose-women
|
url = f"https://player.stv.tv{item['link']}" # https://player.stv.tv/episode/4nlk/loose-women
|
||||||
synopsis = item["summary"]
|
synopsis = item["summary"]
|
||||||
@@ -239,8 +213,7 @@ class StvLoader(BaseLoader):
|
|||||||
}
|
}
|
||||||
self.add_episode_remove_duplicates(series_data, episode)
|
self.add_episode_remove_duplicates(series_data, episode)
|
||||||
|
|
||||||
except KeyError as e:
|
|
||||||
print(f"Error: {e}")
|
|
||||||
|
|
||||||
if tabs > 1:
|
if tabs > 1:
|
||||||
for index in range(1, tabs):
|
for index in range(1, tabs):
|
||||||
@@ -271,12 +244,19 @@ class StvLoader(BaseLoader):
|
|||||||
for item in next_parsed_data["results"]:
|
for item in next_parsed_data["results"]:
|
||||||
try:
|
try:
|
||||||
series_no = item["playerSeries"]["name"]
|
series_no = item["playerSeries"]["name"]
|
||||||
|
if "Episode" in series_no:
|
||||||
|
series_no = 100
|
||||||
|
else:
|
||||||
|
if "-" in series_no:
|
||||||
|
series_no = int(series_no.split("-")[0])
|
||||||
|
else:
|
||||||
|
series_no = int(series_no.split(" ")[1])
|
||||||
title = item["title"]
|
title = item["title"]
|
||||||
url = item["_permalink"]
|
url = item["_permalink"]
|
||||||
synopsis = item["summary"]
|
synopsis = item["summary"]
|
||||||
|
|
||||||
episode = {
|
episode = {
|
||||||
"series_no": int(series_no.replace("Series ", "")),
|
"series_no": int(series_no),
|
||||||
"title": title,
|
"title": title,
|
||||||
"url": url, #
|
"url": url, #
|
||||||
"synopsis": synopsis,
|
"synopsis": synopsis,
|
||||||
|
|||||||
Reference in New Issue
Block a user