audiometa-python 1.3.0__tar.gz → 1.3.3__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 (421) hide show
  1. {audiometa_python-1.3.0/audiometa_python.egg-info → audiometa_python-1.3.3}/PKG-INFO +3 -1
  2. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/README.md +2 -0
  3. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_MetadataManager.py +5 -0
  4. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +3 -12
  5. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +48 -0
  6. audiometa_python-1.3.3/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +191 -0
  7. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +28 -15
  8. audiometa_python-1.3.3/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +76 -0
  9. audiometa_python-1.3.3/audiometa/test/tests/unit/utils/test_disc_number_read.py +66 -0
  10. audiometa_python-1.3.3/audiometa/utils/disc_number_read.py +30 -0
  11. {audiometa_python-1.3.0 → audiometa_python-1.3.3/audiometa_python.egg-info}/PKG-INFO +3 -1
  12. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa_python.egg-info/SOURCES.txt +2 -0
  13. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/pyproject.toml +3 -1
  14. audiometa_python-1.3.0/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -92
  15. audiometa_python-1.3.0/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +0 -32
  16. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/LICENSE +0 -0
  17. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/__init__.py +0 -0
  18. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/__main__.py +0 -0
  19. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/_audio_file.py +0 -0
  20. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/cli.py +0 -0
  21. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/exceptions.py +0 -0
  22. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/__init__.py +0 -0
  23. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +0 -0
  24. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/__init__.py +0 -0
  25. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/__init__.py +0 -0
  26. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_id3v1_preserver.py +0 -0
  27. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
  28. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_flac_handler.py +0 -0
  29. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_reader.py +0 -0
  30. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_writer.py +0 -0
  31. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +0 -0
  32. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/__init__.py +0 -0
  33. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/_riff_bext_chunk.py +0 -0
  34. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +0 -0
  35. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/_riff_file_structure.py +0 -0
  36. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/riff/_riff_info_chunk.py +0 -0
  37. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/vorbis/__init__.py +0 -0
  38. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
  39. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/id3v1/_Id3v1Manager.py +0 -0
  40. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/id3v1/__init__.py +0 -0
  41. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/id3v1/_constants.py +0 -0
  42. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
  43. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
  44. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/__init__.py +0 -0
  45. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/assets/create_test_files.py +0 -0
  46. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/__init__.py +0 -0
  47. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/common/__init__.py +0 -0
  48. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
  49. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
  50. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v1/__init__.py +0 -0
  51. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
  52. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
  53. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
  54. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
  55. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/__init__.py +0 -0
  56. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
  57. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
  58. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
  59. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
  60. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
  61. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/__init__.py +0 -0
  62. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
  63. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
  64. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
  65. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/riff_metadata_getter.py +0 -0
  66. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/riff/riff_metadata_setter.py +0 -0
  67. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/scripts/__init__.py +0 -0
  68. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/technical_info_inspector.py +0 -0
  69. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
  70. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/vorbis/__init__.py +0 -0
  71. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
  72. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
  73. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
  74. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
  75. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/__init__.py +0 -0
  76. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/conftest.py +0 -0
  77. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/__init__.py +0 -0
  78. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
  79. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
  80. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
  81. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
  82. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
  83. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
  84. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
  85. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +0 -0
  86. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
  87. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
  88. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
  89. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
  90. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +0 -0
  91. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
  92. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
  93. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
  94. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_options.py +0 -0
  95. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/read/test_unified.py +0 -0
  96. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
  97. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/test_formatting.py +0 -0
  98. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
  99. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
  100. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
  101. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +0 -0
  102. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
  103. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
  104. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
  105. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
  106. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
  107. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
  108. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
  109. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
  110. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
  111. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
  112. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
  113. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
  114. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
  115. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
  116. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/__init__.py +0 -0
  117. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
  118. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
  119. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
  120. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
  121. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
  122. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
  123. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
  124. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
  125. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
  126. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
  127. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
  128. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
  129. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
  130. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
  131. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
  132. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
  133. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/conftest.py +0 -0
  134. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
  135. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
  136. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +0 -0
  137. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
  138. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
  139. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
  140. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
  141. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
  142. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
  143. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/options/__init__.py +0 -0
  144. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/options/test_include_headers.py +0 -0
  145. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/options/test_include_technical.py +0 -0
  146. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +0 -0
  147. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +0 -0
  148. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +0 -0
  149. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +0 -0
  150. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +0 -0
  151. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +0 -0
  152. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_performance.py +0 -0
  153. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_raw_metadata_includes_unsupported_tags.py +0 -0
  154. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +0 -0
  155. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/get_full_metadata/test_structure.py +0 -0
  156. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
  157. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
  158. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
  159. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
  160. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
  161. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
  162. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
  163. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
  164. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
  165. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
  166. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
  167. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
  168. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
  169. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
  170. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
  171. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
  172. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
  173. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
  174. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
  175. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
  176. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
  177. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
  178. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
  179. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
  180. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
  181. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
  182. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
  183. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
  184. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
  185. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/description/__init__.py +0 -0
  186. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/description/test_deleting.py +0 -0
  187. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/description/test_reading.py +0 -0
  188. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/description/test_writing.py +0 -0
  189. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
  190. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
  191. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +0 -0
  192. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
  193. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
  194. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
  195. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
  196. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
  197. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
  198. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
  199. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +0 -0
  200. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +0 -0
  201. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +0 -0
  202. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +0 -0
  203. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
  204. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
  205. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
  206. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +0 -0
  207. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +0 -0
  208. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +0 -0
  209. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +0 -0
  210. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
  211. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
  212. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
  213. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
  214. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
  215. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
  216. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
  217. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
  218. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/__init__.py +0 -0
  219. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_deleting.py +0 -0
  220. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_reading.py +0 -0
  221. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_writing.py +0 -0
  222. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/__init__.py +0 -0
  223. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_deleting.py +0 -0
  224. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_reading.py +0 -0
  225. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_writing.py +0 -0
  226. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/originator/__init__.py +0 -0
  227. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/originator/test_deleting.py +0 -0
  228. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/originator/test_reading.py +0 -0
  229. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/originator/test_writing.py +0 -0
  230. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
  231. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
  232. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
  233. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
  234. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
  235. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
  236. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +0 -0
  237. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +0 -0
  238. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +0 -0
  239. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
  240. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
  241. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
  242. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
  243. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +0 -0
  244. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +0 -0
  245. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +0 -0
  246. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
  247. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
  248. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
  249. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
  250. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
  251. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
  252. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
  253. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
  254. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
  255. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
  256. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
  257. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
  258. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
  259. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
  260. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
  261. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
  262. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
  263. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
  264. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
  265. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
  266. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +0 -0
  267. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +0 -0
  268. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
  269. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
  270. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
  271. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
  272. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
  273. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
  274. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
  275. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
  276. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +0 -0
  277. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +0 -0
  278. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
  279. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
  280. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
  281. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
  282. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/reading/__init__.py +0 -0
  283. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
  284. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
  285. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
  286. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
  287. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
  288. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
  289. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
  290. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
  291. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/__init__.py +0 -0
  292. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_audio_data_corruption.py +0 -0
  293. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_file.py +0 -0
  294. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_invalid_md5.py +0 -0
  295. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/__init__.py +0 -0
  296. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_invalid_with_metadata_combinations.py +0 -0
  297. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_state_precedence.py +0 -0
  298. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_unset_with_metadata_combinations.py +0 -0
  299. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_fails_with_id3v1.py +0 -0
  300. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_with_id3v2_only.py +0 -0
  301. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_works_without_id3v1.py +0 -0
  302. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_with_metadata_combinations.py +0 -0
  303. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_unset_md5.py +0 -0
  304. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/__init__.py +0 -0
  305. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_delete_original.py +0 -0
  306. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/__init__.py +0 -0
  307. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_flipped_md5.py +0 -0
  308. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_partial_md5.py +0 -0
  309. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_random_md5.py +0 -0
  310. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_md5_repair_with_metadata.py +0 -0
  311. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_non_flac_error.py +0 -0
  312. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_unset_md5.py +0 -0
  313. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/test_bitrate.py +0 -0
  314. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
  315. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
  316. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
  317. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/test_audio_file.py +0 -0
  318. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +0 -0
  319. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/__init__.py +0 -0
  320. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
  321. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
  322. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
  323. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
  324. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
  325. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/__init__.py +0 -0
  326. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_flac_sync.py +0 -0
  327. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_mp3_sync.py +0 -0
  328. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_wav_sync.py +0 -0
  329. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
  330. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
  331. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
  332. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +0 -0
  333. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +0 -0
  334. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +0 -0
  335. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/__init__.py +0 -0
  336. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
  337. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
  338. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
  339. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
  340. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +0 -0
  341. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
  342. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
  343. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
  344. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
  345. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
  346. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
  347. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
  348. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
  349. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
  350. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/cli/__init__.py +0 -0
  351. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/cli/test_cli_colorize.py +0 -0
  352. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
  353. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
  354. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
  355. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
  356. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
  357. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
  358. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -0
  359. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff_info_chunk_fourcc.py +0 -0
  360. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
  361. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
  362. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/__init__.py +0 -0
  363. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/test_disc_number_validation.py +0 -0
  364. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/__init__.py +0 -0
  365. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_format_validation.py +0 -0
  366. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_type_validation.py +0 -0
  367. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
  368. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
  369. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +0 -0
  370. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
  371. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +0 -0
  372. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +0 -0
  373. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/__init__.py +0 -0
  374. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_format_validation.py +0 -0
  375. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_type_validation.py +0 -0
  376. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/__init__.py +0 -0
  377. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_format_validation.py +0 -0
  378. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_type_validation.py +0 -0
  379. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/__init__.py +0 -0
  380. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/test_uuid_format_validation.py +0 -0
  381. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
  382. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
  383. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +0 -0
  384. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +0 -0
  385. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +0 -0
  386. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
  387. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +0 -0
  388. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +0 -0
  389. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +0 -0
  390. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/__init__.py +0 -0
  391. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/test_date_format_validation.py +0 -0
  392. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +0 -0
  393. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
  394. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/__init__.py +0 -0
  395. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/test_track_number_validation.py +0 -0
  396. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +0 -0
  397. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
  398. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/utils/__init__.py +0 -0
  399. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/test/tests/unit/utils/test_raw_metadata_sanitizer.py +0 -0
  400. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/__init__.py +0 -0
  401. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/flac_md5_state.py +0 -0
  402. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/id3v1_genre_code_map.py +0 -0
  403. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/metadata_format.py +0 -0
  404. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/metadata_writing_strategy.py +0 -0
  405. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/mutagen_exception_handler.py +0 -0
  406. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
  407. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/base.py +0 -0
  408. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/config.py +0 -0
  409. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
  410. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/ubuntu.py +0 -0
  411. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
  412. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/rating_profiles.py +0 -0
  413. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/raw_metadata_sanitizer.py +0 -0
  414. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/tool_path_resolver.py +0 -0
  415. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/types.py +0 -0
  416. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa/utils/unified_metadata_key.py +0 -0
  417. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa_python.egg-info/dependency_links.txt +0 -0
  418. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa_python.egg-info/entry_points.txt +0 -0
  419. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa_python.egg-info/requires.txt +0 -0
  420. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/audiometa_python.egg-info/top_level.txt +0 -0
  421. {audiometa_python-1.3.0 → audiometa_python-1.3.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: audiometa-python
3
- Version: 1.3.0
3
+ Version: 1.3.3
4
4
  Summary: A comprehensive Python library for reading and writing audio metadata across multiple formats
5
5
  Author: AudioMeta Python Contributors
6
6
  Author-email: Andreas Garcia <garcia.andreas.1991@gmail.com>
@@ -55,6 +55,8 @@ Dynamic: license-file
55
55
 
56
56
  A powerful, unified Python library for reading and writing audio metadata across multiple formats. AudioMeta supports MP3, FLAC, and WAV audio files, working seamlessly with ID3v1, ID3v2, Vorbis, and RIFF metadata formats through a single, consistent API.
57
57
 
58
+ **Try it**: A demo web app is available at [audiometa.themusictree.org](https://audiometa.themusictree.org).
59
+
58
60
  **Author**: [Andreas Garcia](https://github.com/BehindTheMusicTree)
59
61
 
60
62
  ## ⭐ Show Your Support
@@ -13,6 +13,8 @@
13
13
 
14
14
  A powerful, unified Python library for reading and writing audio metadata across multiple formats. AudioMeta supports MP3, FLAC, and WAV audio files, working seamlessly with ID3v1, ID3v2, Vorbis, and RIFF metadata formats through a single, consistent API.
15
15
 
16
+ **Try it**: A demo web app is available at [audiometa.themusictree.org](https://audiometa.themusictree.org).
17
+
16
18
  **Author**: [Andreas Garcia](https://github.com/BehindTheMusicTree)
17
19
 
18
20
  ## ⭐ Show Your Support
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, TypeVar, Union, cast
5
5
  from mutagen._file import FileType as MutagenMetadata
6
6
 
7
7
  from audiometa.exceptions import InvalidMetadataFieldFormatError, InvalidMetadataFieldTypeError
8
+ from audiometa.utils.disc_number_read import parse_disc_number_from_combined_str
8
9
  from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
9
10
 
10
11
  if TYPE_CHECKING:
@@ -698,6 +699,10 @@ class _MetadataManager:
698
699
  return track_str
699
700
  return None
700
701
 
702
+ # DISCNUMBER / TPOS-style "n", "n/m", "n-m" (formats using the base read path)
703
+ if unified_metadata_key == UnifiedMetadataKey.DISC_NUMBER:
704
+ return parse_disc_number_from_combined_str(str(value[0]))
705
+
701
706
  from typing import get_args, get_origin
702
707
 
703
708
  origin = get_origin(unified_metadata_key_optional_type)
@@ -30,6 +30,7 @@ from mutagen.id3._frames import (
30
30
  )
31
31
  from mutagen.id3._util import ID3NoHeaderError
32
32
 
33
+ from audiometa.utils.disc_number_read import parse_disc_number_from_combined_str, parse_disc_total_from_combined_str
33
34
  from audiometa.utils.raw_metadata_sanitizer import sanitize_id3v2_raw_info
34
35
  from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
35
36
 
@@ -415,12 +416,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
415
416
  if tpos_value is None or len(tpos_value) == 0:
416
417
  return None
417
418
  tpos_str = str(tpos_value[0])
418
- import re
419
-
420
- match = re.match(r"^(\d+)(?:/(\d+))?$", tpos_str)
421
- if match:
422
- return int(match.group(1))
423
- return None
419
+ return parse_disc_number_from_combined_str(tpos_str)
424
420
  if unified_metadata_key == UnifiedMetadataKey.DISC_TOTAL:
425
421
  tpos_key = self.Id3TextFrame.DISC_NUMBER
426
422
  if tpos_key not in raw_clean_metadata:
@@ -429,12 +425,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
429
425
  if tpos_value is None or len(tpos_value) == 0:
430
426
  return None
431
427
  tpos_str = str(tpos_value[0])
432
- import re
433
-
434
- match = re.match(r"^(\d+)/(\d+)$", tpos_str)
435
- if match:
436
- return int(match.group(2))
437
- return None
428
+ return parse_disc_total_from_combined_str(tpos_str)
438
429
  msg = f"Metadata key not handled: {unified_metadata_key}"
439
430
  raise MetadataFieldNotSupportedByMetadataFormatError(msg)
440
431
 
@@ -6,6 +6,11 @@ from typing import TYPE_CHECKING, Any, TypeVar, cast
6
6
  if TYPE_CHECKING:
7
7
  from ...._audio_file import _AudioFile
8
8
  from ....exceptions import FileCorruptedError, InvalidRatingValueError, MetadataFieldNotSupportedByMetadataFormatError
9
+ from ....utils.disc_number_read import (
10
+ parse_disc_number_from_combined_str,
11
+ parse_disc_total_from_combined_str,
12
+ parse_explicit_non_negative_disctotal,
13
+ )
9
14
  from ....utils.rating_profiles import RatingWriteProfile
10
15
  from ....utils.raw_metadata_sanitizer import sanitize_vorbis_raw_info
11
16
  from ....utils.tool_path_resolver import get_tool_path
@@ -260,6 +265,49 @@ class _VorbisManager(_RatingSupportingMetadataManager):
260
265
  # Cast to RawMetadataDict since RawMetadataKey is str, Enum and string keys work
261
266
  self.raw_clean_metadata_uppercase_keys = cast(RawMetadataDict, result_dict)
262
267
 
268
+ def get_unified_metadata_field(self, unified_metadata_key: UnifiedMetadataKey) -> UnifiedMetadataValue:
269
+ if unified_metadata_key not in (
270
+ UnifiedMetadataKey.DISC_NUMBER,
271
+ UnifiedMetadataKey.DISC_TOTAL,
272
+ ):
273
+ return super().get_unified_metadata_field(unified_metadata_key)
274
+
275
+ if self.raw_clean_metadata_uppercase_keys is None:
276
+ self._extract_raw_clean_metadata_uppercase_keys_from_file()
277
+ keys = self.raw_clean_metadata_uppercase_keys
278
+ if keys is None:
279
+ return None
280
+
281
+ disc_number_key = self.VorbisKey.DISC_NUMBER
282
+ disc_total_key = self.VorbisKey.DISC_TOTAL
283
+
284
+ def _first_string(raw_key: RawMetadataKey) -> str | None:
285
+ if raw_key not in keys:
286
+ return None
287
+ vals = keys[raw_key]
288
+ if not vals or len(vals) == 0:
289
+ return None
290
+ v = vals[0]
291
+ if v is None or v == "":
292
+ return None
293
+ return str(v)
294
+
295
+ d = _first_string(disc_number_key)
296
+ t = _first_string(disc_total_key)
297
+
298
+ if unified_metadata_key == UnifiedMetadataKey.DISC_NUMBER:
299
+ if d is None:
300
+ return None
301
+ return parse_disc_number_from_combined_str(d)
302
+
303
+ if t is not None:
304
+ explicit = parse_explicit_non_negative_disctotal(t)
305
+ if explicit is not None:
306
+ return explicit
307
+ if d is None:
308
+ return None
309
+ return parse_disc_total_from_combined_str(d)
310
+
263
311
  def _get_raw_rating_by_traktor_or_not(self, raw_clean_metadata: RawMetadataDict) -> tuple[int | None, bool]:
264
312
  if self.VorbisKey.RATING in raw_clean_metadata:
265
313
  rating_list = raw_clean_metadata[self.VorbisKey.RATING]
@@ -0,0 +1,191 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
5
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
6
+ from audiometa.test.helpers.vorbis.vorbis_metadata_setter import VorbisMetadataSetter
7
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
8
+
9
+
10
+ @pytest.mark.integration
11
+ class TestDiscNumberReading:
12
+ def test_id3v2_with_total(self):
13
+ with temp_file_with_metadata({}, "mp3") as test_file:
14
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1/2"})
15
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
16
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
17
+ assert disc_number == 1
18
+ assert disc_total == 2
19
+
20
+ def test_id3v2_without_total(self):
21
+ with temp_file_with_metadata({}, "mp3") as test_file:
22
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1"})
23
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
24
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
25
+ assert disc_number == 1
26
+ assert disc_total is None
27
+
28
+ def test_id3v2_max_value(self):
29
+ with temp_file_with_metadata({}, "mp3") as test_file:
30
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "99/99"})
31
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
32
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
33
+ assert disc_number == 99
34
+ assert disc_total == 99
35
+
36
+ def test_id3v2_hyphen_separator_read(self):
37
+ with temp_file_with_metadata({}, "mp3") as test_file:
38
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1-2"})
39
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
40
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
41
+ assert disc_number == 1
42
+ assert disc_total == 2
43
+
44
+ def test_id3v2_invalid_tpos_multiple_slashes_returns_none(self):
45
+ with temp_file_with_metadata({}, "mp3") as test_file:
46
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1/2/3"})
47
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
48
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
49
+ assert disc_number is None
50
+ assert disc_total is None
51
+
52
+ def test_id3v2_read_tpos_above_255_not_clamped(self):
53
+ with temp_file_with_metadata({}, "mp3") as test_file:
54
+ ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "256/300"})
55
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
56
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
57
+ assert disc_number == 256
58
+ assert disc_total == 300
59
+
60
+ def test_vorbis_with_total(self):
61
+ with temp_file_with_metadata({}, "flac") as test_file:
62
+ VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1", "disc_total": "2"})
63
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
64
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
65
+ assert disc_number == 1
66
+ assert disc_total == 2
67
+
68
+ def test_vorbis_without_total(self):
69
+ with temp_file_with_metadata({}, "flac") as test_file:
70
+ VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "2"})
71
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
72
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
73
+ assert disc_number == 2
74
+ assert disc_total is None
75
+
76
+ def test_vorbis_disc_number_combined_slash_form(self):
77
+ with temp_file_with_metadata({}, "flac") as test_file:
78
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "3/5")
79
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
80
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
81
+ assert disc_number == 3
82
+ assert disc_total == 5
83
+
84
+ def test_vorbis_discnumber_combined_slash_via_set_metadata(self):
85
+ with temp_file_with_metadata({}, "flac") as test_file:
86
+ VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1/2"})
87
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
88
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
89
+ assert disc_number == 1
90
+ assert disc_total == 2
91
+
92
+ def test_vorbis_disc_number_hyphen_form(self):
93
+ with temp_file_with_metadata({}, "flac") as test_file:
94
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1-2")
95
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
96
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
97
+ assert disc_number == 1
98
+ assert disc_total == 2
99
+
100
+ def test_vorbis_disctotal_overrides_embedded_total(self):
101
+ with temp_file_with_metadata({}, "flac") as test_file:
102
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/3")
103
+ VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "2")
104
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
105
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
106
+ assert disc_number == 1
107
+ assert disc_total == 2
108
+
109
+ def test_vorbis_discnumber_slash_with_matching_disctotal(self):
110
+ with temp_file_with_metadata({}, "flac") as test_file:
111
+ VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1/2", "disc_total": "2"})
112
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
113
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
114
+ assert disc_number == 1
115
+ assert disc_total == 2
116
+
117
+ def test_vorbis_invalid_disctotal_falls_back_to_discnumber_slash(self):
118
+ with temp_file_with_metadata({}, "flac") as test_file:
119
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2")
120
+ VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "bogus")
121
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
122
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
123
+ assert disc_number == 1
124
+ assert disc_total == 2
125
+
126
+ def test_vorbis_negative_disctotal_falls_back_to_discnumber_slash(self):
127
+ with temp_file_with_metadata({}, "flac") as test_file:
128
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2")
129
+ VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "-1")
130
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
131
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
132
+ assert disc_number == 1
133
+ assert disc_total == 2
134
+
135
+ def test_vorbis_invalid_combined_discnumber(self):
136
+ with temp_file_with_metadata({}, "flac") as test_file:
137
+ VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2/3")
138
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
139
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
140
+ assert disc_number is None
141
+ assert disc_total is None
142
+
143
+ def test_vorbis_disctotal_only(self):
144
+ with temp_file_with_metadata({}, "flac") as test_file:
145
+ VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "2")
146
+ disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
147
+ disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
148
+ assert disc_number is None
149
+ assert disc_total == 2
150
+
151
+ def test_id3v1_not_supported(self):
152
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
153
+ from audiometa.utils.metadata_format import MetadataFormat
154
+
155
+ with temp_file_with_metadata({}, "id3v1") as test_file:
156
+ with pytest.raises(
157
+ MetadataFieldNotSupportedByMetadataFormatError,
158
+ match="UnifiedMetadataKey.DISC_NUMBER metadata not supported by ID3v1 format",
159
+ ):
160
+ get_unified_metadata_field(
161
+ test_file, UnifiedMetadataKey.DISC_NUMBER, metadata_format=MetadataFormat.ID3V1
162
+ )
163
+
164
+ with pytest.raises(
165
+ MetadataFieldNotSupportedByMetadataFormatError,
166
+ match="UnifiedMetadataKey.DISC_TOTAL metadata not supported by ID3v1 format",
167
+ ):
168
+ get_unified_metadata_field(
169
+ test_file, UnifiedMetadataKey.DISC_TOTAL, metadata_format=MetadataFormat.ID3V1
170
+ )
171
+
172
+ def test_riff_not_supported(self):
173
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
174
+ from audiometa.utils.metadata_format import MetadataFormat
175
+
176
+ with temp_file_with_metadata({}, "wav") as test_file:
177
+ with pytest.raises(
178
+ MetadataFieldNotSupportedByMetadataFormatError,
179
+ match="UnifiedMetadataKey.DISC_NUMBER metadata not supported by RIFF format",
180
+ ):
181
+ get_unified_metadata_field(
182
+ test_file, UnifiedMetadataKey.DISC_NUMBER, metadata_format=MetadataFormat.RIFF
183
+ )
184
+
185
+ with pytest.raises(
186
+ MetadataFieldNotSupportedByMetadataFormatError,
187
+ match="UnifiedMetadataKey.DISC_TOTAL metadata not supported by RIFF format",
188
+ ):
189
+ get_unified_metadata_field(
190
+ test_file, UnifiedMetadataKey.DISC_TOTAL, metadata_format=MetadataFormat.RIFF
191
+ )
@@ -7,37 +7,50 @@ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
7
 
