Add SONAR
This commit is contained in:
parent
e6e74047ea
commit
8cb3886b67
110
SONAR/__init__.py
Normal file
110
SONAR/__init__.py
Normal file
@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from http.cookiejar import MozillaCookieJar
|
||||
from typing import Any, Optional
|
||||
import re
|
||||
import json
|
||||
|
||||
import click
|
||||
from click import Context
|
||||
from bs4 import BeautifulSoup
|
||||
from pywidevine.cdm import Cdm as WidevineCdm
|
||||
|
||||
from unshackle.core.constants import AnyTrack
|
||||
from unshackle.core.credential import Credential
|
||||
from unshackle.core.service import Service
|
||||
from unshackle.core.titles import Movie, Movies, Title_T
|
||||
from unshackle.core.tracks import Chapter, Tracks, Subtitle
|
||||
from unshackle.core.manifests.hls import HLS
|
||||
|
||||
SUBTITLE_LANGUAGE_MAP = {
|
||||
'dv': 'mul',
|
||||
'vn': 'vi',
|
||||
}
|
||||
|
||||
class SONAR(Service):
|
||||
TITLE_RE = r"^(?:https?://(?:www\.)?sonar\.film/films/)?(?P<video_id>[^/]+)/\?woopaywall_order_key=(?P<order_key>.+)"
|
||||
|
||||
@staticmethod
|
||||
@click.command(name="SONAR", short_help="https://sonar.film", help=__doc__)
|
||||
@click.argument("title", type=str)
|
||||
@click.pass_context
|
||||
def cli(ctx: Context, **kwargs: Any) -> SONAR:
|
||||
return SONAR(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({
|
||||
"PHPSESSID": cache.data,
|
||||
})
|
||||
return
|
||||
|
||||
self.log.info("No cached session cookie, logging in...")
|
||||
r = self.session.get(self.config["endpoints"]["login_form"])
|
||||
|
||||
data = {
|
||||
"username": credential.username,
|
||||
"password": credential.password,
|
||||
}
|
||||
r = self.session.post(self.config["endpoints"]["login_form"], data=data)
|
||||
r.raise_for_status()
|
||||
|
||||
session = self.session.cookies.get_dict().get('PHPSESSID')
|
||||
cache.set(session)
|
||||
|
||||
def get_titles(self) -> Movies:
|
||||
match = re.match(self.TITLE_RE, self.title)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
video_id = match.group("video_id")
|
||||
order_key = match.group("order_key")
|
||||
r = self.session.get(self.config["endpoints"]["video_page"].format(video_id=video_id, order_key=order_key))
|
||||
r.raise_for_status()
|
||||
|
||||
soup = BeautifulSoup(r.text, "html.parser")
|
||||
iframe = soup.find("iframe", {"src": re.compile(".+mediadelivery.net.+")})
|
||||
meta = json.loads(soup.find("script", {"type": "application/ld+json"}).contents[0])
|
||||
|
||||
return Movies([Movie(
|
||||
id_=video_id,
|
||||
service=self.__class__,
|
||||
name=meta["name"],
|
||||
year=meta["datePublished"],
|
||||
language="de",
|
||||
data=iframe["src"],
|
||||
)])
|
||||
|
||||
def get_tracks(self, title: Movie) -> Tracks:
|
||||
r = self.session.get(title.data, headers={"Referer": "https://sonar.film/"})
|
||||
r.raise_for_status()
|
||||
|
||||
soup = BeautifulSoup(r.text, "html.parser")
|
||||
m3u8 = soup.find("source", {"type": "application/vnd.apple.mpegURL"})["src"]
|
||||
self.session.headers["Referer"] = "https://iframe.mediadelivery.net/"
|
||||
tracks = HLS.from_url(m3u8, session=self.session).to_tracks('de')
|
||||
|
||||
subs = []
|
||||
for track in soup.find_all("track", {"kind": "captions"}):
|
||||
lang = track["srclang"]
|
||||
subs.append(Subtitle(
|
||||
url=track["src"],
|
||||
language=SUBTITLE_LANGUAGE_MAP.get(lang, lang),
|
||||
codec=Subtitle.Codec.WebVTT,
|
||||
))
|
||||
|
||||
return tracks + Tracks(subs)
|
||||
|
||||
def get_chapters(self, title: Movie) -> list[Chapter]:
|
||||
return []
|
||||
|
||||
def get_widevine_service_certificate(self, **_: Any) -> str:
|
||||
return None
|
||||
|
||||
def get_widevine_license(self, challenge: bytes, title: Title_T, track: AnyTrack) -> str:
|
||||
return None
|
||||
7
SONAR/config.yaml
Normal file
7
SONAR/config.yaml
Normal file
@ -0,0 +1,7 @@
|
||||
headers:
|
||||
Accept-Language: de-DE,de;q=0.8
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0
|
||||
|
||||
endpoints:
|
||||
login_form: https://sonar.film/mein-konto/
|
||||
video_page: https://sonar.film/films/{video_id}/?woopaywall_order_key={order_key}
|
||||
Loading…
x
Reference in New Issue
Block a user