rekordbox-edit 0.6.0.dev29__tar.gz → 0.6.0.dev40__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.
Files changed (95) hide show
  1. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.gitignore +3 -0
  2. rekordbox_edit-0.6.0.dev40/.readthedocs.yaml +22 -0
  3. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/CHANGELOG.md +14 -3
  4. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/Makefile +7 -1
  5. rekordbox_edit-0.6.0.dev40/PKG-INFO +109 -0
  6. rekordbox_edit-0.6.0.dev40/README.md +89 -0
  7. rekordbox_edit-0.6.0.dev40/docs/api.md +28 -0
  8. rekordbox_edit-0.6.0.dev40/docs/commands/convert.md +46 -0
  9. rekordbox_edit-0.6.0.dev40/docs/commands/edit.md +48 -0
  10. rekordbox_edit-0.6.0.dev40/docs/commands/search.md +29 -0
  11. rekordbox_edit-0.6.0.dev40/docs/filtering.md +108 -0
  12. rekordbox_edit-0.6.0.dev40/docs/index.md +1 -0
  13. rekordbox_edit-0.6.0.dev40/mkdocs.yml +54 -0
  14. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/pyproject.toml +7 -1
  15. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/_click.py +12 -0
  16. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/_utils.py +14 -1
  17. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/convert.py +2 -1
  18. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/edit.py +2 -1
  19. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/search.py +2 -1
  20. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/models.py +9 -1
  21. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/query.py +26 -0
  22. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/test_search.py +48 -0
  23. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/test_utils.py +16 -0
  24. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/test_models.py +28 -0
  25. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/test_query.py +49 -0
  26. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/uv.lock +303 -1
  27. rekordbox_edit-0.6.0.dev29/PKG-INFO +0 -262
  28. rekordbox_edit-0.6.0.dev29/README.md +0 -242
  29. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.agent-style/RULES.md +0 -0
  30. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.agent-style/claude-code.md +0 -0
  31. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/build-release-notes/action.yml +0 -0
  32. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/commitizen-bump/action.yml +0 -0
  33. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
  34. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/e2e/action.yml +0 -0
  35. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/install/action.yml +0 -0
  36. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/lint/action.yml +0 -0
  37. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/actions/test/action.yml +0 -0
  38. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/workflows/cd.yml +0 -0
  39. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/workflows/ci.yml +0 -0
  40. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/workflows/publish.yml +0 -0
  41. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.github/workflows/release.yml +0 -0
  42. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.pre-commit-config.yaml +0 -0
  43. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/.python-version +0 -0
  44. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/AGENTS.md +0 -0
  45. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/CLAUDE.md +0 -0
  46. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/CONTRIBUTING.md +0 -0
  47. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/LICENSE +0 -0
  48. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/codecov.yml +0 -0
  49. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/docker-compose.yml +0 -0
  50. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/__init__.py +0 -0
  51. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/api/__init__.py +0 -0
  52. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/api/_utils.py +0 -0
  53. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/api/convert.py +0 -0
  54. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/api/edit.py +0 -0
  55. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/api/search.py +0 -0
  56. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/__init__.py +0 -0
  57. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/cli/main.py +0 -0
  58. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/display.py +0 -0
  59. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/logger.py +0 -0
  60. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/rekordbox_edit/utils.py +0 -0
  61. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/renovate.json5 +0 -0
  62. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/ruff.toml +0 -0
  63. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/__init__.py +0 -0
  64. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/api/__init__.py +0 -0
  65. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/api/test_convert.py +0 -0
  66. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/api/test_edit.py +0 -0
  67. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/api/test_search.py +0 -0
  68. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/api/test_utils.py +0 -0
  69. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/__init__.py +0 -0
  70. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/test_convert.py +0 -0
  71. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/test_edit.py +0 -0
  72. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/cli/test_main.py +0 -0
  73. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/conftest.py +0 -0
  74. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/Dockerfile +0 -0
  75. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/__init__.py +0 -0
  76. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[macos].json +0 -0
  77. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[windows].json +0 -0
  78. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/__snapshots__/test_journey.ambr +0 -0
  79. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/conftest.py +0 -0
  80. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/01-flac-44_1k-16b.flac +0 -0
  81. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/02-flac-96k-24b.flac +0 -0
  82. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/03-alac-44_1k-16b.m4a +0 -0
  83. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/04-alac-48k-24b.m4a +0 -0
  84. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/05-aiff-44_1k-16b.aiff +0 -0
  85. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/06-wav-96k-24b.wav +0 -0
  86. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/07-mp3-44_1k-320cbr.mp3 +0 -0
  87. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/08-mp3-44_1k-v0vbr.mp3 +0 -0
  88. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/09-aac-44_1k-256kbps.m4a +0 -0
  89. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/audio/10-/303/274/303/261/303/256c/303/266d/303/251-flac-44_1k-16b.flac" +0 -0
  90. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/macos/master.6.8.6.db +0 -0
  91. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/fixtures/windows/master.6.8.6.db +0 -0
  92. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/e2e/test_journey.py +0 -0
  93. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/test_display.py +0 -0
  94. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/test_logger.py +0 -0
  95. {rekordbox_edit-0.6.0.dev29 → rekordbox_edit-0.6.0.dev40}/tests/test_utils.py +0 -0
