rekordbox-edit 0.4.0.dev40__tar.gz → 0.4.0.dev42__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/CHANGELOG.md +3 -1
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/PKG-INFO +1 -1
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/pyproject.toml +1 -1
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/args.py +71 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/convert.py +51 -18
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/edit.py +54 -18
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/uv.lock +1 -1
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.agent-style/RULES.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.agent-style/claude-code.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/commitizen-bump/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/install/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/lint/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/test/action.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/workflows/cd.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/workflows/ci.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/workflows/publish.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/workflows/release.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.gitignore +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.pre-commit-config.yaml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/AGENTS.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/CLAUDE.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/CONTRIBUTING.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/LICENSE +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/Makefile +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/README.md +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/codecov.yml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/_click.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/cli.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/search.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/display.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/logger.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/query.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/utils.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/renovate.json5 +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/ruff.toml +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/commands/__init__.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/commands/test_convert.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/commands/test_edit.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/commands/test_search.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/conftest.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/test_display.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/test_logger.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/test_query.py +0 -0
- {rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
## v0.4.0.
|
|
1
|
+
## v0.4.0.dev42 (2026-06-05)
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
- refactor(commands): group command-specific args into EditArgs and ConvertArgs dataclasses
|
|
5
|
+
- refactor(commands): group confirmation flags into ConfirmationArgs dataclass
|
|
4
6
|
- docs: update README.md
|
|
5
7
|
- refactor(query): group filter args into FilterArgs dataclass
|
|
6
8
|
- refactor(cli): extract convert-specific options into convert_click_options
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rekordbox-edit
|
|
3
|
-
Version: 0.4.0.
|
|
3
|
+
Version: 0.4.0.dev42
|
|
4
4
|
Summary: Tools for managing and modifying a RekordBox library en-masse
|
|
5
5
|
Project-URL: Homepage, https://github.com/jviall/rekordbox-edit
|
|
6
6
|
Project-URL: Repository, https://github.com/jviall/rekordbox-edit
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rekordbox-edit"
|
|
7
|
-
version = "0.4.0.
|
|
7
|
+
version = "0.4.0.dev42"
|
|
8
8
|
description = "Tools for managing and modifying a RekordBox library en-masse"
|
|
9
9
|
authors = [{ name = "James Viall", email= "jamesviall@pm.me"}]
|
|
10
10
|
license = "MIT"
|
|
@@ -52,3 +52,74 @@ def filter_args_from_kwargs(**kwargs) -> FilterArgs:
|
|
|
52
52
|
format=list(kwargs.get("format") or []),
|
|
53
53
|
match_all=bool(kwargs.get("match_all", False)),
|
|
54
54
|
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class ConfirmationArgs:
|
|
59
|
+
"""How the user gates a side effect before it lands.
|
|
60
|
+
|
|
61
|
+
`dry_run` skips the change entirely. `yes` skips confirmation and applies
|
|
62
|
+
the batch. `interactive` prompts per item. With all three false, the
|
|
63
|
+
caller is expected to prompt once for the batch.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
dry_run: bool = False
|
|
67
|
+
yes: bool = False
|
|
68
|
+
interactive: bool = False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def confirmation_args_from_kwargs(**kwargs) -> ConfirmationArgs:
|
|
72
|
+
"""Pack the flat Click kwargs for the `global_click_confirmations` group into a ConfirmationArgs."""
|
|
73
|
+
return ConfirmationArgs(
|
|
74
|
+
dry_run=bool(kwargs.get("dry_run", False)),
|
|
75
|
+
yes=bool(kwargs.get("yes", False)),
|
|
76
|
+
interactive=bool(kwargs.get("interactive", False)),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class EditArgs:
|
|
82
|
+
"""Edit-command inputs that describe what to change.
|
|
83
|
+
|
|
84
|
+
`field` names a column from `FIELD_COLUMNS` in `commands/edit.py`.
|
|
85
|
+
`match_pattern` is the optional substring to find within the current value;
|
|
86
|
+
when omitted, the whole value is replaced. `multi` allows the edit to
|
|
87
|
+
apply to more than one matched track.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
field: str
|
|
91
|
+
replace_value: str
|
|
92
|
+
match_pattern: str | None = None
|
|
93
|
+
multi: bool = False
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def edit_args_from_kwargs(**kwargs) -> EditArgs:
|
|
97
|
+
"""Pack the flat Click kwargs for the `edit_click_options` group plus `field` into an EditArgs."""
|
|
98
|
+
return EditArgs(
|
|
99
|
+
field=kwargs["field"],
|
|
100
|
+
replace_value=kwargs["replace_value"],
|
|
101
|
+
match_pattern=kwargs.get("match_pattern"),
|
|
102
|
+
multi=bool(kwargs.get("multi", False)),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class ConvertArgs:
|
|
108
|
+
"""Convert-command inputs that describe the output and conflict policy.
|
|
109
|
+
|
|
110
|
+
`delete` is tri-state: `None` defers to a per-format default in
|
|
111
|
+
`_convert`, while `True` / `False` are explicit.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
format_out: str
|
|
115
|
+
delete: bool | None = None
|
|
116
|
+
overwrite: bool = False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def convert_args_from_kwargs(**kwargs) -> ConvertArgs:
|
|
120
|
+
"""Pack the flat Click kwargs for the `convert_click_options` group into a ConvertArgs."""
|
|
121
|
+
return ConvertArgs(
|
|
122
|
+
format_out=kwargs["format_out"],
|
|
123
|
+
delete=kwargs.get("delete"),
|
|
124
|
+
overwrite=bool(kwargs.get("overwrite", False)),
|
|
125
|
+
)
|
{rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/convert.py
RENAMED
|
@@ -22,7 +22,14 @@ from rekordbox_edit._click import (
|
|
|
22
22
|
print_option,
|
|
23
23
|
track_ids_argument,
|
|
24
24
|
)
|
|
25
|
-
from rekordbox_edit.args import
|
|
25
|
+
from rekordbox_edit.args import (
|
|
26
|
+
ConfirmationArgs,
|
|
27
|
+
ConvertArgs,
|
|
28
|
+
FilterArgs,
|
|
29
|
+
confirmation_args_from_kwargs,
|
|
30
|
+
convert_args_from_kwargs,
|
|
31
|
+
filter_args_from_kwargs,
|
|
32
|
+
)
|
|
26
33
|
from rekordbox_edit.logger import get_debug_file_path, set_level
|
|
27
34
|
from rekordbox_edit.query import get_filtered_content
|
|
28
35
|
from rekordbox_edit.display import PrintableField, print_track_info
|
|
@@ -286,15 +293,57 @@ def convert_command(
|
|
|
286
293
|
|
|
287
294
|
Skips lossy formats and files already in the target format.
|
|
288
295
|
"""
|
|
296
|
+
filters = filter_args_from_kwargs(
|
|
297
|
+
track_id=track_id,
|
|
298
|
+
track_ids=track_ids,
|
|
299
|
+
playlist=playlist,
|
|
300
|
+
exact_playlist=exact_playlist,
|
|
301
|
+
album=album,
|
|
302
|
+
exact_album=exact_album,
|
|
303
|
+
artist=artist,
|
|
304
|
+
exact_artist=exact_artist,
|
|
305
|
+
title=title,
|
|
306
|
+
exact_title=exact_title,
|
|
307
|
+
path=path,
|
|
308
|
+
exact_path=exact_path,
|
|
309
|
+
format=format,
|
|
310
|
+
match_all=match_all,
|
|
311
|
+
)
|
|
312
|
+
confirmation = confirmation_args_from_kwargs(
|
|
313
|
+
dry_run=dry_run, yes=yes, interactive=interactive
|
|
314
|
+
)
|
|
315
|
+
convert_args = convert_args_from_kwargs(
|
|
316
|
+
format_out=format_out, delete=delete, overwrite=overwrite
|
|
317
|
+
)
|
|
318
|
+
_convert(filters, confirmation, convert_args, print_opt)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _convert(
|
|
322
|
+
filters: FilterArgs,
|
|
323
|
+
confirmation: ConfirmationArgs,
|
|
324
|
+
convert_args: ConvertArgs,
|
|
325
|
+
print_opt: PrintChoice | None,
|
|
326
|
+
) -> None:
|
|
327
|
+
"""Convert audio files for tracks matching `filters`."""
|
|
289
328
|
from rekordbox_edit.utils import ffmpeg_in_path, get_ffmpeg_directions
|
|
290
329
|
|
|
330
|
+
dry_run, yes, interactive = (
|
|
331
|
+
confirmation.dry_run,
|
|
332
|
+
confirmation.yes,
|
|
333
|
+
confirmation.interactive,
|
|
334
|
+
)
|
|
335
|
+
format_out, delete, overwrite = (
|
|
336
|
+
convert_args.format_out,
|
|
337
|
+
convert_args.delete,
|
|
338
|
+
convert_args.overwrite,
|
|
339
|
+
)
|
|
291
340
|
set_level(print_opt)
|
|
292
341
|
|
|
293
342
|
piped_stdin = not sys.stdin.isatty()
|
|
294
343
|
if piped_stdin:
|
|
295
344
|
stdin_data = sys.stdin.read().strip()
|
|
296
345
|
if stdin_data:
|
|
297
|
-
track_ids = list(track_ids
|
|
346
|
+
filters.track_ids = list(filters.track_ids) + stdin_data.split()
|
|
298
347
|
|
|
299
348
|
# Validate --print option requirements
|
|
300
349
|
scripting_mode = print_opt in (PrintChoice.IDS, PrintChoice.SILENT)
|
|
@@ -362,22 +411,6 @@ def convert_command(
|
|
|
362
411
|
logger.debug("Database connection established")
|
|
363
412
|
|
|
364
413
|
# === QUERY & FILTER ===
|
|
365
|
-
filters = filter_args_from_kwargs(
|
|
366
|
-
track_id=track_id,
|
|
367
|
-
track_ids=track_ids,
|
|
368
|
-
playlist=playlist,
|
|
369
|
-
exact_playlist=exact_playlist,
|
|
370
|
-
album=album,
|
|
371
|
-
exact_album=exact_album,
|
|
372
|
-
artist=artist,
|
|
373
|
-
exact_artist=exact_artist,
|
|
374
|
-
title=title,
|
|
375
|
-
exact_title=exact_title,
|
|
376
|
-
path=path,
|
|
377
|
-
exact_path=exact_path,
|
|
378
|
-
format=format,
|
|
379
|
-
match_all=match_all,
|
|
380
|
-
)
|
|
381
414
|
result = get_filtered_content(db, filters)
|
|
382
415
|
filtered_content = result.scalars().all()
|
|
383
416
|
logger.debug(f"Query returned {len(filtered_content)} tracks")
|
|
@@ -16,7 +16,14 @@ from rekordbox_edit._click import (
|
|
|
16
16
|
print_option,
|
|
17
17
|
track_ids_argument,
|
|
18
18
|
)
|
|
19
|
-
from rekordbox_edit.args import
|
|
19
|
+
from rekordbox_edit.args import (
|
|
20
|
+
ConfirmationArgs,
|
|
21
|
+
EditArgs,
|
|
22
|
+
FilterArgs,
|
|
23
|
+
confirmation_args_from_kwargs,
|
|
24
|
+
edit_args_from_kwargs,
|
|
25
|
+
filter_args_from_kwargs,
|
|
26
|
+
)
|
|
20
27
|
from rekordbox_edit.logger import get_debug_file_path, set_level
|
|
21
28
|
from rekordbox_edit.query import get_filtered_content
|
|
22
29
|
from rekordbox_edit.display import PrintableField, print_track_info
|
|
@@ -84,7 +91,52 @@ def edit_command(
|
|
|
84
91
|
print_opt: PrintChoice | None,
|
|
85
92
|
):
|
|
86
93
|
"""Edit a metadata field on tracks in the RekordBox database."""
|
|
94
|
+
filters = filter_args_from_kwargs(
|
|
95
|
+
track_id=track_id,
|
|
96
|
+
track_ids=track_ids,
|
|
97
|
+
playlist=playlist,
|
|
98
|
+
exact_playlist=exact_playlist,
|
|
99
|
+
album=album,
|
|
100
|
+
exact_album=exact_album,
|
|
101
|
+
artist=artist,
|
|
102
|
+
exact_artist=exact_artist,
|
|
103
|
+
title=title,
|
|
104
|
+
exact_title=exact_title,
|
|
105
|
+
path=path,
|
|
106
|
+
exact_path=exact_path,
|
|
107
|
+
format=format,
|
|
108
|
+
match_all=match_all,
|
|
109
|
+
)
|
|
110
|
+
confirmation = confirmation_args_from_kwargs(
|
|
111
|
+
dry_run=dry_run, yes=yes, interactive=interactive
|
|
112
|
+
)
|
|
113
|
+
edit_args = edit_args_from_kwargs(
|
|
114
|
+
field=field,
|
|
115
|
+
replace_value=replace_value,
|
|
116
|
+
match_pattern=match_pattern,
|
|
117
|
+
multi=multi,
|
|
118
|
+
)
|
|
119
|
+
_edit(filters, confirmation, edit_args, print_opt)
|
|
120
|
+
|
|
87
121
|
|
|
122
|
+
def _edit(
|
|
123
|
+
filters: FilterArgs,
|
|
124
|
+
confirmation: ConfirmationArgs,
|
|
125
|
+
edit_args: EditArgs,
|
|
126
|
+
print_opt: PrintChoice | None,
|
|
127
|
+
) -> None:
|
|
128
|
+
"""Apply a field edit to tracks matching `filters`."""
|
|
129
|
+
dry_run, yes, interactive = (
|
|
130
|
+
confirmation.dry_run,
|
|
131
|
+
confirmation.yes,
|
|
132
|
+
confirmation.interactive,
|
|
133
|
+
)
|
|
134
|
+
field, replace_value, match_pattern, multi = (
|
|
135
|
+
edit_args.field,
|
|
136
|
+
edit_args.replace_value,
|
|
137
|
+
edit_args.match_pattern,
|
|
138
|
+
edit_args.multi,
|
|
139
|
+
)
|
|
88
140
|
set_level(print_opt)
|
|
89
141
|
|
|
90
142
|
piped_stdin = False
|
|
@@ -92,7 +144,7 @@ def edit_command(
|
|
|
92
144
|
stdin_data = sys.stdin.read().strip()
|
|
93
145
|
if stdin_data:
|
|
94
146
|
piped_stdin = True
|
|
95
|
-
track_ids = list(track_ids
|
|
147
|
+
filters.track_ids = list(filters.track_ids) + stdin_data.split()
|
|
96
148
|
|
|
97
149
|
scripting_mode = print_opt in (PrintChoice.IDS, PrintChoice.SILENT)
|
|
98
150
|
if scripting_mode and not (dry_run or yes):
|
|
@@ -107,22 +159,6 @@ def edit_command(
|
|
|
107
159
|
if not db.session:
|
|
108
160
|
raise RuntimeError("Failed to connect to Rekordbox Database: No Session.")
|
|
109
161
|
|
|
110
|
-
filters = filter_args_from_kwargs(
|
|
111
|
-
track_id=track_id,
|
|
112
|
-
track_ids=track_ids,
|
|
113
|
-
playlist=playlist,
|
|
114
|
-
exact_playlist=exact_playlist,
|
|
115
|
-
album=album,
|
|
116
|
-
exact_album=exact_album,
|
|
117
|
-
artist=artist,
|
|
118
|
-
exact_artist=exact_artist,
|
|
119
|
-
title=title,
|
|
120
|
-
exact_title=exact_title,
|
|
121
|
-
path=path,
|
|
122
|
-
exact_path=exact_path,
|
|
123
|
-
format=format,
|
|
124
|
-
match_all=match_all,
|
|
125
|
-
)
|
|
126
162
|
result = get_filtered_content(db, filters)
|
|
127
163
|
tracks = result.scalars().all()
|
|
128
164
|
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/commitizen-bump/action.yml
RENAMED
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/.github/actions/install/action.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.4.0.dev40 → rekordbox_edit-0.4.0.dev42}/rekordbox_edit/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|