rekordbox-edit 0.9.0.dev22__tar.gz → 0.9.0.dev29__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.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.pre-commit-config.yaml +2 -2
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/CHANGELOG.md +26 -3
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/PKG-INFO +1 -1
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/api.md +31 -29
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/commands/search.md +6 -6
- rekordbox_edit-0.9.0.dev29/docs/filtering.md +108 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/pyproject.toml +7 -1
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/_click.py +7 -1
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/_utils.py +1 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/models.py +7 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/query.py +48 -24
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/test_search.py +9 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/test_utils.py +8 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/test_journey.py +39 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/test_models.py +7 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/test_query.py +101 -65
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/uv.lock +1 -1
- rekordbox_edit-0.9.0.dev22/docs/filtering.md +0 -112
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.agent-style/RULES.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.agent-style/claude-code.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/build-release-notes/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/build-release-notes/build_release_notes.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/commit-check/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/commitizen-bump/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/e2e/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/install/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/lint/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/actions/test/action.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/workflows/cd.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/workflows/ci.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/workflows/publish.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.github/workflows/release.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.gitignore +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.python-version +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/.readthedocs.yaml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/AGENTS.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/CLAUDE.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/CONTRIBUTING.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/LICENSE +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/Makefile +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/README.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/codecov.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docker-compose.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/commands/convert.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/commands/edit.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/faqs.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/index.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/docs/stylesheets/extra.css +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/mkdocs.yml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/_utils.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/convert.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/edit.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/field_handlers.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/api/search.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/convert.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/edit.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/main.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/cli/search.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/display.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/logger.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/rekordbox_edit/utils.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/renovate.json5 +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/README.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/convert-export-impact-test-plan.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/convert-export-impact.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r1-21-postexport-full.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r2b-10-deviceedit.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r3-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r3-10-deviceedit.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r3-40-resync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/export-r3-41-reexport-full.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-11317782-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-11317782-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-121715696-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-140193439-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-140193439-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-258421826-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-268012584-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-268012584-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-53013048-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/evidence/subject-54793376-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/scripts/export_diff.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-export-impact/scripts/export_snapshot.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/convert-anlz-cue-impact-experiment2-plan.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/convert-anlz-cue-impact-experiment2.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/convert-anlz-cue-impact-test-plan.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/convert-anlz-cue-impact-verification.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/convert-anlz-cue-impact.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/decisions/convert-and-reanalysis-impact.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/decisions/convert-helper-structure.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/01-inventory.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/02-cue-schema.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/03-cue-fields-by-format.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/04-anlz-deep.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/05-census.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/06-content-columns.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/07-analysis-flags.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/exp2-00-pvb2-origin.txt +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-00-zero.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-04.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-05.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-04.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-05.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-06.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-then-high.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-unlocked-ref.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-174954387-nth-mid-normal.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-postanalyze2.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postopen.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-postanalyze2.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-locked.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-unlocked-reanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-postlock.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-230928195-prelock.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-00-zero.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-04.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-05.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-01.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-02.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-03.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-04.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-05.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-06.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-locked.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-then-high.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-27790898-nth-mid-normal.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postanalyze.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postconv.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/README.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/analysis_flags.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/anlz_census.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/anlz_deep.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/content_columns.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/cue_fields_by_format.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/cue_schema.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/grid_drift.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/inventory.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/pvb2_origin.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/reset_fresh_to_zero.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/restore_fixtures.sh +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/convert-reanalysis-impact/scripts/row_snapshot.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/decisions/edit-field-handlers.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/edit-relational-fields-test-plan.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/edit-relational-fields.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-112264610-e2-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-112264610-e2-10-reuse.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-141833798-e3b-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-141833798-e3b-10-newalbum.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-145166719-e0-census.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-176388182-e1-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-176388182-e1-10-reuse.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-183309432-e4-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-183309432-e4-10-orphaned.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-47413782-v-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-47413782-v-10-reuse.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-50395296-v-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-50395296-v-10-reuse.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-57701453-e3-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-57701453-e3-10-diffartist.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-71974950-v-00-baseline.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/evidence/rel-71974950-v-10-reuse.json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/scripts/relational_diff.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/edit-relational-fields/scripts/relational_snapshot.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/file-types/README.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/file-types/decisions/unknown-file-types.md +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/shared/scripts/subject_diff.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/research/shared/scripts/subject_snapshot.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/ruff.toml +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/test_convert.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/test_edit.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/test_field_handlers.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/test_search.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/api/test_utils.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/test_convert.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/test_edit.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/cli/test_main.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/conftest.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/Dockerfile +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/__init__.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[macos].json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[windows].json +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/__snapshots__/test_journey.ambr +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/conftest.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/01-flac-44_1k-16b.flac +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/02-flac-96k-24b.flac +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/03-alac-44_1k-16b.m4a +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/04-alac-48k-24b.m4a +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/05-aiff-44_1k-16b.aiff +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/06-wav-96k-24b.wav +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/07-mp3-44_1k-320cbr.mp3 +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/08-mp3-44_1k-v0vbr.mp3 +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/09-aac-44_1k-256kbps.m4a +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/audio/10-/303/274/303/261/303/256c/303/266d/303/251-flac-44_1k-16b.flac" +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/macos/master.6.8.6.db +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/fixtures/windows/master.6.8.6.db +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/e2e/test_edit_fields.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/test_display.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/test_logger.py +0 -0
- {rekordbox_edit-0.9.0.dev22 → rekordbox_edit-0.9.0.dev29}/tests/test_utils.py +0 -0
|
@@ -19,7 +19,7 @@ repos:
|
|
|
19
19
|
- id: check-toml
|
|
20
20
|
- id: check-case-conflict
|
|
21
21
|
- repo: https://github.com/commitizen-tools/commitizen
|
|
22
|
-
rev: v4.
|
|
22
|
+
rev: v4.18.0
|
|
23
23
|
hooks:
|
|
24
24
|
- id: commitizen
|
|
25
25
|
stages: [commit-msg]
|
|
@@ -32,7 +32,7 @@ repos:
|
|
|
32
32
|
files: pyproject\.toml$
|
|
33
33
|
pass_filenames: false
|
|
34
34
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
35
|
-
rev: v0.16.
|
|
35
|
+
rev: v0.16.4
|
|
36
36
|
hooks:
|
|
37
37
|
- id: ruff-check
|
|
38
38
|
args: [--fix]
|
|
@@ -1,6 +1,29 @@
|
|
|
1
|
-
## v0.9.0.
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
## v0.9.0.dev29 (2026-08-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
- docs(filtering): document grouped default and --match-any
|
|
5
|
+
- test(e2e): cover grouped default and --match-any against the fixture DB
|
|
6
|
+
- Locks in the original bug report (--title + --format now intersect
|
|
7
|
+
instead of union) plus the new --match-any flat-OR escape hatch.
|
|
8
|
+
- feat(query): add --match-any flat-OR mode
|
|
9
|
+
- Grouped mode is now the default (previous commit), so --match-all's
|
|
10
|
+
old job — flattening everything into one OR-vs-AND switch — needs an
|
|
11
|
+
explicit OR counterpart for anyone who still wants the old fully-broad
|
|
12
|
+
search. match_all and match_any are mutually exclusive.
|
|
13
|
+
- feat(query)!: group filter conditions by kind, OR within a kind and AND across kinds
|
|
14
|
+
- CollectionQuery previously combined every condition in one flat list
|
|
15
|
+
with a single OR/AND switch, so combining two different filters (e.g.
|
|
16
|
+
--title and --format) matched their union instead of their
|
|
17
|
+
intersection. Conditions now bucket by filter kind (title, artist,
|
|
18
|
+
album, playlist, format, path, track_id); the default groups OR
|
|
19
|
+
within a bucket and ANDs across buckets. match_all()/match_any() still
|
|
20
|
+
flatten everything into one AND/OR, unchanged in meaning.
|
|
21
|
+
- chore(deps): update pre-commit hook astral-sh/ruff-pre-commit to v0.16.4 (#184)
|
|
22
|
+
- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
|
|
23
|
+
- chore(deps): update pre-commit hook commitizen-tools/commitizen to v4.18.0 (#183)
|
|
24
|
+
- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
|
|
25
|
+
- chore(deps): update pre-commit hook commitizen-tools/commitizen to v4.17.1 (#181)
|
|
26
|
+
- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
|
|
4
27
|
- docs: add research directory with reverse-engineering findings
|
|
5
28
|
- Promote the durable Rekordbox behavior research out of the ignored ai-docs
|
|
6
29
|
tree into a committed, per-investigation research/ directory. Each folder is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rekordbox-edit
|
|
3
|
-
Version: 0.9.0.
|
|
3
|
+
Version: 0.9.0.dev29
|
|
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
|
|
@@ -8,11 +8,13 @@ from rekordbox_edit.api import search
|
|
|
8
8
|
from rekordbox_edit.models import SearchRequest
|
|
9
9
|
|
|
10
10
|
db = Rekordbox6Database()
|
|
11
|
-
response = search(db, SearchRequest(artist=["Daft Punk"], format=["flac"]
|
|
11
|
+
response = search(db, SearchRequest(artist=["Daft Punk"], format=["flac"]))
|
|
12
12
|
for track in response.tracks:
|
|
13
13
|
print(track.ID, track.Title)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Different filter kinds — `artist` and `format` above — AND together by default; repeated values of the same filter OR together. Pass `match_all=True` to flatten everything into one AND, or `match_any=True` to flatten everything into one OR.
|
|
17
|
+
|
|
16
18
|
`--print json` on any CLI command emits exactly these response envelopes, so the models below also document the JSON you get when scripting.
|
|
17
19
|
|
|
18
20
|
## Functions
|
|
@@ -28,65 +30,65 @@ for track in response.tracks:
|
|
|
28
30
|
The models form three layers: the [`FilterArgs`][rekordbox_edit.models.FilterArgs] base that every command shares, the per-command requests and responses, and the lower-level domain types those req/resp models are built from.
|
|
29
31
|
|
|
30
32
|
::: rekordbox_edit.models.FilterArgs
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
options:
|
|
34
|
+
heading_level: 3
|
|
33
35
|
|
|
34
36
|
### Search
|
|
35
37
|
|
|
36
38
|
::: rekordbox_edit.models.SearchRequest
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
options:
|
|
40
|
+
heading_level: 4
|
|
39
41
|
|
|
40
42
|
::: rekordbox_edit.models.SearchResponse
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
options:
|
|
44
|
+
heading_level: 4
|
|
43
45
|
|
|
44
46
|
### Edit
|
|
45
47
|
|
|
46
48
|
::: rekordbox_edit.models.EditRequest
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
options:
|
|
50
|
+
heading_level: 4
|
|
49
51
|
|
|
50
52
|
::: rekordbox_edit.models.EditResponse
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
options:
|
|
54
|
+
heading_level: 4
|
|
53
55
|
|
|
54
56
|
::: rekordbox_edit.models.EditResult
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
options:
|
|
58
|
+
heading_level: 4
|
|
57
59
|
|
|
58
60
|
### Convert
|
|
59
61
|
|
|
60
62
|
::: rekordbox_edit.models.ConvertRequest
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
options:
|
|
64
|
+
heading_level: 4
|
|
63
65
|
|
|
64
66
|
::: rekordbox_edit.models.ConvertResponse
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
options:
|
|
68
|
+
heading_level: 4
|
|
67
69
|
|
|
68
70
|
::: rekordbox_edit.models.ConvertResult
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
options:
|
|
72
|
+
heading_level: 4
|
|
71
73
|
|
|
72
74
|
### Miscellaneous
|
|
73
75
|
|
|
74
76
|
::: rekordbox_edit.models.Track
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
options:
|
|
78
|
+
heading_level: 4
|
|
77
79
|
|
|
78
80
|
::: rekordbox_edit.models.EditOp
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
options:
|
|
82
|
+
heading_level: 4
|
|
81
83
|
|
|
82
84
|
::: rekordbox_edit.models.ConvertOp
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
options:
|
|
86
|
+
heading_level: 4
|
|
85
87
|
|
|
86
88
|
::: rekordbox_edit.models.SkippedTrack
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
options:
|
|
90
|
+
heading_level: 4
|
|
89
91
|
|
|
90
92
|
::: rekordbox_edit.models.SkipReason
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
options:
|
|
94
|
+
heading_level: 4
|
|
@@ -11,8 +11,8 @@ rbe search --artist "Aphex Twin" --format flac
|
|
|
11
11
|
# Get all the track IDs in a playlist
|
|
12
12
|
rbe search --playlist "Techno" --print ids
|
|
13
13
|
|
|
14
|
-
#
|
|
15
|
-
rbe search --
|
|
14
|
+
# Tracks that are either flac, or in this playlist
|
|
15
|
+
rbe search --playlist "Techno" --format flac --match-any
|
|
16
16
|
|
|
17
17
|
# Feed results to another command
|
|
18
18
|
rbe search --artist "Lauryn Hill" --print ids | rbe convert --yes
|
|
@@ -23,7 +23,7 @@ See [Filtering](../filtering.md) for the full filter language and piping recipes
|
|
|
23
23
|
## Reference
|
|
24
24
|
|
|
25
25
|
::: mkdocs-click
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 supports filtering by all of the [`FilterArgs`][rekordbox_edit.models.FilterArgs]. The filters determine which tracks a command operates on.
|
|
4
|
+
|
|
5
|
+
## Filter Options
|
|
6
|
+
|
|
7
|
+
By default any filters provided are grouped by kind: repeating the _same_ filter with different values matches tracks that satisfy _any_ of those values (an OR), while combining _different_ filters narrows to tracks that satisfy every one of them (an AND). Pass `--match-all` to find results that match each and every filter value. Pass `--match-any` to instead match tracks that satisfy any single filter value provided.
|
|
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` | Rekordbox file type is `FMT` (`mp3`, `mp4`, `aac`, `flac`, `alac`, `wav`, `aiff`, `video`, `invalid`) |
|
|
21
|
+
| `--path TEXT` | file path contains `TEXT`, case-insensitive |
|
|
22
|
+
| `--resolved-path TEXT` | file path contains `TEXT` after resolving it to an absolute path, case-insensitive |
|
|
23
|
+
| `--first N` | return only the first N results |
|
|
24
|
+
| `--last N` | return only the last N results |
|
|
25
|
+
|
|
26
|
+
> [!TIP]
|
|
27
|
+
> Filters that are "exact" are case-sensitive (e.g. `--exact-artist 'HOOBASTANK'` won't match "Hoobastank") whereas their counterparts (`--artist`) are case-insensitive and match substrings.
|
|
28
|
+
|
|
29
|
+
> [!NOTE]
|
|
30
|
+
> Path filters match case-insensitively on every platform because the filesystems Rekordbox supports (NTFS and APFS) treat paths case-insensitively themselves.
|
|
31
|
+
|
|
32
|
+
### Examples
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Tracks by either artist (repeated filters OR together, by default)
|
|
36
|
+
rbe search --artist "Daft Punk" --artist "Justice"
|
|
37
|
+
|
|
38
|
+
# Tracks matching artist AND format (different filters AND together, by default)
|
|
39
|
+
rbe search --artist "Aphex Twin" --format flac
|
|
40
|
+
|
|
41
|
+
# Tracks that are either flac, or by Aphex Twin
|
|
42
|
+
rbe search --artist "Aphex Twin" --format flac --match-any
|
|
43
|
+
|
|
44
|
+
# Tracks that match both Tom Petty and The Heartbreakers
|
|
45
|
+
rbe search --artist "Tom Petty" --artist "The Heartbreakers" --match-all
|
|
46
|
+
|
|
47
|
+
# All the songs in this playlist
|
|
48
|
+
rbe search --exact-playlist "Main Room 2024"
|
|
49
|
+
|
|
50
|
+
# All the songs in any "house" or "disco" playlists
|
|
51
|
+
rbe search --playlist "house" --playlist "disco"
|
|
52
|
+
|
|
53
|
+
# All the songs in my library that aren't in any playlist
|
|
54
|
+
rbe search --playlist ""
|
|
55
|
+
|
|
56
|
+
# The first 10 tracks that either live under a "Favorites" folder or have the word "remix" somewhere in the file path
|
|
57
|
+
rbe search --path "Favorites/" --path "remix" --first 10
|
|
58
|
+
|
|
59
|
+
# The track at an exact location
|
|
60
|
+
rbe search --resolved-path "/Users/djmustard/Music/banger.mp3"
|
|
61
|
+
|
|
62
|
+
# Every track under a folder, given relative to the current directory
|
|
63
|
+
rbe search --resolved-path "../Music/house/"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Track ID Arguments
|
|
67
|
+
|
|
68
|
+
Any positional argument that is not a defined option is interpreted as one or more track IDs:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
rbe search 12345 67890
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
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.
|
|
75
|
+
|
|
76
|
+
## Output Levels
|
|
77
|
+
|
|
78
|
+
All commands take `--print [silent|ids|info|debug|json]`:
|
|
79
|
+
|
|
80
|
+
- `info` (default): human-readable output
|
|
81
|
+
- `debug`: adds application state detail; debug logs for every run are also written to a log file (the path to which is shown in `--help`)
|
|
82
|
+
- `silent`: no output at all
|
|
83
|
+
- `ids`: print only the matching track IDs, space-separated — designed for piping between consecutive `rbe` commands.
|
|
84
|
+
- `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))
|
|
85
|
+
|
|
86
|
+
!!! note
|
|
87
|
+
|
|
88
|
+
`silent`, `ids`, and `json` are non-interactive print modes, so they require `--yes` or `--dry-run`.
|
|
89
|
+
|
|
90
|
+
## Scripting and Piping
|
|
91
|
+
|
|
92
|
+
`--print ids` output feeds straight into another command's track-ID arguments:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Convert all of the items found by the initial search command
|
|
96
|
+
rbe search --artist "Lauryn Hill" --print ids | rbe convert --yes
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**OR between AND-groups** — merge results from two commands using a subshell:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Convert all (Daft Punk AND flac) OR (Justice AND aiff)
|
|
103
|
+
{ rbe search --artist "Daft Punk" --format flac --print ids; \
|
|
104
|
+
rbe search --artist "Justice" --format aiff --print ids; } \
|
|
105
|
+
| rbe convert --format-out mp3 --dry-run
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For richer pipelines, `--print json` emits the same selection as a structured database dump for `jq` and other shell tools. Use the [API functions](api.md#functions) if you want to build a more complex python script.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rekordbox-edit"
|
|
7
|
-
version = "0.9.0.
|
|
7
|
+
version = "0.9.0.dev29"
|
|
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"
|
|
@@ -62,6 +62,9 @@ exclude-newer = "3 days"
|
|
|
62
62
|
|
|
63
63
|
[tool.coverage.run]
|
|
64
64
|
branch = true
|
|
65
|
+
omit = [
|
|
66
|
+
"research"
|
|
67
|
+
]
|
|
65
68
|
data_file = ".coverage/coverage.db"
|
|
66
69
|
[tool.coverage.html]
|
|
67
70
|
directory = ".coverage/html/"
|
|
@@ -78,6 +81,9 @@ python-version = "3.11"
|
|
|
78
81
|
[tool.ty.analysis]
|
|
79
82
|
allowed-unresolved-imports = ["pyrekordbox", "ffmpeg"]
|
|
80
83
|
|
|
84
|
+
[tool.ty.src]
|
|
85
|
+
exclude = ["research/"]
|
|
86
|
+
|
|
81
87
|
[tool.commitizen]
|
|
82
88
|
name = "cz_customize"
|
|
83
89
|
tag_format = "v$version"
|
|
@@ -115,7 +115,13 @@ global_click_filters = [
|
|
|
115
115
|
"--match-all",
|
|
116
116
|
type=bool,
|
|
117
117
|
is_flag=True,
|
|
118
|
-
help="
|
|
118
|
+
help="Flatten every filter value, including repeats, into one AND",
|
|
119
|
+
),
|
|
120
|
+
click.option(
|
|
121
|
+
"--match-any",
|
|
122
|
+
type=bool,
|
|
123
|
+
is_flag=True,
|
|
124
|
+
help="Flatten every filter value into one OR, ignoring the default grouping",
|
|
119
125
|
),
|
|
120
126
|
]
|
|
121
127
|
|
|
@@ -50,6 +50,7 @@ class FilterArgs(BaseModel):
|
|
|
50
50
|
first: int | None = Field(default=None, gt=0)
|
|
51
51
|
last: int | None = Field(default=None, gt=0)
|
|
52
52
|
match_all: bool = False
|
|
53
|
+
match_any: bool = False
|
|
53
54
|
|
|
54
55
|
@model_validator(mode="after")
|
|
55
56
|
def _check_first_last_exclusive(self) -> "FilterArgs":
|
|
@@ -57,6 +58,12 @@ class FilterArgs(BaseModel):
|
|
|
57
58
|
raise ValueError("'first' and 'last' are mutually exclusive")
|
|
58
59
|
return self
|
|
59
60
|
|
|
61
|
+
@model_validator(mode="after")
|
|
62
|
+
def _check_match_mode_exclusive(self) -> "FilterArgs":
|
|
63
|
+
if self.match_all and self.match_any:
|
|
64
|
+
raise ValueError("'match_all' and 'match_any' are mutually exclusive")
|
|
65
|
+
return self
|
|
66
|
+
|
|
60
67
|
|
|
61
68
|
# ── Command args ──────────────────────────────────────────────────────────
|
|
62
69
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import List, Tuple, Union
|
|
4
|
+
from typing import List, Literal, Tuple, Union
|
|
5
5
|
|
|
6
6
|
from pyrekordbox import Rekordbox6Database
|
|
7
7
|
from pyrekordbox.db6.tables import (
|
|
@@ -18,35 +18,47 @@ from rekordbox_edit.models import FilterArgs
|
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
|
+
MatchMode = Literal["grouped", "all", "any"]
|
|
22
|
+
|
|
21
23
|
|
|
22
24
|
class CollectionQuery:
|
|
23
|
-
def __init__(self,
|
|
25
|
+
def __init__(self, mode: MatchMode = "grouped"):
|
|
24
26
|
self._stmt = select(DjmdContent)
|
|
25
|
-
self._conditions: list[ColumnElement[bool]] =
|
|
27
|
+
self._conditions: dict[str, list[ColumnElement[bool]]] = {}
|
|
26
28
|
self._limit_count = None
|
|
27
29
|
self._last_count = None
|
|
28
|
-
self.
|
|
30
|
+
self._mode: MatchMode = mode
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def _flat_conditions(self) -> list[ColumnElement[bool]]:
|
|
34
|
+
"""Every condition across every filter-kind bucket, as one flat list."""
|
|
35
|
+
return [c for conditions in self._conditions.values() for c in conditions]
|
|
29
36
|
|
|
30
37
|
def _copy(self) -> "CollectionQuery":
|
|
31
38
|
"""Create a copy of this query in its current state."""
|
|
32
39
|
new_inst = CollectionQuery.__new__(CollectionQuery)
|
|
33
40
|
new_inst._stmt = self._stmt._clone()
|
|
34
|
-
new_inst._conditions =
|
|
41
|
+
new_inst._conditions = {
|
|
42
|
+
group: conditions.copy() for group, conditions in self._conditions.items()
|
|
43
|
+
}
|
|
35
44
|
new_inst._limit_count = self._limit_count
|
|
36
45
|
new_inst._last_count = self._last_count
|
|
37
|
-
new_inst.
|
|
46
|
+
new_inst._mode = self._mode
|
|
38
47
|
return new_inst
|
|
39
48
|
|
|
49
|
+
def _append_condition(self, group: str, condition: ColumnElement[bool]) -> None:
|
|
50
|
+
self._conditions.setdefault(group, []).append(condition)
|
|
51
|
+
|
|
40
52
|
def match_any(self) -> "CollectionQuery":
|
|
41
|
-
"""
|
|
53
|
+
"""Flatten every condition, across every filter kind, into one OR."""
|
|
42
54
|
new_inst = self._copy()
|
|
43
|
-
new_inst.
|
|
55
|
+
new_inst._mode = "any"
|
|
44
56
|
return new_inst
|
|
45
57
|
|
|
46
58
|
def match_all(self) -> "CollectionQuery":
|
|
47
|
-
"""
|
|
59
|
+
"""Flatten every condition, across every filter kind, into one AND."""
|
|
48
60
|
new_inst = self._copy()
|
|
49
|
-
new_inst.
|
|
61
|
+
new_inst._mode = "all"
|
|
50
62
|
return new_inst
|
|
51
63
|
|
|
52
64
|
def by_track_ids(self, track_ids: Union[str, List[str]]) -> "CollectionQuery":
|
|
@@ -54,7 +66,7 @@ class CollectionQuery:
|
|
|
54
66
|
new_inst = self._copy()
|
|
55
67
|
if isinstance(track_ids, str):
|
|
56
68
|
track_ids = [track_ids]
|
|
57
|
-
new_inst.
|
|
69
|
+
new_inst._append_condition("track_id", DjmdContent.ID.in_(track_ids))
|
|
58
70
|
return new_inst
|
|
59
71
|
|
|
60
72
|
def by_artist(self, artist_name: str, exact: bool = False) -> "CollectionQuery":
|
|
@@ -73,7 +85,7 @@ class CollectionQuery:
|
|
|
73
85
|
else:
|
|
74
86
|
condition = ArtistAlias.Name.ilike(f"%{artist_name}%")
|
|
75
87
|
|
|
76
|
-
new_inst.
|
|
88
|
+
new_inst._append_condition("artist", condition)
|
|
77
89
|
return new_inst
|
|
78
90
|
|
|
79
91
|
def by_title(self, title: str, exact: bool = False) -> "CollectionQuery":
|
|
@@ -88,7 +100,7 @@ class CollectionQuery:
|
|
|
88
100
|
else:
|
|
89
101
|
condition = DjmdContent.Title.ilike(f"%{title}%")
|
|
90
102
|
|
|
91
|
-
new_inst.
|
|
103
|
+
new_inst._append_condition("title", condition)
|
|
92
104
|
return new_inst
|
|
93
105
|
|
|
94
106
|
def by_album(self, album_name: str, exact: bool = False) -> "CollectionQuery":
|
|
@@ -107,7 +119,7 @@ class CollectionQuery:
|
|
|
107
119
|
else:
|
|
108
120
|
condition = AlbumAlias.Name.ilike(f"%{album_name}%")
|
|
109
121
|
|
|
110
|
-
new_inst.
|
|
122
|
+
new_inst._append_condition("album", condition)
|
|
111
123
|
return new_inst
|
|
112
124
|
|
|
113
125
|
def by_playlist(self, playlist_name: str, exact: bool = False) -> "CollectionQuery":
|
|
@@ -128,7 +140,7 @@ class CollectionQuery:
|
|
|
128
140
|
else:
|
|
129
141
|
condition = PlaylistAlias.Name.ilike(f"%{playlist_name}%")
|
|
130
142
|
|
|
131
|
-
new_inst.
|
|
143
|
+
new_inst._append_condition("playlist", condition)
|
|
132
144
|
return new_inst
|
|
133
145
|
|
|
134
146
|
def by_format(self, format_name: str) -> "CollectionQuery":
|
|
@@ -144,7 +156,7 @@ class CollectionQuery:
|
|
|
144
156
|
try:
|
|
145
157
|
file_type_codes = get_file_type_codes_for_format(format_name)
|
|
146
158
|
condition = DjmdContent.FileType.in_(file_type_codes)
|
|
147
|
-
new_inst.
|
|
159
|
+
new_inst._append_condition("format", condition)
|
|
148
160
|
except ValueError:
|
|
149
161
|
logger.warning(f"Invalid format: {format_name}")
|
|
150
162
|
return new_inst
|
|
@@ -174,7 +186,7 @@ class CollectionQuery:
|
|
|
174
186
|
else:
|
|
175
187
|
pattern = path_str.replace("\\", "/")
|
|
176
188
|
|
|
177
|
-
new_inst.
|
|
189
|
+
new_inst._append_condition("path", DjmdContent.FolderPath.ilike(f"%{pattern}%"))
|
|
178
190
|
return new_inst
|
|
179
191
|
|
|
180
192
|
def limit(self, count: int) -> "CollectionQuery":
|
|
@@ -214,14 +226,24 @@ class CollectionQuery:
|
|
|
214
226
|
stmt = self._stmt
|
|
215
227
|
|
|
216
228
|
if self._conditions:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
if self._mode == "all":
|
|
230
|
+
logger.debug(
|
|
231
|
+
f"Building query with {len(self._flat_conditions)} condition(s) using flat AND logic"
|
|
232
|
+
)
|
|
233
|
+
combined_condition = and_(*self._flat_conditions)
|
|
234
|
+
elif self._mode == "any":
|
|
235
|
+
logger.debug(
|
|
236
|
+
f"Building query with {len(self._flat_conditions)} condition(s) using flat OR logic"
|
|
237
|
+
)
|
|
238
|
+
combined_condition = or_(*self._flat_conditions)
|
|
223
239
|
else:
|
|
224
|
-
|
|
240
|
+
logger.debug(
|
|
241
|
+
f"Building query with {len(self._conditions)} filter group(s) using grouped AND-of-OR logic"
|
|
242
|
+
)
|
|
243
|
+
group_conditions = [
|
|
244
|
+
or_(*conditions) for conditions in self._conditions.values()
|
|
245
|
+
]
|
|
246
|
+
combined_condition = and_(*group_conditions)
|
|
225
247
|
stmt = stmt.where(combined_condition)
|
|
226
248
|
|
|
227
249
|
if self._last_count is not None:
|
|
@@ -298,6 +320,8 @@ def get_filtered_content(
|
|
|
298
320
|
|
|
299
321
|
if filters.match_all:
|
|
300
322
|
query = query.match_all()
|
|
323
|
+
elif filters.match_any:
|
|
324
|
+
query = query.match_any()
|
|
301
325
|
|
|
302
326
|
if filters.first is not None:
|
|
303
327
|
query = query.limit(filters.first)
|
|
@@ -98,6 +98,15 @@ class TestSearchCommand:
|
|
|
98
98
|
assert result.exit_code == 2
|
|
99
99
|
assert "mutually exclusive" in result.output
|
|
100
100
|
|
|
101
|
+
@patch("rekordbox_edit.cli._utils.Rekordbox6Database")
|
|
102
|
+
def test_match_all_and_match_any_together_is_usage_error(self, mock_db_class):
|
|
103
|
+
mock_db_class.return_value = Mock(session=Mock())
|
|
104
|
+
|
|
105
|
+
result = CliRunner().invoke(search_command, ["--match-all", "--match-any"])
|
|
106
|
+
|
|
107
|
+
assert result.exit_code == 2
|
|
108
|
+
assert "mutually exclusive" in result.output
|
|
109
|
+
|
|
101
110
|
@patch("rekordbox_edit.cli._utils.Rekordbox6Database")
|
|
102
111
|
def test_first_rejects_zero(self, mock_db_class):
|
|
103
112
|
mock_db_class.return_value = Mock(session=Mock())
|
|
@@ -140,6 +140,14 @@ class TestNarrowToTrackIds:
|
|
|
140
140
|
|
|
141
141
|
assert narrowed.last is None
|
|
142
142
|
|
|
143
|
+
def test_clears_match_modes(self):
|
|
144
|
+
args = SearchRequest(match_any=True)
|
|
145
|
+
|
|
146
|
+
narrowed = _narrow_to_track_ids(args, ["a"])
|
|
147
|
+
|
|
148
|
+
assert narrowed.match_all is False
|
|
149
|
+
assert narrowed.match_any is False
|
|
150
|
+
|
|
143
151
|
|
|
144
152
|
class TestPrintResponseIds:
|
|
145
153
|
def test_prints_space_separated_ids(self, capsys):
|
|
@@ -88,6 +88,45 @@ def test_search_match_all_combo(cli):
|
|
|
88
88
|
assert len(matches) == 1
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def test_search_title_and_format_intersect_by_default(cli):
|
|
92
|
+
"""The original bug report: different filter kinds AND by default now.
|
|
93
|
+
Title narrows to track 1 ("Wave Alpha"); format narrows to all 3 FLACs.
|
|
94
|
+
The intersection is just track 1 — no --match-all needed."""
|
|
95
|
+
matches = _tracks(
|
|
96
|
+
cli(
|
|
97
|
+
"search", "--title", WAVE_ALPHA_TITLE, "--format", "flac", "--print", "json"
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
assert len(matches) == 1
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_search_default_matches_old_match_all_combo(cli):
|
|
104
|
+
"""Same combo as test_search_match_all_combo, without the flag —
|
|
105
|
+
different filter kinds (format, artist) AND by default now."""
|
|
106
|
+
matches = _tracks(
|
|
107
|
+
cli("search", "--format", "flac", "--artist", "Beta", "--print", "json")
|
|
108
|
+
)
|
|
109
|
+
assert len(matches) == 1
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_search_match_any_flattens_across_filter_kinds(cli):
|
|
113
|
+
"""--match-any flattens everything to OR: track 1 (by title) plus both
|
|
114
|
+
mp3 tracks (by format) — zero overlap, since track 1 is FLAC."""
|
|
115
|
+
matches = _tracks(
|
|
116
|
+
cli(
|
|
117
|
+
"search",
|
|
118
|
+
"--title",
|
|
119
|
+
WAVE_ALPHA_TITLE,
|
|
120
|
+
"--format",
|
|
121
|
+
"mp3",
|
|
122
|
+
"--match-any",
|
|
123
|
+
"--print",
|
|
124
|
+
"json",
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
assert len(matches) == 3
|
|
128
|
+
|
|
129
|
+
|
|
91
130
|
def test_search_empty_result_exits_zero(cli):
|
|
92
131
|
result = cli("search", "--title", "DefinitelyNotInLibrary", "--print", "json")
|
|
93
132
|
assert result.returncode == 0
|
|
@@ -73,6 +73,13 @@ class TestFilterArgs:
|
|
|
73
73
|
with pytest.raises(ValidationError, match="mutually exclusive"):
|
|
74
74
|
FilterArgs(first=2, last=3)
|
|
75
75
|
|
|
76
|
+
def test_match_any_defaults_false(self):
|
|
77
|
+
assert FilterArgs().match_any is False
|
|
78
|
+
|
|
79
|
+
def test_match_all_and_match_any_mutually_exclusive(self):
|
|
80
|
+
with pytest.raises(ValidationError, match="mutually exclusive"):
|
|
81
|
+
FilterArgs(match_all=True, match_any=True)
|
|
82
|
+
|
|
76
83
|
|
|
77
84
|
class TestSearchRequest:
|
|
78
85
|
def test_is_filter_args(self):
|