@@ -49,3 +49,6 @@ Thumbs.db
49
49
 
50
50
  .claude
51
51
  docs/superpowers
52
+
53
+ # MkDocs build output
54
+ site/
@@ -0,0 +1,22 @@
1
+ # Read the Docs configuration file
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
+
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.13"
10
+ jobs:
11
+ create_environment:
12
+ - asdf plugin add uv
13
+ - asdf install uv latest
14
+ - asdf global uv latest
15
+ install:
16
+ - uv sync --frozen --group docs
17
+ build:
18
+ html:
19
+ - uv run --group docs mkdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html
20
+
21
+ mkdocs:
22
+ configuration: mkdocs.yml
@@ -1,6 +1,17 @@
1
- ## v0.6.0.dev29 (2026-06-10)
2
-
3
-
1
+ ## v0.6.0.dev40 (2026-06-11)
2
+
3
+
4
+ - docs: add api reference page
5
+ - docs: add convert command page
6
+ - docs: add edit command page
7
+ - docs: add search command page
8
+ - docs: add filtering page
9
+ - docs: configure read the docs build
10
+ - docs: scaffold mkdocs material site
11
+ - docs: trim README to overview and quick start
12
+ - chore: add docs dependency group
13
+ - feat: add --last filter to return only the last N results
14
+ - feat: add --first filter to return only the first N results
4
15
  - test(e2e): update windows snapshot with unicode representation
5
16
  - test(e2e): force utf-8 encoding of stdout
6
17
  - test(e2e): align TZ to UTC
@@ -1,4 +1,4 @@
1
- .PHONY: test test-e2e test-e2e-docker test-e2e-snapshot-update coverage lint format typecheck install-hooks run-hooks
1
+ .PHONY: test test-e2e test-e2e-docker test-e2e-snapshot-update coverage lint format typecheck install-hooks run-hooks docs docs-build
2
2
 
3
3
  test:
4
4
  uv run pytest tests
@@ -34,3 +34,9 @@ install-hooks:
34
34
 
35
35
  run-hooks:
36
36
  uv run pre-commit run --all-files
