format code
This commit is contained in:
parent
5272a3d356
commit
1c57673dc4
27
main.py
27
main.py
|
@ -1,27 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
from musicutil.commands.process_command import ProcessCommand
|
|
||||||
from musicutil.commands.copy_command import CopyCommand
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Highly Opinionated Music ')
|
|
||||||
subparsers = parser.add_subparsers(dest="subparser_name")
|
|
||||||
|
|
||||||
process_parser = subparsers.add_parser('process')
|
|
||||||
process_parser.add_argument('src', type=str, help='src base music directory')
|
|
||||||
process_parser.add_argument('--dry-run', action='store_true')
|
|
||||||
|
|
||||||
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-level', type=str, help='transcode level', default="copy")
|
|
||||||
copy_parser.add_argument('--skip-existing', action='store_true')
|
|
||||||
copy_parser.add_argument('--single-directory', action='store_true')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.subparser_name == "process":
|
|
||||||
ProcessCommand(args.src, args.dry_run).run()
|
|
||||||
elif args.subparser_name == "copy":
|
|
||||||
CopyCommand(args.src, args.dest, args.transcode_level, args.single_directory, args.skip_existing).run()
|
|
52
musicutil/__main__.py
Normal file
52
musicutil/__main__.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from .commands.process_command import ProcessCommand
|
||||||
|
from .commands.copy_command import CopyCommand
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="chaos's musicutil")
|
||||||
|
subparsers = parser.add_subparsers(dest="subparser_name")
|
||||||
|
|
||||||
|
process_parser = subparsers.add_parser('process')
|
||||||
|
process_parser.add_argument(
|
||||||
|
'src',
|
||||||
|
type=str,
|
||||||
|
help='src base music directory')
|
||||||
|
process_parser.add_argument(
|
||||||
|
'--dry-run', action='store_true')
|
||||||
|
|
||||||
|
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-level',
|
||||||
|
type=str,
|
||||||
|
help='transcode level',
|
||||||
|
default="copy")
|
||||||
|
copy_parser.add_argument(
|
||||||
|
'--skip-existing',
|
||||||
|
action='store_true')
|
||||||
|
copy_parser.add_argument(
|
||||||
|
'--single-directory',
|
||||||
|
action='store_true')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.subparser_name == "process":
|
||||||
|
ProcessCommand(args.src, args.dry_run).run()
|
||||||
|
elif args.subparser_name == "copy":
|
||||||
|
CopyCommand(
|
||||||
|
args.src,
|
||||||
|
args.dest,
|
||||||
|
args.transcode_level,
|
||||||
|
args.single_directory,
|
||||||
|
args.skip_existing
|
||||||
|
).run()
|
|
@ -8,10 +8,12 @@ from shutil import copy as copy_file
|
||||||
from copy import deepcopy as deep_copy
|
from copy import deepcopy as deep_copy
|
||||||
from subprocess import run as run_command
|
from subprocess import run as run_command
|
||||||
|
|
||||||
|
|
||||||
class CopyCommandState:
|
class CopyCommandState:
|
||||||
files: list[File] = []
|
files: list[File] = []
|
||||||
transcoded_files: list[File] = []
|
transcoded_files: list[File] = []
|
||||||
|
|
||||||
|
|
||||||
class CopyCommand():
|
class CopyCommand():
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
src: str,
|
src: str,
|
||||||
|
@ -65,7 +67,8 @@ class CopyCommand():
|
||||||
|
|
||||||
def _transcode_copy(self, file: File):
|
def _transcode_copy(self, file: File):
|
||||||
src = file.join_path_to()
|
src = file.join_path_to()
|
||||||
dest = file.join_filename() if self.single_directory else file.join_path_from_src()
|
dest = file.join_filename(
|
||||||
|
) if self.single_directory else file.join_path_from_src()
|
||||||
dest = self.dest + "/" + dest
|
dest = self.dest + "/" + dest
|
||||||
|
|
||||||
exists = path_exists(dest)
|
exists = path_exists(dest)
|
||||||
|
@ -77,7 +80,11 @@ class CopyCommand():
|
||||||
dest,
|
dest,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print("Skipping", src, "as already is copied at", dest)
|
print(
|
||||||
|
"Skipping",
|
||||||
|
src,
|
||||||
|
"as already is copied at",
|
||||||
|
dest)
|
||||||
|
|
||||||
self.state.transcoded_files.append(file)
|
self.state.transcoded_files.append(file)
|
||||||
|
|
||||||
|
@ -89,7 +96,8 @@ class CopyCommand():
|
||||||
new_file = deep_copy(file)
|
new_file = deep_copy(file)
|
||||||
new_file.extension = transcoded_file_extension
|
new_file.extension = transcoded_file_extension
|
||||||
|
|
||||||
dest_filepath = new_file.join_filename() if self.single_directory else new_file.join_path_from_src()
|
dest_filepath = new_file.join_filename(
|
||||||
|
) if self.single_directory else new_file.join_path_from_src()
|
||||||
dest_filepath = self.dest + "/" + dest_filepath
|
dest_filepath = self.dest + "/" + dest_filepath
|
||||||
|
|
||||||
if (self.skip_existing and path_exists(dest_filepath)):
|
if (self.skip_existing and path_exists(dest_filepath)):
|
||||||
|
@ -135,7 +143,8 @@ class CopyCommand():
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
directories.add(file.path_from_src)
|
directories.add(file.path_from_src)
|
||||||
for dir in directories:
|
for dir in directories:
|
||||||
make_directories(self.dest + "/" + dir, exist_ok=True)
|
make_directories(
|
||||||
|
self.dest + "/" + dir, exist_ok=True)
|
||||||
|
|
||||||
if self.transcode_level == "copy":
|
if self.transcode_level == "copy":
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
|
@ -143,5 +152,5 @@ class CopyCommand():
|
||||||
return
|
return
|
||||||
elif self.transcode_level in ["high", "medium", "low"]:
|
elif self.transcode_level in ["high", "medium", "low"]:
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
self._transcode_with_level(file, self.transcode_level)
|
self._transcode_with_level(
|
||||||
|
file, self.transcode_level)
|
||||||
|
|
|
@ -6,9 +6,11 @@ from ..utils.substitutions import reduce_to_ascii_and_substitute
|
||||||
from copy import deepcopy as deep_copy
|
from copy import deepcopy as deep_copy
|
||||||
from os import rename as rename_file
|
from os import rename as rename_file
|
||||||
|
|
||||||
|
|
||||||
class ProcessCommandState:
|
class ProcessCommandState:
|
||||||
files: list[File] = []
|
files: list[File] = []
|
||||||
|
|
||||||
|
|
||||||
class ProcessCommand():
|
class ProcessCommand():
|
||||||
def __init__(self, src: str, dry_run: bool):
|
def __init__(self, src: str, dry_run: bool):
|
||||||
self.src = src
|
self.src = src
|
||||||
|
@ -32,22 +34,25 @@ class ProcessCommand():
|
||||||
tags = load_tag_information(file)
|
tags = load_tag_information(file)
|
||||||
file.tags = tags
|
file.tags = tags
|
||||||
|
|
||||||
|
|
||||||
def _rename_file(self, file: File) -> File:
|
def _rename_file(self, file: File) -> File:
|
||||||
filename = file.filename
|
filename = file.filename
|
||||||
artist = file.tags.artist.replace("\n", "")
|
artist = file.tags.artist.replace("\n", "")
|
||||||
title = file.tags.title.replace("\n", "")
|
title = file.tags.title.replace("\n", "")
|
||||||
|
|
||||||
proper_filename = reduce_to_ascii_and_substitute(f"{artist} - {title}")
|
proper_filename = reduce_to_ascii_and_substitute(
|
||||||
|
f"{artist} - {title}")
|
||||||
|
|
||||||
if filename != proper_filename:
|
if filename != proper_filename:
|
||||||
print(f"Renaming \"{filename}\"", "to" + f"\"{proper_filename}\"" + "\n")
|
print(f"Renaming \"{filename}\"", "to" +
|
||||||
|
f"\"{proper_filename}\"" + "\n")
|
||||||
|
|
||||||
new_file = deep_copy(file)
|
new_file = deep_copy(file)
|
||||||
new_file.filename = proper_filename
|
new_file.filename = proper_filename
|
||||||
|
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
rename_file(file.join_path_to(), new_file.join_path_to())
|
rename_file(
|
||||||
|
file.join_path_to(),
|
||||||
|
new_file.join_path_to())
|
||||||
# so that other steps after read the new file and not
|
# so that other steps after read the new file and not
|
||||||
# the orig pre-rename file when not dry run
|
# the orig pre-rename file when not dry run
|
||||||
return new_file
|
return new_file
|
||||||
|
@ -59,4 +64,5 @@ class ProcessCommand():
|
||||||
|
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
index = self.state.files.index(file)
|
index = self.state.files.index(file)
|
||||||
self.state.files[index] = self._rename_file(file)
|
self.state.files[index] = self._rename_file(
|
||||||
|
file)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# All file extensions that are supported and have tag
|
||||||
|
# extraction
|
||||||
supported_formats = ["mp3", "flac"]
|
supported_formats = ["mp3", "flac"]
|
||||||
|
|
||||||
sub_char = "_"
|
sub_char = "_"
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Tags:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return repr(self.to_dict())
|
return repr(self.to_dict())
|
||||||
|
|
||||||
|
|
||||||
class File:
|
class File:
|
||||||
filename = ""
|
filename = ""
|
||||||
extension = ""
|
extension = ""
|
||||||
|
|
|
@ -3,6 +3,7 @@ from ..types import File, Tags
|
||||||
from mutagen.mp3 import EasyMP3 as MP3
|
from mutagen.mp3 import EasyMP3 as MP3
|
||||||
from mutagen.flac import FLAC
|
from mutagen.flac import FLAC
|
||||||
|
|
||||||
|
|
||||||
def load_tag_information(file: File) -> Tags:
|
def load_tag_information(file: File) -> Tags:
|
||||||
path = file.join_path_to()
|
path = file.join_path_to()
|
||||||
tags = Tags()
|
tags = Tags()
|
||||||
|
|
|
@ -4,13 +4,15 @@ from os.path import relpath
|
||||||
from ..types import File
|
from ..types import File
|
||||||
from ..meta import supported_formats
|
from ..meta import supported_formats
|
||||||
|
|
||||||
|
|
||||||
def scan_for_music(src: str) -> list[File]:
|
def scan_for_music(src: str) -> list[File]:
|
||||||
files: list[File] = []
|
files: list[File] = []
|
||||||
for format in supported_formats:
|
for format in supported_formats:
|
||||||
for path in Path(src).rglob("*." + format):
|
for path in Path(src).rglob("*." + format):
|
||||||
file = File()
|
file = File()
|
||||||
file.path_to = str(path.parent)
|
file.path_to = str(path.parent)
|
||||||
file.path_from_src = relpath(str(path.parent), src)
|
file.path_from_src = relpath(
|
||||||
|
str(path.parent), src)
|
||||||
file.filename = path.stem
|
file.filename = path.stem
|
||||||
file.extension = path.suffix.replace(".", "")
|
file.extension = path.suffix.replace(".", "")
|
||||||
files.append(file)
|
files.append(file)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from ..meta import sub_char, substitutions
|
from ..meta import sub_char, substitutions
|
||||||
from fold_to_ascii import fold
|
from fold_to_ascii import fold
|
||||||
|
|
||||||
|
|
||||||
def reduce_to_ascii_and_substitute(filename: str):
|
def reduce_to_ascii_and_substitute(filename: str):
|
||||||
filename = filename.replace("/", sub_char)
|
filename = filename.replace("/", sub_char)
|
||||||
filename = filename.replace("\\", sub_char)
|
filename = filename.replace("\\", sub_char)
|
||||||
filename = filename.replace("\n", "")
|
filename = filename.replace("\n", "")
|
||||||
for sub_before in substitutions.keys():
|
for sub_before in substitutions.keys():
|
||||||
filename = filename.replace(sub_before, substitutions[sub_before])
|
filename = filename.replace(
|
||||||
|
sub_before, substitutions[sub_before])
|
||||||
filename = fold(filename)
|
filename = fold(filename)
|
||||||
return filename
|
return filename
|
||||||
|
|
5
pyproject.toml
Normal file
5
pyproject.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[tool.autopep8]
|
||||||
|
max_line_length = 60
|
||||||
|
in-place = true
|
||||||
|
recursive = true
|
||||||
|
aggressive = 3
|
|
@ -2,6 +2,6 @@
|
||||||
let
|
let
|
||||||
fold-to-ascii = (py: py.callPackage ./nix-extra-deps/fold-to-ascii.nix { });
|
fold-to-ascii = (py: py.callPackage ./nix-extra-deps/fold-to-ascii.nix { });
|
||||||
my_python = pkgs.python39.withPackages
|
my_python = pkgs.python39.withPackages
|
||||||
(py: with py; [ py.mutagen (fold-to-ascii py) ]);
|
(py: with py; [ py.mutagen (fold-to-ascii py) py.autopep8 ]);
|
||||||
|
|
||||||
in pkgs.mkShell { packages = with pkgs; [ my_python ffmpeg ]; }
|
in pkgs.mkShell { packages = with pkgs; [ my_python ffmpeg ]; }
|
||||||
|
|
Loading…
Reference in a new issue