Adding transcoder
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from typing import Union, List
|
||||
|
||||
import rich.repr
|
||||
|
||||
from rich.console import Console
|
||||
from rich.progress import (
|
||||
Progress,
|
||||
TextColumn,
|
||||
BarColumn,
|
||||
SpinnerColumn,
|
||||
TimeRemainingColumn
|
||||
)
|
||||
|
||||
import groove.path
|
||||
|
||||
from groove.exceptions import ConfigurationError
|
||||
|
||||
|
||||
@rich.repr.auto(angular=True)
|
||||
class Transcoder:
|
||||
"""
|
||||
SYNOPSIS
|
||||
|
||||
USAGE
|
||||
|
||||
ARGS
|
||||
|
||||
EXAMPLES
|
||||
|
||||
INSTANCE ATTRIBUTES
|
||||
"""
|
||||
|
||||
def __init__(self, console: Union[Console, None] = None) -> None:
|
||||
self.console = console or Console()
|
||||
self._transcoded = 0
|
||||
self._processed = 0
|
||||
self._total = 0
|
||||
|
||||
def transcode(self, sources: List) -> int:
|
||||
"""
|
||||
Transcode the list of source files
|
||||
"""
|
||||
count = len(sources)
|
||||
|
||||
if not os.environ.get('TRANSCODER', None):
|
||||
raise ConfigurationError("Cannot transcode tracks without a TRANSCODR defined in your environment.")
|
||||
|
||||
cache = groove.path.cache_root()
|
||||
if not cache.exists():
|
||||
cache.mkdir()
|
||||
|
||||
async def _do_transcode(progress, task_id):
|
||||
tasks = set()
|
||||
for relpath in sources:
|
||||
self._total += 1
|
||||
progress.update(task_id, total=self._total)
|
||||
tasks.add(asyncio.create_task(self._transcode_one_track(relpath, progress, task_id)))
|
||||
progress.start_task(task_id)
|
||||
|
||||
progress = Progress(
|
||||
TimeRemainingColumn(compact=True, elapsed_when_finished=True),
|
||||
BarColumn(bar_width=15),
|
||||
TextColumn("[progress.percentage]{task.percentage:>3.0f}%", justify="left"),
|
||||
TextColumn("[dim]|"),
|
||||
TextColumn("[title]{task.total:-6d}[/title] [b]total", justify="right"),
|
||||
TextColumn("[dim]|"),
|
||||
TextColumn("[title]{task.fields[transcoded]:-6d}[/title] [b]new", justify="right"),
|
||||
TextColumn("[dim]|"),
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
console=self.console,
|
||||
)
|
||||
with progress:
|
||||
task_id = progress.add_task(
|
||||
f"[bright]Transcoding [link]{count} tracks[/link]...",
|
||||
transcoded=0,
|
||||
total=0,
|
||||
start=False
|
||||
)
|
||||
asyncio.run(_do_transcode(progress, task_id))
|
||||
progress.update(
|
||||
task_id,
|
||||
transcoded=self._transcoded,
|
||||
completed=self._total,
|
||||
description=f"[bright]Transcode of [link]{count} tracks[/link] complete!",
|
||||
)
|
||||
|
||||
def _get_or_create_cache_dir(self, relpath):
|
||||
cached_path = groove.path.transcoded_media(relpath)
|
||||
cached_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
return cached_path
|
||||
|
||||
def _run_transcoder(self, infile, outfile):
|
||||
cmd = []
|
||||
for part in os.environ['TRANSCODER'].split():
|
||||
if part == 'INFILE':
|
||||
cmd.append(str(infile))
|
||||
elif part == 'OUTFILE':
|
||||
cmd.append(str(outfile))
|
||||
else:
|
||||
cmd.append(part)
|
||||
|
||||
output = ''
|
||||
try:
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.console.error(f"Transcoder failed with status {e.returncode}: {' '.join(cmd)}")
|
||||
self.console.error(output)
|
||||
|
||||
async def _transcode_one_track(self, relpath, progress, task_id):
|
||||
"""
|
||||
Transcode one track, if it isn't already cached.
|
||||
"""
|
||||
self._processed += 1
|
||||
|
||||
source_path = groove.path.media(relpath)
|
||||
if not source_path.exists():
|
||||
logging.error(f"Source does not exist: [link]{source_path}[/link].")
|
||||
return
|
||||
|
||||
cached_path = self._get_or_create_cache_dir(relpath)
|
||||
if cached_path.exists():
|
||||
self.console.debug(f"Skipping existing [link]{cached_path}[/link].")
|
||||
return
|
||||
|
||||
self.console.debug(f"Transcoding [link]{cached_path}[/link]")
|
||||
self._run_transcoder(source_path, cached_path)
|
||||
|
||||
progress.update(
|
||||
task_id,
|
||||
transcoded=self._transcoded,
|
||||
processed=self._processed,
|
||||
description=f"[bright]Transcoded [link]{relpath}[/link]",
|
||||
)
|
||||
Reference in New Issue
Block a user