devine-services/MTSP/__init__.py

102 lines
2.9 KiB
Python
Raw Normal View History

2025-08-03 01:47:10 +02:00
from __future__ import annotations
from http.cookiejar import MozillaCookieJar
from typing import Any, Optional
import re
import click
from click import Context
from bs4 import BeautifulSoup
from devine.core.credential import Credential
from devine.core.service import Service
from devine.core.titles import Movie, Movies
from devine.core.tracks import Chapter, Tracks
from devine.core.manifests.dash import DASH
class MTSP(Service):
TITLE_RE = r"^(?:https?://(?:www\.)?magentasport\.de/event/[^/]+)?/[0-9]+/(?P<video_id>[0-9]+)"
@staticmethod
@click.command(name="MTSP", short_help="https://magentasport.de", help=__doc__)
@click.argument("title", type=str)
@click.pass_context
def cli(ctx: Context, **kwargs: Any) -> MTSP:
return MTSP(ctx, **kwargs)
def __init__(self, ctx: Context, title: str):
self.title = title
super().__init__(ctx)
def authenticate(self, cookies: Optional[MozillaCookieJar] = None, credential: Optional[Credential] = None) -> None:
cache = self.cache.get(f"session_{credential.sha1}")
if cache and not cache.expired:
self.session.cookies.update({
"session": cache.data,
"entitled": "1",
})
return
self.log.info("No cached session cookie, logging in...")
r = self.session.get(self.config["endpoints"]["login_form"])
r.raise_for_status()
tid, xsrf_name, xsrf_value = self.get_login_tid_xsrf(r.text)
data = {
"tid": tid,
xsrf_name: xsrf_value,
"pkc": "",
"webauthn_supported": "false",
"pw_usr": credential.username
}
r = self.session.post(self.config["endpoints"]["login_post"], data=data)
r.raise_for_status()
tid, xsrf_name, xsrf_value = self.get_login_tid_xsrf(r.text)
data = {
"tid": tid,
xsrf_name: xsrf_value,
"hidden_usr": credential.username,
"pw_pwd": credential.password,
"persist_session_displayed": "1",
"persist_session": "on"
}
r = self.session.post(self.config["endpoints"]["login_post"], data=data)
r.raise_for_status()
session = self.session.cookies.get_dict().get('session')
cache.set(session)
def get_titles(self) -> Movies:
video_id = re.match(self.TITLE_RE, self.title).group("video_id")
r = self.session.get(self.config["endpoints"]["video_config"].format(video_id=video_id))
config = r.json()
return Movies([Movie(
id_=video_id,
service=self.__class__,
name=config["title"],
language="de",
data=config,
)])
def get_tracks(self, title: Movie) -> Tracks:
r = self.session.post(title.data['streamAccess'])
access = r.json()
tracks = DASH.from_url(access["data"]["stream"]["dash"]).to_tracks(title.language)
return tracks
def get_chapters(self, title: Movie) -> list[Chapter]:
return [
]
def get_login_tid_xsrf(self, html):
soup = BeautifulSoup(html, "html.parser")
form = soup.find("form", id="login")
xsrf = form.find("input", {"name": re.compile("^xsrf_")})
tid = form.find("input", {"name": "tid"})
return tid.get("value"), xsrf.get('name'), xsrf.get("value")