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,140 +8,149 @@ 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,
|
||||||
dest: str,
|
dest: str,
|
||||||
transcode_level: str,
|
transcode_level: str,
|
||||||
single_directory: bool,
|
single_directory: bool,
|
||||||
skip_existing: bool
|
skip_existing: bool
|
||||||
):
|
):
|
||||||
self.src = src
|
self.src = src
|
||||||
self.dest = dest
|
self.dest = dest
|
||||||
self.transcode_level = transcode_level
|
self.transcode_level = transcode_level
|
||||||
self.single_directory = single_directory
|
self.single_directory = single_directory
|
||||||
self.skip_existing = skip_existing
|
self.skip_existing = skip_existing
|
||||||
self.state = CopyCommandState()
|
self.state = CopyCommandState()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print("Copying")
|
print("Copying")
|
||||||
self.scan_for_music()
|
self.scan_for_music()
|
||||||
self.load_tag_information()
|
self.load_tag_information()
|
||||||
if self.single_directory:
|
if self.single_directory:
|
||||||
self.check_for_collisions()
|
self.check_for_collisions()
|
||||||
self.transcode_files()
|
self.transcode_files()
|
||||||
|
|
||||||
def scan_for_music(self):
|
def scan_for_music(self):
|
||||||
print("Scanning For Music")
|
print("Scanning For Music")
|
||||||
self.state.files = scan_for_music(self.src)
|
self.state.files = scan_for_music(self.src)
|
||||||
|
|
||||||
def load_tag_information(self):
|
def load_tag_information(self):
|
||||||
print("Loading Tag Information")
|
print("Loading Tag Information")
|
||||||
|
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
file.tags = load_tag_information(file)
|
file.tags = load_tag_information(file)
|
||||||
|
|
||||||
def check_for_collisions(self):
|
def check_for_collisions(self):
|
||||||
print("Checking For Colisions")
|
print("Checking For Colisions")
|
||||||
seen = set()
|
seen = set()
|
||||||
dupes = []
|
dupes = []
|
||||||
|
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
filename = file.filename
|
filename = file.filename
|
||||||
if filename in seen:
|
if filename in seen:
|
||||||
dupes.append(filename)
|
dupes.append(filename)
|
||||||
else:
|
else:
|
||||||
seen.add(filename)
|
seen.add(filename)
|
||||||
|
|
||||||
if len(dupes) > 0:
|
if len(dupes) > 0:
|
||||||
print("Dupes Found:", dupes)
|
print("Dupes Found:", dupes)
|
||||||
print("Cannot continue using --single-directory")
|
print("Cannot continue using --single-directory")
|
||||||
print("Please rename or remove duplicates")
|
print("Please rename or remove duplicates")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
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(
|
||||||
dest = self.dest + "/" + dest
|
) if self.single_directory else file.join_path_from_src()
|
||||||
|
dest = self.dest + "/" + dest
|
||||||
|
|
||||||
exists = path_exists(dest)
|
exists = path_exists(dest)
|
||||||
|
|
||||||
if (self.skip_existing and not exists) or not self.skip_existing:
|
if (self.skip_existing and not exists) or not self.skip_existing:
|
||||||
print("Copying", src, "to", dest)
|
print("Copying", src, "to", dest)
|
||||||
copy_file(
|
copy_file(
|
||||||
src,
|
src,
|
||||||
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)
|
||||||
|
|
||||||
def _transcode_with_level(self, file: File, level: str):
|
def _transcode_with_level(self, file: File, level: str):
|
||||||
transcoded_file_extension = "opus"
|
transcoded_file_extension = "opus"
|
||||||
|
|
||||||
src = file.join_path_to()
|
src = file.join_path_to()
|
||||||
|
|
||||||
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(
|
||||||
dest_filepath = self.dest + "/" + dest_filepath
|
) if self.single_directory else new_file.join_path_from_src()
|
||||||
|
dest_filepath = self.dest + "/" + dest_filepath
|
||||||
|
|
||||||
if (self.skip_existing and path_exists(dest_filepath)):
|
if (self.skip_existing and path_exists(dest_filepath)):
|
||||||
print("Skipping transcoding", dest_filepath)
|
print("Skipping transcoding", dest_filepath)
|
||||||
self.state.transcoded_files.append(new_file)
|
self.state.transcoded_files.append(new_file)
|
||||||
return
|
return
|
||||||
|
|
||||||
bitrate = ""
|
bitrate = ""
|
||||||
|
|
||||||
if self.transcode_level == "high":
|
if self.transcode_level == "high":
|
||||||
bitrate = "128K"
|
bitrate = "128K"
|
||||||
elif self.transcode_level == "medium":
|
elif self.transcode_level == "medium":
|
||||||
bitrate = "96K"
|
bitrate = "96K"
|
||||||
elif self.transcode_level == "low":
|
elif self.transcode_level == "low":
|
||||||
bitrate = "64K"
|
bitrate = "64K"
|
||||||
|
|
||||||
print("Transcoding", src, "to", dest_filepath)
|
print("Transcoding", src, "to", dest_filepath)
|
||||||
|
|
||||||
title = file.tags.title
|
title = file.tags.title
|
||||||
artist = file.tags.artist
|
artist = file.tags.artist
|
||||||
|
|
||||||
# TODO: check for errors
|
# TODO: check for errors
|
||||||
run_command([
|
run_command([
|
||||||
"ffmpeg",
|
"ffmpeg",
|
||||||
"-y",
|
"-y",
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel", "warning",
|
"-loglevel", "warning",
|
||||||
"-i", src,
|
"-i", src,
|
||||||
"-c:a", "libopus",
|
"-c:a", "libopus",
|
||||||
"-b:a", bitrate,
|
"-b:a", bitrate,
|
||||||
"-metadata", f"title=\"{title}\"",
|
"-metadata", f"title=\"{title}\"",
|
||||||
"-metadata", f"artist=\"{artist}\"",
|
"-metadata", f"artist=\"{artist}\"",
|
||||||
dest_filepath
|
dest_filepath
|
||||||
])
|
])
|
||||||
|
|
||||||
self.state.transcoded_files.append(new_file)
|
self.state.transcoded_files.append(new_file)
|
||||||
|
|
||||||
def transcode_files(self):
|
def transcode_files(self):
|
||||||
print("Transcoding Files")
|
print("Transcoding Files")
|
||||||
|
|
||||||
if not self.single_directory:
|
if not self.single_directory:
|
||||||
directories = set()
|
directories = set()
|
||||||
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":
|
|
||||||
for file in self.state.files:
|
|
||||||
self._transcode_copy(file)
|
|
||||||
return
|
|
||||||
elif self.transcode_level in ["high", "medium", "low"]:
|
|
||||||
for file in self.state.files:
|
|
||||||
self._transcode_with_level(file, self.transcode_level)
|
|
||||||
|
|
||||||
|
if self.transcode_level == "copy":
|
||||||
|
for file in self.state.files:
|
||||||
|
self._transcode_copy(file)
|
||||||
|
return
|
||||||
|
elif self.transcode_level in ["high", "medium", "low"]:
|
||||||
|
for file in self.state.files:
|
||||||
|
self._transcode_with_level(
|
||||||
|
file, self.transcode_level)
|
||||||
|
|
|
@ -6,57 +6,63 @@ 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
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
self.state = ProcessCommandState()
|
self.state = ProcessCommandState()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print("Renaming")
|
print("Renaming")
|
||||||
self.scan_for_music()
|
self.scan_for_music()
|
||||||
self.load_tag_information()
|
self.load_tag_information()
|
||||||
self.rename_files()
|
self.rename_files()
|
||||||
|
|
||||||
def scan_for_music(self):
|
def scan_for_music(self):
|
||||||
print("Scanning For Music")
|
print("Scanning For Music")
|
||||||
self.state.files = scan_for_music(self.src)
|
self.state.files = scan_for_music(self.src)
|
||||||
|
|
||||||
def load_tag_information(self):
|
def load_tag_information(self):
|
||||||
print("Loading Tag Information")
|
print("Loading Tag Information")
|
||||||
|
|
||||||
for file in self.state.files:
|
for file in self.state.files:
|
||||||
tags = load_tag_information(file)
|
tags = load_tag_information(file)
|
||||||
file.tags = tags
|
file.tags = tags
|
||||||
|
|
||||||
|
def _rename_file(self, file: File) -> File:
|
||||||
|
filename = file.filename
|
||||||
|
artist = file.tags.artist.replace("\n", "")
|
||||||
|
title = file.tags.title.replace("\n", "")
|
||||||
|
|
||||||
def _rename_file(self, file: File) -> File:
|
proper_filename = reduce_to_ascii_and_substitute(
|
||||||
filename = file.filename
|
f"{artist} - {title}")
|
||||||
artist = file.tags.artist.replace("\n", "")
|
|
||||||
title = file.tags.title.replace("\n", "")
|
|
||||||
|
|
||||||
proper_filename = reduce_to_ascii_and_substitute(f"{artist} - {title}")
|
if filename != proper_filename:
|
||||||
|
print(f"Renaming \"{filename}\"", "to" +
|
||||||
|
f"\"{proper_filename}\"" + "\n")
|
||||||
|
|
||||||
if filename != proper_filename:
|
new_file = deep_copy(file)
|
||||||
print(f"Renaming \"{filename}\"", "to" + f"\"{proper_filename}\"" + "\n")
|
new_file.filename = proper_filename
|
||||||
|
|
||||||
new_file = deep_copy(file)
|
if not self.dry_run:
|
||||||
new_file.filename = proper_filename
|
rename_file(
|
||||||
|
file.join_path_to(),
|
||||||
|
new_file.join_path_to())
|
||||||
|
# so that other steps after read the new file and not
|
||||||
|
# the orig pre-rename file when not dry run
|
||||||
|
return new_file
|
||||||
|
else:
|
||||||
|
return file
|
||||||
|
|
||||||
if not self.dry_run:
|
def rename_files(self):
|
||||||
rename_file(file.join_path_to(), new_file.join_path_to())
|
print("Renaming files")
|
||||||
# so that other steps after read the new file and not
|
|
||||||
# the orig pre-rename file when not dry run
|
|
||||||
return new_file
|
|
||||||
else:
|
|
||||||
return file
|
|
||||||
|
|
||||||
def rename_files(self):
|
for file in self.state.files:
|
||||||
print("Renaming files")
|
index = self.state.files.index(file)
|
||||||
|
self.state.files[index] = self._rename_file(
|
||||||
for file in self.state.files:
|
file)
|
||||||
index = self.state.files.index(file)
|
|
||||||
self.state.files[index] = self._rename_file(file)
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
# All file extensions that are supported and have tag
|
||||||
|
# extraction
|
||||||
supported_formats = ["mp3", "flac"]
|
supported_formats = ["mp3", "flac"]
|
||||||
|
|
||||||
sub_char = "_"
|
sub_char = "_"
|
||||||
|
|
||||||
substitutions = {
|
substitutions = {
|
||||||
"α": "a",
|
"α": "a",
|
||||||
}
|
}
|
|
@ -1,43 +1,44 @@
|
||||||
class Tags:
|
class Tags:
|
||||||
title = ""
|
title = ""
|
||||||
artist = ""
|
artist = ""
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
"title": self.title,
|
"title": self.title,
|
||||||
"artist": self.artist
|
"artist": self.artist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.to_dict())
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return repr(self.to_dict())
|
|
||||||
|
|
||||||
class File:
|
class File:
|
||||||
filename = ""
|
filename = ""
|
||||||
extension = ""
|
extension = ""
|
||||||
# The path to the actual file
|
# The path to the actual file
|
||||||
path_to = ""
|
path_to = ""
|
||||||
# The path relative to the source directory
|
# The path relative to the source directory
|
||||||
path_from_src = ""
|
path_from_src = ""
|
||||||
|
|
||||||
tags = Tags()
|
tags = Tags()
|
||||||
|
|
||||||
def join_filename(self):
|
def join_filename(self):
|
||||||
return f"{self.filename}.{self.extension}"
|
return f"{self.filename}.{self.extension}"
|
||||||
|
|
||||||
def join_path_to(self):
|
def join_path_to(self):
|
||||||
return f"{self.path_to}/{self.filename}.{self.extension}"
|
return f"{self.path_to}/{self.filename}.{self.extension}"
|
||||||
|
|
||||||
def join_path_from_src(self):
|
def join_path_from_src(self):
|
||||||
return f"{self.path_from_src}/{self.filename}.{self.extension}"
|
return f"{self.path_from_src}/{self.filename}.{self.extension}"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
"filename": self.filename,
|
"filename": self.filename,
|
||||||
"extension": self.extension,
|
"extension": self.extension,
|
||||||
"path_to": self.path_to,
|
"path_to": self.path_to,
|
||||||
"path_from_src": self.path_from_src,
|
"path_from_src": self.path_from_src,
|
||||||
"tags": self.tags.to_dict(),
|
"tags": self.tags.to_dict(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return repr(self.to_dict())
|
return repr(self.to_dict())
|
||||||
|
|
|
@ -3,18 +3,19 @@ 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()
|
||||||
if file.extension == "mp3":
|
if file.extension == "mp3":
|
||||||
mp3 = MP3(path)
|
mp3 = MP3(path)
|
||||||
tags.title = mp3["title"][0]
|
tags.title = mp3["title"][0]
|
||||||
tags.artist = mp3["artist"][0]
|
tags.artist = mp3["artist"][0]
|
||||||
elif file.extension == "flac":
|
elif file.extension == "flac":
|
||||||
flac = FLAC(path)
|
flac = FLAC(path)
|
||||||
tags.title = flac["title"][0]
|
tags.title = flac["title"][0]
|
||||||
tags.artist = flac["artist"][0]
|
tags.artist = flac["artist"][0]
|
||||||
else:
|
else:
|
||||||
print("Invalid / Unsupported Container")
|
print("Invalid / Unsupported Container")
|
||||||
exit()
|
exit()
|
||||||
return tags
|
return tags
|
||||||
|
|
|
@ -4,14 +4,16 @@ 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(
|
||||||
file.filename = path.stem
|
str(path.parent), src)
|
||||||
file.extension = path.suffix.replace(".", "")
|
file.filename = path.stem
|
||||||
files.append(file)
|
file.extension = path.suffix.replace(".", "")
|
||||||
return files
|
files.append(file)
|
||||||
|
return files
|
||||||
|
|
|
@ -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(
|
||||||
filename = fold(filename)
|
sub_before, substitutions[sub_before])
|
||||||
return filename
|
filename = fold(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