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.
Files changed (384) hide show
  1. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CHANGELOG.md +15 -3
  2. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/PKG-INFO +1 -1
  3. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/pyproject.toml +1 -1
  4. rekordbox_edit-0.13.0.dev9/rekordbox_edit/api/_anlz.py +86 -0
  5. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_utils.py +21 -5
  6. rekordbox_edit-0.13.0.dev9/tests/anlz_helpers.py +38 -0
  7. rekordbox_edit-0.13.0.dev9/tests/api/test_anlz.py +76 -0
  8. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_convert.py +0 -28
  9. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_utils.py +63 -0
  10. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/uv.lock +1 -1
  11. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.agent-style/RULES.md +0 -0
  12. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.agent-style/claude-code.md +0 -0
  13. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/build-release-notes/action.yml +0 -0
  14. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/build-release-notes/build_release_notes.py +0 -0
  15. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commit-check/action.yml +0 -0
  16. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commitizen-bump/action.yml +0 -0
  17. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/commitizen-bump/commitizen-bump.sh +0 -0
  18. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/e2e/action.yml +0 -0
  19. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/install/action.yml +0 -0
  20. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/lint/action.yml +0 -0
  21. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/actions/test/action.yml +0 -0
  22. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/cd.yml +0 -0
  23. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/ci.yml +0 -0
  24. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/publish.yml +0 -0
  25. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.github/workflows/release.yml +0 -0
  26. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.gitignore +0 -0
  27. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.pre-commit-config.yaml +0 -0
  28. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.python-version +0 -0
  29. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/.readthedocs.yaml +0 -0
  30. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/AGENTS.md +0 -0
  31. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CLAUDE.md +0 -0
  32. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/CONTRIBUTING.md +0 -0
  33. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/LICENSE +0 -0
  34. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/Makefile +0 -0
  35. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/README.md +0 -0
  36. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/codecov.yml +0 -0
  37. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docker-compose.yml +0 -0
  38. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/api.md +0 -0
  39. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/convert.md +0 -0
  40. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/edit.md +0 -0
  41. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/import.md +0 -0
  42. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/remove.md +0 -0
  43. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/commands/search.md +0 -0
  44. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/faqs.md +0 -0
  45. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/filtering.md +0 -0
  46. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/index.md +0 -0
  47. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/docs/stylesheets/extra.css +0 -0
  48. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/mkdocs.yml +0 -0
  49. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/__init__.py +0 -0
  50. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/_tag_fields.py +0 -0
  51. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/__init__.py +0 -0
  52. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_convert.py +0 -0
  53. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_edit.py +0 -0
  54. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_field_handlers.py +0 -0
  55. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_import.py +0 -0
  56. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_relations.py +0 -0
  57. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_remove.py +0 -0
  58. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/api/_search.py +0 -0
  59. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/__init__.py +0 -0
  60. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_click.py +0 -0
  61. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_progress.py +0 -0
  62. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/_utils.py +0 -0
  63. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/convert.py +0 -0
  64. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/edit.py +0 -0
  65. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/import_.py +0 -0
  66. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/main.py +0 -0
  67. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/remove.py +0 -0
  68. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/cli/search.py +0 -0
  69. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/display.py +0 -0
  70. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/errors.py +0 -0
  71. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/locking.py +0 -0
  72. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/logger.py +0 -0
  73. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/models.py +0 -0
  74. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/query.py +0 -0
  75. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/tags.py +0 -0
  76. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/rekordbox_edit/utils.py +0 -0
  77. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/renovate.json5 +0 -0
  78. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/README.md +0 -0
  79. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/beets-plugin-integration.md +0 -0
  80. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/decisions/converted-original-disposition.md +0 -0
  81. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/convert-repoint.txt +0 -0
  82. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/event-order.txt +0 -0
  83. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/file-level-encode.txt +0 -0
  84. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/id-stability.txt +0 -0
  85. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/evidence/media-field-roundtrip.txt +0 -0
  86. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/convert_repoint.py +0 -0
  87. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/event_probe.py +0 -0
  88. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/file_level_encode.py +0 -0
  89. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/id_stability.py +0 -0
  90. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/beets-plugin-integration/scripts/media_field_roundtrip.py +0 -0
  91. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/convert-export-impact-test-plan.md +0 -0
  92. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/convert-export-impact.md +0 -0
  93. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-00-baseline.json +0 -0
  94. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-10-postconvert.json +0 -0
  95. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r1-20-postexport.json +0 -0
  96. {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
  97. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2-00-baseline.json +0 -0
  98. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-00-baseline.json +0 -0
  99. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-10-deviceedit.json +0 -0
  100. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r2b-30-postsync.json +0 -0
  101. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-00-baseline.json +0 -0
  102. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-10-deviceedit.json +0 -0
  103. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/evidence/export-r3-40-resync.json +0 -0
  104. {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
  105. {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
  106. {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
  107. {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
  108. {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
  109. {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
  110. {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
  111. {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
  112. {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
  113. {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
  114. {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
  115. {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
  116. {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
  117. {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
  118. {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
  119. {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
  120. {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
  121. {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
  122. {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
  123. {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
  124. {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
  125. {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
  126. {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
  127. {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
  128. {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
  129. {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
  130. {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
  131. {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
  132. {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
  133. {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
  134. {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
  135. {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
  136. {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
  137. {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
  138. {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
  139. {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
  140. {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
  141. {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
  142. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/scripts/export_diff.py +0 -0
  143. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-export-impact/scripts/export_snapshot.py +0 -0
  144. {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
  145. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-experiment2.md +0 -0
  146. {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
  147. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact-verification.md +0 -0
  148. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/convert-anlz-cue-impact.md +0 -0
  149. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/decisions/convert-and-reanalysis-impact.md +0 -0
  150. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/decisions/convert-helper-structure.md +0 -0
  151. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/01-inventory.txt +0 -0
  152. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/02-cue-schema.txt +0 -0
  153. {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
  154. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/04-anlz-deep.txt +0 -0
  155. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/05-census.txt +0 -0
  156. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/06-content-columns.txt +0 -0
  157. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/07-analysis-flags.txt +0 -0
  158. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/exp2-00-pvb2-origin.txt +0 -0
  159. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-00-zero.json +0 -0
  160. {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
  161. {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
  162. {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
  163. {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
  164. {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
  165. {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
  166. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-01.json +0 -0
  167. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-02.json +0 -0
  168. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-03.json +0 -0
  169. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-04.json +0 -0
  170. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-high-05.json +0 -0
  171. {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
  172. {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
  173. {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
  174. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-01.json +0 -0
  175. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-02.json +0 -0
  176. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-03.json +0 -0
  177. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-04.json +0 -0
  178. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-05.json +0 -0
  179. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-174954387-normal-06.json +0 -0
  180. {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
  181. {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
  182. {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
  183. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-00-baseline.json +0 -0
  184. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postanalyze.json +0 -0
  185. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205157376-aiff-postconv.json +0 -0
  186. {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
  187. {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
  188. {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
  189. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-00-baseline.json +0 -0
  190. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postanalyze.json +0 -0
  191. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postconv.json +0 -0
  192. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-aiff-postopen.json +0 -0
  193. {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
  194. {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
  195. {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
  196. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-flac-postconv.json +0 -0
  197. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postanalyze.json +0 -0
  198. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-205795680-mp3-postconv.json +0 -0
  199. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-00-baseline.json +0 -0
  200. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-locked.json +0 -0
  201. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-mp3-postconv.json +0 -0
  202. {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
  203. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-postlock.json +0 -0
  204. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-230928195-prelock.json +0 -0
  205. {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
  206. {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
  207. {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
  208. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-00-zero.json +0 -0
  209. {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
  210. {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
  211. {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
  212. {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
  213. {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
  214. {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
  215. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-01.json +0 -0
  216. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-02.json +0 -0
  217. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-03.json +0 -0
  218. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-04.json +0 -0
  219. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-high-05.json +0 -0
  220. {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
  221. {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
  222. {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
  223. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-01.json +0 -0
  224. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-02.json +0 -0
  225. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-03.json +0 -0
  226. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-04.json +0 -0
  227. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-05.json +0 -0
  228. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-06.json +0 -0
  229. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-27790898-normal-locked.json +0 -0
  230. {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
  231. {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
  232. {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
  233. {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
  234. {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
  235. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-baseline.json +0 -0
  236. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postanalyze.json +0 -0
  237. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/evidence/subject-7691309-pvb2-postconv.json +0 -0
  238. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/README.md +0 -0
  239. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/analysis_flags.py +0 -0
  240. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/anlz_census.py +0 -0
  241. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/anlz_deep.py +0 -0
  242. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/content_columns.py +0 -0
  243. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/cue_fields_by_format.py +0 -0
  244. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/cue_schema.py +0 -0
  245. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/grid_drift.py +0 -0
  246. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/inventory.py +0 -0
  247. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/pvb2_origin.py +0 -0
  248. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/reset_fresh_to_zero.py +0 -0
  249. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/restore_fixtures.sh +0 -0
  250. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-reanalysis-impact/scripts/row_snapshot.py +0 -0
  251. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/convert-thread-scaling.md +0 -0
  252. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/evidence/thread-scaling.txt +0 -0
  253. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/_sources.py +0 -0
  254. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/format_scaling.py +0 -0
  255. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/shipped_path_scaling.py +0 -0
  256. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/convert-thread-scaling/scripts/write_cost.py +0 -0
  257. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/database-concurrency.md +0 -0
  258. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/evidence/plan-apply-probes.txt +0 -0
  259. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/evidence/usn-spikes.txt +0 -0
  260. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/plan-apply-window.md +0 -0
  261. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/block_reservation.py +0 -0
  262. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/concurrent_increment.py +0 -0
  263. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/identity_probe.py +0 -0
  264. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/membership_probe.py +0 -0
  265. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/snapshot_probe.py +0 -0
  266. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/scripts/wal_snapshot.py +0 -0
  267. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/database-concurrency/usn-maintenance.md +0 -0
  268. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/decisions/edit-field-handlers.md +0 -0
  269. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/edit-relational-fields-test-plan.md +0 -0
  270. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/edit-relational-fields.md +0 -0
  271. {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
  272. {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
  273. {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
  274. {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
  275. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/evidence/rel-145166719-e0-census.json +0 -0
  276. {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
  277. {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
  278. {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
  279. {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
  280. {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
  281. {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
  282. {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
  283. {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
  284. {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
  285. {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
  286. {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
  287. {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
  288. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/scripts/relational_diff.py +0 -0
  289. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/edit-relational-fields/scripts/relational_snapshot.py +0 -0
  290. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/file-types/README.md +0 -0
  291. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/file-types/decisions/unknown-file-types.md +0 -0
  292. {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
  293. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/column-coverage-gig.json +0 -0
  294. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/datecreated-source-gig.json +0 -0
  295. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/filetype-searchstr-gig.json +0 -0
  296. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/evidence/filetype-searchstr-local.json +0 -0
  297. {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
  298. {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
  299. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/import-track-row-shape.md +0 -0
  300. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/column_coverage.py +0 -0
  301. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/datecreated_source.py +0 -0
  302. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/filetype_and_searchstr.py +0 -0
  303. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/import_row_shape.py +0 -0
  304. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/import-track-row-shape/scripts/tag_key_mapping.py +0 -0
  305. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/decisions/remove-command-behavior.md +0 -0
  306. {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
  307. {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
  308. {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
  309. {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
  310. {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
  311. {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
  312. {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
  313. {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
  314. {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
  315. {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
  316. {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
  317. {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
  318. {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
  319. {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
  320. {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
  321. {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
  322. {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
  323. {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
  324. {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
  325. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/remove-track-impact-test-plan.md +0 -0
  326. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/remove-track-impact.md +0 -0
  327. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/build_fixtures.py +0 -0
  328. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/removal_diff.py +0 -0
  329. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/removal_snapshot.py +0 -0
  330. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/remove-track-impact/scripts/restore.sh +0 -0
  331. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/shared/scripts/subject_diff.py +0 -0
  332. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/research/shared/scripts/subject_snapshot.py +0 -0
  333. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/ruff.toml +0 -0
  334. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/__init__.py +0 -0
  335. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/__init__.py +0 -0
  336. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/conftest.py +0 -0
  337. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_edit.py +0 -0
  338. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_field_handlers.py +0 -0
  339. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_import.py +0 -0
  340. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_package.py +0 -0
  341. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_relations.py +0 -0
  342. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_remove.py +0 -0
  343. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/api/test_search.py +0 -0
  344. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/__init__.py +0 -0
  345. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_convert.py +0 -0
  346. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_edit.py +0 -0
  347. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_import.py +0 -0
  348. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_locking.py +0 -0
  349. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_main.py +0 -0
  350. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_progress.py +0 -0
  351. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_remove.py +0 -0
  352. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_search.py +0 -0
  353. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/cli/test_utils.py +0 -0
  354. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/conftest.py +0 -0
  355. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/Dockerfile +0 -0
  356. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__init__.py +0 -0
  357. {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
  358. {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
  359. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/__snapshots__/test_journey.ambr +0 -0
  360. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/conftest.py +0 -0
  361. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/01-flac-44_1k-16b.flac +0 -0
  362. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/02-flac-96k-24b.flac +0 -0
  363. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/03-alac-44_1k-16b.m4a +0 -0
  364. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/04-alac-48k-24b.m4a +0 -0
  365. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/05-aiff-44_1k-16b.aiff +0 -0
  366. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/06-wav-96k-24b.wav +0 -0
  367. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/07-mp3-44_1k-320cbr.mp3 +0 -0
  368. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/08-mp3-44_1k-v0vbr.mp3 +0 -0
  369. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/audio/09-aac-44_1k-256kbps.m4a +0 -0
  370. {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
  371. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/macos/master.6.8.6.db +0 -0
  372. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/fixtures/windows/master.6.8.6.db +0 -0
  373. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_edit_fields.py +0 -0
  374. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_import.py +0 -0
  375. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_journey.py +0 -0
  376. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/e2e/test_remove.py +0 -0
  377. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_display.py +0 -0
  378. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_locking.py +0 -0
  379. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_logger.py +0 -0
  380. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_models.py +0 -0
  381. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_query.py +0 -0
  382. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_tag_fields.py +0 -0
  383. {rekordbox_edit-0.13.0.dev8 → rekordbox_edit-0.13.0.dev9}/tests/test_tags.py +0 -0
  384. {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.dev8 (2026-09-08)
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.dev8
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.dev8"
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
- No-op for tracks without an analysis.
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
- anlz_files = db.read_anlz_files(content.ID)
90
- for anlz_path, anlz in anlz_files.items():
91
- anlz.set_path(new_ppth)
92
- anlz.save(anlz_path)
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"
@@ -1277,7 +1277,7 @@ wheels = [
1277
1277
 
1278
1278
  [[package]]
1279
1279
  name = "rekordbox-edit"
1280
- version = "0.13.0.dev8"
1280
+ version = "0.13.0.dev9"
1281
1281
  source = { editable = "." }
1282
1282
  dependencies = [
1283
1283
  { name = "click" },