This commit is contained in:
VineFeeder
2026-07-11 14:13:47 +01:00
parent acc7af1c02
commit 1572c47808
358 changed files with 91282 additions and 39 deletions
@@ -136,6 +136,7 @@ def result(service: Service, profile: Optional[str] = None, **_: Any) -> None:
result_text = f"[bold text]{result.title}[/]"
if result.url:
result_text = f"[link={result.url}]{result_text}[/link]"
if result.label:
result_text += f" [pink]{result.label}[/]"
if result.description:
@@ -143,7 +144,7 @@ def result(service: Service, profile: Optional[str] = None, **_: Any) -> None:
result_text += f"\n[bright_black]id: {result.id}[/]"
search_results.add(result_text + "\n")
# update cookies
# update cookie
cookie_file = dl.get_cookie_path(service_tag, profile)
if cookie_file:
dl.save_cookies(cookie_file, service.session.cookies)
@@ -9,6 +9,7 @@ class SearchResult:
description: Optional[str] = None,
label: Optional[str] = None,
url: Optional[str] = None,
image: Optional[str] = None
):
"""
A Search Result for any support Title Type.
@@ -33,12 +34,15 @@ class SearchResult:
raise TypeError(f"Expected label to be a {str}, not {type(label)}")
if not isinstance(url, (str, type(None))):
raise TypeError(f"Expected url to be a {str}, not {type(url)}")
if not isinstance(image, (str, type(None))):
raise TypeError(f"Expected image to be a {str}, not {type(image)}")
self.id = id_
self.title = title
self.description = description
self.label = label
self.url = url
self.image = image
__all__ = ("SearchResult",)
@@ -22,8 +22,8 @@ class STV(Service):
Service code for STV Player streaming service (https://player.stv.tv/).
\b
Version: 1.0.3
Author: stabbedbybrick
Version: 1.0.4
Author: stabbedbybrick; search corrected by Angela
Authorization: None
Robustness:
L3: 1080p
@@ -68,6 +68,7 @@ class STV(Service):
synopsis = result['attributes']["long_description"]
label = result["attributes"]["subGenre"]
#image = result["attributes"]["images"][0]["_filepath"].split("&w")[0] if result["attributes"]["images"] else None
yield SearchResult(
id_= self.config["endpoints"]["prefix"].strip("/") + result["attributes"]["permalink"],
@@ -75,6 +76,7 @@ class STV(Service):
description=synopsis,
label=label,
url=url,
#image=image
)
def get_titles(self) -> Union[Movies, Series]:
@@ -43,10 +43,10 @@ class TPTV(Service):
Service code for TPTVencore streaming service (https://www.TPTVencore.co.uk/).
\b
version 1.1.0
Date: June 2026
version 1.3.0
Date: July 2026
Author: A_n_g_e_l_a
Authorization: email/password for service in envied.yaml
Authorization: email/password for service in envied.yaml
Robustness:
DRM free... with rare exceptions L3
@@ -190,8 +190,29 @@ class TPTV(Service):
self.authorization = tokens
def search(self) -> Generator[SearchResult, None, None]:
print(f"Searching not implemented in Envied for TPTVencore. Please use VineFeeder instead.")
return None
search_term = self.title.replace(" ", "+")
response = self.session.get(self.config["endpoints"]["search"].format(query=search_term))
response.raise_for_status()
results = json.loads(response.content.decode("utf-8"))
for result in results["data"]:
url = result['video']['playback'].replace("api/core/play", "playback")
title = result['title']
synopsis = result['description'].replace('\n', ' ')
label = result["subtype"]
id = result["video"]["playback"].replace("api/core/play", "playback")
yield SearchResult(
id_= id,
title=title,
description=synopsis,
label=label,
url=url,
)
def get_titles(self) -> Union[Movies, Series]:
data = self.get_data(self.title)
@@ -178,7 +178,7 @@ class BaseLoader:
return
def add_episode(self, series_name, episode):
def add_episode(self, series_name, episode, uhd=None):
"""Add an episode to the series in memory.
Episode may be Any"""
if series_name not in self.series_data:
@@ -246,13 +246,19 @@ class BaseLoader:
def get_final_episode_list(self):
return self.final_episode_data
def display_final_episode_list(self, final_episode_data):
def display_final_episode_list(self, final_episode_data, check_uhd=False):
"""Use beaupy to display episodes for a selected series."""
# episodes = self.series_data.get(series_name, [])
episode_list = [
f"{ep['series_no']}, {ep['title']}, {ep['url']}, \n\t {ep['synopsis']}"
for ep in final_episode_data
]
if check_uhd:
episode_list = [
f"{ep['series_no']}, {ep['title']}, {ep['url']}, UHD={ep['uhd']}, \n\t {ep['synopsis']}"
for ep in final_episode_data
]
else:
episode_list = [
f"{ep['series_no']}, {ep['title']}, {ep['url']}, \n\t {ep['synopsis']}"
for ep in final_episode_data
]
selected_episodes = select_multiple(
episode_list,
preprocessor=lambda val: prettify(val),
@@ -9,6 +9,7 @@ from vinefeeder.parsing_utils import extract_params_json, parse_json, split, spl
from rich.console import Console
import jmespath
from scrapy.selector import Selector
import json
console = Console()
@@ -151,7 +152,7 @@ class BbcLoader(BaseLoader):
print(
"Error downloading video:",
e,
"Is self.DOWNLOAD_ORCHESTRATOR installed correctly via 'pip install self.DOWNLOAD_ORCHESTRATOR?",
f"Is {self.DOWNLOAD_ORCHESTRATOR} installed correctly via 'pip install {self.DOWNLOAD_ORCHESTRATOR}?",
)
else:
@@ -166,7 +167,7 @@ class BbcLoader(BaseLoader):
print(
"Error downloading video:",
e,
"Is self.DOWNLOAD_ORCHESTRATOR installed correctly via 'pip install self.DOWNLOAD_ORCHESTRATOR?",
f"Is {self.DOWNLOAD_ORCHESTRATOR} installed correctly via 'pip install {self.DOWNLOAD_ORCHESTRATOR}?",
)
return
@@ -213,15 +214,11 @@ class BbcLoader(BaseLoader):
def fetch_videos(self, search_term):
"""Fetch videos from BBC using a search term."""
url = "https://ibl.api.bbc.co.uk/ibl/v1/new-search"
# url = f"https://search.api.bbci.co.uk/formula/iplayer-ibl-root?q={search_term}&apikey=D2FgtcTxGqqIgLsfBWTJdrQh2tVdeaAp&seqId=0582e0f0-b911-11ee-806c-11c6c885ab56"
params = {
"q": search_term,
"rights": "web",
#'mixin': 'live'
}
url = f"https://ibl.api.bbc.co.uk/ibl/v1/new-search?q={search_term}&rights=mobile&size=10&sort=relevance&start=0"
try:
html = self.get_data(url, self.headers, params)
html = self.get_data(url, self.headers)
if "new_search" not in html:
print("Nothing found for that search; try again.")
return
@@ -290,10 +287,10 @@ class BbcLoader(BaseLoader):
parsed_data = parse_json(myhtml)
# testing
#file = open("init_data.json", "w")
#file.write(json.dumps(parsed_data))
#file.close()
#console.print_json(data=parsed_data)
# file = open("init_data.json", "w")
# file.write(json.dumps(parsed_data))
# file.close()
# console.print_json(data=parsed_data)
self.clear_series_data() # Clear existing series data
self.options_list = split_options(self.options)
@@ -317,6 +314,8 @@ class BbcLoader(BaseLoader):
episodes = parsed_data.get("programme_episodes").get("elements")
for item in episodes:
try:
# programme_episodes►elements►0►versions►0►uhd
uhd = item.get("versions", [{}])[0].get("uhd", False)
series_no = item["subtitle"].split(":")[0].split(" ")[1]
if int(series_no):
pass
@@ -330,21 +329,23 @@ class BbcLoader(BaseLoader):
], # .split(' ')[-1] or '01',
"url": "https://www.bbc.co.uk/iplayer/episode/" + item["id"],
"synopsis": item["synopses"]["small"] or None,
"uhd": uhd or False,
}
except Exception:
try:
episode = {
"series_no": 100, # special or one-off'
"series_no": int(100), # special or one-off'
# 'title' is episode number here, some services use descriptive text
"title": item["subtitle"], # could be date
"url": "https://www.bbc.co.uk/iplayer/episode/"
+ item["id"],
"synopsis": item["synopses"]["small"] or None,
"uhd": item.get("versions", [{}])[0].get("uhd", False) or False,
}
except KeyError as e:
print(f"Error: {e}")
continue # Skip any episode that doesn't have the required information
self.add_episode(series_name, episode)
self.add_episode(series_name, episode, uhd=uhd)
# Single episode expedite download
else:
@@ -356,6 +357,9 @@ class BbcLoader(BaseLoader):
self.AVAILABLE_HLG = True
break
# self.options_list = split_options(self.options)
try:
if BbcLoader.HLG and self.AVAILABLE_HLG:
command = (
@@ -378,7 +382,7 @@ class BbcLoader(BaseLoader):
print(
"Error downloading video:",
e,
"Is self.DOWNLOAD_ORCHESTRATOR installed correctly via 'pip install self.DOWNLOAD_ORCHESTRATOR?",
f"Is {self.DOWNLOAD_ORCHESTRATOR} installed correctly via 'pip install {self.DOWNLOAD_ORCHESTRATOR}'?",
)
return
@@ -386,17 +390,22 @@ class BbcLoader(BaseLoader):
series_name
) # creates list of series; allows user selection of wanted series prepares an episode list over chosen series
selected_final_episodes = self.display_final_episode_list(
self.final_episode_data
self.final_episode_data, check_uhd=True
)
# specific to BBC
# self.options_list = split_options(self.options)
for item in selected_final_episodes:
# check for UHD content
for hlg_item in self.uhd_list:
if series_name.lower() in hlg_item:
self.AVAILABLE_HLG = True
break
#print(type(item))
#print(item)
for part in item.split(","):
if "UHD" in part:
uhd = part.split("UHD=")[1].strip()
# Sanity check for UHD content
if uhd=="True":
self.AVAILABLE_HLG = True
else:
self.AVAILABLE_HLG = False
for part in item.split(","):
if "https" in part:
url = part.strip()
@@ -419,7 +428,7 @@ class BbcLoader(BaseLoader):
Returns:
None
"""
beaupylist = []
#beaupylist = []
req = self.client.get(browse_url, headers=self.headers)
init_data = extract_params_json(req.content.decode(), "__IPLAYER_REDUX_STATE__")