20 Commits

Author SHA1 Message Date
Jamie Hardt
49055ef881 lint 2025-05-25 11:25:54 -07:00
Jamie Hardt
ecc93640c2 Completed the feature. 2025-05-25 11:23:55 -07:00
Jamie Hardt
538da34a0c lint 2025-05-25 10:55:09 -07:00
Jamie Hardt
2d4ea5a8d8 /John/George 2025-05-25 10:52:59 -07:00
Jamie Hardt
532f67e3a8 Refactored some code 2025-05-25 09:32:59 -07:00
Jamie Hardt
4989832247 autopep (added explicit encoding for from-file) 2025-05-25 08:29:57 -07:00
Jamie Hardt
549f49da31 autopep 2025-05-25 08:28:32 -07:00
Jamie Hardt
ba3b0dbf96 Added implementation 2025-05-25 08:27:11 -07:00
Jamie Hardt
2c135d413e twiddle text 2025-05-24 21:30:14 -07:00
Jamie Hardt
334fa56a2c Update __main__.py 2025-05-24 20:59:53 -07:00
Jamie Hardt
66ac136270 autopep 2025-05-20 15:23:14 -07:00
Jamie Hardt
aa64d5e183 Fixed a bug in the increment code
Not sure how that happened I thought this used to work!
2025-05-20 15:19:46 -07:00
Jamie Hardt
6766e81b23 Commenting this out for now 2024-10-17 21:32:34 -07:00
Jamie Hardt
a2ce03a259 Added default lines to the top of a new list 2024-10-17 12:19:08 -07:00
Jamie Hardt
0ba40893df Adding some blank picture methods...
...to be implemented later if ever a need.
2024-10-17 09:50:27 -07:00
Jamie Hardt
e2b93f5183 Fixed obvious bug in --help-commands 2024-10-16 14:39:41 -07:00
Jamie Hardt
7015e80cf9 Merge pull request #1 from iluvcapra/iluvcapra-patch-py313
Add support for Python 3.13
2024-10-16 14:33:43 -07:00
Jamie Hardt
042f3116dd Update pyproject.toml 2024-10-16 14:33:02 -07:00
Jamie Hardt
20518fa31c Update pyproject.toml 2024-10-16 14:32:31 -07:00
Jamie Hardt
c4a2e380de Update pylint.yml
Adding 3.13 to test matrix
2024-10-16 14:30:09 -07:00
4 changed files with 104 additions and 45 deletions

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"] python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}

View File

