Skip to content

Commit

Permalink
feat(binaries): Move all binary definitions to core/binaries file
Browse files Browse the repository at this point in the history
This simplifies and centralizes all definitions on where these binaries can be found to a singular reference, making it easier to modify, edit, and improve.
  • Loading branch information
rlaphoenix committed Apr 24, 2024
1 parent 9768de8 commit 677fd9c
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 61 deletions.
5 changes: 3 additions & 2 deletions devine/commands/dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from rich.text import Text
from rich.tree import Tree

from devine.core import binaries
from devine.core.config import config
from devine.core.console import console
from devine.core.constants import DOWNLOAD_LICENCE_ONLY, AnyTrack, context_settings
Expand All @@ -51,7 +52,7 @@
from devine.core.titles.episode import Episode
from devine.core.tracks import Audio, Subtitle, Tracks, Video
from devine.core.tracks.attachment import Attachment
from devine.core.utilities import get_binary_path, get_system_fonts, is_close_match, time_elapsed_since
from devine.core.utilities import get_system_fonts, is_close_match, time_elapsed_since
from devine.core.utils.click_types import LANGUAGE_RANGE, QUALITY_LIST, SEASON_RANGE, ContextData, MultipleChoice
from devine.core.utils.collections import merge_dict
from devine.core.utils.subprocess import ffprobe
Expand Down Expand Up @@ -198,7 +199,7 @@ def __init__(
self.proxy_providers.append(Basic(**config.proxy_providers["basic"]))
if config.proxy_providers.get("nordvpn"):
self.proxy_providers.append(NordVPN(**config.proxy_providers["nordvpn"]))
if get_binary_path("hola-proxy"):
if binaries.HolaProxy:
self.proxy_providers.append(Hola())
for proxy_provider in self.proxy_providers:
self.log.info(f"Loaded {proxy_provider.__class__.__name__}: {proxy_provider}")
Expand Down
4 changes: 2 additions & 2 deletions devine/commands/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
from rich.tree import Tree

from devine.commands.dl import dl
from devine.core import binaries
from devine.core.config import config
from devine.core.console import console
from devine.core.constants import context_settings
from devine.core.proxies import Basic, Hola, NordVPN
from devine.core.service import Service
from devine.core.services import Services
from devine.core.utilities import get_binary_path
from devine.core.utils.click_types import ContextData
from devine.core.utils.collections import merge_dict

Expand Down Expand Up @@ -72,7 +72,7 @@ def search(
proxy_providers.append(Basic(**config.proxy_providers["basic"]))
if config.proxy_providers.get("nordvpn"):
proxy_providers.append(NordVPN(**config.proxy_providers["nordvpn"]))
if get_binary_path("hola-proxy"):
if binaries.HolaProxy:
proxy_providers.append(Hola())
for proxy_provider in proxy_providers:
log.info(f"Loaded {proxy_provider.__class__.__name__}: {proxy_provider}")
Expand Down
7 changes: 3 additions & 4 deletions devine/commands/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import click

from devine.core import binaries
from devine.core.config import config
from devine.core.constants import context_settings
from devine.core.utilities import get_binary_path


@click.command(
Expand All @@ -29,11 +29,10 @@ def serve(host: str, port: int, caddy: bool) -> None:
from pywidevine import serve

if caddy:
executable = get_binary_path("caddy")
if not executable:
if not binaries.Caddy:
raise click.ClickException("Caddy executable \"caddy\" not found but is required for --caddy.")
caddy_p = subprocess.Popen([
executable,
binaries.Caddy,
"run",
"--config", str(config.directories.user_configs / "Caddyfile")
])
Expand Down
21 changes: 9 additions & 12 deletions devine/commands/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import click
from pymediainfo import MediaInfo

from devine.core import binaries
from devine.core.constants import context_settings
from devine.core.utilities import get_binary_path


@click.group(short_help="Various helper scripts and programs.", context_settings=context_settings)
Expand Down Expand Up @@ -38,8 +38,7 @@ def crop(path: Path, aspect: str, letter: bool, offset: int, preview: bool) -> N
as it may go from being 2px away from a perfect crop, to 20px over-cropping
again due to sub-sampled chroma.
"""
executable = get_binary_path("ffmpeg")
if not executable:
if not binaries.FFMPEG:
raise click.ClickException("FFmpeg executable \"ffmpeg\" not found but is required.")

if path.is_dir():
Expand Down Expand Up @@ -87,15 +86,15 @@ def crop(path: Path, aspect: str, letter: bool, offset: int, preview: bool) -> N
]))))]

ffmpeg_call = subprocess.Popen([
executable, "-y",
binaries.FFMPEG, "-y",
"-i", str(video_path),
"-map", "0:v:0",
"-c", "copy",
"-bsf:v", crop_filter
] + out_path, stdout=subprocess.PIPE)
try:
if preview:
previewer = get_binary_path("mpv", "ffplay")
previewer = binaries.MPV or binaries.FFPlay
if not previewer:
raise click.ClickException("MPV/FFplay executables weren't found but are required for previewing.")
subprocess.Popen((previewer, "-"), stdin=ffmpeg_call.stdout)
Expand All @@ -120,8 +119,7 @@ def range_(path: Path, full: bool, preview: bool) -> None:
then you're video may have the range set to the wrong value. Flip its range to the
opposite value and see if that fixes it.
"""
executable = get_binary_path("ffmpeg")
if not executable:
if not binaries.FFMPEG:
raise click.ClickException("FFmpeg executable \"ffmpeg\" not found but is required.")

if path.is_dir():
Expand Down Expand Up @@ -157,15 +155,15 @@ def range_(path: Path, full: bool, preview: bool) -> None:
]))))]