37
+
38
+ docs:
39
+ uv run --group docs mkdocs serve
40
+
41
+ docs-build:
42
+ uv run --group docs mkdocs build --strict
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: rekordbox-edit
3
+ Version: 0.6.0.dev40
4
+ Summary: Tools for managing and modifying a RekordBox library en-masse
5
+ Project-URL: Homepage, https://github.com/jviall/rekordbox-edit
6
+ Project-URL: Repository, https://github.com/jviall/rekordbox-edit
7
+ Project-URL: Issues, https://github.com/jviall/rekordbox-edit/issues
8
+ Author-email: James Viall <jamesviall@pm.me>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: bulk,convert,database,dj,edit,music,rekordbox
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: click<=9.0.0,>=8.0.0
14
+ Requires-Dist: ffmpeg-python>=0.2.0
15
+ Requires-Dist: platformdirs<5.0.0,>=4.3.8
16
+ Requires-Dist: pydantic<3,>=2.0
17
+ Requires-Dist: pyrekordbox==0.4.4
18
+ Requires-Dist: rich<15.1.0,>=15.0.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # rekordbox-edit
22
+
23
+ [![Build](https://img.shields.io/github/actions/workflow/status/jviall/rekordbox-edit/cd.yml?branch=main&logo=github&style=flat)](https://github.com/jviall/rekordbox-edit/blob/main/.github/workflows/cd.yml)
24
+ [![Coverage](https://codecov.io/gh/jviall/rekordbox-edit/graph/badge.svg?token=ILZ1XHE61V)](https://codecov.io/gh/jviall/rekordbox-edit)
25
+ [![Version](https://img.shields.io/pypi/v/rekordbox-edit?style=flat)](https://pypi.org/project/rekordbox-edit/)
26
+ [![Platforms](https://img.shields.io/badge/platform-win%20%7C%20osx-blue?style=flat)](https://pypi.org/project/rekordbox-edit/)
27
+ [![License](https://img.shields.io/pypi/l/rekordbox-edit?color=lightgrey)](https://github.com/jviall/rekordbox-edit/blob/main/LICENSE)
28
+
29
+ A command-line tool for bulk operations on your Rekordbox library. Search tracks, edit metadata, and convert audio formats — updating your database while preserving all your cues, analysis, and metadata.
30
+
31
+ > [!CAUTION]
32
+ > This tool can modify your Rekordbox database and audio files. Always back up your data first.
33
+ > No warranty is provided--you assume all risk and liability of data loss in using this.
34
+ > See [Safety and Best Practices](#safety-and-best-practices)
35
+
36
+ **Full documentation: [rekordbox-edit.readthedocs.io](https://rekordbox-edit.readthedocs.io/)**
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install rekordbox-edit
42
+ ```
43
+
44
+ **Requirements:**
45
+
46
+ - Python 3.11+
47
+ - FFmpeg (for audio conversion)
48
+
49
+ ## Quick Start
50
+
51
+ Search your library:
52
+
53
+ ```bash
54
+ rbe search --artist "Daft Punk" --format flac
55
+ rbe search --playlist "House Favorites"
56
+ ```
57
+
58
+ Edit track metadata:
59
+
60
+ ```bash
61
+ # Fix a typo across every matching title (previews and confirms first)
62
+ rbe edit --title "Teh" Title --match "Teh" --replace "The" --multi
63
+ ```
64
+
65
+ Convert audio files:
66
+
67
+ ```bash
68
+ # Preview what would be converted
69
+ rbe convert --artist "Daft Punk" --dry-run
70
+
71
+ # Convert all FLAC or WAV files to AIFF (default output format)
72
+ rbe convert --format flac --format wav --yes
73
+ ```
74
+
75
+ See the [documentation](https://rekordbox-edit.readthedocs.io/) for every command, the full filtering language, and scripting recipes.
76
+
77
+ ## Safety and Best Practices
78
+
79
+ **Before using this tool:**
80
+
81
+ 1. **Back up your Rekordbox database**
82
+
83
+ Rekordbox already keeps multiple backups. But every time you close it, it creates a fresh one and deletes the oldest, so repetitive exits will quickly make those backups fairly useless.
84
+
85
+ You should make manual copies of RB's database backups before using this. You can usually find them in `~/Library/Pioneer/rekordbox/` on macOS or `%APPDATA%\Pioneer\rekordbox\` on Windows.
86
+
87
+ 2. **Back up your music library**
88
+
89
+ If you don't have a back up already it's a very worthwhile investment, even if you don't plan to use this tool! Find yourself a cheap external drive, you won't regret it.
90
+
91
+ And generally limit the potential impact of a mistake by using filters to target a few tracks at a time e.g. `--artist "Crazy Frog" --first 5` before targeting a larger set, and always run with `--dry-run` first.
92
+
93
+ ## AI Usage
94
+
95
+ I believe it's important to be aware of and to disclose AI usage. In many ways it's being forced upon us without us having much choice in the matter, and it's a gross and oppressive experience. While it has lots of potential to benefit the common good, mostly it's only furthered capitalist greed.
96
+
97
+ I'm mostly attempting to thoughtfully disclose that generative AI _has_ been a significant tool in building out this project. I don't personally enjoy too much coding in my personal time, but I feel passionate about making `rekordbox-edit`--AI has admittedly helped me bridge that gap between my capacity and my vision. I'm a career professional software engineer who takes pride in their work, and I don't want to produce a vibe coded mess any more than you want to experience it. Please validate the quality of this project yourself--at the end of the day it's just code written by some stranger.
98
+
99
+ If it's any consolation, my main test subject has been my own 10,000+ track RekordBox library--a risk I do not take lightly!
100
+
101
+ ## Credits
102
+
103
+ This project exists thanks to [@dylanjones](https://github.com/dylanjones), the creator of [pyrekordbox](https://github.com/dylanljones/pyrekordbox), which provides the Python API for Rekordbox databases.
104
+
105
+ I built this tool to help correct my own bad habits and missteps in managing and organizing my rekordbox library. If it helps you too, great! If you find issues or have ideas, contributions are welcome.
106
+
107
+ ## Contributing
108
+
109
+ See [CONTRIBUTING.md](https://github.com/jviall/rekordbox-edit/blob/main/CONTRIBUTING.md) for development setup, testing, and contribution guidelines.
@@ -0,0 +1,89 @@
1
+ # rekordbox-edit
2
+
3
+ [![Build](https://img.shields.io/github/actions/workflow/status/jviall/rekordbox-edit/cd.yml?branch=main&logo=github&style=flat)](https://github.com/jviall/rekordbox-edit/blob/main/.github/workflows/cd.yml)
4
+ [![Coverage](https://codecov.io/gh/jviall/rekordbox-edit/graph/badge.svg?token=ILZ1XHE61V)](https://codecov.io/gh/jviall/rekordbox-edit)
5
+ [![Version](https://img.shields.io/pypi/v/rekordbox-edit?style=flat)](https://pypi.org/project/rekordbox-edit/)
6
+ [![Platforms](https://img.shields.io/badge/platform-win%20%7C%20osx-blue?style=flat)](https://pypi.org/project/rekordbox-edit/)
7
+ [![License](https://img.shields.io/pypi/l/rekordbox-edit?color=lightgrey)](https://github.com/jviall/rekordbox-edit/blob/main/LICENSE)
8
+
9
+ A command-line tool for bulk operations on your Rekordbox library. Search tracks, edit metadata, and convert audio formats — updating your database while preserving all your cues, analysis, and metadata.
10
+
11
+ > [!CAUTION]
12
+ > This tool can modify your Rekordbox database and audio files. Always back up your data first.
13
+ > No warranty is provided--you assume all risk and liability of data loss in using this.
14
+ > See [Safety and Best Practices](#safety-and-best-practices)
15
+
16
+ **Full documentation: [rekordbox-edit.readthedocs.io](https://rekordbox-edit.readthedocs.io/)**
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install rekordbox-edit
22
+ ```
23
+
24
+ **Requirements:**
25
+
26
+ - Python 3.11+
27
+ - FFmpeg (for audio conversion)
28
+
29
+ ## Quick Start
30
+
31
+ Search your library:
32
+
33
+ ```bash
34
+ rbe search --artist "Daft Punk" --format flac
35
+ rbe search --playlist "House Favorites"
36
+ ```
37
+
38
+ Edit track metadata:
39
+
40
+ ```bash
41
+ # Fix a typo across every matching title (previews and confirms first)
42
+ rbe edit --title "Teh" Title --match "Teh" --replace "The" --multi
43
+ ```
44
+
45
+ Convert audio files:
46
+
47
+ ```bash
48
+ # Preview what would be converted
49
+ rbe convert --artist "Daft Punk" --dry-run
50
+
51
+ # Convert all FLAC or WAV files to AIFF (default output format)
52
+ rbe convert --format flac --format wav --yes
53
+ ```
54
+
55
+ See the [documentation](https://rekordbox-edit.readthedocs.io/) for every command, the full filtering language, and scripting recipes.
56
+
57
+ ## Safety and Best Practices
58
+
59
+ **Before using this tool:**
60
+
61
+ 1. **Back up your Rekordbox database**
62
+
63
+ Rekordbox already keeps multiple backups. But every time you close it, it creates a fresh one and deletes the oldest, so repetitive exits will quickly make those backups fairly useless.
64
+
65
+ You should make manual copies of RB's database backups before using this. You can usually find them in `~/Library/Pioneer/rekordbox/` on macOS or `%APPDATA%\Pioneer\rekordbox\` on Windows.
66
+
67
+ 2. **Back up your music library**
68
+
69
+ If you don't have a back up already it's a very worthwhile investment, even if you don't plan to use this tool! Find yourself a cheap external drive, you won't regret it.
70
+
71
+ And generally limit the potential impact of a mistake by using filters to target a few tracks at a time e.g. `--artist "Crazy Frog" --first 5` before targeting a larger set, and always run with `--dry-run` first.
72
+
73
+ ## AI Usage
74
+
75
+ I believe it's important to be aware of and to disclose AI usage. In many ways it's being forced upon us without us having much choice in the matter, and it's a gross and oppressive experience. While it has lots of potential to benefit the common good, mostly it's only furthered capitalist greed.
76
+
77
+ I'm mostly attempting to thoughtfully disclose that generative AI _has_ been a significant tool in building out this project. I don't personally enjoy too much coding in my personal time, but I feel passionate about making `rekordbox-edit`--AI has admittedly helped me bridge that gap between my capacity and my vision. I'm a career professional software engineer who takes pride in their work, and I don't want to produce a vibe coded mess any more than you want to experience it. Please validate the quality of this project yourself--at the end of the day it's just code written by some stranger.
78
+
79
+ If it's any consolation, my main test subject has been my own 10,000+ track RekordBox library--a risk I do not take lightly!
80
+
81
+ ## Credits
82
+
83
+ This project exists thanks to [@dylanjones](https://github.com/dylanjones), the creator of [pyrekordbox](https://github.com/dylanljones/pyrekordbox), which provides the Python API for Rekordbox databases.
84
+
85
+ I built this tool to help correct my own bad habits and missteps in managing and organizing my rekordbox library. If it helps you too, great! If you find issues or have ideas, contributions are welcome.
86
+
87
+ ## Contributing
88
+
89
+ See [CONTRIBUTING.md](https://github.com/jviall/rekordbox-edit/blob/main/CONTRIBUTING.md) for development setup, testing, and contribution guidelines.
@@ -0,0 +1,28 @@
1
+ # API Reference
2
+
3
+ Everything the CLI does is available from Python. The public surface is the three functions in `rekordbox_edit.api` and the Pydantic models in `rekordbox_edit.models` that describe their inputs and outputs.
4
+
5
+ ```python
6
+ from pyrekordbox import Rekordbox6Database
7
+ from rekordbox_edit.api import search
8
+ from rekordbox_edit.models import SearchArgs
9
+
10
+ db = Rekordbox6Database()
11
+ response = search(db, SearchArgs(artist=["Daft Punk"], format=["flac"], match_all=True))
12
+ for track in response.tracks:
13
+ print(track.ID, track.Title)
14
+ ```
15
+
16
+ `--print json` on any CLI command emits exactly these response envelopes, so the models below also document the JSON you get when scripting.
17
+
18
+ ## Functions
19
+
20
+ ::: rekordbox_edit.api.search
21
+
22
+ ::: rekordbox_edit.api.edit
23
+
24
+ ::: rekordbox_edit.api.convert
25
+
26
+ ## Models
27
+
28
+ ::: rekordbox_edit.models
@@ -0,0 +1,46 @@
1
+ # convert
2
+
3
+ Convert audio files between formats and update the Rekordbox database to point at the new files. Your cues, analysis, beatgrids, and all metadata are preserved.
4
+
5
+ ## Supported Formats
6
+
7
+ - **Input:** FLAC, AIFF, WAV (lossless only — lossy sources are skipped)
8
+ - **Output:** AIFF (default), FLAC, WAV, ALAC, or MP3 (320kbps CBR)
9
+
10
+ Tracks already in the target format are skipped, as are tracks whose output file already exists (override with `--overwrite`).
11
+
12
+ ## Originals: Delete or Keep
13
+
14
+ After a successful conversion the original file is **deleted** for lossless output (you can always convert back) and **kept** for MP3 output (the quality loss is one-way). Override either default with `--delete` or `--keep`.
15
+
16
+ ## Examples
17
+
18
+ ```bash
19
+ # Preview conversion
20
+ rbe convert --format-out aiff --format flac --dry-run
21
+
22
+ # Convert and skip confirmation
23
+ rbe convert --format-out wav --artist "Burial" --yes
24
+
25
+ # Convert to MP3 but delete originals
26
+ rbe convert --format-out mp3 --playlist "Export" --yes --delete
27
+
28
+ # Keep originals when converting to AIFF
29
+ rbe convert --format-out aiff --format flac --yes --keep
30
+
31
+ # Get just the IDs of files that would be converted
32
+ rbe convert --format-out aiff --format flac --print ids --dry-run
33
+
34
+ # Convert everything a search finds
35
+ rbe search --artist "Lauryn Hill" --print ids | rbe convert --yes
36
+ ```
37
+
38
+ `--interactive` confirms each file individually; like `edit`, converting while Rekordbox is open triggers a warning (or a refusal in scripting modes). See [Filtering](../filtering.md) for the full filter language.
39
+
40
+ ## Reference
41
+
42
+ ::: mkdocs-click
43
+ :module: rekordbox_edit.cli.convert
44
+ :command: convert_command
45
+ :prog_name: rbe convert
46
+ :depth: 1
@@ -0,0 +1,48 @@
1
+ # edit
2
+
3
+ Bulk-edit a metadata field on tracks in your Rekordbox database.
4
+
5
+ ```bash
6
+ rbe edit [OPTIONS] [TRACK-IDS]... FIELD
7
+ ```
8
+
9
+ `FIELD` names the metadata field to change. Currently `Title` is the only editable field; more are planned.
10
+
11
+ `--replace` supplies the new value. On its own it overwrites the whole field; add `--match PATTERN` to find that literal text within the field and replace only that portion:
12
+
13
+ ```bash
14
+ # Rename one track outright
15
+ rbe edit --exact-title "Untitled 3" Title --replace "Acid Rain"
16
+
17
+ # Fix a typo across many titles (substring replacement)
18
+ rbe edit --title "Teh" Title --match "Teh" --replace "The" --multi
19
+ ```
20
+
21
+ ## Safety Rails
22
+
23
+ - **Preview and confirm by default.** Without flags, `edit` shows every planned change and asks once before applying. `--interactive` confirms each track individually; `--dry-run` previews without writing; `--yes` skips the prompt.
24
+ - **Single-track by default.** When filters match more than one track, `edit` refuses unless you pass `--multi`. This keeps a too-broad filter from rewriting your whole library.
25
+ - **Rekordbox running:** editing while Rekordbox is open risks conflicts, so `edit` warns (or refuses, in scripting modes).
26
+
27
+ ## Examples
28
+
29
+ ```bash
30
+ # Preview a cleanup without touching the database
31
+ rbe edit --title "(Original Mix)" Title --match " (Original Mix)" --replace "" --multi --dry-run
32
+
33
+ # Apply it, confirming each track
34
+ rbe edit --title "(Original Mix)" Title --match " (Original Mix)" --replace "" --multi --interactive
35
+
36
+ # Pipe a search result in and edit those exact tracks
37
+ rbe search --playlist "Mislabeled" --print ids | rbe edit Title --match " " --replace " " --multi --yes
38
+ ```
39
+
40
+ See [Filtering](../filtering.md) for the full filter language.
41
+
42
+ ## Reference
43
+
44
+ ::: mkdocs-click
45
+ :module: rekordbox_edit.cli.edit
46
+ :command: edit_command
47
+ :prog_name: rbe edit
48
+ :depth: 1
@@ -0,0 +1,29 @@
1
+ # search
2
+
3
+ Find and display tracks in your Rekordbox database. `search` is read-only: it never modifies the database or your files, which makes it the safe way to rehearse a [filter](../filtering.md) before handing it to `edit` or `convert`.
4
+
5
+ ## Examples
6
+
7
+ ```bash
8
+ # Show all FLAC tracks by an artist
9
+ rbe search --artist "Aphex Twin" --format flac
10
+
11
+ # Get all the track IDs in a playlist
12
+ rbe search --playlist "Techno" --print ids
13
+
14
+ # Find tracks matching ALL filters (AND logic)
15
+ rbe search --artist "Burial" --album "Untrue" --match-all
16
+
17
+ # Feed results to another command
18
+ rbe search --artist "Lauryn Hill" --print ids | rbe convert --yes
19
+ ```
20
+
21
+ See [Filtering](../filtering.md) for the full filter language and piping recipes.
22
+
23
+ ## Reference
24
+
25
+ ::: mkdocs-click
26
+ :module: rekordbox_edit.cli.search
27
+ :command: search_command
28
+ :prog_name: rbe search
29
+ :depth: 1
@@ -0,0 +1,108 @@
1
+ # Filtering
2
+
3
+ Every command (`search`, `edit`, `convert`) selects tracks with the same filter options. The filters decide *which* tracks a command sees; the command's own options decide what happens to them.
4
+
5
+ ## Filter Options
6
+
7
+ Repeating a filter, or combining different filters, matches tracks that satisfy *any* of them (OR logic). Pass `--match-all` to require *every* filter to match (AND logic).
8
+
9
+ | Option | Matches tracks whose... |
10
+ | --- | --- |
11
+ | `--track-id ID` | database track ID equals `ID` |
12
+ | `--title TEXT` | title contains `TEXT` |
13
+ | `--exact-title TEXT` | title is exactly `TEXT` |
14
+ | `--artist TEXT` | artist name contains `TEXT` |
15
+ | `--exact-artist TEXT` | artist name is exactly `TEXT` |
16
+ | `--album TEXT` | album name contains `TEXT` |
17
+ | `--exact-album TEXT` | album name is exactly `TEXT` |
18
+ | `--playlist TEXT` | playlist name contains `TEXT` |
19
+ | `--exact-playlist TEXT` | playlist name is exactly `TEXT` |
20
+ | `--format FMT` | file format is `FMT` (`mp3`, `flac`, `aiff`, `wav`, `m4a`) |
21
+ | `--path TEXT` | file path contains `TEXT` (matched against the folder path, filename, or both) |
22
+ | `--exact-path TEXT` | file path is exactly `TEXT` (resolved to an absolute path before matching) |
23
+
24
+ **Examples:**
25
+
26
+ ```bash
27
+ # Tracks by either artist (OR)
28
+ rbe search --artist "Daft Punk" --artist "Justice"
29
+
30
+ # Tracks matching artist AND format
31
+ rbe search --artist "Aphex Twin" --format flac --match-all
32
+
33
+ # All the songs in this playlist
34
+ rbe search --exact-playlist "Main Room 2024"
35
+
36
+ # All the songs in all my "house" or "disco" playlists
37
+ rbe search --playlist "house" --playlist "disco"
38
+
39
+ # All the songs in my library that aren't in any playlist
40
+ rbe search --playlist ""
41
+
42
+ # Tracks whose path contains a folder or filename substring
43
+ rbe search --path "Favorites/" --path "track.wav"
44
+
45
+ # The track at an exact location
46
+ rbe search --exact-path "/Users/djmustard/Music/banger.mp3"
47
+ ```
48
+
49
+ ## Limiting Results
50
+
51
+ - `--first N`: return only the first N results
52
+ - `--last N`: return only the last N results
53
+
54
+ The two are mutually exclusive. They make a great blast radius limiter while you refine a filter: `rbe convert --artist "Crazy Frog" --first 5 --dry-run`.
55
+
56
+ ## Track ID Arguments
57
+
58
+ Any positional argument that is not a defined option is interpreted as one or more track IDs:
59
+
60
+ ```bash
61
+ rbe search 12345 67890
62
+ ```
63
+
64
+ Track IDs can also arrive on stdin (see [Scripting and Piping](#scripting-and-piping)). Piped IDs require `--yes` or `--dry-run`, since prompting would interrupt a pipeline.
65
+
66
+ ## Output Levels
67
+
68
+ All commands take `--print [silent|ids|info|debug|json]`:
69
+
70
+ - `info` (default): human-readable output
71
+ - `debug`: adds application state detail; debug logs for every run are also written to a log file (the path is shown in `--help`)
72
+ - `silent`: no output
73
+ - `ids`: print only the matching track IDs, space-separated — designed for piping
74
+ - `json`: dump the full response envelope as JSON — a list of [`Track`][rekordbox_edit.models.Track] records plus a result summary (see the response models in the [API Reference](api.md))
75
+
76
+ !!! note
77
+
78
+ `silent`, `ids`, and `json` exist for scripting, so they require `--yes` or `--dry-run`: an interactive confirmation prompt would contradict them.
79
+
80
+ ## Scripting and Piping
81
+
82
+ `--print ids` output feeds straight into another command's track-ID arguments:
83
+
84
+ ```bash
85
+ # Convert all of the items found by the initial search command
86
+ rbe search --artist "Lauryn Hill" --print ids | rbe convert --yes
87
+ ```
88
+
89
+ Piping composes OR and AND logic that a single command cannot express:
90
+
91
+ **AND-narrowing** — pipe a broad OR result into a second command with `--match-all` to intersect:
92
+
93
+ ```bash
94
+ # (Daft Punk OR Justice) AND flac
95
+ rbe search --artist "Daft Punk" --artist "Justice" --print ids \
96
+ | rbe search --format flac --match-all
97
+ ```
98
+
99
+ **OR between AND-groups** — merge results from two commands using a subshell:
100
+
101
+ ```bash
102
+ # (Daft Punk AND flac) OR (Justice AND aiff)
103
+ { rbe search --artist "Daft Punk" --format flac --match-all --print ids; \
104
+ rbe search --artist "Justice" --format aiff --match-all --print ids; } \
105
+ | rbe convert --format-out mp3 --dry-run
106
+ ```
107
+
108
+ For richer pipelines, `--print json` emits the same selection as structured data for `jq` or a Python script.
@@ -0,0 +1 @@
1
+ --8<-- "README.md"
@@ -0,0 +1,54 @@
1
+ site_name: rekordbox-edit
2
+ site_description: Tools for managing and modifying a RekordBox library en-masse
3
+ site_url: https://rekordbox-edit.readthedocs.io/
4
+ repo_url: https://github.com/jviall/rekordbox-edit
5
+ repo_name: jviall/rekordbox-edit
6
+
7
+ exclude_docs: |
8
+ superpowers/
9
+
10
+ theme:
11
+ name: material
12
+ palette:
13
+ - media: "(prefers-color-scheme: light)"
14
+ scheme: default
15
+ toggle:
16
+ icon: material/brightness-7
17
+ name: Switch to dark mode
18
+ - media: "(prefers-color-scheme: dark)"
19
+ scheme: slate
20
+ toggle:
21
+ icon: material/brightness-4
22
+ name: Switch to light mode
23
+ features:
24
+ - content.code.copy
25
+
26
+ plugins:
27
+ - search
28
+ - mkdocstrings:
29
+ handlers:
30
+ python:
31
+ options:
32
+ filters: ["!^_"]
33
+ show_root_heading: true
34
+ show_source: false
35
+ members_order: source
36
+
37
+ markdown_extensions:
38
+ - admonition
39
+ - attr_list
40
+ - github-callouts
41
+ - mkdocs-click
42
+ - pymdownx.snippets:
43
+ base_path: ["."]
44
+ check_paths: true
45
+ - pymdownx.superfences
46
+
47
+ nav:
48
+ - Getting Started: index.md
49
+ - Filtering: filtering.md
50
+ - Commands:
51
+ - search: commands/search.md
52
+ - edit: commands/edit.md
53
+ - convert: commands/convert.md
54
+ - API Reference: api.md
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "rekordbox-edit"
7
- version = "0.6.0.dev29"
7
+ version = "0.6.0.dev40"
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"
@@ -33,6 +33,12 @@ dev = [
33
33
  "ty>=0.0.1,<1",
34
34
  "syrupy>=5,<6",
35
35
  ]
36
+ docs = [
37
+ "mkdocs-material>=9.5,<10",
38
+ "mkdocstrings[python]>=0.27,<1",
39
+ "mkdocs-click>=0.8,<1",
40
+ "markdown-callouts>=0.4,<1",
41
+ ]
36
42
 
37
43
  [tool.pytest.ini_options]
38
44
  markers = [
@@ -95,6 +95,18 @@ global_click_filters = [
95
95
  multiple=True,
96
96
  help="Find tracks of this format",
97
97
  ),
98
+ click.option(
99
+ "--first",
100
+ type=click.IntRange(min=1),
101
+ default=None,
102
+ help="Return only the first N results",
103
+ ),
104
+ click.option(
105
+ "--last",
106
+ type=click.IntRange(min=1),
107
+ default=None,
108
+ help="Return only the last N results",
109
+ ),
98
110
  click.option(
99
111
  "--match-all",
100
112
  type=bool,
@@ -4,9 +4,10 @@ import functools
4
4
  import logging
5
5
  import sys
6
6
  from copy import copy
7
+ from typing import TypeVar
7
8
 
8
9
  import click
9
- from pydantic import BaseModel
10
+ from pydantic import BaseModel, ValidationError
10
11
  from pyrekordbox import Rekordbox6Database
11
12
  from pyrekordbox.utils import get_rekordbox_pid
12
13
 
@@ -17,6 +18,16 @@ logger = logging.getLogger(__name__)
17
18
 
18
19
  SCRIPTING_MODES = (PrintChoice.IDS, PrintChoice.SILENT, PrintChoice.JSON)
19
20
 
21
+ _ArgsT = TypeVar("_ArgsT", bound=BaseModel)
22
+
23
+
24
+ def _build_args(model_cls: type[_ArgsT], kwargs: dict) -> _ArgsT:
25
+ """Construct the command's args model, surfacing validation failures as usage errors."""
26
+ try:
27
+ return model_cls(**kwargs)
28
+ except ValidationError as e:
29
+ raise click.UsageError("; ".join(err["msg"] for err in e.errors())) from e
30
+
20
31
 
21
32
  def _handle_stdin(args) -> bool:
22
33
  """Append track IDs from piped stdin to args.track_ids. Returns True if IDs were piped."""
@@ -70,6 +81,8 @@ def _narrow_to_track_ids(args, ids: list[str]):
70
81
  setattr(narrowed, field_name, [])
71
82
  narrowed.track_ids = list(ids)
72
83
  narrowed.match_all = False
84
+ narrowed.first = None
85
+ narrowed.last = None
73
86
  return narrowed
74
87
 
75
88