rekordbox-edit 0.13.0.dev8__tar.gz → 0.13.0.dev9__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.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CHANGELOG.md +15 -3
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/PKG-INFO +1 -1
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/pyproject.toml +1 -1
- rekordbox_edit-0.13.0.dev9/rekordbox_edit/api/_anlz.py +86 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_utils.py +21 -5
- rekordbox_edit-0.13.0.dev9/tests/anlz_helpers.py +38 -0
- rekordbox_edit-0.13.0.dev9/tests/api/test_anlz.py +76 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_convert.py +0 -28
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_utils.py +63 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/uv.lock +1 -1
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.agent-style/RULES.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.agent-style/claude-code.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/build-release-notes/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/build-release-notes/build_release_notes.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commit-check/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commitizen-bump/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/e2e/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/install/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/lint/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/test/action.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/cd.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/ci.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/publish.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/release.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.gitignore +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.pre-commit-config.yaml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.python-version +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.readthedocs.yaml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/AGENTS.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CLAUDE.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CONTRIBUTING.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/LICENSE +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/Makefile +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/README.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/codecov.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docker-compose.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/api.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/convert.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/edit.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/import.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/remove.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/search.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/faqs.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/filtering.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/index.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/stylesheets/extra.css +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/mkdocs.yml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/_tag_fields.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_convert.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_edit.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_field_handlers.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_import.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_relations.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_remove.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_search.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_click.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_progress.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_utils.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/convert.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/edit.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/import_.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/main.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/remove.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/search.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/display.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/errors.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/locking.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/logger.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/models.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/query.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/tags.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/utils.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/renovate.json5 +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/README.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/beets-plugin-integration.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/decisions/converted-original-disposition.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/convert-repoint.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/event-order.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/file-level-encode.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/id-stability.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/media-field-roundtrip.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/convert_repoint.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/event_probe.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/file_level_encode.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/id_stability.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/media_field_roundtrip.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/convert-export-impact-test-plan.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/convert-export-impact.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-21-postexport-full.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-10-deviceedit.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-10-deviceedit.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-40-resync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-41-reexport-full.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-11317782-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-11317782-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-121715696-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-140193439-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-140193439-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-258421826-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-268012584-r3-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-268012584-r3-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r2b-00-lib.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-53013048-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r1-10-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r1-20-postexport.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r2b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r2b-20-postconvert.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/subject-54793376-r2b-30-postsync.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/scripts/export_diff.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/scripts/export_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-experiment2-plan.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-experiment2.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-test-plan.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-verification.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/decisions/convert-and-reanalysis-impact.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/decisions/convert-helper-structure.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/01-inventory.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/02-cue-schema.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/03-cue-fields-by-format.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/04-anlz-deep.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/05-census.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/06-content-columns.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/07-analysis-flags.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/exp2-00-pvb2-origin.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-00-zero.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-high-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-dyn-normal-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-04.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-05.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-auto-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-04.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-05.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-06.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-then-high.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-unlocked-ref.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-nth-mid-normal.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-combined-ctrl-postanalyze2.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postopen.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-ctrl-postanalyze2.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-locked.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-unlocked-reanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-postlock.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-prelock.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-231283665-iso-rate-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-00-zero.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-high-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-dyn-normal-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-04.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-05.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-auto-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-01.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-02.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-03.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-04.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-05.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-06.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-locked.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-then-high.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-nth-mid-normal.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-34178159-iso-depth-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postanalyze.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postconv.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/README.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/analysis_flags.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/anlz_census.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/anlz_deep.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/content_columns.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/cue_fields_by_format.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/cue_schema.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/grid_drift.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/inventory.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/pvb2_origin.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/reset_fresh_to_zero.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/restore_fixtures.sh +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/row_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/convert-thread-scaling.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/evidence/thread-scaling.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/_sources.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/format_scaling.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/shipped_path_scaling.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/write_cost.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/database-concurrency.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/evidence/plan-apply-probes.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/evidence/usn-spikes.txt +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/plan-apply-window.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/block_reservation.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/concurrent_increment.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/identity_probe.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/membership_probe.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/snapshot_probe.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/wal_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/usn-maintenance.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/decisions/edit-field-handlers.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/edit-relational-fields-test-plan.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/edit-relational-fields.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-112264610-e2-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-112264610-e2-10-reuse.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-141833798-e3b-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-141833798-e3b-10-newalbum.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-145166719-e0-census.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-176388182-e1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-176388182-e1-10-reuse.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-183309432-e4-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-183309432-e4-10-orphaned.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-47413782-v-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-47413782-v-10-reuse.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-50395296-v-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-50395296-v-10-reuse.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-57701453-e3-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-57701453-e3-10-diffartist.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-71974950-v-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-71974950-v-10-reuse.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/scripts/relational_diff.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/scripts/relational_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/file-types/README.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/file-types/decisions/unknown-file-types.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/decisions/commit-semantics-and-usn.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/column-coverage-gig.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/datecreated-source-gig.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/filetype-searchstr-gig.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/filetype-searchstr-local.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/import-row-shape-gig.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/tag-key-mapping-gig.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/import-track-row-shape.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/column_coverage.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/datecreated_source.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/filetype_and_searchstr.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/import_row_shape.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/tag_key_mapping.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/decisions/remove-command-behavior.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-109570093-r8-00-imported.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-109570093-r8-10-analyzed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-114745319-r1-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-114745319-r1-10-removed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-120331280-f6-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-120331280-f6-10-control.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-137975518-f3-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-137975518-f3-10-control.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-139425629-r6-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-139425629-r6-10-removed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-14241481-r5-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-14241481-r5-10-removed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-143461275-r7-01-folder-art.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-265892207-r3-00-baseline.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-265892207-r3-10-removed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-265892207-r4-10-playlist-only.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-36337051-r7-00-folder-art.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-74039842-r8-00-imported.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/evidence/rm-74039842-r8-10-analyzed.json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/remove-track-impact-test-plan.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/remove-track-impact.md +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/build_fixtures.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/removal_diff.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/removal_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/restore.sh +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/shared/scripts/subject_diff.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/shared/scripts/subject_snapshot.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/ruff.toml +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/conftest.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_edit.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_field_handlers.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_import.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_package.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_relations.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_remove.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_search.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_convert.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_edit.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_import.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_locking.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_main.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_progress.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_remove.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_search.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_utils.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/conftest.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/Dockerfile +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__init__.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[macos].json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__snapshots__/test_journey/test_search_full_json_snapshot[windows].json +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__snapshots__/test_journey.ambr +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/conftest.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/01-flac-44_1k-16b.flac +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/02-flac-96k-24b.flac +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/03-alac-44_1k-16b.m4a +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/04-alac-48k-24b.m4a +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/05-aiff-44_1k-16b.aiff +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/06-wav-96k-24b.wav +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/07-mp3-44_1k-320cbr.mp3 +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/08-mp3-44_1k-v0vbr.mp3 +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/09-aac-44_1k-256kbps.m4a +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/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.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/macos/master.6.8.6.db +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/windows/master.6.8.6.db +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_edit_fields.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_import.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_journey.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_remove.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_display.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_locking.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_logger.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_models.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_query.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_tag_fields.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_tags.py +0 -0
- {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
## v0.13.0.
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
## v0.13.0.dev9 (2026-09-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
- fix: preserve unreadable ANLZ tags when rewriting a track's path
|
|
5
|
+
- The PPTH rewrite went through AnlzFile.save(), which rebuilds a file from
|
|
6
|
+
the tags pyrekordbox parsed and discards the rest. PVB2, the seek index
|
|
7
|
+
Rekordbox writes for every analysed FLAC, is one it has no structure for,
|
|
8
|
+
so every edit and convert that changed a filename dropped it. Across a
|
|
9
|
+
24,698-file library, 1,787 files lost an 8,032-byte PVB2, and 10 more
|
|
10
|
+
could not be parsed at all, leaving a stale path behind a successful write.
|
|
11
|
+
- _anlz.py rewrites the tag by splicing bytes and correcting len_file. Tags
|
|
12
|
+
are walked by declared length instead of being parsed, so a tag with no
|
|
13
|
+
reader here survives and an unparseable file is still rewritten. Each
|
|
14
|
+
analysis file is handled on its own, so one malformed file no longer
|
|
15
|
+
abandons the rest of a track's analysis.
|
|
4
16
|
- docs(research): investigate integrating rekordbox-edit with beets
|
|
5
17
|
- fix(edit): give the records an edit creates and collects their USNs
|
|
6
18
|
- An edit that reassigned a relational field left the record it created
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rekordbox-edit
|
|
3
|
-
Version: 0.13.0.
|
|
3
|
+
Version: 0.13.0.dev9
|
|
4
4
|
Summary: Tools for managing and modifying a RekordBox library en-masse
|
|
5
5
|
Project-URL: Homepage, https://github.com/jviall/rekordbox-edit
|
|
6
6
|
Project-URL: Repository, https://github.com/jviall/rekordbox-edit
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rekordbox-edit"
|
|
7
|
-
version = "0.13.0.
|
|
7
|
+
version = "0.13.0.dev9"
|
|
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"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Byte-level reading and rewriting of the path tag in ANLZ analysis files.
|
|
2
|
+
|
|
3
|
+
An ANLZ file is a 28-byte header followed by a flat run of tags, each carrying
|
|
4
|
+
its own length and none referring to another's position. Rewriting the stored
|
|
5
|
+
path is therefore a splice: replace the PPTH tag, correct the file length, and
|
|
6
|
+
every other byte survives.
|
|
7
|
+
|
|
8
|
+
That byte preservation is the point. `pyrekordbox`'s `AnlzFile.save()` rebuilds
|
|
9
|
+
a file from the tags its parser recognized and silently discards the rest, which
|
|
10
|
+
loses `PVB2`, the seek index Rekordbox writes for FLAC tracks.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import struct
|
|
14
|
+
|
|
15
|
+
#: type, len_header, len_file, then four values this module does not interpret.
|
|
16
|
+
_FILE_HEADER = struct.Struct(">4sIIIIII")
|
|
17
|
+
#: type, len_header, len_tag. Every tag starts with these, whatever follows.
|
|
18
|
+
_TAG_HEADER = struct.Struct(">4sII")
|
|
19
|
+
_MAGIC = b"PMAI"
|
|
20
|
+
_PATH_TAG = b"PPTH"
|
|
21
|
+
#: PPTH holds its path after the tag header and a 4-byte character count.
|
|
22
|
+
_PATH_OFFSET = _TAG_HEADER.size + 4
|
|
23
|
+
#: The path is stored UTF-16 big-endian with a terminating null character.
|
|
24
|
+
_TERMINATOR = b"\x00\x00"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AnlzFormatError(ValueError):
|
|
28
|
+
"""The bytes given are not a well-formed ANLZ file."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _walk_tags(data: bytes):
|
|
32
|
+
"""Yield `(offset, tag_type, len_tag)` per tag, without reading contents.
|
|
33
|
+
|
|
34
|
+
Walking by declared length rather than by parsing means a tag this codebase
|
|
35
|
+
has no structure for is still traversable.
|
|
36
|
+
"""
|
|
37
|
+
if len(data) < _FILE_HEADER.size:
|
|
38
|
+
raise AnlzFormatError("shorter than an ANLZ file header")
|
|
39
|
+
magic, len_header = _FILE_HEADER.unpack_from(data, 0)[:2]
|
|
40
|
+
if magic != _MAGIC:
|
|
41
|
+
raise AnlzFormatError(f"expected {_MAGIC!r} magic, found {magic!r}")
|
|
42
|
+
|
|
43
|
+
offset = len_header
|
|
44
|
+
while offset + _TAG_HEADER.size <= len(data):
|
|
45
|
+
tag_type, _len_tag_header, len_tag = _TAG_HEADER.unpack_from(data, offset)
|
|
46
|
+
if len_tag <= 0 or offset + len_tag > len(data):
|
|
47
|
+
raise AnlzFormatError(
|
|
48
|
+
f"tag {tag_type!r} at offset {offset} declares length {len_tag}, "
|
|
49
|
+
f"which overruns the {len(data)}-byte file"
|
|
50
|
+
)
|
|
51
|
+
yield offset, tag_type, len_tag
|
|
52
|
+
offset += len_tag
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _find_path_tag(data: bytes) -> tuple[int, int]:
|
|
56
|
+
for offset, tag_type, len_tag in _walk_tags(data):
|
|
57
|
+
if tag_type == _PATH_TAG:
|
|
58
|
+
return offset, len_tag
|
|
59
|
+
raise AnlzFormatError(f"no {_PATH_TAG.decode()} tag in this file")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _build_path_tag(path: str) -> bytes:
|
|
63
|
+
encoded = path.encode("utf-16-be") + _TERMINATOR
|
|
64
|
+
content = struct.pack(">I", len(encoded)) + encoded
|
|
65
|
+
return (
|
|
66
|
+
_TAG_HEADER.pack(_PATH_TAG, _PATH_OFFSET, _TAG_HEADER.size + len(content))
|
|
67
|
+
+ content
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def read_path(data: bytes) -> str:
|
|
72
|
+
"""The path held in the file's PPTH tag."""
|
|
73
|
+
offset, _len_tag = _find_path_tag(data)
|
|
74
|
+
(len_path,) = struct.unpack_from(">I", data, offset + _TAG_HEADER.size)
|
|
75
|
+
start = offset + _PATH_OFFSET
|
|
76
|
+
return data[start : start + len_path - len(_TERMINATOR)].decode("utf-16-be")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def set_path(data: bytes, path: str) -> bytes:
|
|
80
|
+
"""Return `data` with its PPTH tag holding `path`, all other bytes kept."""
|
|
81
|
+
offset, len_tag = _find_path_tag(data)
|
|
82
|
+
spliced = data[:offset] + _build_path_tag(path) + data[offset + len_tag :]
|
|
83
|
+
|
|
84
|
+
magic, len_header, _stale_len, *trailing = _FILE_HEADER.unpack_from(spliced, 0)
|
|
85
|
+
header = _FILE_HEADER.pack(magic, len_header, len(spliced), *trailing)
|
|
86
|
+
return header + spliced[_FILE_HEADER.size :]
|
|
@@ -9,6 +9,8 @@ from pyrekordbox.utils import get_rekordbox_pid
|
|
|
9
9
|
from sqlalchemy import text
|
|
10
10
|
|
|
11
11
|
from rekordbox_edit._tag_fields import TAG_FIELDS
|
|
12
|
+
from rekordbox_edit.api._anlz import AnlzFormatError
|
|
13
|
+
from rekordbox_edit.api._anlz import set_path as set_anlz_path
|
|
12
14
|
from rekordbox_edit.errors import RekordboxRunningError
|
|
13
15
|
from rekordbox_edit.locking import SCRIPTED_TIMEOUT, database_lock
|
|
14
16
|
from rekordbox_edit.models import Track
|
|
@@ -81,15 +83,29 @@ def _update_anlz_paths(
|
|
|
81
83
|
"""Rewrite the PPTH path tag in a track's ANLZ files to the given file
|
|
82
84
|
name, in rekordbox's device-relative ``?/<name>`` form.
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
Splices the tag into the file's existing bytes rather than rebuilding it
|
|
87
|
+
from parsed structures, so tags this codebase has no reader for survive.
|
|
88
|
+
Rebuilding drops them, and one of them is `PVB2`, the seek index Rekordbox
|
|
89
|
+
writes for every analysed FLAC.
|
|
90
|
+
|
|
91
|
+
Each file is handled on its own: a malformed one is reported and skipped
|
|
92
|
+
rather than abandoning the rest of the track's analysis. No-op for tracks
|
|
93
|
+
without an analysis.
|
|
85
94
|
"""
|
|
86
95
|
if not content.AnalysisDataPath:
|
|
87
96
|
return
|
|
88
97
|
new_ppth = f"?/{new_filename}"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
for anlz_path in db.get_anlz_paths(content.ID).values():
|
|
99
|
+
if anlz_path is None:
|
|
100
|
+
continue
|
|
101
|
+
try:
|
|
102
|
+
with open(anlz_path, "rb") as fh:
|
|
103
|
+
updated = set_anlz_path(fh.read(), new_ppth)
|
|
104
|
+
with open(anlz_path, "wb") as fh:
|
|
105
|
+
fh.write(updated)
|
|
106
|
+
except (AnlzFormatError, OSError) as e:
|
|
107
|
+
_logger.warning(f"Could not rewrite the path tag in {anlz_path}: {e}")
|
|
108
|
+
continue
|
|
93
109
|
_logger.debug(f"Updated PPTH of {anlz_path} to {new_ppth}")
|
|
94
110
|
|
|
95
111
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Assemble ANLZ bytes for tests.
|
|
2
|
+
|
|
3
|
+
An ANLZ file is a 28-byte PMAI header followed by a flat run of tags. Building
|
|
4
|
+
that layout here lets a test place a tag no parser in this codebase understands,
|
|
5
|
+
which is the case the path rewrite has to survive.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import struct
|
|
9
|
+
|
|
10
|
+
FILE_HEADER = struct.Struct(">4sIIIIII")
|
|
11
|
+
_TAG_HEADER = struct.Struct(">4sII")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def tag(tag_type: bytes, content: bytes) -> bytes:
|
|
15
|
+
"""One tag: type, header length, total length, then content."""
|
|
16
|
+
return (
|
|
17
|
+
_TAG_HEADER.pack(tag_type, _TAG_HEADER.size, _TAG_HEADER.size + len(content))
|
|
18
|
+
+ content
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def path_tag(path: str) -> bytes:
|
|
23
|
+
"""A PPTH tag holding `path`, in Rekordbox's UTF-16 big-endian layout."""
|
|
24
|
+
encoded = path.encode("utf-16-be") + b"\x00\x00"
|
|
25
|
+
content = struct.pack(">I", len(encoded)) + encoded
|
|
26
|
+
return _TAG_HEADER.pack(b"PPTH", 16, _TAG_HEADER.size + len(content)) + content
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def anlz(*tags: bytes) -> bytes:
|
|
30
|
+
"""A complete ANLZ file wrapping `tags`."""
|
|
31
|
+
body = b"".join(tags)
|
|
32
|
+
return FILE_HEADER.pack(b"PMAI", 28, 28 + len(body), 0, 0, 0, 0) + body
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
#: Stands in for PVB2, which pyrekordbox has no structure for and drops on a
|
|
36
|
+
#: parse-and-rebuild. The contents are recognizable so a test can assert they
|
|
37
|
+
#: came through untouched.
|
|
38
|
+
UNPARSED_TAG = tag(b"PVB2", b"\xde\xad\xbe\xef" * 8)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Byte-level ANLZ path rewriting."""
|
|
2
|
+
|
|
3
|
+
import struct
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from pyrekordbox.anlz.file import AnlzFile
|
|
7
|
+
|
|
8
|
+
from tests.anlz_helpers import FILE_HEADER, UNPARSED_TAG, anlz, path_tag, tag
|
|
9
|
+
|
|
10
|
+
from rekordbox_edit.api._anlz import AnlzFormatError, read_path, set_path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestSetPath:
|
|
14
|
+
def test_writes_a_path_rekordbox_can_read_back(self):
|
|
15
|
+
data = anlz(path_tag("?/old name.flac"))
|
|
16
|
+
|
|
17
|
+
result = set_path(data, "?/new name.mp3")
|
|
18
|
+
|
|
19
|
+
# Verified through pyrekordbox's own parser, not our reader, so this
|
|
20
|
+
# asserts the output is well-formed rather than merely self-consistent.
|
|
21
|
+
assert AnlzFile.parse(result).get("path") == "?/new name.mp3"
|
|
22
|
+
|
|
23
|
+
def test_preserves_tags_the_parser_does_not_understand(self):
|
|
24
|
+
data = anlz(path_tag("?/old.flac"), UNPARSED_TAG)
|
|
25
|
+
|
|
26
|
+
result = set_path(data, "?/new.mp3")
|
|
27
|
+
|
|
28
|
+
assert UNPARSED_TAG in result
|
|
29
|
+
|
|
30
|
+
def test_writing_the_same_path_leaves_bytes_unchanged(self):
|
|
31
|
+
data = anlz(path_tag("?/song.flac"), UNPARSED_TAG)
|
|
32
|
+
|
|
33
|
+
assert set_path(data, "?/song.flac") == data
|
|
34
|
+
|
|
35
|
+
def test_updates_len_file_when_the_path_length_changes(self):
|
|
36
|
+
data = anlz(path_tag("?/short.flac"), UNPARSED_TAG)
|
|
37
|
+
|
|
38
|
+
result = set_path(data, "?/a considerably longer name.flac")
|
|
39
|
+
|
|
40
|
+
assert FILE_HEADER.unpack_from(result, 0)[2] == len(result)
|
|
41
|
+
|
|
42
|
+
def test_rewrites_a_file_pyrekordbox_cannot_parse(self):
|
|
43
|
+
# A PQTZ tag whose content is too short for its struct: pyrekordbox
|
|
44
|
+
# raises, but the tag run is still walkable by declared length.
|
|
45
|
+
data = anlz(path_tag("?/old.flac"), tag(b"PQTZ", b"\x00"))
|
|
46
|
+
with pytest.raises(Exception):
|
|
47
|
+
AnlzFile.parse(data)
|
|
48
|
+
|
|
49
|
+
result = set_path(data, "?/new.mp3")
|
|
50
|
+
|
|
51
|
+
assert read_path(result) == "?/new.mp3"
|
|
52
|
+
|
|
53
|
+
def test_rejects_a_file_that_is_not_anlz(self):
|
|
54
|
+
with pytest.raises(AnlzFormatError):
|
|
55
|
+
set_path(b"NOPE" + b"\x00" * 40, "?/new.mp3")
|
|
56
|
+
|
|
57
|
+
def test_rejects_a_file_with_no_path_tag(self):
|
|
58
|
+
with pytest.raises(AnlzFormatError):
|
|
59
|
+
set_path(anlz(UNPARSED_TAG), "?/new.mp3")
|
|
60
|
+
|
|
61
|
+
def test_rejects_a_tag_that_overruns_the_file(self):
|
|
62
|
+
good = anlz(path_tag("?/old.flac"))
|
|
63
|
+
# Declare a tag length past the end of the buffer.
|
|
64
|
+
corrupt = bytearray(good)
|
|
65
|
+
struct.pack_into(">I", corrupt, 28 + 8, 9999)
|
|
66
|
+
with pytest.raises(AnlzFormatError):
|
|
67
|
+
set_path(bytes(corrupt), "?/new.mp3")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TestReadPath:
|
|
71
|
+
def test_returns_the_stored_path(self):
|
|
72
|
+
assert read_path(anlz(path_tag("?/song.flac"))) == "?/song.flac"
|
|
73
|
+
|
|
74
|
+
def test_rejects_a_file_with_no_path_tag(self):
|
|
75
|
+
with pytest.raises(AnlzFormatError):
|
|
76
|
+
read_path(anlz(UNPARSED_TAG))
|
|
@@ -27,7 +27,6 @@ from rekordbox_edit.api._convert import (
|
|
|
27
27
|
_run_ffmpeg,
|
|
28
28
|
_sweep_orphan_temp_files,
|
|
29
29
|
_temp_output_path,
|
|
30
|
-
_update_anlz_paths,
|
|
31
30
|
convert,
|
|
32
31
|
)
|
|
33
32
|
from sqlalchemy import text
|
|
@@ -2578,33 +2577,6 @@ class TestApplyConvertedRecord:
|
|
|
2578
2577
|
assert content.SampleRate == 48000
|
|
2579
2578
|
|
|
2580
2579
|
|
|
2581
|
-
class TestUpdateAnlzPaths:
|
|
2582
|
-
def test_rewrites_ppth_to_device_relative_form(self, make_djmd_content_item):
|
|
2583
|
-
mock_db = Mock()
|
|
2584
|
-
content = make_djmd_content_item(ID=7)
|
|
2585
|
-
content.AnalysisDataPath = "share/PIONEER/USBANLZ/x/ANLZ0000.DAT"
|
|
2586
|
-
dat, ext = Mock(), Mock()
|
|
2587
|
-
mock_db.read_anlz_files.return_value = {
|
|
2588
|
-
"/a/ANLZ0000.DAT": dat,
|
|
2589
|
-
"/a/ANLZ0000.EXT": ext,
|
|
2590
|
-
}
|
|
2591
|
-
|
|
2592
|
-
_update_anlz_paths(mock_db, content, "new song.aiff")
|
|
2593
|
-
|
|
2594
|
-
dat.set_path.assert_called_once_with("?/new song.aiff")
|
|
2595
|
-
dat.save.assert_called_once_with("/a/ANLZ0000.DAT")
|
|
2596
|
-
ext.set_path.assert_called_once_with("?/new song.aiff")
|
|
2597
|
-
ext.save.assert_called_once_with("/a/ANLZ0000.EXT")
|
|
2598
|
-
|
|
2599
|
-
def test_skips_track_without_analysis(self, make_djmd_content_item):
|
|
2600
|
-
mock_db = Mock()
|
|
2601
|
-
content = make_djmd_content_item(ID=7) # AnalysisDataPath defaults to None
|
|
2602
|
-
|
|
2603
|
-
_update_anlz_paths(mock_db, content, "new.aiff")
|
|
2604
|
-
|
|
2605
|
-
mock_db.read_anlz_files.assert_not_called()
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
2580
|
class TestRollbackSession:
|
|
2609
2581
|
def test_rolls_back_session(self, mock_db):
|
|
2610
2582
|
_rollback_session(mock_db)
|
|
@@ -9,9 +9,12 @@ from filelock import FileLock, Timeout
|
|
|
9
9
|
from pyrekordbox import Rekordbox6Database
|
|
10
10
|
from sqlalchemy import text
|
|
11
11
|
|
|
12
|
+
from tests.anlz_helpers import UNPARSED_TAG, anlz, path_tag
|
|
12
13
|
from tests.api.conftest import close_database
|
|
13
14
|
|
|
15
|
+
from rekordbox_edit.api._anlz import read_path
|
|
14
16
|
from rekordbox_edit.api._utils import (
|
|
17
|
+
_update_anlz_paths,
|
|
15
18
|
reserve_usns,
|
|
16
19
|
stamp_usns,
|
|
17
20
|
track_from_content,
|
|
@@ -261,3 +264,63 @@ class TestWriting:
|
|
|
261
264
|
pass
|
|
262
265
|
finally:
|
|
263
266
|
foreign.release()
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class TestUpdateAnlzPaths:
|
|
270
|
+
"""The path rewrite must not disturb anything else in the file: these are
|
|
271
|
+
the only copy of a track's analysis, and tags this codebase cannot parse
|
|
272
|
+
still belong to Rekordbox."""
|
|
273
|
+
|
|
274
|
+
@pytest.fixture()
|
|
275
|
+
def analysed(self, tmp_path, make_djmd_content_item):
|
|
276
|
+
"""A track whose DAT and EXT files exist on disk, the EXT carrying a
|
|
277
|
+
tag no parser here understands."""
|
|
278
|
+
dat = tmp_path / "ANLZ0000.DAT"
|
|
279
|
+
ext = tmp_path / "ANLZ0000.EXT"
|
|
280
|
+
dat.write_bytes(anlz(path_tag("?/old name.flac")))
|
|
281
|
+
ext.write_bytes(anlz(path_tag("?/old name.flac"), UNPARSED_TAG))
|
|
282
|
+
|
|
283
|
+
db = Mock()
|
|
284
|
+
db.get_anlz_paths.return_value = {"DAT": dat, "EXT": ext}
|
|
285
|
+
content = make_djmd_content_item(ID=7)
|
|
286
|
+
content.AnalysisDataPath = "share/PIONEER/USBANLZ/x/ANLZ0000.DAT"
|
|
287
|
+
return db, content, dat, ext
|
|
288
|
+
|
|
289
|
+
def test_rewrites_the_path_in_every_analysis_file(self, analysed):
|
|
290
|
+
db, content, dat, ext = analysed
|
|
291
|
+
|
|
292
|
+
_update_anlz_paths(db, content, "new song.mp3")
|
|
293
|
+
|
|
294
|
+
assert read_path(dat.read_bytes()) == "?/new song.mp3"
|
|
295
|
+
assert read_path(ext.read_bytes()) == "?/new song.mp3"
|
|
296
|
+
|
|
297
|
+
def test_preserves_tags_the_parser_does_not_understand(self, analysed):
|
|
298
|
+
db, content, _dat, ext = analysed
|
|
299
|
+
|
|
300
|
+
_update_anlz_paths(db, content, "new song.mp3")
|
|
301
|
+
|
|
302
|
+
assert UNPARSED_TAG in ext.read_bytes()
|
|
303
|
+
|
|
304
|
+
def test_leaves_other_files_alone_when_one_is_malformed(self, analysed):
|
|
305
|
+
db, content, dat, ext = analysed
|
|
306
|
+
ext.write_bytes(b"not an anlz file at all")
|
|
307
|
+
|
|
308
|
+
_update_anlz_paths(db, content, "new song.mp3")
|
|
309
|
+
|
|
310
|
+
assert read_path(dat.read_bytes()) == "?/new song.mp3"
|
|
311
|
+
|
|
312
|
+
def test_skips_a_track_without_analysis(self, make_djmd_content_item):
|
|
313
|
+
db = Mock()
|
|
314
|
+
content = make_djmd_content_item(ID=7) # AnalysisDataPath defaults to None
|
|
315
|
+
|
|
316
|
+
_update_anlz_paths(db, content, "new.mp3")
|
|
317
|
+
|
|
318
|
+
db.get_anlz_paths.assert_not_called()
|
|
319
|
+
|
|
320
|
+
def test_skips_an_analysis_file_that_does_not_exist(self, analysed, tmp_path):
|
|
321
|
+
db, content, dat, _ext = analysed
|
|
322
|
+
db.get_anlz_paths.return_value = {"DAT": dat, "EXT": tmp_path / "absent.EXT"}
|
|
323
|
+
|
|
324
|
+
_update_anlz_paths(db, content, "new song.mp3")
|
|
325
|
+
|
|
326
|
+
assert read_path(dat.read_bytes()) == "?/new song.mp3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commit-check/action.yml
RENAMED
|
File without changes
|
{rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commitizen-bump/action.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/install/action.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_field_handlers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|