8
8
  @pytest.mark.integration
9
9
  class TestTrackNumberReadingEdgeCases:
10
- def test_trailing_slash(self):
11
- with temp_file_with_metadata({"track_number": "5/"}, "mp3") as test_file:
10
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
11
+ def test_trailing_slash(self, fmt):
12
+ with temp_file_with_metadata({"track_number": "5/"}, fmt) as test_file:
12
13
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
13
14
  assert track_number == "5/"
14
15
 
15
- def test_leading_slash_no_track(self):
16
- with temp_file_with_metadata({"track_number": "/12"}, "mp3") as test_file:
16
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
17
+ def test_leading_slash_no_track(self, fmt):
18
+ with temp_file_with_metadata({"track_number": "/12"}, fmt) as test_file:
17
19
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
18
20
  assert track_number is None
19
21
 
20
- def test_non_numeric_values(self):
21
- with temp_file_with_metadata({"track_number": "abc/def"}, "mp3") as test_file:
22
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
23
+ def test_non_numeric_values(self, fmt):
24
+ with temp_file_with_metadata({"track_number": "abc/def"}, fmt) as test_file:
22
25
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
23
26
  assert track_number is None
24
27
 
25
- def test_empty_string(self):
26
- with temp_file_with_metadata({"track_number": ""}, "mp3") as test_file:
28
+ @pytest.mark.parametrize(
29
+ ("fmt", "expected"),
30
+ [
31
+ ("mp3", None),
32
+ ("flac", ""),
33
+ ],
34
+ )
35
+ def test_empty_string(self, fmt, expected):
36
+ with temp_file_with_metadata({"track_number": ""}, fmt) as test_file:
27
37
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
28
- assert track_number is None
38
+ assert track_number == expected
29
39
 
