mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 12:05:07 +00:00
fix(import): read export files through mediaexport
The command still required the old v2 format.
This commit is contained in:
@@ -189,7 +189,7 @@ order the service used, then renumbers the episodes into the order you asked for
|
||||
| `--cdm-only` / `--vaults-only` | Use only the CDM, or only Key Vaults, for key acquisition. |
|
||||
| `--cdm <name>` | Use the named CDM device from the `cdm` config mapping for this run, ignoring the service/default mapping. |
|
||||
| `--skip-dl` | Skip the download but still retrieve keys. |
|
||||
| `--export` | Export track info and keys to a JSON file in the exports directory. |
|
||||
| `--export` | Export track info and keys to a `mediaexport` JSON file in the exports directory. |
|
||||
|
||||
### Network & proxy
|
||||
|
||||
@@ -263,7 +263,7 @@ unshackle forwards any `dl` options after the file verbatim, so you can override
|
||||
unshackle import export.json -r HDR10 --proxy US
|
||||
```
|
||||
|
||||
The export file must be a valid v2 export from a current version of unshackle, made with `dl --export`, and must contain a `service` tag.
|
||||
The export file can be a `mediaexport` file from `dl --export`, an export from an older version of unshackle, or an export from unidl. The file must name the service it came from.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
"""Tests for the ``unshackle import`` command: it reads every export format and forwards to ``dl``."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from unshackle.commands.dl import dl
|
||||
|
||||
KID = "00000000000000000000000000000001"
|
||||
KEY = "aa" * 16
|
||||
|
||||
import_cli = importlib.import_module("unshackle.commands.import").ImportCommand.cli
|
||||
|
||||
MEDIAEXPORT = {
|
||||
"kind": "mediaexport",
|
||||
"version": 1,
|
||||
"service": {"tag": "EXAMPLE", "name": "Example"},
|
||||
"titles": [
|
||||
{
|
||||
"id": "movie-1",
|
||||
"kind": "movie",
|
||||
"title": "Example Movie",
|
||||
"manifests": [{"url": "https://example.test/m.mpd", "type": "dash", "role": "primary"}],
|
||||
"keys": {KID: KEY},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
UNSHACKLE_V2 = {
|
||||
"version": 2,
|
||||
"service": "EXAMPLE",
|
||||
"titles": {
|
||||
"movie-1": {
|
||||
"meta": {"type": "movie", "name": "Example Movie"},
|
||||
"manifest_url": "https://example.test/m.mpd",
|
||||
"manifest_type": "DASH",
|
||||
"tracks": {"v1": {"id": "v1", "url": "https://example.test/m.mpd", "keys": {KID: KEY}}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
UNIDL_V1 = {
|
||||
"kind": "unidl-export",
|
||||
"version": 1,
|
||||
"service": "EXAMPLE",
|
||||
"titles": [
|
||||
{
|
||||
"title": {"id": "movie-1", "kind": "movie", "name": "Example Movie"},
|
||||
"manifest_url": "https://example.test/m.mpd",
|
||||
"keys": [f"{KID}:{KEY}"],
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def forwarded(monkeypatch: pytest.MonkeyPatch) -> list[list[str]]:
|
||||
"""The argument lists the import command sends to ``dl``."""
|
||||
calls: list[list[str]] = []
|
||||
|
||||
def fake_main(*, args: list[str], **_: Any) -> None:
|
||||
calls.append(list(args))
|
||||
|
||||
monkeypatch.setattr(dl.cli, "main", fake_main)
|
||||
return calls
|
||||
|
||||
|
||||
@pytest.mark.parametrize("raw", [MEDIAEXPORT, UNSHACKLE_V2, UNIDL_V1], ids=["mediaexport", "unshackle-v2", "unidl-v1"])
|
||||
def test_import_forwards_service_tag(tmp_path: Path, forwarded: list[list[str]], raw: dict[str, Any]) -> None:
|
||||
export = tmp_path / "export.json"
|
||||
export.write_text(json.dumps(raw), encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(import_cli, [str(export), "-r", "HDR10"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert forwarded == [["-r", "HDR10", "--import", str(export), "EXAMPLE"]]
|
||||
|
||||
|
||||
def test_import_rejects_a_file_that_is_not_an_export(tmp_path: Path, forwarded: list[list[str]]) -> None:
|
||||
export = tmp_path / "export.json"
|
||||
export.write_text(json.dumps({"hello": "world"}), encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(import_cli, [str(export)])
|
||||
|
||||
assert result.exit_code != 0
|
||||
assert "is not a usable export file" in result.output
|
||||
assert forwarded == []
|
||||
@@ -1,10 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import click
|
||||
import mediaexport
|
||||
|
||||
from unshackle.commands.dl import dl
|
||||
from unshackle.core.constants import context_settings
|
||||
@@ -33,19 +32,13 @@ class ImportCommand:
|
||||
raise click.ClickException(f"Export file not found: {export_file}")
|
||||
|
||||
try:
|
||||
data: dict[str, Any] = json.loads(export_file.read_text(encoding="utf8"))
|
||||
except json.JSONDecodeError as e:
|
||||
raise click.ClickException(f"Export file is not valid JSON: {e}")
|
||||
doc = mediaexport.read(export_file)
|
||||
except mediaexport.ExportError as e:
|
||||
raise click.ClickException(f"{export_file} is not a usable export file: {e}")
|
||||
|
||||
if data.get("version") != 2:
|
||||
raise click.ClickException(
|
||||
f"Unsupported export version {data.get('version')!r}. "
|
||||
"Re-create the export with a current build of unshackle."
|
||||
)
|
||||
|
||||
service_tag = data.get("service")
|
||||
service_tag = doc.service_tag
|
||||
if not service_tag:
|
||||
raise click.ClickException("Export file is missing the 'service' tag.")
|
||||
raise click.ClickException("Export file does not name the service it came from.")
|
||||
|
||||
args = [*dl_args, "--import", str(export_file), service_tag]
|
||||
dl.cli.main(args=args, prog_name="unshackle dl", standalone_mode=False)
|
||||
|
||||
Reference in New Issue
Block a user