Compare commits

...

2 Commits

Author SHA1 Message Date
875ed7a668 dedupe before transcoding 2025-07-12 14:24:14 +01:00
599e76d44b implement transcoder as layer
- copy worker over

note: originally removed in commit 641abcdd90
2025-07-12 14:23:50 +01:00
4 changed files with 129 additions and 3 deletions

View File

@ -1,2 +1,4 @@
from .layer import Layer from .layer import Layer
from .worker import Worker
from .transcoder import Transcoder from .transcoder import Transcoder
from .dedupe import Dedupe

45
src/layers/transcoder.py Normal file
View File

@ -0,0 +1,45 @@
from pathlib import Path
from multiprocessing import Pool, Manager, set_start_method
from log import Log, LogCat
from .worker import Worker
from dir import Root
from .layer import Layer
class Transcoder(Layer):
def __init__(self, encoder: Path, extension: str, output_root: Path, log: Log, log_path: Path):
super().__init__(log, 'TCD')
self.encoder = encoder
self.extension = extension
self.output_root = output_root
self.log_path = log_path
def _process(self, root: Root):
transcode_list = root.all_files
self._transcode(transcode_list, self.encoder)
def _transcode(self, transcode_list: list, encoder: Path, workers=16):
manager = Manager()
queue = manager.Queue()
log = Log(self.log_path, queue)
logcat = LogCat(log.queue, "TCD")
args = [(str(self.output_root), self.extension, track, encoder, logcat) for track in transcode_list]
with Pool(workers) as pool:
pool.starmap(self.worker, args)
pool.close()
pool.join()
log.stop()
def _transcode_single_thread(self, transcode_list: list, encoder: Path):
log = Log(self.log_path)
logcat = LogCat(log.queue, "TCD")
worker_args = [(track, encoder) for track in transcode_list]
for track, encoder in worker_args:
self.worker(str(self.output_root), self.extension, track, encoder, logcat)
log.stop()
@staticmethod
def worker(output_root, extension, track, encoder, log):
w = Worker(output_root, extension)
w.transcode_worker(track, encoder, log)

70
src/layers/worker.py Normal file
View File

@ -0,0 +1,70 @@
import shutil
import subprocess
from pathlib import Path
from dir.file import File
class Worker:
def __init__(self, output_root, extension):
self.output_root = Path(output_root)
self.extension = extension
def transcode_worker(self, track: File, encoder, log):
if track.is_art:
return self.copy_album_art(track, log)
elif track.is_audio:
return self.transcode_audio(track, encoder, log)
else:
log.info("WRK", f"File {track.path} ignored")
def copy_album_art(self, file: File, log):
self.create_directories(file)
output_path = file.output_file(self.output_root, file.extension[1:])
if output_path.exists():
log.info("ART", f"Skipped {output_path}")
return
try:
shutil.copy(file.path, output_path)
log.info("ART", f"Successfully copied {output_path}")
except FileExistsError:
log.warning("ART", f"File exists: {output_path}")
except Exception:
log.error("ART", f"{file.path} failed to copy")
def transcode_audio(self, track, encoder, log):
track_output = track.output_file(self.output_root, self.extension)
if track_output.exists():
log.info("AUD", f"Skipped {track_output}")
return
self.create_directories(track)
encoder_args = self.encoder_args(encoder, track, log)
try:
subprocess.run(encoder_args, capture_output=True, text=True, check=True)
log.info("AUD", f"Transcoded '{track}' successfully.")
except Exception:
log.error("AUD", f"ERROR: Transcoding of '{track}' failed.")
def encoder_args(self, encoder, track, log):
track_output = track.output_file(self.output_root, self.extension)
enc_filename = encoder.parts[-1]
encoder_args = ""
if enc_filename == "opusenc.exe":
additional_args = ('--bitrate', '128', '--music')
encoder_args = (str(encoder),) + additional_args + (str(track.path), str(track_output))
elif enc_filename == "qaac64.exe":
additional_args = (str(track), '-o', str(track_output), '--threading')
encoder_args = (str(encoder),) + additional_args
else:
log.error("AUD", f"Encoder {encoder} not recognised.")
return encoder_args
def create_directories(self, track: File):
if not track.artist_out(self.output_root).exists():
try:
track.artist_out(self.output_root).mkdir()
except FileExistsError:
pass
if not track.album_out(self.output_root).exists():
try:
track.album_out(self.output_root).mkdir()
except FileExistsError:
pass

View File

@ -1,8 +1,9 @@
import argparse import argparse
from os.path import realpath from os.path import realpath
from pathlib import Path from pathlib import Path
from transcode import Transcoder from dir import Root
from log import Log from log import Log
from layers import Dedupe, Transcoder
def get_args(): def get_args():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -17,9 +18,17 @@ def main(input_dir: Path, output_dir: Path, encoder: Path, out_extension: str =
log_path = wd / "logs" log_path = wd / "logs"
if encoder.parts[-1] == "qaac64.exe": if encoder.parts[-1] == "qaac64.exe":
out_extension = "m4a" out_extension = "m4a"
transcoder = Transcoder(encoder, out_extension, input_dir, output_dir, log_path) log = Log(log_path)
transcoder.transcode() input_root = Root(input_dir, log)
output_root = Root(output_dir, log)
dedupe = Dedupe(output_root, log)
dedupe.process(input_root)
transcoder = Transcoder(encoder, out_extension, output_dir, log, log_path)
transcoder.process(input_root)
log.stop()
if __name__ == '__main__': if __name__ == '__main__':
args = get_args() args = get_args()