feat: enable use of http headers for providers

This commit is contained in:
Benex254
2024-08-17 15:17:53 +03:00
parent abab2540a3
commit 454341eaf5
10 changed files with 101 additions and 22 deletions

View File

@@ -176,6 +176,7 @@ def search(config: Config, anime_titles: str, episode_range: str):
stream_anime()
return
link = stream_link["link"]
stream_headers = server["headers"]
episode_title = server["episode_title"]
else:
with Progress() as progress:
@@ -204,16 +205,17 @@ def search(config: Config, anime_titles: str, episode_range: str):
stream_anime()
return
link = stream_link["link"]
stream_headers = servers[server]["headers"]
episode_title = servers[server]["episode_title"]
print(f"[purple]Now Playing:[/] {search_result} Episode {episode}")
if config.sync_play:
from ..utils.syncplay import SyncPlayer
SyncPlayer(link, episode_title)
SyncPlayer(link, episode_title, headers=stream_headers)
else:
run_mpv(link, episode_title)
except Exception as e:
run_mpv(link, episode_title, headers=stream_headers)
except IndexError as e:
print(e)
input("Enter to continue")
stream_anime()

View File

@@ -117,7 +117,9 @@ def media_player_controls(
from ..utils.syncplay import SyncPlayer
stop_time, total_time = SyncPlayer(
current_episode_stream_link, selected_server["episode_title"]
current_episode_stream_link,
selected_server["episode_title"],
headers=selected_server["headers"],
)
elif config.use_mpv_mod:
from ..utils.player import player
@@ -128,6 +130,7 @@ def media_player_controls(
fastanime_runtime_state,
config,
selected_server["episode_title"],
headers=selected_server["headers"],
)
# TODO: implement custom aniskip
@@ -148,6 +151,7 @@ def media_player_controls(
selected_server["episode_title"],
start_time=start_time,
custom_args=custom_args,
headers=selected_server["headers"],
)
# either update the watch history to the next episode or current depending on progress
@@ -509,7 +513,9 @@ def provider_anime_episode_servers_menu(
from ..utils.syncplay import SyncPlayer
stop_time, total_time = SyncPlayer(
current_stream_link, selected_server["episode_title"]
current_stream_link,
selected_server["episode_title"],
headers=selected_server["headers"],
)
elif config.use_mpv_mod:
from ..utils.player import player
@@ -520,6 +526,7 @@ def provider_anime_episode_servers_menu(
fastanime_runtime_state,
config,
selected_server["episode_title"],
headers=selected_server["headers"],
)
# TODO: implement custom aniskip intergration
@@ -543,6 +550,7 @@ def provider_anime_episode_servers_menu(
selected_server["episode_title"],
start_time=start_time,
custom_args=custom_args,
headers=selected_server["headers"],
)
print("Finished at: ", stop_time)

View File

@@ -2,6 +2,8 @@ import re
import shutil
import subprocess
from fastanime.constants import S_PLATFORM
def stream_video(MPV, url, mpv_args, custom_args):
process = subprocess.Popen(
@@ -52,6 +54,7 @@ def run_mpv(
start_time: str = "0",
ytdl_format="",
custom_args=[],
headers={},
):
# Determine if mpv is available
MPV = shutil.which("mpv")
@@ -61,7 +64,7 @@ def run_mpv(
# Regex to check if the link is a YouTube URL
youtube_regex = r"(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/.+"
if not MPV:
if not MPV and not S_PLATFORM == "win32":
# Determine if the link is a YouTube URL
if re.match(youtube_regex, link):
# Android specific commands to launch mpv with a YouTube URL
@@ -100,6 +103,11 @@ def run_mpv(
else:
# General mpv command with custom arguments
mpv_args = []
if headers:
mpv_headers = "--http-header-fields="
for header_name, header_value in headers.items():
mpv_headers += f"{header_name}:{header_value},"
mpv_args.append(mpv_headers)
if start_time != "0":
mpv_args.append(f"--start={start_time}")
if title:

View File

@@ -151,6 +151,7 @@ class MpvPlayer(object):
fastanime_runtime_state,
config: "Config",
title,
headers={},
):
self.anime_provider = anime_provider
self.fastanime_runtime_state = fastanime_runtime_state
@@ -174,6 +175,11 @@ class MpvPlayer(object):
# mpv_player.cache = "yes"
# mpv_player.cache_pause = "no"
mpv_player.title = title
mpv_headers = ""
if headers:
for header_name, header_value in headers.items():
mpv_headers += f"{header_name}:{header_value},"
mpv_player.http_header_fields = mpv_headers
mpv_player.play(stream_link)

View File

@@ -4,7 +4,7 @@ import subprocess
from .tools import exit_app
def SyncPlayer(url: str, anime_title=None, *args):
def SyncPlayer(url: str, anime_title=None, headers={}, *args):
# TODO: handle m3u8 multi quality streams
#
# check for SyncPlay
@@ -14,6 +14,12 @@ def SyncPlayer(url: str, anime_title=None, *args):
exit_app(1)
return "0", "0"
# start SyncPlayer
mpv_args = []
if headers:
mpv_headers = "--http-header-fields="
for header_name, header_value in headers.items():
mpv_headers += f"{header_name}:{header_value},"
mpv_args.append(mpv_headers)
if not anime_title:
subprocess.run(
[
@@ -23,7 +29,13 @@ def SyncPlayer(url: str, anime_title=None, *args):
)
else:
subprocess.run(
[SYNCPLAY_EXECUTABLE, url, "--", f"--force-media-title={anime_title}"]
[
SYNCPLAY_EXECUTABLE,
url,
"--",
f"--force-media-title={anime_title}",
*mpv_args,
]
)
# for compatability

View File

@@ -9,4 +9,5 @@ SERVERS_AVAILABLE = [
"weTransfer",
"wixmp",
"kwik",
"Yt",
]

View File

@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING
from requests.exceptions import Timeout
from ...anime_provider.base_provider import AnimeProvider
from ..utils import decode_hex_string, give_random_quality
from ..utils import give_random_quality, one_digit_symmetric_xor
from .constants import (
ALLANIME_API_ENDPOINT,
ALLANIME_BASE,
@@ -205,23 +205,45 @@ class AllAnimeAPI(AnimeProvider):
# filter the working streams no need to get all since the others are mostly hsl
# TODO: should i just get all the servers and handle the hsl??
if embed.get("sourceName", "") not in (
"Sak",
"Kir",
"S-mp4",
"Luf-mp4",
"Default",
# priorities based on death note
"Sak", # 7
"S-mp4", # 7.9
"Luf-mp4", # 7.7
"Default", # 8.5
"Yt-mp4", # 7.9
"Kir", # NA
# "Vid-mp4" # 4
# "Ok", # 3.5
# "Ss-Hls", # 5.5
# "Mp4", # 4
):
continue
url = embed.get("sourceUrl")
#
if not url:
continue
if url.startswith("--"):
url = url[2:]
url = one_digit_symmetric_xor(56, url)
if "tools.fast4speed.rsvp" in url:
yield {
"server": "Yt",
"episode_title": f'{anime["title"]}; Episode {episode_number}',
"headers": {"Referer": f"https://{ALLANIME_BASE}/"},
"links": [
{
"link": url,
"quality": "1080",
}
],
} # pyright:ignore
continue
# get the stream url for an episode of the defined source names
parsed_url = decode_hex_string(url)
embed_url = f"https://{ALLANIME_BASE}{parsed_url.replace('clock', 'clock.json')}"
embed_url = (
f"https://{ALLANIME_BASE}{url.replace('clock', 'clock.json')}"
)
resp = self.session.get(
embed_url,
headers={
@@ -230,12 +252,14 @@ class AllAnimeAPI(AnimeProvider):
},
timeout=10,
)
if resp.status_code == 200:
match embed["sourceName"]:
case "Luf-mp4":
logger.debug("allanime:Found streams from gogoanime")
yield {
"server": "gogoanime",
"headers": {},
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
@@ -246,6 +270,7 @@ class AllAnimeAPI(AnimeProvider):
logger.debug("allanime:Found streams from wetransfer")
yield {
"server": "wetransfer",
"headers": {},
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
@@ -256,6 +281,7 @@ class AllAnimeAPI(AnimeProvider):
logger.debug("allanime:Found streams from sharepoint")
yield {
"server": "sharepoint",
"headers": {},
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
@@ -266,6 +292,7 @@ class AllAnimeAPI(AnimeProvider):
logger.debug("allanime:Found streams from dropbox")
yield {
"server": "dropbox",
"headers": {},
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
@@ -276,20 +303,22 @@ class AllAnimeAPI(AnimeProvider):
logger.debug("allanime:Found streams from wixmp")
yield {
"server": "wixmp",
"headers": {},
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": give_random_quality(resp.json()["links"]),
} # pyright:ignore
except Timeout:
logger.error(
"Timeout has been exceeded this could mean allanime is down or you have lost internet connection"
)
return []
except Exception as e:
logger.error(f"FA(Allanime): {e}")
return []
except Exception as e:
logger.error(f"FA(Allanime): {e}")
return []
@@ -301,7 +330,7 @@ if __name__ == "__main__":
import subprocess
import sys
from InquirerPy import inquirer, validator
from InquirerPy import inquirer, validator # pyright:ignore
anime = input("Enter the anime name: ")
translation = input("Enter the translation type: ")

View File

@@ -183,7 +183,12 @@ class AnimePaheApi(AnimeProvider):
episode["title"] or f"{anime['title']}; Episode {episode['episode']}"
)
# get all links
streams = {"server": "kwik", "links": [], "episode_title": episode_title}
streams = {
"server": "kwik",
"links": [],
"episode_title": episode_title,
"headers": {},
}
for res_dict in res_dicts:
# get embed url
embed_url = res_dict["data-src"]

View File

@@ -60,12 +60,12 @@ class EpisodeStream(TypedDict):
hls: bool | None
mp4: bool | None
priority: int | None
headers: dict | None
quality: Literal["360", "720", "1080", "unknown"]
translation_type: Literal["dub", "sub"]
class Server(TypedDict):
headers: dict
server: str
episode_title: str
links: list[EpisodeStream]

View File

@@ -44,6 +44,14 @@ def give_random_quality(links: list[dict]):
]
def one_digit_symmetric_xor(password: int, target: str):
def genexp():
for segment in bytearray.fromhex(target):
yield segment ^ password
return bytes(genexp()).decode("utf-8")
def decode_hex_string(hex_string):
"""some of the sources encrypt the urls into hex codes this function decrypts the urls