nixfiles/musicutil/commands/copy_command.py

228 lines
6.8 KiB
Python
Raw Normal View History

2022-02-06 15:51:42 +00:00
from musicutil.utils.do_replaygain import do_replaygain
2022-02-04 13:35:01 +00:00
from ..types import File
from ..utils.scan_for_music import scan_for_music
from ..utils.load_tag_information import load_tag_information
2022-02-06 15:20:12 +00:00
from ..transcode_presets import print_transcode_presets, transcode_presets_list
from ..utils.transcoder import TranscodeConfig, transcode, get_transcode_config
2022-02-04 13:32:22 +00:00
from os import makedirs as make_directories
from os.path import exists as path_exists
from shutil import copy as copy_file
from copy import deepcopy as deep_copy
2022-02-04 13:54:10 +00:00
class CopyCommandState:
files: list[File] = []
transcoded_files: list[File] = []
2022-02-06 16:18:14 +00:00
2022-02-06 15:20:12 +00:00
class CopyCommandArgs():
src: str
dest: str
transcode_preset: str
custom_transcoder_config: str
single_directory: bool
skip_existing: bool
2022-02-06 15:51:42 +00:00
skip_replaygain: bool
2022-02-06 15:20:12 +00:00
2022-02-06 16:18:14 +00:00
2022-02-06 15:20:12 +00:00
def add_copy_command(subparsers):
copy_parser = subparsers.add_parser('copy')
copy_parser.add_argument(
'src',
type=str,
help='src base music directory')
copy_parser.add_argument(
'dest',
type=str,
help='dest music directory')
copy_parser.add_argument(
'--transcode-preset',
type=str,
help='transcode preset (copy = no transcode)',
default="copy")
copy_parser.add_argument(
'--custom-transcoder-config',
type=str,
help='custom transcoder config')
copy_parser.add_argument(
'--skip-existing',
action='store_true')
2022-02-06 15:51:42 +00:00
copy_parser.add_argument(
'--skip-replaygain',
action='store_true')
2022-02-06 15:20:12 +00:00
copy_parser.add_argument(
'--single-directory',
action='store_true')
2022-02-06 16:18:14 +00:00
2022-02-06 15:20:12 +00:00
def get_copy_args(args) -> CopyCommandArgs:
command_args = CopyCommandArgs()
command_args.src = args.src
command_args.dest = args.dest
command_args.transcode_preset = args.transcode_preset
command_args.custom_transcoder_config = args.custom_transcoder_config
command_args.single_directory = args.single_directory
command_args.skip_existing = args.skip_existing
2022-02-06 15:51:42 +00:00
command_args.skip_replaygain = args.skip_replaygain
2022-02-06 15:20:12 +00:00
return command_args
2022-02-06 16:18:14 +00:00
2022-02-04 13:54:10 +00:00
class CopyCommand():
2022-02-06 15:20:12 +00:00
def __init__(self, args: CopyCommandArgs):
self.args = args
2022-02-04 13:54:10 +00:00
self.state = CopyCommandState()
def run(self):
2022-02-06 15:20:12 +00:00
if self.args.transcode_preset == "list":
print_transcode_presets()
2022-02-06 09:57:47 +00:00
exit()
2022-02-04 13:54:10 +00:00
print("Copying")
self.scan_for_music()
self.load_tag_information()
2022-02-06 15:20:12 +00:00
if self.args.single_directory:
2022-02-04 13:54:10 +00:00
self.check_for_collisions()
self.transcode_files()
2022-02-06 15:20:12 +00:00
if self.args.single_directory:
2022-02-04 16:19:11 +00:00
self.create_mappings()
2022-02-06 15:51:42 +00:00
if not self.args.skip_replaygain:
self.add_replaygain_tags()
2022-02-04 13:54:10 +00:00
def scan_for_music(self):
print("Scanning For Music")
2022-02-06 15:20:12 +00:00
self.state.files = scan_for_music(self.args.src)
2022-02-04 13:54:10 +00:00
def load_tag_information(self):
print("Loading Tag Information")
for file in self.state.files:
file.tags = load_tag_information(file)
def check_for_collisions(self):
print("Checking For Colisions")
seen = set()
dupes = []
for file in self.state.files:
filename = file.filename
if filename in seen:
dupes.append(filename)
else:
seen.add(filename)
if len(dupes) > 0:
print("Dupes Found:", dupes)
print("Cannot continue using --single-directory")
print("Please rename or remove duplicates")
exit()
def _transcode_copy(self, file: File):
src = file.join_path_to()
dest = file.join_filename(
2022-02-06 15:20:12 +00:00
) if self.args.single_directory else file.join_path_from_src()
dest = self.args.dest + "/" + dest
2022-02-04 13:54:10 +00:00
exists = path_exists(dest)
should_skip = False
if self.args.skip_existing and exists:
should_skip = True
if should_skip:
2022-02-04 13:54:10 +00:00
print("Copying", src, "to", dest)
copy_file(
src,
dest,
)
else:
print(
"Skipping",
src,
"as already is copied at",
dest)
self.state.transcoded_files.append(file)
2022-02-06 16:18:14 +00:00
def _transcode_with_config(
self,
file: File,
trans_config: TranscodeConfig):
2022-02-04 13:54:10 +00:00
src = file.join_path_to()
new_file = deep_copy(file)
2022-02-04 16:19:11 +00:00
new_file.extension = trans_config.file_extension
2022-02-04 13:54:10 +00:00
dest_filepath = ""
if self.args.single_directory:
dest_filepath = new_file.join_filename()
else:
dest_filepath = new_file.join_path_from_src()
2022-02-06 15:20:12 +00:00
dest_filepath = self.args.dest + "/" + dest_filepath
2022-02-04 13:54:10 +00:00
should_skip_transcode = self.args.skip_existing and path_exists(
dest_filepath)
if should_skip_transcode:
2022-02-04 13:54:10 +00:00
print("Skipping transcoding", dest_filepath)
self.state.transcoded_files.append(new_file)
return
print("Transcoding", src, "to", dest_filepath)
transcode(file, trans_config, dest_filepath)
2022-02-04 13:54:10 +00:00
self.state.transcoded_files.append(new_file)
def transcode_files(self):
print("Transcoding Files")
2022-02-06 15:20:12 +00:00
if not self.args.single_directory:
# set can't contain duplicates
# so it only creates a dir once
2022-02-04 13:54:10 +00:00
directories = set()
for file in self.state.files:
directories.add(file.path_from_src)
for dir in directories:
make_directories(
2022-02-06 16:18:14 +00:00
self.args.dest + "/" + dir,
exist_ok=True)
2022-02-04 13:54:10 +00:00
2022-02-06 15:20:12 +00:00
is_transcode_config_set = self.args.custom_transcoder_config is not None
if self.args.transcode_preset == "copy" and not is_transcode_config_set:
2022-02-04 13:54:10 +00:00
for file in self.state.files:
self._transcode_copy(file)
return
2022-02-06 15:20:12 +00:00
else:
global trans_config
trans_config = None
if is_transcode_config_set:
with open(self.args.custom_transcoder_config, "r+") as f:
trans_config = TranscodeConfig()
trans_config.load_from_file(f)
else:
2022-02-06 16:18:14 +00:00
trans_config = get_transcode_config(
self.args.transcode_preset)
2022-02-06 15:20:12 +00:00
2022-02-04 13:54:10 +00:00
for file in self.state.files:
2022-02-06 15:20:12 +00:00
self._transcode_with_config(
file, trans_config)
2022-02-04 16:19:11 +00:00
def create_mappings(self):
with open(self.dest + "/" + "mappings.txt", "w") as f:
f.write("\n".join([
f"{file.path_from_src} <- {file.filename}" for file in self.state.files
]))
2022-02-06 15:51:42 +00:00
def add_replaygain_tags(self):
print("Adding ReplayGain Tags")
for file in self.state.files:
2022-02-06 16:18:14 +00:00
print(
f"Adding ReplayGain Tags to \"{file.filename}.{file.extension}\"")
2022-02-06 15:51:42 +00:00
2022-02-06 16:18:14 +00:00
do_replaygain(file)