rekordbox-edit 0.9.0.dev22__tar.gz → 0.9.0.dev29__tar.gz

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