audiometa-python 0.4.1__tar.gz → 0.6.0__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 (361) hide show
  1. {audiometa_python-0.4.1/audiometa_python.egg-info → audiometa_python-0.6.0}/PKG-INFO +6 -4
  2. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/README.md +5 -3
  3. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/__init__.py +88 -79
  4. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/_audio_file.py +4 -4
  5. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/cli.py +4 -0
  6. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_MetadataManager.py +40 -0
  7. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +2 -0
  8. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +226 -2
  9. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +7 -0
  10. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +2 -0
  11. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_getter.py +101 -0
  12. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_setter.py +116 -0
  13. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/conftest.py +15 -0
  14. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +9 -0
  15. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_formatting.py +1 -1
  16. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +9 -0
  17. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
  18. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
  19. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
  20. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
  21. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
  22. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/test_options.py +1 -1
  23. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
  24. audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
  25. audiometa_python-0.4.1/audiometa/test/tests/integration/get_full_metadata/test_parsed_fields_keys.py → audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_structure.py +77 -1
  26. audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
  27. audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
  28. audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
  29. audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
  30. audiometa_python-0.6.0/audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
  31. audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
  32. audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
  33. audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
  34. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/types.py +1 -1
  35. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/unified_metadata_key.py +2 -0
  36. {audiometa_python-0.4.1 → audiometa_python-0.6.0/audiometa_python.egg-info}/PKG-INFO +6 -4
  37. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/SOURCES.txt +13 -2
  38. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/pyproject.toml +1 -1
  39. audiometa_python-0.4.1/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +0 -297
  40. audiometa_python-0.4.1/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata_edge_cases.py +0 -231
  41. audiometa_python-0.4.1/audiometa/test/tests/integration/technical_info/test_bitrate.py +0 -38
  42. audiometa_python-0.4.1/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -57
  43. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/LICENSE +0 -0
  44. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/__main__.py +0 -0
  45. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/exceptions.py +0 -0
  46. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/__init__.py +0 -0
  47. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +0 -0
  48. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/__init__.py +0 -0
  49. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/__init__.py +0 -0
  50. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
  51. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/__init__.py +0 -0
  52. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/__init__.py +0 -0
  53. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
  54. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/_Id3v1Manager.py +0 -0
  55. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/__init__.py +0 -0
  56. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/_constants.py +0 -0
  57. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
  58. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
  59. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/__init__.py +0 -0
  60. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/assets/create_test_files.py +0 -0
  61. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/__init__.py +0 -0
  62. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/__init__.py +0 -0
  63. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
  64. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
  65. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/__init__.py +0 -0
  66. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
  67. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
  68. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
  69. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
  70. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/__init__.py +0 -0
  71. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
  72. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
  73. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
  74. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
  75. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
  76. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/__init__.py +0 -0
  77. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
  78. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
  79. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
  80. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/scripts/__init__.py +0 -0
  81. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/technical_info_inspector.py +0 -0
  82. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
  83. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/__init__.py +0 -0
  84. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
  85. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
  86. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
  87. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
  88. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/__init__.py +0 -0
  89. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/__init__.py +0 -0
  90. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
  91. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
  92. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
  93. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
  94. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
  95. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
  96. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
  97. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +0 -0
  98. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
  99. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
  100. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
  101. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
  102. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
  103. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
  104. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
  105. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_options.py +0 -0
  106. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_unified.py +0 -0
  107. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
  108. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
  109. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
  110. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
  111. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
  112. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
  113. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
  114. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
  115. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
  116. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
  117. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
  118. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
  119. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
  120. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
  121. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
  122. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
  123. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
  124. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
  125. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/__init__.py +0 -0
  126. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
  127. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
  128. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
  129. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
  130. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
  131. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
  132. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
  133. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
  134. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
  135. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
  136. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
  137. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
  138. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
  139. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
  140. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
  141. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_with_id3v2_tags.py +0 -0
  142. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
  143. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/conftest.py +0 -0
  144. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
  145. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
  146. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +0 -0
  147. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
  148. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
  149. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
  150. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
  151. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
  152. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
  153. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +0 -0
  154. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
  155. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
  156. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
  157. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
  158. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
  159. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
  160. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
  161. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
  162. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
  163. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
  164. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
  165. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
  166. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
  167. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
  168. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
  169. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
  170. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
  171. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
  172. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
  173. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
  174. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
  175. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
  176. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
  177. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
  178. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
  179. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
  180. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
  181. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
  182. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
  183. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
  184. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
  185. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -0
  186. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +0 -0
  187. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
  188. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
  189. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
  190. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
  191. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
  192. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
  193. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
  194. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +0 -0
  195. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +0 -0
  196. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +0 -0
  197. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +0 -0
  198. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
  199. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
  200. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
  201. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
  202. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
  203. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
  204. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
  205. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
  206. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
  207. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
  208. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
  209. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
  210. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
  211. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
  212. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
  213. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
  214. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
  215. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +0 -0
  216. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +0 -0
  217. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +0 -0
  218. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
  219. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
  220. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
  221. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
  222. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +0 -0
  223. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +0 -0
  224. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +0 -0
  225. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
  226. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
  227. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
  228. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
  229. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
  230. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
  231. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
  232. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
  233. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
  234. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
  235. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
  236. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
  237. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
  238. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
  239. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +0 -0
  240. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +0 -0
  241. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
  242. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
  243. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
  244. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
  245. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
  246. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
  247. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +0 -0
  248. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +0 -0
  249. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
  250. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
  251. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
  252. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
  253. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
  254. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
  255. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
  256. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
  257. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +0 -0
  258. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +0 -0
  259. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
  260. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
  261. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
  262. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
  263. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/__init__.py +0 -0
  264. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
  265. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
  266. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
  267. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
  268. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
  269. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
  270. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
  271. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
  272. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/__init__.py +0 -0
  273. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_audio_data_corruption.py +0 -0
  274. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_flipped_md5.py +0 -0
  275. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_non_flac_error.py +0 -0
  276. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_partial_md5.py +0 -0
  277. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_random_md5.py +0 -0
  278. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_unset_md5.py +0 -0
  279. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +0 -0
  280. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
  281. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
  282. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
  283. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/test_audio_file.py +0 -0
  284. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +0 -0
  285. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/__init__.py +0 -0
  286. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
  287. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
  288. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
  289. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
  290. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
  291. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
  292. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
  293. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +0 -0
  294. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
  295. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +0 -0
  296. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +0 -0
  297. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +0 -0
  298. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/__init__.py +0 -0
  299. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
  300. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
  301. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
  302. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
  303. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +0 -0
  304. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
  305. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
  306. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
  307. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
  308. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
  309. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
  310. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
  311. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
  312. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
  313. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/cli/__init__.py +0 -0
  314. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
  315. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
  316. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
  317. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
  318. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
  319. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
  320. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
  321. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
  322. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
  323. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
  324. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +0 -0
  325. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
  326. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +0 -0
  327. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +0 -0
  328. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
  329. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
  330. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +0 -0
  331. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +0 -0
  332. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +0 -0
  333. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
  334. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +0 -0
  335. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +0 -0
  336. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +0 -0
  337. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_date_format_validation.py +0 -0
  338. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_disc_number_validation.py +0 -0
  339. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_track_number_validation.py +0 -0
  340. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +0 -0
  341. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
  342. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +0 -0
  343. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
  344. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/__init__.py +0 -0
  345. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/id3v1_genre_code_map.py +0 -0
  346. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/metadata_format.py +0 -0
  347. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/metadata_writing_strategy.py +0 -0
  348. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/mutagen_exception_handler.py +0 -0
  349. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
  350. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/base.py +0 -0
  351. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/config.py +0 -0
  352. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
  353. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/ubuntu.py +0 -0
  354. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
  355. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/rating_profiles.py +0 -0
  356. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/tool_path_resolver.py +0 -0
  357. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/dependency_links.txt +0 -0
  358. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/entry_points.txt +0 -0
  359. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/requires.txt +0 -0
  360. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/top_level.txt +0 -0
  361. {audiometa_python-0.4.1 → audiometa_python-0.6.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: audiometa-python
3
- Version: 0.4.1
3
+ Version: 0.6.0
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>
@@ -153,6 +153,8 @@ Your support helps make this project better for everyone! 🎵
153
153
 
154
154
  ### Format Capabilities
155
155
 
156
+ For comprehensive information about each metadata format (history, structure, advantages, disadvantages, use cases), see the **[Metadata Formats Guide](docs/METADATA_FORMATS.md)**.
157
+
156
158
  #### ID3v1 Metadata Format
157
159
 
158
160
  - **Primary Support**: MP3 files (native format)
@@ -577,7 +579,7 @@ if is_audio_file("path/to/your/audio.flac"):
577
579
  file_size = get_file_size("path/to/your/audio.flac")
578
580
 
579
581
  print(f"Duration: {duration} seconds")
580
- print(f"Bitrate: {bitrate} kbps")
582
+ print(f"Bitrate: {bitrate} bps ({bitrate // 1000} kbps)")
581
583
  print(f"Sample Rate: {sample_rate} Hz")
582
584
  print(f"Channels: {channels}")
583
585
  print(f"File Size: {file_size} bytes")
@@ -709,7 +711,7 @@ print(f"Artists: {full_metadata['unified_metadata'][UnifiedMetadataKey.ARTISTS]}
709
711
 
710
712
  # Access technical information
711
713
  print(f"Duration: {full_metadata['technical_info']['duration_seconds']} seconds")
712
- print(f"Bitrate: {full_metadata['technical_info']['bitrate_kbps']} kbps")
714
+ print(f"Bitrate: {full_metadata['technical_info']['bitrate_bps']} bps ({full_metadata['technical_info']['bitrate_bps'] // 1000} kbps)")
713
715
  print(f"Sample Rate: {full_metadata['technical_info']['sample_rate_hz']} Hz")
714
716
  print(f"Channels: {full_metadata['technical_info']['channels']}")
715
717
  print(f"File Size: {full_metadata['technical_info']['file_size_bytes']} bytes")
@@ -749,7 +751,7 @@ A comprehensive dictionary containing:
749
751
  },
750
752
  'technical_info': {
751
753
  'duration_seconds': 180.5,
752
- 'bitrate_kbps': 320,
754
+ 'bitrate_bps': 320000,
753
755
  'sample_rate_hz': 44100,
754
756
  'channels': 2,
755
757
  'file_size_bytes': 7234567,
@@ -111,6 +111,8 @@ Your support helps make this project better for everyone! 🎵
111
111
 
112
112
  ### Format Capabilities
113
113
 
114
+ For comprehensive information about each metadata format (history, structure, advantages, disadvantages, use cases), see the **[Metadata Formats Guide](docs/METADATA_FORMATS.md)**.
115
+
114
116
  #### ID3v1 Metadata Format
115
117
 
116
118
  - **Primary Support**: MP3 files (native format)
@@ -535,7 +537,7 @@ if is_audio_file("path/to/your/audio.flac"):
535
537
  file_size = get_file_size("path/to/your/audio.flac")
536
538
 
537
539
  print(f"Duration: {duration} seconds")
538
- print(f"Bitrate: {bitrate} kbps")
540
+ print(f"Bitrate: {bitrate} bps ({bitrate // 1000} kbps)")
539
541
  print(f"Sample Rate: {sample_rate} Hz")
540
542
  print(f"Channels: {channels}")
541
543
  print(f"File Size: {file_size} bytes")
@@ -667,7 +669,7 @@ print(f"Artists: {full_metadata['unified_metadata'][UnifiedMetadataKey.ARTISTS]}
667
669
 
668
670
  # Access technical information
669
671
  print(f"Duration: {full_metadata['technical_info']['duration_seconds']} seconds")
670
- print(f"Bitrate: {full_metadata['technical_info']['bitrate_kbps']} kbps")
672
+ print(f"Bitrate: {full_metadata['technical_info']['bitrate_bps']} bps ({full_metadata['technical_info']['bitrate_bps'] // 1000} kbps)")
671
673
  print(f"Sample Rate: {full_metadata['technical_info']['sample_rate_hz']} Hz")
672
674
  print(f"Channels: {full_metadata['technical_info']['channels']}")
673
675
  print(f"File Size: {full_metadata['technical_info']['file_size_bytes']} bytes")
@@ -707,7 +709,7 @@ A comprehensive dictionary containing:
707
709
  },
708
710
  'technical_info': {
709
711
  'duration_seconds': 180.5,
710
- 'bitrate_kbps': 320,
712
+ 'bitrate_bps': 320000,
711
713
  'sample_rate_hz': 44100,
712
714
  'channels': 2,
713
715
  'file_size_bytes': 7234567,
@@ -392,6 +392,80 @@ def _validate_unified_metadata_types(unified_metadata: UnifiedMetadata) -> None:
392
392
  )
393
393
 
394
394
 
395
+ def _validate_rating_value(unified_metadata: UnifiedMetadata, normalized_rating_max_value: int | None) -> None:
396
+ """Validate rating value if present.
397
+
398
+ This is a shared helper used by both validate_metadata_for_update() and update_metadata().
399
+ """
400
+ if UnifiedMetadataKey.RATING not in unified_metadata:
401
+ return
402
+
403
+ rating_value = unified_metadata[UnifiedMetadataKey.RATING]
404
+ if rating_value is None:
405
+ return
406
+
407
+ if isinstance(rating_value, int | float):
408
+ # In raw mode (no normalization), only accept floats that can be parsed to int
409
+ # This allows the library to accept values like 196.0 as 196
410
+ if normalized_rating_max_value is None and isinstance(rating_value, float):
411
+ if rating_value.is_integer():
412
+ # Note: We can't modify the original dict here, caller handles this if needed
413
+ pass
414
+ else:
415
+ from .exceptions import InvalidRatingValueError
416
+
417
+ msg = (
418
+ f"Rating value {rating_value} is invalid. In raw mode, float values must be whole numbers "
419
+ f"(e.g., 196.0). Half-star values like {rating_value} require normalization."
420
+ )
421
+ raise InvalidRatingValueError(msg)
422
+ from .manager._rating_supporting._RatingSupportingMetadataManager import _RatingSupportingMetadataManager
423
+
424
+ _RatingSupportingMetadataManager.validate_rating_value(rating_value, normalized_rating_max_value)
425
+ else:
426
+ from .exceptions import InvalidRatingValueError
427
+
428
+ msg = f"Rating value must be numeric, got {type(rating_value).__name__}"
429
+ raise InvalidRatingValueError(msg)
430
+
431
+
432
+ def _validate_metadata_field_formats(unified_metadata: UnifiedMetadata) -> None:
433
+ """Validate format of metadata fields that have specific format requirements.
434
+
435
+ Validates release_date, track_number, disc_number, disc_total, and isrc formats.
436
+ This is a shared helper used by both validate_metadata_for_update() and update_metadata().
437
+ """
438
+ # Validate release date if present and non-empty
439
+ if UnifiedMetadataKey.RELEASE_DATE in unified_metadata:
440
+ release_date_value = unified_metadata[UnifiedMetadataKey.RELEASE_DATE]
441
+ if release_date_value is not None and isinstance(release_date_value, str) and release_date_value:
442
+ _MetadataManager.validate_release_date(release_date_value)
443
+
444
+ # Validate track number if present and non-empty
445
+ if UnifiedMetadataKey.TRACK_NUMBER in unified_metadata:
446
+ track_number_value = unified_metadata[UnifiedMetadataKey.TRACK_NUMBER]
447
+ if track_number_value is not None and isinstance(track_number_value, str | int):
448
+ _MetadataManager.validate_track_number(track_number_value)
449
+
450
+ # Validate disc number if present and non-empty
451
+ if UnifiedMetadataKey.DISC_NUMBER in unified_metadata:
452
+ disc_number_value = unified_metadata[UnifiedMetadataKey.DISC_NUMBER]
453
+ if disc_number_value is not None and isinstance(disc_number_value, int):
454
+ _MetadataManager.validate_disc_number(disc_number_value)
455
+
456
+ # Validate disc total if present
457
+ if UnifiedMetadataKey.DISC_TOTAL in unified_metadata:
458
+ disc_total_value = unified_metadata[UnifiedMetadataKey.DISC_TOTAL]
459
+ if disc_total_value is None or isinstance(disc_total_value, int):
460
+ _MetadataManager.validate_disc_total(disc_total_value)
461
+
462
+ # Validate ISRC format if present and non-empty
463
+ if UnifiedMetadataKey.ISRC in unified_metadata:
464
+ isrc_value = unified_metadata[UnifiedMetadataKey.ISRC]
465
+ if isrc_value is not None and isinstance(isrc_value, str) and isrc_value:
466
+ _MetadataManager.validate_isrc(isrc_value)
467
+
468
+
395
469
  def validate_metadata_for_update(
396
470
  unified_metadata: dict[UnifiedMetadataKey, Any] | UnifiedMetadata,
397
471
  normalized_rating_max_value: int | None = None,
@@ -463,67 +537,11 @@ def validate_metadata_for_update(
463
537
  # Validate types
464
538
  _validate_unified_metadata_types(normalized_metadata)
465
539
 
466
- # Validate rating if present and non-empty
467
- if UnifiedMetadataKey.RATING in normalized_metadata:
468
- rating_value = normalized_metadata[UnifiedMetadataKey.RATING]
469
- if rating_value is not None:
470
- if isinstance(rating_value, int | float):
471
- # In raw mode (no normalization), only accept floats that can be parsed to int
472
- # This allows the library to accept values like 196.0 as 196
473
- if normalized_rating_max_value is None and isinstance(rating_value, float):
474
- if rating_value.is_integer():
475
- rating_value = int(rating_value)
476
- normalized_metadata[UnifiedMetadataKey.RATING] = rating_value
477
- else:
478
- from .exceptions import InvalidRatingValueError
479
-
480
- msg = (
481
- f"Rating value {rating_value} is invalid. In raw mode, float values must be whole numbers "
482
- f"(e.g., 196.0). Half-star values like {rating_value} require normalization."
483
- )
484
- raise InvalidRatingValueError(msg)
485
- from .manager._rating_supporting._RatingSupportingMetadataManager import (
486
- _RatingSupportingMetadataManager,
487
- )
488
-
489
- _RatingSupportingMetadataManager.validate_rating_value(rating_value, normalized_rating_max_value)
490
- else:
491
- from .exceptions import InvalidRatingValueError
492
-
493
- msg = f"Rating value must be numeric, got {type(rating_value).__name__}"
494
- raise InvalidRatingValueError(msg)
495
-
496
- # Validate release date if present and non-empty
497
- if UnifiedMetadataKey.RELEASE_DATE in normalized_metadata:
498
- release_date_value = normalized_metadata[UnifiedMetadataKey.RELEASE_DATE]
499
- if release_date_value is not None and isinstance(release_date_value, str) and release_date_value:
500
- from .manager._MetadataManager import _MetadataManager
501
-
502
- _MetadataManager.validate_release_date(release_date_value)
503
-
504
- # Validate track number if present and non-empty
505
- if UnifiedMetadataKey.TRACK_NUMBER in normalized_metadata:
506
- track_number_value = normalized_metadata[UnifiedMetadataKey.TRACK_NUMBER]
507
- if track_number_value is not None:
508
- from .manager._MetadataManager import _MetadataManager
509
-
510
- if isinstance(track_number_value, str | int):
511
- _MetadataManager.validate_track_number(track_number_value)
512
-
513
- # Validate disc number if present and non-empty
514
- if UnifiedMetadataKey.DISC_NUMBER in normalized_metadata:
515
- disc_number_value = normalized_metadata[UnifiedMetadataKey.DISC_NUMBER]
516
- if disc_number_value is not None:
517
- from .manager._MetadataManager import _MetadataManager
518
-
519
- _MetadataManager.validate_disc_number(disc_number_value)
520
-
521
- # Validate disc total if present
522
- if UnifiedMetadataKey.DISC_TOTAL in normalized_metadata:
523
- disc_total_value = normalized_metadata[UnifiedMetadataKey.DISC_TOTAL]
524
- from .manager._MetadataManager import _MetadataManager
540
+ # Validate rating if present
541
+ _validate_rating_value(normalized_metadata, normalized_rating_max_value)
525
542
 
526
- _MetadataManager.validate_disc_total(disc_total_value)
543
+ # Validate field formats (release_date, track_number, disc_number, disc_total, isrc)
544
+ _validate_metadata_field_formats(normalized_metadata)
527
545
 
528
546
 
529
547
  def update_metadata(
@@ -641,22 +659,11 @@ def update_metadata(
641
659
  # Validate provided unified_metadata value types before attempting any writes
642
660
  _validate_unified_metadata_types(unified_metadata)
643
661
 
644
- # Validate release date format if present and non-empty
645
- if UnifiedMetadataKey.RELEASE_DATE in unified_metadata:
646
- release_date_value = unified_metadata[UnifiedMetadataKey.RELEASE_DATE]
647
- if release_date_value is not None and isinstance(release_date_value, str) and release_date_value:
648
- from .manager._MetadataManager import _MetadataManager
649
-
650
- _MetadataManager.validate_release_date(release_date_value)
651
-
652
- # Validate track number format if present and non-empty
653
- if UnifiedMetadataKey.TRACK_NUMBER in unified_metadata:
654
- track_number_value = unified_metadata[UnifiedMetadataKey.TRACK_NUMBER]
655
- if track_number_value is not None:
656
- from .manager._MetadataManager import _MetadataManager
662
+ # Validate rating if present
663
+ _validate_rating_value(unified_metadata, normalized_rating_max_value)
657
664
 
658
- if isinstance(track_number_value, str | int):
659
- _MetadataManager.validate_track_number(track_number_value)
665
+ # Validate field formats (release_date, track_number, disc_number, disc_total, isrc)
666
+ _validate_metadata_field_formats(unified_metadata)
660
667
 
661
668
  _handle_metadata_strategy(
662
669
  audio_file,
@@ -941,7 +948,7 @@ def get_bitrate(file: PublicFileType) -> int:
941
948
  file: Audio file path (str or Path)
942
949
 
943
950
  Returns:
944
- Bitrate in bits per second
951
+ Bitrate in bits per second (bps)
945
952
 
946
953
  Raises:
947
954
  FileTypeNotSupportedError: If the file format is not supported
@@ -950,6 +957,7 @@ def get_bitrate(file: PublicFileType) -> int:
950
957
  Examples:
951
958
  bitrate = get_bitrate("song.mp3")
952
959
  print(f"Bitrate: {bitrate} bps")
960
+ print(f"Bitrate: {bitrate // 1000} kbps")
953
961
  """
954
962
  audio_file = _AudioFile(file)
955
963
  return audio_file.get_bitrate()
@@ -1160,7 +1168,8 @@ def get_full_metadata(
1160
1168
 
1161
1169
  # Access technical information
1162
1170
  print(f"Duration: {full_metadata['technical_info']['duration_seconds']} seconds")
1163
- print(f"Bitrate: {full_metadata['technical_info']['bitrate_kbps']} kbps")
1171
+ bitrate_bps = full_metadata['technical_info']['bitrate_bps']
1172
+ print(f"Bitrate: {bitrate_bps} bps ({bitrate_bps // 1000} kbps)")
1164
1173
 
1165
1174
  # Access format-specific metadata
1166
1175
  print(f"ID3v2 Title: {full_metadata['metadata_format']['id3v2']['title']}")
@@ -1199,7 +1208,7 @@ def get_full_metadata(
1199
1208
  try:
1200
1209
  result["technical_info"] = {
1201
1210
  "duration_seconds": audio_file.get_duration_in_sec(),
1202
- "bitrate_kbps": audio_file.get_bitrate(),
1211
+ "bitrate_bps": audio_file.get_bitrate(),
1203
1212
  "sample_rate_hz": audio_file.get_sample_rate(),
1204
1213
  "channels": audio_file.get_channels(),
1205
1214
  "file_size_bytes": get_file_size(file),
@@ -1212,7 +1221,7 @@ def get_full_metadata(
1212
1221
  except Exception:
1213
1222
  result["technical_info"] = {
1214
1223
  "duration_seconds": 0,
1215
- "bitrate_kbps": 0,
1224
+ "bitrate_bps": 0,
1216
1225
  "sample_rate_hz": 0,
1217
1226
  "channels": 0,
1218
1227
  "file_size_bytes": 0,
@@ -174,7 +174,7 @@ class _AudioFile:
174
174
  audio = MP3(path)
175
175
  # Get MP3 bitrate directly from audio stream
176
176
  if audio.info.bitrate:
177
- return int(audio.info.bitrate) // 1000
177
+ return int(audio.info.bitrate)
178
178
  return 0
179
179
  if self.file_extension == ".wav":
180
180
  try:
@@ -208,7 +208,7 @@ class _AudioFile:
208
208
  stream = data["streams"][0]
209
209
  # Get bitrate directly if available
210
210
  if "bit_rate" in stream:
211
- return int(stream["bit_rate"]) // 1000
211
+ return int(stream["bit_rate"])
212
212
 
213
213
  # Calculate from sample_rate * channels * bits_per_sample if no direct bitrate
214
214
  sample_rate = int(stream.get("sample_rate", 0))
@@ -219,7 +219,7 @@ class _AudioFile:
219
219
  msg = "Missing audio stream information"
220
220
  raise RuntimeError(msg) from None
221
221
 
222
- return (sample_rate * channels * bits_per_sample) // 1000
222
+ return sample_rate * channels * bits_per_sample
223
223
  except json.JSONDecodeError as e:
224
224
  msg = "Failed to parse audio file metadata from ffprobe output"
225
225
  raise AudioFileMetadataParseError(msg) from e
@@ -228,7 +228,7 @@ class _AudioFile:
228
228
  raise RuntimeError(msg) from exc
229
229
  elif self.file_extension == ".flac":
230
230
  audio_info = cast(StreamInfo, FLAC(path).info)
231
- return int(float(audio_info.bitrate) / 1000)
231
+ return int(audio_info.bitrate)
232
232
  else:
233
233
  msg = f"Reading is not supported for file type: {self.file_extension}"
234
234
  raise FileTypeNotSupportedError(msg)
@@ -93,6 +93,7 @@ def format_as_table(data: dict[str, Any]) -> str:
93
93
  "comment",
94
94
  "replaygain",
95
95
  "archival_location",
96
+ "isrc",
96
97
  }
97
98
  if unified_keys.intersection(set(data.keys())):
98
99
  # This is a unified metadata dict, wrap it
@@ -189,6 +190,8 @@ def _write_metadata(args: argparse.Namespace) -> None:
189
190
  metadata[UnifiedMetadataKey.REPLAYGAIN] = args.replaygain
190
191
  if args.archival_location and args.archival_location.strip():
191
192
  metadata[UnifiedMetadataKey.ARCHIVAL_LOCATION] = args.archival_location
193
+ if args.isrc and args.isrc.strip():
194
+ metadata[UnifiedMetadataKey.ISRC] = args.isrc
192
195
 
193
196
  # List fields (can be specified multiple times)
194
197
  if args.artist:
@@ -428,6 +431,7 @@ Examples:
428
431
  write_parser.add_argument("--comment", help="Comment")
429
432
  write_parser.add_argument("--replaygain", help="ReplayGain information")
430
433
  write_parser.add_argument("--archival-location", help="Archival location")
434
+ write_parser.add_argument("--isrc", help="International Standard Recording Code (12 characters)")
431
435
  write_parser.add_argument(
432
436
  "--force-format",
433
437
  choices=["id3v2", "id3v1", "vorbis", "riff"],
@@ -215,6 +215,46 @@ class _MetadataManager:
215
215
  UnifiedMetadataKey.DISC_TOTAL.value, "non-negative integer", str(disc_total)
216
216
  )
217
217
 
218
+ @staticmethod
219
+ def validate_isrc(isrc: str) -> None:
220
+ """Validate ISRC (International Standard Recording Code) format.
221
+
222
+ ISRC must be in one of the following formats:
223
+ - 12 alphanumeric characters without hyphens (e.g., "USRC17607839")
224
+ - 15 characters with hyphens in format CC-XXX-YY-NNNNN (e.g., "US-RC1-76-07839")
225
+ where CC=country code, XXX=registrant, YY=year, NNNNN=unique ID
226
+ - Empty string is allowed (represents no ISRC)
227
+
228
+ Args:
229
+ isrc: The ISRC string to validate
230
+
231
+ Raises:
232
+ InvalidMetadataFieldFormatError: If the ISRC format is invalid
233
+
234
+ Examples:
235
+ >>> _MetadataManager.validate_isrc("USRC17607839") # Valid (12 chars)
236
+ >>> _MetadataManager.validate_isrc("US-RC1-76-07839") # Valid (with hyphens)
237
+ >>> _MetadataManager.validate_isrc("") # Valid (empty string)
238
+ >>> _MetadataManager.validate_isrc("ABC") # Raises InvalidMetadataFieldFormatError
239
+ """
240
+ if not isrc:
241
+ return
242
+
243
+ # 12 alphanumeric characters without hyphens
244
+ if re.match(r"^[A-Za-z0-9]{12}$", isrc):
245
+ return
246
+
247
+ # 15 characters with hyphens: CC-XXX-YY-NNNNN
248
+ if re.match(r"^[A-Za-z]{2}-[A-Za-z0-9]{3}-\d{2}-\d{5}$", isrc):
249
+ return
250
+
251
+ raise InvalidMetadataFieldFormatError(
252
+ UnifiedMetadataKey.ISRC.value,
253
+ "12 alphanumeric characters (e.g., 'USRC17607839') or 15 characters with hyphens "
254
+ "(e.g., 'US-RC1-76-07839')",
255
+ isrc,
256
+ )
257
+
218
258
  @abstractmethod
219
259
  def _extract_mutagen_metadata(self) -> MutagenMetadata:
220
260
  raise NotImplementedError
@@ -283,6 +283,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
283
283
  UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: self.Id3TextFrame.UNSYNCHRONIZED_LYRICS,
284
284
  UnifiedMetadataKey.COMMENT: self.Id3TextFrame.COMMENT,
285
285
  UnifiedMetadataKey.REPLAYGAIN: None,
286
+ UnifiedMetadataKey.ISRC: self.Id3TextFrame.ISRC,
286
287
  }
287
288
  metadata_keys_direct_map_write: dict[UnifiedMetadataKey, RawMetadataKey | None] = {
288
289
  UnifiedMetadataKey.TITLE: self.Id3TextFrame.TITLE,
@@ -303,6 +304,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
303
304
  UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: self.Id3TextFrame.UNSYNCHRONIZED_LYRICS,
304
305
  UnifiedMetadataKey.COMMENT: self.Id3TextFrame.COMMENT,
305
306
  UnifiedMetadataKey.REPLAYGAIN: None,
307
+ UnifiedMetadataKey.ISRC: self.Id3TextFrame.ISRC,
306
308
  }
307
309
 
308
310
  super().__init__(