ffmpeg_call = subprocess.Popen([
executable, "-y",
binaries.FFMPEG, "-y",
"-i", str(video_path),
"-map", "0:v:0",
"-c", "copy",
"-bsf:v", f"{metadata_key}=video_full_range_flag={int(full)}"
] + out_path, stdout=subprocess.PIPE)
try:
if preview:
previewer = get_binary_path("mpv", "ffplay")
previewer = binaries.MPV or binaries.FFPlay
if not previewer:
raise click.ClickException("MPV/FFplay executables weren't found but are required for previewing.")
subprocess.Popen((previewer, "-"), stdin=ffmpeg_call.stdout)
Expand All @@ -188,8 +186,7 @@ def test(path: Path, map_: str) -> None:
You may choose specific streams using the -m/--map parameter. E.g.,
'0:v:0' to test the first video stream, or '0:a' to test all audio streams.
"""
executable = get_binary_path("ffmpeg")
if not executable:
if not binaries.FFMPEG:
raise click.ClickException("FFmpeg executable \"ffmpeg\" not found but is required.")

if path.is_dir():
Expand All @@ -199,7 +196,7 @@ def test(path: Path, map_: str) -> None:
for video_path in paths:
print("Starting...")
p = subprocess.Popen([
executable, "-hide_banner",
binaries.FFMPEG, "-hide_banner",
"-benchmark",
"-i", str(video_path),
"-map", map_,
Expand Down
34 changes: 34 additions & 0 deletions devine/core/binaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sys

from devine.core.utilities import get_binary_path

__shaka_platform = {
"win32": "win",
"darwin": "osx"
}.get(sys.platform, sys.platform)

FFMPEG = get_binary_path("ffmpeg")
FFProbe = get_binary_path("ffprobe")
FFPlay = get_binary_path("ffplay")
SubtitleEdit = get_binary_path("SubtitleEdit")
ShakaPackager = get_binary_path(
"shaka-packager",
"packager",
f"packager-{__shaka_platform}",
f"packager-{__shaka_platform}-x64"
)
Aria2 = get_binary_path("aria2c", "aria2")
CCExtractor = get_binary_path(
"ccextractor",
"ccextractorwin",
"ccextractorwinfull"
)
HolaProxy = get_binary_path("hola-proxy")
MPV = get_binary_path("mpv")
Caddy = get_binary_path("caddy")


__all__ = (
"FFMPEG", "FFProbe", "FFPlay", "SubtitleEdit", "ShakaPackager",
"Aria2", "CCExtractor", "HolaProxy", "MPV", "Caddy"
)
8 changes: 4 additions & 4 deletions devine/core/downloaders/aria2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
from rich import filesize
from rich.text import Text

from devine.core import binaries
from devine.core.config import config
from devine.core.console import console
from devine.core.constants import DOWNLOAD_CANCELLED
from devine.core.utilities import get_binary_path, get_extension, get_free_port
from devine.core.utilities import get_extension, get_free_port


def rpc(caller: Callable, secret: str, method: str, params: Optional[list[Any]] = None) -> Any:
Expand Down Expand Up @@ -87,8 +88,7 @@ def download(
if not isinstance(urls, list):
urls = [urls]

executable = get_binary_path("aria2c", "aria2")
if not executable:
if not binaries.Aria2:
raise EnvironmentError("Aria2c executable not found...")

if proxy and not proxy.lower().startswith("http://"):
Expand Down Expand Up @@ -186,7 +186,7 @@ def download(
try:
p = subprocess.Popen(
[
executable,
binaries.Aria2,
*arguments
],
stdin=subprocess.PIPE,
Expand Down
10 changes: 4 additions & 6 deletions devine/core/drm/widevine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import base64
import shutil
import subprocess
import sys
import textwrap
from pathlib import Path
from typing import Any, Callable, Optional, Union
Expand All @@ -17,10 +16,11 @@
from requests import Session
from rich.text import Text

from devine.core import binaries
from devine.core.config import config
from devine.core.console import console
from devine.core.constants import AnyTrack
from devine.core.utilities import get_binary_path, get_boxes
from devine.core.utilities import get_boxes
from devine.core.utils.subprocess import ffprobe


Expand Down Expand Up @@ -223,9 +223,7 @@ def decrypt(self, path: Path) -> None:
if not self.content_keys:
raise ValueError("Cannot decrypt a Track without any Content Keys...")

platform = {"win32": "win", "darwin": "osx"}.get(sys.platform, sys.platform)
executable = get_binary_path("shaka-packager", "packager", f"packager-{platform}", f"packager-{platform}-x64")
if not executable:
if not binaries.ShakaPackager:
raise EnvironmentError("Shaka Packager executable not found but is required.")
if not path or not path.exists():
raise ValueError("Tried to decrypt a file that does not exist.")
Expand All @@ -252,7 +250,7 @@ def decrypt(self, path: Path) -> None:
]

p = subprocess.Popen(
[executable, *arguments],
[binaries.ShakaPackager, *arguments],
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
universal_newlines=True
Expand Down
8 changes: 4 additions & 4 deletions devine/core/manifests/hls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
from pywidevine.pssh import PSSH
from requests import Session

from devine.core import binaries
from devine.core.constants import DOWNLOAD_CANCELLED, DOWNLOAD_LICENCE_ONLY, AnyTrack
from devine.core.downloaders import requests as requests_downloader
from devine.core.drm import DRM_T, ClearKey, Widevine
from devine.core.events import events
from devine.core.tracks import Audio, Subtitle, Tracks, Video
from devine.core.utilities import get_binary_path, get_extension, is_close_match, try_ensure_utf8
from devine.core.utilities import get_extension, is_close_match, try_ensure_utf8


class HLS:
Expand Down Expand Up @@ -556,8 +557,7 @@ def merge_segments(segments: list[Path], save_path: Path) -> int:
Returns the file size of the merged file.
"""
ffmpeg = get_binary_path("ffmpeg")
if not ffmpeg:
if not binaries.FFMPEG:
raise EnvironmentError("FFmpeg executable was not found but is required to merge HLS segments.")

