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.
- {audiometa_python-0.4.1/audiometa_python.egg-info → audiometa_python-0.6.0}/PKG-INFO +6 -4
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/README.md +5 -3
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/__init__.py +88 -79
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/_audio_file.py +4 -4
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/cli.py +4 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_MetadataManager.py +40 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +2 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +226 -2
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +7 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +2 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_getter.py +101 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_setter.py +116 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/conftest.py +15 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +9 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_formatting.py +1 -1
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +9 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/test_options.py +1 -1
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
- 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
- audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
- audiometa_python-0.6.0/audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
- audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
- audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
- audiometa_python-0.6.0/audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/types.py +1 -1
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/unified_metadata_key.py +2 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0/audiometa_python.egg-info}/PKG-INFO +6 -4
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/SOURCES.txt +13 -2
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/pyproject.toml +1 -1
- audiometa_python-0.4.1/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +0 -297
- audiometa_python-0.4.1/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata_edge_cases.py +0 -231
- audiometa_python-0.4.1/audiometa/test/tests/integration/technical_info/test_bitrate.py +0 -38
- audiometa_python-0.4.1/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -57
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/LICENSE +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/__main__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/exceptions.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/riff/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/_Id3v1Manager.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/_constants.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/assets/create_test_files.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/scripts/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/technical_info_inspector.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_options.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/read/test_unified.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/conftest.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- {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
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/test_audio_file.py +0 -0
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/cli/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
- {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
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/id3v1_genre_code_map.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/metadata_format.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/metadata_writing_strategy.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/mutagen_exception_handler.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/base.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/config.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/ubuntu.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/rating_profiles.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa/utils/tool_path_resolver.py +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/dependency_links.txt +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/entry_points.txt +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/requires.txt +0 -0
- {audiometa_python-0.4.1 → audiometa_python-0.6.0}/audiometa_python.egg-info/top_level.txt +0 -0
- {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.
|
|
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']['
|
|
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
|
-
'
|
|
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']['
|
|
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
|
-
'
|
|
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
|
|
467
|
-
|
|
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
|
-
|
|
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
|
|
645
|
-
|
|
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
|
-
|
|
659
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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)
|
|
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"])
|
|
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
|
|
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(
|
|
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__(
|