2025-03-18 00:17:27 +05:30
|
|
|
import xmltodict
|
|
|
|
import asyncio
|
|
|
|
import base64
|
|
|
|
import json
|
|
|
|
import math
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import urllib.parse
|
|
|
|
import uuid
|
|
|
|
from copy import copy
|
|
|
|
from hashlib import md5
|
|
|
|
|
|
|
|
import requests
|
|
|
|
from langcodes import Language
|
|
|
|
from langcodes.tag_parser import LanguageTagError
|
|
|
|
|
|
|
|
from vinetrimmer import config
|
|
|
|
from vinetrimmer.objects import AudioTrack, TextTrack, Track, Tracks, VideoTrack
|
2025-03-18 00:23:51 +05:30
|
|
|
from vinetrimmer.utils import Cdm
|
2025-03-18 00:17:27 +05:30
|
|
|
from vinetrimmer.utils.io import aria2c
|
2025-03-18 00:23:51 +05:30
|
|
|
from vinetrimmer.utils.xml import load_xml
|
2025-03-18 00:17:27 +05:30
|
|
|
from vinetrimmer.vendor.pymp4.parser import Box
|
|
|
|
|
2025-03-18 00:23:51 +05:30
|
|
|
|
2025-03-18 00:17:27 +05:30
|
|
|
def parse(*, url=None, data=None, source, session=None, downloader=None):
|
|
|
|
"""
|
|
|
|
Convert an Smooth Streaming ISM (IIS Smooth Streaming Manifest) document to a Tracks object
|
|
|
|
with video, audio and subtitle track objects where available.
|
|
|
|
|
|
|
|
:param url: URL of the ISM document.
|
|
|
|
:param data: The ISM document as a string.
|
|
|
|
:param source: Source tag for the returned tracks.
|
|
|
|
:param session: Used for any remote calls, e.g. getting the MPD document from an URL.
|
|
|
|
Can be useful for setting custom headers, proxies, etc.
|
|
|
|
:param downloader: Downloader to use. Accepted values are None (use requests to download)
|
|
|
|
and aria2c.
|
|
|
|
|
|
|
|
Don't forget to manually handle the addition of any needed or extra information or values
|
|
|
|
like `encrypted`, `pssh`, `hdr10`, `dv`, etc. Essentially anything that is per-service
|
|
|
|
should be looked at. Some of these values like `pssh` will be attempted to be set automatically
|
|
|
|
if possible but if you definitely have the values in the service, then set them.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
url = "https://test.playready.microsoft.com/media/profficialsite/tearsofsteel_4k.ism.smoothstreaming/manifest" # https://testweb.playready.microsoft.com/Content/Content2X
|
|
|
|
session = requests.Session(headers={"X-Example": "foo"})
|
|
|
|
tracks = Tracks.from_ism(
|
|
|
|
url,
|
|
|
|
session=session,
|
|
|
|
source="MICROSOFT",
|
|
|
|
)
|
|
|
|
|
|
|
|
url = "https://test.playready.microsoft.com/media/profficialsite/tearsofsteel_4k.ism.smoothstreaming/manifest"
|
|
|
|
session = requests.Session(headers={"X-Example": "foo"})
|
|
|
|
tracks = Tracks.from_ism(url=url, data=session.get(url).text, source="MICROSOFT")
|
|
|
|
"""
|
2025-03-18 00:23:51 +05:30
|
|
|
tracks = []
|
2025-03-18 00:17:27 +05:30
|
|
|
if not data:
|
|
|
|
if not url:
|
|
|
|
raise ValueError("Neither a URL nor a document was provided to Tracks.from_ism")
|
|
|
|
base_url = url.rsplit('/', 1)[0] + '/'
|
|
|
|
if downloader is None:
|
|
|
|
data = (session or requests).get(url).text
|
|
|
|
elif downloader == "aria2c":
|
|
|
|
out = os.path.join(config.directories.temp, url.split("/")[-1])
|
|
|
|
asyncio.run(aria2c(url, out))
|
|
|
|
|
|
|
|
with open(out, encoding="utf-8") as fd:
|
|
|
|
data = fd.read()
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.unlink(out)
|
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise ValueError(f"Unsupported downloader: {downloader}")
|
|
|
|
|
2025-03-18 00:23:51 +05:30
|
|
|
root = load_xml(data)
|
|
|
|
if root.tag != "SmoothStreamingMedia":
|
2025-03-18 00:17:27 +05:30
|
|
|
raise ValueError("Non-ISM document provided to Tracks.from_ism")
|