@@ -8,8 +8,9 @@ from subprocess import CalledProcessError, run
import sys import sys
from argparse import ArgumentParser from argparse import ArgumentParser
import shlex import shlex
from typing import Callable from typing import Callable, List, Tuple
import inspect import inspect
from io import StringIO
from tqdm import tqdm from tqdm import tqdm
@@ -29,56 +30,83 @@ def execute_batch_list(batch_list_path: str, dry_run: bool, interactive: bool):
parser.eval(line, line_no, interactive) parser.eval(line, line_no, interactive)
def create_batch_list(command_file: str, recursive=True, sort_mode='path'): def sort_flac_files(file_list, mode):
"Sort flac files"
if mode == 'path':
return sorted(file_list)
if mode == 'mtime':
return sorted(file_list, key=os.path.getmtime)
if mode == 'ctime':
return sorted(file_list, key=os.path.getctime)
if mode == 'name':
return sorted(file_list, key=os.path.basename)
return file_list
def write_batchfile_entries_for_file(path, metadatums) -> Tuple[dict, str]:
"Create batchfile entries for `path`"
buffer = StringIO()
try:
this_file_metadata = metadata_funcs.read_metadata(path)
except CalledProcessError as e:
buffer.write(f"# !!! METAFLAC ERROR ({e.returncode}) while reading "
f"metadata from the file {path}\n\n")
return metadatums, buffer.getvalue()
for this_key, this_value in this_file_metadata.items():
if this_key not in metadatums:
buffer.write(f":set {this_key} "
f"{shlex.quote(this_value)}\n")
metadatums[this_key] = this_value
else:
if this_value != metadatums[this_key]:
buffer.write(f":set {this_key} "
f"{shlex.quote(this_value)}"
"\n")
metadatums[this_key] = this_value
keys = list(metadatums.keys())
for key in keys:
if key not in this_file_metadata:
buffer.write(f":unset {key}\n")
del metadatums[key]
buffer.write(path + "\n\n")
return metadatums, buffer.getvalue()
def create_batch_list(flac_files: List[str], command_file: str,
sort_mode='path'):
""" """
Read all FLAC files in the cwd and create a batchfile that re-creates all Read all FLAC files in the cwd and create a batchfile that re-creates all
of their metadata. of their metadata.
:param recursive: Recursively enter directories :param flac_files: Paths of files to create batchfile from
:param command_file: Name of new batchfile
:param sort_mode: Order of paths in the batch list. Either 'path', :param sort_mode: Order of paths in the batch list. Either 'path',
'mtime', 'ctime', 'name' 'mtime', 'ctime', 'name'
:param input_files: FLAC files to scan
""" """
flac_files = sort_flac_files(flac_files, sort_mode)
with open(command_file, mode='w', encoding='utf-8') as f: with open(command_file, mode='w', encoding='utf-8') as f:
f.write("# mfbatch\n\n")
metadatums = {} metadatums = {}
flac_files = glob('./**/*.flac', recursive=recursive)
if sort_mode == 'path': f.write("# mfbatch\n\n")
flac_files = sorted(flac_files)
elif sort_mode == 'mtime':
flac_files = sorted(flac_files, key=os.path.getmtime)
elif sort_mode == 'ctime':
flac_files = sorted(flac_files, key=os.path.getctime)
elif sort_mode == 'name':
flac_files = sorted(flac_files, key=os.path.basename)
for path in tqdm(flac_files, unit='File', desc='Scanning FLAC files'): for path in tqdm(flac_files, unit='File',
try: desc='Scanning with metaflac...'):
this_file_metadata = metadata_funcs.read_metadata(path)
except CalledProcessError as e:
f.write(f"# !!! METAFLAC ERROR ({e.returncode}) while reading "
f"metadata from the file {path}\n\n")
continue
for this_key, this_value in this_file_metadata.items(): metadatums, buffer = write_batchfile_entries_for_file(path,
if this_key not in metadatums: metadatums)
f.write(f":set {this_key} " f.write(buffer)
f"{shlex.quote(this_value)}\n")
metadatums[this_key] = this_value
else:
if this_value != metadatums[this_key]:
f.write(f":set {this_key} "
f"{shlex.quote(this_value)}"
"\n")
metadatums[this_key] = this_value
keys = list(metadatums.keys()) f.write("# mfbatch: create batchlist operation complete\n")
for key in keys:
if key not in this_file_metadata:
f.write(f":unset {key}\n")
del metadatums[key]
f.write(path + "\n\n")
def main(): def main():
@@ -91,6 +119,10 @@ def main():
op.add_argument('-c', '--create', default=False, op.add_argument('-c', '--create', default=False,
action='store_true', action='store_true',
help='create a new list') help='create a new list')
op.add_argument('-F', '--from-file', metavar='FILE_LIST', action='store',
default=None, help="get file paths from FILE_LIST when "
"creating, instead of scanning directory"
"a new list")
op.add_argument('-e', '--edit', action='store_true', op.add_argument('-e', '--edit', action='store_true',
help="open batch file in the default editor", help="open batch file in the default editor",
default=False) default=False)
@@ -123,7 +155,7 @@ def main():
if options.help_commands: if options.help_commands:
print("Command Help\n------------") print("Command Help\n------------")
commands = [command for command in dir(BatchfileParser) if commands = [command for command in dir(BatchfileParser) if
not command.startswith('_') or command != "eval"] not command.startswith('_') and command != "eval"]
print(f"{inspect.cleandoc(BatchfileParser.__doc__ or '')}\n\n") print(f"{inspect.cleandoc(BatchfileParser.__doc__ or '')}\n\n")
for command in commands: for command in commands:
meth = getattr(BatchfileParser, command) meth = getattr(BatchfileParser, command)
@@ -138,7 +170,18 @@ def main():
if options.create: if options.create:
mode_given = True mode_given = True
create_batch_list(options.batchfile, sort_mode=options.sort) flac_files: List[str] = []
if options.from_file:
with open(options.from_file, mode='r',
encoding='utf-8') as from_file:
flac_files = [line.strip() for line in from_file.readlines()]
else:
flac_files = glob('./**/*.flac', recursive=True)
# print(flac_files)
create_batch_list(flac_files, options.batchfile,
sort_mode=options.sort)
if options.edit: if options.edit:
mode_given = True mode_given = True

View File

@@ -131,9 +131,9 @@ class CommandEnv:
""" """
Increment all increment keys. Increment all increment keys.
""" """
for k, v in self.incr.items(): for k, _ in self.incr.items():
v = int(v) val = int(self.metadatums[k])
self.metadatums[k] = self.incr[k] % (v + 1) self.metadatums[k] = self.incr[k] % (val + 1)
class BatchfileParser: class BatchfileParser:
@@ -329,3 +329,18 @@ they appear in the batchfile.
""" """
val = args[0] val = args[0]
self.env.set_once('DESCRIPTION', val) self.env.set_once('DESCRIPTION', val)
# def picture(self, args):
# """
# picture PATH
# Add PATH as a picture (flac picture type 0) to this and every
# subsequent file.
# """
# pass
#
# def nopicture(self, args):
# """
# unpicture
# Remove all p
# """
# pass

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "mfbatch" name = "mfbatch"
version = "0.5.0" version = "0.5.1"
description = "MetaFlac batch editor" description = "MetaFlac batch editor"
authors = ["Jamie Hardt <jamiehardt@me.com>"] authors = ["Jamie Hardt <jamiehardt@me.com>"]
readme = "README.md" readme = "README.md"
@@ -13,6 +13,7 @@ classifiers = [
'Environment :: Console', 'Environment :: Console',
'License :: OSI Approved :: MIT License', 'License :: OSI Approved :: MIT License',
'Topic :: Multimedia :: Sound/Audio :: Editors', 'Topic :: Multimedia :: Sound/Audio :: Editors',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.10',