demuxer_file = segments[0].parent / "ffmpeg_concat_demuxer.txt"
Expand All @@ -567,7 +567,7 @@ def merge_segments(segments: list[Path], save_path: Path) -> int:
]))

subprocess.check_call([
ffmpeg, "-hide_banner",
binaries.FFMPEG, "-hide_banner",
"-loglevel", "panic",
"-f", "concat",
"-safe", "0",
Expand Down
4 changes: 2 additions & 2 deletions devine/core/proxies/hola.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import subprocess
from typing import Optional

from devine.core import binaries
from devine.core.proxies.proxy import Proxy
from devine.core.utilities import get_binary_path


class Hola(Proxy):
Expand All @@ -13,7 +13,7 @@ def __init__(self):
Proxy Service using Hola's direct connections via the hola-proxy project.
https://github.com/Snawoot/hola-proxy
"""
self.binary = get_binary_path("hola-proxy")
self.binary = binaries.HolaProxy
if not self.binary:
raise EnvironmentError("hola-proxy executable not found but is required for the Hola proxy provider.")

Expand Down
18 changes: 8 additions & 10 deletions devine/core/tracks/subtitle.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
from pymp4.parser import MP4
from subtitle_filter import Subtitles

from devine.core import binaries
from devine.core.tracks.track import Track
from devine.core.utilities import get_binary_path, try_ensure_utf8
from devine.core.utilities import try_ensure_utf8


class Subtitle(Track):
Expand Down Expand Up @@ -233,14 +234,13 @@ def convert(self, codec: Subtitle.Codec) -> Path:

output_path = self.path.with_suffix(f".{codec.value.lower()}")

sub_edit_executable = get_binary_path("SubtitleEdit")
if sub_edit_executable and self.codec not in (Subtitle.Codec.fTTML, Subtitle.Codec.fVTT):
if binaries.SubtitleEdit and self.codec not in (Subtitle.Codec.fTTML, Subtitle.Codec.fVTT):
sub_edit_format = {
Subtitle.Codec.SubStationAlphav4: "AdvancedSubStationAlpha",
Subtitle.Codec.TimedTextMarkupLang: "TimedText1.0"
}.get(codec, codec.name)
sub_edit_args = [
sub_edit_executable,
binaries.SubtitleEdit,
"/Convert", self.path, sub_edit_format,
f"/outputfilename:{output_path.name}",
"/encoding:utf8"
Expand Down Expand Up @@ -500,8 +500,7 @@ def strip_hearing_impaired(self) -> None:
if not self.path or not self.path.exists():
raise ValueError("You must download the subtitle track first.")

executable = get_binary_path("SubtitleEdit")
if executable:
if binaries.SubtitleEdit:
if self.codec == Subtitle.Codec.SubStationAlphav4:
output_format = "AdvancedSubStationAlpha"
elif self.codec == Subtitle.Codec.TimedTextMarkupLang:
Expand All @@ -510,7 +509,7 @@ def strip_hearing_impaired(self) -> None:
output_format = self.codec.name
subprocess.run(
[
executable,
binaries.SubtitleEdit,
"/Convert", self.path, output_format,
"/encoding:utf8",
"/overwrite",
Expand Down Expand Up @@ -539,8 +538,7 @@ def reverse_rtl(self) -> None:
if not self.path or not self.path.exists():
raise ValueError("You must download the subtitle track first.")

executable = get_binary_path("SubtitleEdit")
if not executable:
if not binaries.SubtitleEdit:
raise EnvironmentError("SubtitleEdit executable not found...")

if self.codec == Subtitle.Codec.SubStationAlphav4:
Expand All @@ -552,7 +550,7 @@ def reverse_rtl(self) -> None:

subprocess.run(
[
executable,
binaries.SubtitleEdit,
"/Convert", self.path, output_format,
"/ReverseRtlStartEnd",
"/encoding:utf8",
Expand Down
Loading

0 comments on commit 677fd9c

Please sign in to comment.