forked from DRMTalks/devine
Implement new get_key_id() method to Track
This commit is contained in:
parent
853a021ac0
commit
73bd17ec94
|
@ -1,16 +1,19 @@
|
||||||
|
import base64
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, Iterable, Optional, Union
|
from typing import Any, Callable, Iterable, Optional, Union
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from langcodes import Language
|
from langcodes import Language
|
||||||
|
|
||||||
from devine.core.constants import TERRITORY_MAP
|
from devine.core.constants import TERRITORY_MAP
|
||||||
from devine.core.drm import DRM_T
|
from devine.core.drm import DRM_T
|
||||||
from devine.core.utilities import get_binary_path
|
from devine.core.utilities import get_binary_path, get_boxes
|
||||||
|
from devine.core.utils.subprocess import ffprobe
|
||||||
|
|
||||||
|
|
||||||
class Track:
|
class Track:
|
||||||
|
@ -84,6 +87,43 @@ class Track:
|
||||||
extra_parts.append(TERRITORY_MAP.get(territory, territory))
|
extra_parts.append(TERRITORY_MAP.get(territory, territory))
|
||||||
return ", ".join(extra_parts) or None
|
return ", ".join(extra_parts) or None
|
||||||
|
|
||||||
|
def get_key_id(self, init_data: Optional[bytes] = None, *args, **kwargs) -> Optional[UUID]:
|
||||||
|
"""
|
||||||
|
Probe the DRM encryption Key ID (KID) for this specific track.
|
||||||
|
|
||||||
|
It currently supports finding the Key ID by probing the track's stream
|
||||||
|
with ffprobe for `enc_key_id` data, as well as for mp4 `tenc` (Track
|
||||||
|
Encryption) boxes.
|
||||||
|
|
||||||
|
It explicitly ignores PSSH information like the `PSSH` box, as the box
|
||||||
|
is likely to contain multiple Key IDs that may or may not be for this
|
||||||
|
specific track.
|
||||||
|
|
||||||
|
To retrieve the initialization segment, this method calls :meth:`get_init_segment`
|
||||||
|
with the positional and keyword arguments. The return value of `get_init_segment`
|
||||||
|
is then used to determine the Key ID.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The Key ID as a UUID object, or None if the Key ID could not be determined.
|
||||||
|
"""
|
||||||
|
if not init_data:
|
||||||
|
init_data = self.get_init_segment(*args, **kwargs)
|
||||||
|
if not isinstance(init_data, bytes):
|
||||||
|
raise TypeError(f"Expected init_data to be bytes, not {init_data!r}")
|
||||||
|
|
||||||
|
# try get via ffprobe, needed for non mp4 data e.g. WEBM from Google Play
|
||||||
|
probe = ffprobe(init_data)
|
||||||
|
if probe:
|
||||||
|
for stream in probe.get("streams") or []:
|
||||||
|
enc_key_id = stream.get("tags", {}).get("enc_key_id")
|
||||||
|
if enc_key_id:
|
||||||
|
return UUID(bytes=base64.b64decode(enc_key_id))
|
||||||
|
|
||||||
|
# look for track encryption mp4 boxes
|
||||||
|
for tenc in get_boxes(init_data, b"tenc"):
|
||||||
|
if tenc.key_ID.int != 0:
|
||||||
|
return tenc.key_ID
|
||||||
|
|
||||||
def get_init_segment(
|
def get_init_segment(
|
||||||
self,
|
self,
|
||||||
maximum_size: int = 20000,
|
maximum_size: int = 20000,
|
||||||
|
|
Loading…
Reference in New Issue