30
- def test_multiple_slashes(self):
31
- with temp_file_with_metadata({"track_number": "5/12/15"}, "mp3") as test_file:
40
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
41
+ def test_multiple_slashes(self, fmt):
42
+ with temp_file_with_metadata({"track_number": "5/12/15"}, fmt) as test_file:
32
43
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
33
44
  assert track_number is None
34
45
 
35
- def test_different_separator(self):
36
- with temp_file_with_metadata({"track_number": "5-12"}, "mp3") as test_file:
46
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
47
+ def test_different_separator(self, fmt):
48
+ with temp_file_with_metadata({"track_number": "5-12"}, fmt) as test_file:
37
49
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
38
50
  assert track_number == "5-12"
39
51
 
40
- def test_leading_zeros_preserved(self):
41
- with temp_file_with_metadata({"track_number": "01"}, "mp3") as test_file:
52
+ @pytest.mark.parametrize("fmt", ["mp3", "flac"])
53
+ def test_leading_zeros_preserved(self, fmt):
54
+ with temp_file_with_metadata({"track_number": "01"}, fmt) as test_file:
42
55
  track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
43
56
  assert track_number == "01"
@@ -0,0 +1,76 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field, update_metadata
4
+ from audiometa.test.helpers.id3v1.id3v1_metadata_getter import ID3v1MetadataGetter
5
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
6
+ from audiometa.utils.metadata_format import MetadataFormat
7
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
8
+
9
+
10
+ @pytest.mark.integration
11
+ class TestTrackNumberReading:
12
+ def test_id3v1_1(self):
13
+ with temp_file_with_metadata({"title": "Test Song", "track": "99"}, "id3v1") as test_file:
14
+ raw_metadata = ID3v1MetadataGetter.get_raw_metadata(test_file)
15
+ assert raw_metadata.get("track") == 99
16
+
17
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
18
+ assert track_number == "99"
19
+
20
+ def test_id3v2(self):
21
+ with temp_file_with_metadata({"title": "Test Song", "track_number": "99/99"}, "mp3") as test_file:
22
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
23
+ assert track_number == "99/99"
24
+
25
+ def test_vorbis(self):
26
+ with temp_file_with_metadata({"title": "Test Song", "track_number": "99"}, "flac") as test_file:
27
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
28
+ assert track_number == "99"
29
+
30
+ @pytest.mark.parametrize(
31
+ ("raw", "expected"),
32
+ [
33
+ ("5/12", "5/12"),
34
+ ("4/11", "4/11"),
35
+ ("5-12", "5-12"),
36
+ ],
37
+ )
38
+ def test_vorbis_track_number_combined_or_hyphen(self, raw, expected):
39
+ with temp_file_with_metadata({"title": "Test Song", "track_number": raw}, "flac") as test_file:
40
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
41
+ assert track_number == expected
42
+
43
+ def test_riff(self):
44
+ with temp_file_with_metadata({"title": "Test Song", "track_number": None}, "wav") as test_file:
45
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
46
+ assert track_number is None
47
+
48
+ @pytest.mark.parametrize(
49
+ ("written", "expected"),
50
+ [
51
+ ("5/12", "5/12"),
52
+ ("4/11", "4/11"),
53
+ ("5-12", "5-12"),
54
+ ],
55
+ )
56
+ def test_riff_track_number_reads_like_shared_rule_after_unified_write(self, written, expected):
57
+ with temp_file_with_metadata({}, "wav") as test_file:
58
+ update_metadata(
59
+ test_file,
60
+ {UnifiedMetadataKey.TRACK_NUMBER: written},
61
+ metadata_format=MetadataFormat.RIFF,
62
+ )
63
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
64
+ assert track_number == expected
65
+
66
+ @pytest.mark.parametrize(
67
+ ("raw", "expected"),
68
+ [
69
+ ("5/12", "5/12"),
70
+ ("5-12", "5-12"),
71
+ ],
72
+ )
73
+ def test_id3v2_track_number_combined_or_hyphen(self, raw, expected):
74
+ with temp_file_with_metadata({"title": "Test Song", "track_number": raw}, "mp3") as test_file:
75
+ track_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.TRACK_NUMBER)
76
+ assert track_number == expected
@@ -0,0 +1,66 @@
1
+ import pytest
2
+
3
+ from audiometa.utils.disc_number_read import (
4
+ parse_disc_number_from_combined_str,
5
+ parse_disc_total_from_combined_str,
6
+ parse_explicit_non_negative_disctotal,
7
+ )
8
+
9
+
10
+ @pytest.mark.unit
11
+ class TestDiscNumberReadParsing:
12
+ @pytest.mark.parametrize(
13
+ ("s", "expected"),
14
+ [
15
+ ("1", 1),
16
+ ("01", 1),
17
+ ("1/2", 1),
18
+ ("1-2", 1),
19
+ ("99/100", 99),
20
+ ],
21
+ )
22
+ def test_parse_disc_number_ok(self, s, expected):
23
+ assert parse_disc_number_from_combined_str(s) == expected
24
+
25
+ @pytest.mark.parametrize(
26
+ "s",
27
+ ["", "1/2/3", "x", "1-", "-1", "1/"],
28
+ )
29
+ def test_parse_disc_number_none(self, s):
30
+ assert parse_disc_number_from_combined_str(s) is None
31
+
32
+ @pytest.mark.parametrize(
33
+ ("s", "expected"),
34
+ [
35
+ ("1/2", 2),
36
+ ("1-2", 2),
37
+ ("0/5", 5),
38
+ ],
39
+ )
40
+ def test_parse_disc_total_from_combined_ok(self, s, expected):
41
+ assert parse_disc_total_from_combined_str(s) == expected
42
+
43
+ @pytest.mark.parametrize(
44
+ "s",
45
+ ["1", "1/2/3", "", "x"],
46
+ )
47
+ def test_parse_disc_total_from_combined_none(self, s):
48
+ assert parse_disc_total_from_combined_str(s) is None
49
+
50
+ @pytest.mark.parametrize(
51
+ ("s", "expected"),
52
+ [
53
+ ("0", 0),
54
+ ("2", 2),
55
+ ("42", 42),
56
+ ],
57
+ )
58
+ def test_parse_explicit_disctotal_ok(self, s, expected):
59
+ assert parse_explicit_non_negative_disctotal(s) == expected
60
+
61
+ @pytest.mark.parametrize(
62
+ "s",
63
+ ["", "bogus", "-1", "1.5"],
64
+ )
65
+ def test_parse_explicit_disctotal_none(self, s):
66
+ assert parse_explicit_non_negative_disctotal(s) is None
@@ -0,0 +1,30 @@
1
+ """Parse combined disc index/total strings (ID3v2 TPOS-style) for unified metadata read."""
2
+
3
+ import re
4
+
5
+ _DISC_NUMBER_RE = re.compile(r"^(\d+)(?:[-/](\d+))?$")
6
+ _DISC_TOTAL_FROM_COMBINED_RE = re.compile(r"^(\d+)[-/](\d+)$")
7
+
8
+
9
+ def parse_disc_number_from_combined_str(value: str) -> int | None:
10
+ m = _DISC_NUMBER_RE.match(value)
11
+ if m:
12
+ return int(m.group(1))
13
+ return None
14
+
15
+
16
+ def parse_disc_total_from_combined_str(value: str) -> int | None:
17
+ m = _DISC_TOTAL_FROM_COMBINED_RE.match(value)
18
+ if m:
19
+ return int(m.group(2))
20
+ return None
21
+
22
+
23
+ def parse_explicit_non_negative_disctotal(value: str) -> int | None:
24
+ try:
25
+ n = int(value)
26
+ except (ValueError, TypeError):
27
+ return None
28
+ if n < 0:
29
+ return None
30
+ return n
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: audiometa-python
3
- Version: 1.3.0
3
+ Version: 1.3.3
4
4
  Summary: A comprehensive Python library for reading and writing audio metadata across multiple formats
