mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2025-10-23 15:11:08 +00:00
feat(binaries): ✨ Add support for MKVToolNix and mkvpropedit
* Introduced `MKVToolNix` and `mkvpropedit` binaries to the project. * Updated the environment check to include required status for dependencies. * Enhanced the `Tracks` class to raise an error if `MKVToolNix` is not found. * Modified the `_apply_tags` function to utilize the `mkvpropedit` binary from the binaries module.
This commit is contained in:
@@ -15,7 +15,6 @@ from unshackle.core.config import POSSIBLE_CONFIG_PATHS, config, config_path
|
|||||||
from unshackle.core.console import console
|
from unshackle.core.console import console
|
||||||
from unshackle.core.constants import context_settings
|
from unshackle.core.constants import context_settings
|
||||||
from unshackle.core.services import Services
|
from unshackle.core.services import Services
|
||||||
from unshackle.core.utils.osenvironment import get_os_arch
|
|
||||||
|
|
||||||
|
|
||||||
@click.group(short_help="Manage and configure the project environment.", context_settings=context_settings)
|
@click.group(short_help="Manage and configure the project environment.", context_settings=context_settings)
|
||||||
@@ -28,31 +27,37 @@ def check() -> None:
|
|||||||
"""Checks environment for the required dependencies."""
|
"""Checks environment for the required dependencies."""
|
||||||
table = Table(title="Dependencies", expand=True)
|
table = Table(title="Dependencies", expand=True)
|
||||||
table.add_column("Name", no_wrap=True)
|
table.add_column("Name", no_wrap=True)
|
||||||
|
table.add_column("Required", justify="center")
|
||||||
table.add_column("Installed", justify="center")
|
table.add_column("Installed", justify="center")
|
||||||
table.add_column("Path", no_wrap=False, overflow="fold")
|
table.add_column("Path", no_wrap=False, overflow="fold")
|
||||||
|
|
||||||
# builds shaka-packager based on os, arch
|
# Define all dependencies with their binary objects and required status
|
||||||
packager_dep = get_os_arch("packager")
|
|
||||||
|
|
||||||
# Helper function to find binary with multiple possible names
|
|
||||||
def find_binary(*names):
|
|
||||||
for name in names:
|
|
||||||
if binaries.find(name):
|
|
||||||
return name
|
|
||||||
return names[0] # Return first name as fallback for display
|
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{"name": "CCExtractor", "binary": "ccextractor"},
|
{"name": "FFMpeg", "binary": binaries.FFMPEG, "required": True},
|
||||||
{"name": "FFMpeg", "binary": "ffmpeg"},
|
{"name": "FFProbe", "binary": binaries.FFProbe, "required": True},
|
||||||
{"name": "MKVToolNix", "binary": "mkvmerge"},
|
{"name": "Shaka-Packager", "binary": binaries.ShakaPackager, "required": True},
|
||||||
{"name": "Shaka-Packager", "binary": find_binary("shaka-packager", "packager", packager_dep)},
|
{"name": "MKVToolNix", "binary": binaries.MKVToolNix, "required": True},
|
||||||
{"name": "N_m3u8DL-RE", "binary": find_binary("N_m3u8DL-RE", "n-m3u8dl-re")},
|
{"name": "Mkvpropedit", "binary": binaries.Mkvpropedit, "required": True},
|
||||||
{"name": "Aria2(c)", "binary": "aria2c"},
|
{"name": "CCExtractor", "binary": binaries.CCExtractor, "required": False},
|
||||||
|
{"name": "FFPlay", "binary": binaries.FFPlay, "required": False},
|
||||||
|
{"name": "SubtitleEdit", "binary": binaries.SubtitleEdit, "required": False},
|
||||||
|
{"name": "Aria2(c)", "binary": binaries.Aria2, "required": False},
|
||||||
|
{"name": "HolaProxy", "binary": binaries.HolaProxy, "required": False},
|
||||||
|
{"name": "MPV", "binary": binaries.MPV, "required": False},
|
||||||
|
{"name": "Caddy", "binary": binaries.Caddy, "required": False},
|
||||||
|
{"name": "N_m3u8DL-RE", "binary": binaries.N_m3u8DL_RE, "required": False},
|
||||||
]
|
]
|
||||||
|
|
||||||
for dep in dependencies:
|
for dep in dependencies:
|
||||||
path = binaries.find(dep["binary"])
|
path = dep["binary"]
|
||||||
|
|
||||||
|
# Required column
|
||||||
|
if dep["required"]:
|
||||||
|
required = "[red]Yes[/red]"
|
||||||
|
else:
|
||||||
|
required = "No"
|
||||||
|
|
||||||
|
# Installed column
|
||||||
if path:
|
if path:
|
||||||
installed = "[green]:heavy_check_mark:[/green]"
|
installed = "[green]:heavy_check_mark:[/green]"
|
||||||
path_output = str(path)
|
path_output = str(path)
|
||||||
@@ -61,7 +66,7 @@ def check() -> None:
|
|||||||
path_output = "Not Found"
|
path_output = "Not Found"
|
||||||
|
|
||||||
# Add to the table
|
# Add to the table
|
||||||
table.add_row(dep["name"], installed, path_output)
|
table.add_row(dep["name"], required, installed, path_output)
|
||||||
|
|
||||||
# Display the result
|
# Display the result
|
||||||
console.print(Padding(table, (1, 5)))
|
console.print(Padding(table, (1, 5)))
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ HolaProxy = find("hola-proxy")
|
|||||||
MPV = find("mpv")
|
MPV = find("mpv")
|
||||||
Caddy = find("caddy")
|
Caddy = find("caddy")
|
||||||
N_m3u8DL_RE = find("N_m3u8DL-RE", "n-m3u8dl-re")
|
N_m3u8DL_RE = find("N_m3u8DL-RE", "n-m3u8dl-re")
|
||||||
|
MKVToolNix = find("mkvmerge")
|
||||||
|
Mkvpropedit = find("mkvpropedit")
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@@ -63,5 +65,7 @@ __all__ = (
|
|||||||
"MPV",
|
"MPV",
|
||||||
"Caddy",
|
"Caddy",
|
||||||
"N_m3u8DL_RE",
|
"N_m3u8DL_RE",
|
||||||
|
"MKVToolNix",
|
||||||
|
"Mkvpropedit",
|
||||||
"find",
|
"find",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeRe
|
|||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.tree import Tree
|
from rich.tree import Tree
|
||||||
|
|
||||||
|
from unshackle.core import binaries
|
||||||
from unshackle.core.config import config
|
from unshackle.core.config import config
|
||||||
from unshackle.core.console import console
|
from unshackle.core.console import console
|
||||||
from unshackle.core.constants import LANGUAGE_MAX_DISTANCE, AnyTrack, TrackT
|
from unshackle.core.constants import LANGUAGE_MAX_DISTANCE, AnyTrack, TrackT
|
||||||
@@ -290,8 +291,11 @@ class Tracks:
|
|||||||
progress: Update a rich progress bar via `completed=...`. This must be the
|
progress: Update a rich progress bar via `completed=...`. This must be the
|
||||||
progress object's update() func, pre-set with task id via functools.partial.
|
progress object's update() func, pre-set with task id via functools.partial.
|
||||||
"""
|
"""
|
||||||
|
if not binaries.MKVToolNix:
|
||||||
|
raise RuntimeError("MKVToolNix (mkvmerge) is required for muxing but was not found")
|
||||||
|
|
||||||
cl = [
|
cl = [
|
||||||
"mkvmerge",
|
str(binaries.MKVToolNix),
|
||||||
"--no-date", # remove dates from the output for security
|
"--no-date", # remove dates from the output for security
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from difflib import SequenceMatcher
|
from difflib import SequenceMatcher
|
||||||
@@ -12,6 +11,7 @@ from typing import Optional, Tuple
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from unshackle.core import binaries
|
||||||
from unshackle.core.config import config
|
from unshackle.core.config import config
|
||||||
from unshackle.core.titles.episode import Episode
|
from unshackle.core.titles.episode import Episode
|
||||||
from unshackle.core.titles.movie import Movie
|
from unshackle.core.titles.movie import Movie
|
||||||
@@ -175,8 +175,7 @@ def external_ids(tmdb_id: int, kind: str) -> dict:
|
|||||||
def _apply_tags(path: Path, tags: dict[str, str]) -> None:
|
def _apply_tags(path: Path, tags: dict[str, str]) -> None:
|
||||||
if not tags:
|
if not tags:
|
||||||
return
|
return
|
||||||
mkvpropedit = shutil.which("mkvpropedit")
|
if not binaries.Mkvpropedit:
|
||||||
if not mkvpropedit:
|
|
||||||
log.debug("mkvpropedit not found on PATH; skipping tags")
|
log.debug("mkvpropedit not found on PATH; skipping tags")
|
||||||
return
|
return
|
||||||
log.debug("Applying tags to %s: %s", path, tags)
|
log.debug("Applying tags to %s: %s", path, tags)
|
||||||
@@ -189,7 +188,7 @@ def _apply_tags(path: Path, tags: dict[str, str]) -> None:
|
|||||||
tmp_path = Path(f.name)
|
tmp_path = Path(f.name)
|
||||||
try:
|
try:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[mkvpropedit, str(path), "--tags", f"global:{tmp_path}"],
|
[str(binaries.Mkvpropedit), str(path), "--tags", f"global:{tmp_path}"],
|
||||||
check=False,
|
check=False,
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
|
|||||||
Reference in New Issue
Block a user