5
5
  Author: AudioMeta Python Contributors
6
6
  Author-email: Andreas Garcia <garcia.andreas.1991@gmail.com>
@@ -55,6 +55,8 @@ Dynamic: license-file
55
55
 
56
56
  A powerful, unified Python library for reading and writing audio metadata across multiple formats. AudioMeta supports MP3, FLAC, and WAV audio files, working seamlessly with ID3v1, ID3v2, Vorbis, and RIFF metadata formats through a single, consistent API.
57
57
 
58
+ **Try it**: A demo web app is available at [audiometa.themusictree.org](https://audiometa.themusictree.org).
59
+
58
60
  **Author**: [Andreas Garcia](https://github.com/BehindTheMusicTree)
59
61
 
60
62
  ## ⭐ Show Your Support
@@ -389,8 +389,10 @@ audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/test_dat
389
389
  audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/__init__.py
390
390
  audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/test_track_number_validation.py
391
391
  audiometa/test/tests/unit/utils/__init__.py
392
+ audiometa/test/tests/unit/utils/test_disc_number_read.py
392
393
  audiometa/test/tests/unit/utils/test_raw_metadata_sanitizer.py
393
394
  audiometa/utils/__init__.py
395
+ audiometa/utils/disc_number_read.py
394
396
  audiometa/utils/flac_md5_state.py
395
397
  audiometa/utils/id3v1_genre_code_map.py
396
398
  audiometa/utils/metadata_format.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "audiometa-python"
7
- version = "1.3.0"
7
+ version = "1.3.3"
8
8
  description = "A comprehensive Python library for reading and writing audio metadata across multiple formats"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -107,6 +107,8 @@ ignore = ["N999", "PLR0911", "PLR0912", "PLR0913", "PLR0914", "PLR0915", "TRY301
107
107
  # T201 (print) is acceptable in demo scripts - they are CLI/demo tools, not library code
108
108
  "scripts/run_demo_tape.py" = ["T201"]
109
109
  "scripts/demo_repl.py" = ["T201"]
110
+ # Release script: CLI tool; relax exception/literal and magic-number rules for clarity
111
+ "scripts/prepare_release.py" = ["TRY003", "EM101", "EM102", "PLR2004", "DTZ011", "RUF005", "T201"]
110
112
 
111
113
  [tool.mypy]
112
114
  python_version = "3.12"