audiometa-python 1.3.2__tar.gz → 1.4.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-1.3.2/audiometa_python.egg-info → audiometa_python-1.4.0}/PKG-INFO +44 -4
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/README.md +42 -2
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/__init__.py +53 -1
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_MetadataManager.py +5 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +3 -12
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +48 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +13 -1
- audiometa_python-1.4.0/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +191 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +28 -15
- audiometa_python-1.4.0/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +76 -0
- audiometa_python-1.4.0/audiometa/test/tests/unit/test_get_supported_unified_metadata_field_ids.py +48 -0
- audiometa_python-1.4.0/audiometa/test/tests/unit/utils/test_disc_number_read.py +66 -0
- audiometa_python-1.4.0/audiometa/test/tests/unit/utils/test_unified_metadata_field_schema.py +88 -0
- audiometa_python-1.4.0/audiometa/utils/disc_number_read.py +30 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/types.py +12 -0
- audiometa_python-1.4.0/audiometa/utils/unified_metadata_field_schema.py +80 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0/audiometa_python.egg-info}/PKG-INFO +44 -4
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa_python.egg-info/SOURCES.txt +5 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/pyproject.toml +2 -2
- audiometa_python-1.3.2/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -92
- audiometa_python-1.3.2/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +0 -32
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/LICENSE +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/__main__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/_audio_file.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/cli.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/exceptions.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_id3v1_preserver.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_flac_handler.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_reader.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_writer.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/_riff_bext_chunk.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/_riff_file_structure.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/riff/_riff_info_chunk.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/vorbis/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/id3v1/_Id3v1Manager.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/id3v1/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/id3v1/_constants.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/assets/create_test_files.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/common/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v1/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/riff_metadata_getter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/riff/riff_metadata_setter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/scripts/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/technical_info_inspector.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/vorbis/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/conftest.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_options.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/read/test_unified.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/test_formatting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/conftest.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/options/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/options/test_include_headers.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/options/test_include_technical.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_performance.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_raw_metadata_includes_unsupported_tags.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/get_full_metadata/test_structure.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/description/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/description/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/description/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/description/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/originator/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/originator/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/originator/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/originator/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_audio_data_corruption.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_file.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_invalid_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_invalid_with_metadata_combinations.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_state_precedence.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_unset_with_metadata_combinations.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_fails_with_id3v1.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_with_id3v2_only.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_works_without_id3v1.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_with_metadata_combinations.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_unset_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_delete_original.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_flipped_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_partial_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_random_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_md5_repair_with_metadata.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_non_flac_error.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_unset_md5.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/test_bitrate.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/test_audio_file.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_flac_sync.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_mp3_sync.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_wav_sync.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/cli/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/cli/test_cli_colorize.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff_info_chunk_fourcc.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/test_disc_number_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_format_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_type_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_format_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_type_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_format_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_type_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/test_uuid_format_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/test_date_format_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/test_track_number_validation.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/utils/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/test/tests/unit/utils/test_raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/flac_md5_state.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/id3v1_genre_code_map.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/metadata_format.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/metadata_writing_strategy.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/mutagen_exception_handler.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/base.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/config.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/ubuntu.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/rating_profiles.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/tool_path_resolver.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa/utils/unified_metadata_key.py +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa_python.egg-info/dependency_links.txt +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa_python.egg-info/entry_points.txt +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa_python.egg-info/requires.txt +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/audiometa_python.egg-info/top_level.txt +0 -0
- {audiometa_python-1.3.2 → audiometa_python-1.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: audiometa-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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>
|
|
@@ -9,7 +9,7 @@ Project-URL: Homepage, https://github.com/BehindTheMusicTree/audiometa
|
|
|
9
9
|
Project-URL: Repository, https://github.com/BehindTheMusicTree/audiometa
|
|
10
10
|
Project-URL: Issues, https://github.com/BehindTheMusicTree/audiometa/issues
|
|
11
11
|
Keywords: audio,metadata,mp3,flac,wav,id3,vorbis,riff
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -321,11 +321,13 @@ AudioMeta uses a combination of Python libraries and external command-line tools
|
|
|
321
321
|
|
|
322
322
|
### Reading Metadata
|
|
323
323
|
|
|
324
|
-
When reading metadata,
|
|
324
|
+
When reading metadata, the main entry points are `get_unified_metadata`, `get_unified_metadata_field`, and `get_full_metadata`. For tooling and UIs, `get_unified_metadata_field_schema` and `get_supported_unified_metadata_field_ids` describe the full unified vocabulary and which fields are writable for a given file’s primary format.
|
|
325
325
|
|
|
326
326
|
- `get_unified_metadata`: Reads all metadata from a file and returns a unified dictionary.
|
|
327
327
|
- `get_unified_metadata_field`: Reads a specific metadata field from a file.
|
|
328
|
-
- `get_full_metadata`: Reads all metadata from a file and returns a dictionary including headers and
|
|
328
|
+
- `get_full_metadata`: Reads all metadata from a file and returns a dictionary including headers, technical info, raw tags, **unified field schema**, and **per-file supported unified field ids**.
|
|
329
|
+
- `get_unified_metadata_field_schema`: Returns wire-oriented descriptors (`id`, `label`, `multiple`, `value_type`, `optional_value`) for every `UnifiedMetadataKey` (no file required).
|
|
330
|
+
- `get_supported_unified_metadata_field_ids`: Returns sorted unified field ids that have a write mapping for the file’s primary metadata format.
|
|
329
331
|
|
|
330
332
|
#### Reading from a specific metadata format
|
|
331
333
|
|
|
@@ -413,6 +415,21 @@ except MetadataFieldNotSupportedByMetadataFormatError as e:
|
|
|
413
415
|
print(f"Error: {e}")
|
|
414
416
|
```
|
|
415
417
|
|
|
418
|
+
#### Unified field schema and writable field ids
|
|
419
|
+
|
|
420
|
+
**`get_unified_metadata_field_schema()`** returns one descriptor per `UnifiedMetadataKey`: stable string **`id`** (the enum value), English **`label`**, **`multiple`**, JSON-oriented **`value_type`**, and **`optional_value`**. Use it for forms, validation, or API docs without hard-coding the enum.
|
|
421
|
+
|
|
422
|
+
**`get_supported_unified_metadata_field_ids(file)`** returns sorted **`UnifiedMetadataKey.value`** strings for fields that have a non-`None` write mapping in the file’s **primary** (native) metadata format.
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
from audiometa import get_unified_metadata_field_schema, get_supported_unified_metadata_field_ids
|
|
426
|
+
|
|
427
|
+
schema = get_unified_metadata_field_schema()
|
|
428
|
+
writable_on_this_file = get_supported_unified_metadata_field_ids("song.mp3")
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
`get_full_metadata` always includes **`unified_metadata_field_schema`** (same list as above) and **`supported_unified_metadata_field_ids`** for that path. The **`audiometa read`** command surfaces these keys in **JSON** and **YAML** output; **table** output only prints unified, technical, and format metadata sections.
|
|
432
|
+
|
|
416
433
|
#### Reading Full Metadata From All Formats Including Headers and Technical Info
|
|
417
434
|
|
|
418
435
|
**`get_full_metadata(file_path, include_headers=True, include_technical=True, include_raw_binary_data=False)`**
|
|
@@ -425,6 +442,8 @@ Gets comprehensive metadata including all available information from a file, inc
|
|
|
425
442
|
from audiometa import get_full_metadata
|
|
426
443
|
|
|
427
444
|
full_metadata = get_full_metadata("song.mp3")
|
|
445
|
+
# full_metadata["unified_metadata_field_schema"] — all unified keys
|
|
446
|
+
# full_metadata["supported_unified_metadata_field_ids"] — writable via primary format
|
|
428
447
|
```
|
|
429
448
|
|
|
430
449
|
### Validate Metadata Before Update
|
|
@@ -702,6 +721,7 @@ This function provides the most complete view of an audio file by combining:
|
|
|
702
721
|
- Technical information (duration, bitrate, sample rate, channels, file size)
|
|
703
722
|
- Format-specific headers and structure information
|
|
704
723
|
- Raw metadata details from each format (when include_raw_binary_data is False, binary/opaque content such as APIC, PRIV, TRAKTOR4 is summarized as size placeholders)
|
|
724
|
+
- **Unified field schema** (`unified_metadata_field_schema`) and **per-file writable unified ids** (`supported_unified_metadata_field_ids`); see `get_unified_metadata_field_schema` and `get_supported_unified_metadata_field_ids`
|
|
705
725
|
|
|
706
726
|
```python
|
|
707
727
|
from audiometa import get_full_metadata, UnifiedMetadataKey
|
|
@@ -713,6 +733,10 @@ full_metadata = get_full_metadata("song.mp3")
|
|
|
713
733
|
print(f"Title: {full_metadata['unified_metadata'][UnifiedMetadataKey.TITLE]}")
|
|
714
734
|
print(f"Artists: {full_metadata['unified_metadata'][UnifiedMetadataKey.ARTISTS]}")
|
|
715
735
|
|
|
736
|
+
# Field vocabulary and ids writable for this file's primary format
|
|
737
|
+
print(full_metadata["unified_metadata_field_schema"][0])
|
|
738
|
+
print(full_metadata["supported_unified_metadata_field_ids"])
|
|
739
|
+
|
|
716
740
|
# Access technical information
|
|
717
741
|
print(f"Duration: {full_metadata['technical_info']['duration_seconds']} seconds")
|
|
718
742
|
print(f"Bitrate: {full_metadata['technical_info']['bitrate_bps']} bps ({full_metadata['technical_info']['bitrate_bps'] // 1000} kbps)")
|
|
@@ -839,6 +863,22 @@ A comprehensive dictionary containing:
|
|
|
839
863
|
'chunk_structure': {...}
|
|
840
864
|
}
|
|
841
865
|
},
|
|
866
|
+
'unified_metadata_field_schema': [
|
|
867
|
+
{
|
|
868
|
+
'id': 'title',
|
|
869
|
+
'label': 'Title',
|
|
870
|
+
'multiple': False,
|
|
871
|
+
'value_type': 'string',
|
|
872
|
+
'optional_value': False,
|
|
873
|
+
},
|
|
874
|
+
# ... one entry per UnifiedMetadataKey
|
|
875
|
+
],
|
|
876
|
+
'supported_unified_metadata_field_ids': [
|
|
877
|
+
'album',
|
|
878
|
+
'artists',
|
|
879
|
+
'title',
|
|
880
|
+
# ... ids with a write mapping for this file's primary format
|
|
881
|
+
],
|
|
842
882
|
'format_priorities': {
|
|
843
883
|
'file_extension': '.mp3',
|
|
844
884
|
'reading_order': ['id3v2', 'id3v1'],
|
|
@@ -279,11 +279,13 @@ AudioMeta uses a combination of Python libraries and external command-line tools
|
|
|
279
279
|
|
|
280
280
|
### Reading Metadata
|
|
281
281
|
|
|
282
|
-
When reading metadata,
|
|
282
|
+
When reading metadata, the main entry points are `get_unified_metadata`, `get_unified_metadata_field`, and `get_full_metadata`. For tooling and UIs, `get_unified_metadata_field_schema` and `get_supported_unified_metadata_field_ids` describe the full unified vocabulary and which fields are writable for a given file’s primary format.
|
|
283
283
|
|
|
284
284
|
- `get_unified_metadata`: Reads all metadata from a file and returns a unified dictionary.
|
|
285
285
|
- `get_unified_metadata_field`: Reads a specific metadata field from a file.
|
|
286
|
-
- `get_full_metadata`: Reads all metadata from a file and returns a dictionary including headers and
|
|
286
|
+
- `get_full_metadata`: Reads all metadata from a file and returns a dictionary including headers, technical info, raw tags, **unified field schema**, and **per-file supported unified field ids**.
|
|
287
|
+
- `get_unified_metadata_field_schema`: Returns wire-oriented descriptors (`id`, `label`, `multiple`, `value_type`, `optional_value`) for every `UnifiedMetadataKey` (no file required).
|
|
288
|
+
- `get_supported_unified_metadata_field_ids`: Returns sorted unified field ids that have a write mapping for the file’s primary metadata format.
|
|
287
289
|
|
|
288
290
|
#### Reading from a specific metadata format
|
|
289
291
|
|
|
@@ -371,6 +373,21 @@ except MetadataFieldNotSupportedByMetadataFormatError as e:
|
|
|
371
373
|
print(f"Error: {e}")
|
|
372
374
|
```
|
|
373
375
|
|
|
376
|
+
#### Unified field schema and writable field ids
|
|
377
|
+
|
|
378
|
+
**`get_unified_metadata_field_schema()`** returns one descriptor per `UnifiedMetadataKey`: stable string **`id`** (the enum value), English **`label`**, **`multiple`**, JSON-oriented **`value_type`**, and **`optional_value`**. Use it for forms, validation, or API docs without hard-coding the enum.
|
|
379
|
+
|
|
380
|
+
**`get_supported_unified_metadata_field_ids(file)`** returns sorted **`UnifiedMetadataKey.value`** strings for fields that have a non-`None` write mapping in the file’s **primary** (native) metadata format.
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
from audiometa import get_unified_metadata_field_schema, get_supported_unified_metadata_field_ids
|
|
384
|
+
|
|
385
|
+
schema = get_unified_metadata_field_schema()
|
|
386
|
+
writable_on_this_file = get_supported_unified_metadata_field_ids("song.mp3")
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`get_full_metadata` always includes **`unified_metadata_field_schema`** (same list as above) and **`supported_unified_metadata_field_ids`** for that path. The **`audiometa read`** command surfaces these keys in **JSON** and **YAML** output; **table** output only prints unified, technical, and format metadata sections.
|
|
390
|
+
|
|
374
391
|
#### Reading Full Metadata From All Formats Including Headers and Technical Info
|
|
375
392
|
|
|
376
393
|
**`get_full_metadata(file_path, include_headers=True, include_technical=True, include_raw_binary_data=False)`**
|
|
@@ -383,6 +400,8 @@ Gets comprehensive metadata including all available information from a file, inc
|
|
|
383
400
|
from audiometa import get_full_metadata
|
|
384
401
|
|
|
385
402
|
full_metadata = get_full_metadata("song.mp3")
|
|
403
|
+
# full_metadata["unified_metadata_field_schema"] — all unified keys
|
|
404
|
+
# full_metadata["supported_unified_metadata_field_ids"] — writable via primary format
|
|
386
405
|
```
|
|
387
406
|
|
|
388
407
|
### Validate Metadata Before Update
|
|
@@ -660,6 +679,7 @@ This function provides the most complete view of an audio file by combining:
|
|
|
660
679
|
- Technical information (duration, bitrate, sample rate, channels, file size)
|
|
661
680
|
- Format-specific headers and structure information
|
|
662
681
|
- Raw metadata details from each format (when include_raw_binary_data is False, binary/opaque content such as APIC, PRIV, TRAKTOR4 is summarized as size placeholders)
|
|
682
|
+
- **Unified field schema** (`unified_metadata_field_schema`) and **per-file writable unified ids** (`supported_unified_metadata_field_ids`); see `get_unified_metadata_field_schema` and `get_supported_unified_metadata_field_ids`
|
|
663
683
|
|
|
664
684
|
```python
|
|
665
685
|
from audiometa import get_full_metadata, UnifiedMetadataKey
|
|
@@ -671,6 +691,10 @@ full_metadata = get_full_metadata("song.mp3")
|
|
|
671
691
|
print(f"Title: {full_metadata['unified_metadata'][UnifiedMetadataKey.TITLE]}")
|
|
672
692
|
print(f"Artists: {full_metadata['unified_metadata'][UnifiedMetadataKey.ARTISTS]}")
|
|
673
693
|
|
|
694
|
+
# Field vocabulary and ids writable for this file's primary format
|
|
695
|
+
print(full_metadata["unified_metadata_field_schema"][0])
|
|
696
|
+
print(full_metadata["supported_unified_metadata_field_ids"])
|
|
697
|
+
|
|
674
698
|
# Access technical information
|
|
675
699
|
print(f"Duration: {full_metadata['technical_info']['duration_seconds']} seconds")
|
|
676
700
|
print(f"Bitrate: {full_metadata['technical_info']['bitrate_bps']} bps ({full_metadata['technical_info']['bitrate_bps'] // 1000} kbps)")
|
|
@@ -797,6 +821,22 @@ A comprehensive dictionary containing:
|
|
|
797
821
|
'chunk_structure': {...}
|
|
798
822
|
}
|
|
799
823
|
},
|
|
824
|
+
'unified_metadata_field_schema': [
|
|
825
|
+
{
|
|
826
|
+
'id': 'title',
|
|
827
|
+
'label': 'Title',
|
|
828
|
+
'multiple': False,
|
|
829
|
+
'value_type': 'string',
|
|
830
|
+
'optional_value': False,
|
|
831
|
+
},
|
|
832
|
+
# ... one entry per UnifiedMetadataKey
|
|
833
|
+
],
|
|
834
|
+
'supported_unified_metadata_field_ids': [
|
|
835
|
+
'album',
|
|
836
|
+
'artists',
|
|
837
|
+
'title',
|
|
838
|
+
# ... ids with a write mapping for this file's primary format
|
|
839
|
+
],
|
|
800
840
|
'format_priorities': {
|
|
801
841
|
'file_extension': '.mp3',
|
|
802
842
|
'reading_order': ['id3v2', 'id3v1'],
|
|
@@ -34,10 +34,13 @@ from .utils.flac_md5_state import FlacMd5State
|
|
|
34
34
|
from .utils.metadata_format import MetadataFormat
|
|
35
35
|
from .utils.metadata_writing_strategy import MetadataWritingStrategy
|
|
36
36
|
from .utils.types import UnifiedMetadata, UnifiedMetadataValue
|
|
37
|
+
from .utils.unified_metadata_field_schema import get_unified_metadata_field_schema
|
|
37
38
|
from .utils.unified_metadata_key import UnifiedMetadataKey
|
|
38
39
|
|
|
39
40
|
__all__ = [
|
|
40
41
|
"UnifiedMetadataKey",
|
|
42
|
+
"get_unified_metadata_field_schema",
|
|
43
|
+
"get_supported_unified_metadata_field_ids",
|
|
41
44
|
"FlacMd5State",
|
|
42
45
|
"MetadataFormat",
|
|
43
46
|
"MetadataWritingStrategy",
|
|
@@ -79,6 +82,35 @@ METADATA_FORMAT_MANAGER_CLASS_MAP: dict[MetadataFormat, type] = {
|
|
|
79
82
|
type PublicFileType = str | Path
|
|
80
83
|
|
|
81
84
|
|
|
85
|
+
def _supported_unified_metadata_field_ids_from_manager(manager: _MetadataManager | None) -> list[str]:
|
|
86
|
+
if manager is None:
|
|
87
|
+
return []
|
|
88
|
+
wmap = getattr(manager, "metadata_keys_direct_map_write", None)
|
|
89
|
+
if not wmap:
|
|
90
|
+
return []
|
|
91
|
+
return sorted(ukey.value for ukey, raw_key in wmap.items() if raw_key is not None)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_supported_unified_metadata_field_ids(file: PublicFileType) -> list[str]:
|
|
95
|
+
"""Return unified field ids writable to the file's primary (native) metadata format.
|
|
96
|
+
|
|
97
|
+
Keys are :attr:`UnifiedMetadataKey.value` strings. Fields with no write mapping
|
|
98
|
+
for that format (``None`` in the manager's write map) are omitted.
|
|
99
|
+
"""
|
|
100
|
+
audio_file = _AudioFile(file)
|
|
101
|
+
available_formats = MetadataFormat.get_priorities().get(audio_file.file_extension, [])
|
|
102
|
+
if not available_formats:
|
|
103
|
+
return []
|
|
104
|
+
target_format = available_formats[0]
|
|
105
|
+
manager = _get_metadata_manager(
|
|
106
|
+
audio_file=audio_file,
|
|
107
|
+
metadata_format=target_format,
|
|
108
|
+
normalized_rating_max_value=None,
|
|
109
|
+
id3v2_version=None,
|
|
110
|
+
)
|
|
111
|
+
return _supported_unified_metadata_field_ids_from_manager(manager)
|
|
112
|
+
|
|
113
|
+
|
|
82
114
|
def _get_metadata_manager(
|
|
83
115
|
audio_file: _AudioFile,
|
|
84
116
|
metadata_format: MetadataFormat | None = None,
|
|
@@ -1290,7 +1322,18 @@ def get_full_metadata(
|
|
|
1290
1322
|
TRAKTOR4). If False (default), such content is replaced by size placeholders.
|
|
1291
1323
|
|
|
1292
1324
|
Returns:
|
|
1293
|
-
Comprehensive dictionary
|
|
1325
|
+
Comprehensive dictionary. Top-level keys always include:
|
|
1326
|
+
|
|
1327
|
+
- ``unified_metadata``: Same merged view as :func:`get_unified_metadata`
|
|
1328
|
+
- ``technical_info``, ``metadata_format``, ``headers``, ``raw_metadata``: As documented below;
|
|
1329
|
+
``technical_info`` / ``headers`` may be empty dicts when disabled via parameters
|
|
1330
|
+
- ``unified_metadata_field_schema``: List of field descriptors (``id``, ``label``, ``multiple``,
|
|
1331
|
+
``value_type``, ``optional_value``) for every
|
|
1332
|
+
:class:`~audiometa.utils.unified_metadata_key.UnifiedMetadataKey`; same data as
|
|
1333
|
+
:func:`get_unified_metadata_field_schema`
|
|
1334
|
+
- ``supported_unified_metadata_field_ids``: Sorted :attr:`UnifiedMetadataKey.value` strings writable
|
|
1335
|
+
for this file's primary metadata format (see :func:`get_supported_unified_metadata_field_ids`)
|
|
1336
|
+
- ``format_priorities``: Extension, reading order, and primary writing format
|
|
1294
1337
|
|
|
1295
1338
|
Raises:
|
|
1296
1339
|
FileTypeNotSupportedError: If the file format is not supported
|
|
@@ -1315,6 +1358,10 @@ def get_full_metadata(
|
|
|
1315
1358
|
# Access header information
|
|
1316
1359
|
print(f"ID3v2 Version: {full_metadata['headers']['id3v2']['version']}")
|
|
1317
1360
|
print(f"Has ID3v1 Header: {full_metadata['headers']['id3v1']['present']}")
|
|
1361
|
+
|
|
1362
|
+
# Full unified key schema; writable field ids for this file's primary format
|
|
1363
|
+
print(len(full_metadata['unified_metadata_field_schema']))
|
|
1364
|
+
print(full_metadata['supported_unified_metadata_field_ids'])
|
|
1318
1365
|
"""
|
|
1319
1366
|
audio_file = _AudioFile(file)
|
|
1320
1367
|
|
|
@@ -1324,6 +1371,9 @@ def get_full_metadata(
|
|
|
1324
1371
|
# Get file-specific format priorities
|
|
1325
1372
|
available_formats = MetadataFormat.get_priorities().get(audio_file.file_extension, [])
|
|
1326
1373
|
|
|
1374
|
+
primary_format = available_formats[0] if available_formats else None
|
|
1375
|
+
primary_manager = all_managers.get(primary_format) if primary_format is not None else None
|
|
1376
|
+
|
|
1327
1377
|
# Initialize result structure
|
|
1328
1378
|
result: dict[str, Any] = {
|
|
1329
1379
|
"unified_metadata": {},
|
|
@@ -1331,6 +1381,8 @@ def get_full_metadata(
|
|
|
1331
1381
|
"metadata_format": {},
|
|
1332
1382
|
"headers": {},
|
|
1333
1383
|
"raw_metadata": {},
|
|
1384
|
+
"unified_metadata_field_schema": get_unified_metadata_field_schema(),
|
|
1385
|
+
"supported_unified_metadata_field_ids": _supported_unified_metadata_field_ids_from_manager(primary_manager),
|
|
1334
1386
|
"format_priorities": {
|
|
1335
1387
|
"file_extension": audio_file.file_extension,
|
|
1336
1388
|
"reading_order": [fmt.value for fmt in available_formats],
|
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, TypeVar, Union, cast
|
|
|
5
5
|
from mutagen._file import FileType as MutagenMetadata
|
|
6
6
|
|
|
7
7
|
from audiometa.exceptions import InvalidMetadataFieldFormatError, InvalidMetadataFieldTypeError
|
|
8
|
+
from audiometa.utils.disc_number_read import parse_disc_number_from_combined_str
|
|
8
9
|
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
@@ -698,6 +699,10 @@ class _MetadataManager:
|
|
|
698
699
|
return track_str
|
|
699
700
|
return None
|
|
700
701
|
|
|
702
|
+
# DISCNUMBER / TPOS-style "n", "n/m", "n-m" (formats using the base read path)
|
|
703
|
+
if unified_metadata_key == UnifiedMetadataKey.DISC_NUMBER:
|
|
704
|
+
return parse_disc_number_from_combined_str(str(value[0]))
|
|
705
|
+
|
|
701
706
|
from typing import get_args, get_origin
|
|
702
707
|
|
|
703
708
|
origin = get_origin(unified_metadata_key_optional_type)
|
|
@@ -30,6 +30,7 @@ from mutagen.id3._frames import (
|
|
|
30
30
|
)
|
|
31
31
|
from mutagen.id3._util import ID3NoHeaderError
|
|
32
32
|
|
|
33
|
+
from audiometa.utils.disc_number_read import parse_disc_number_from_combined_str, parse_disc_total_from_combined_str
|
|
33
34
|
from audiometa.utils.raw_metadata_sanitizer import sanitize_id3v2_raw_info
|
|
34
35
|
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
35
36
|
|
|
@@ -415,12 +416,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
|
|
|
415
416
|
if tpos_value is None or len(tpos_value) == 0:
|
|
416
417
|
return None
|
|
417
418
|
tpos_str = str(tpos_value[0])
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
match = re.match(r"^(\d+)(?:/(\d+))?$", tpos_str)
|
|
421
|
-
if match:
|
|
422
|
-
return int(match.group(1))
|
|
423
|
-
return None
|
|
419
|
+
return parse_disc_number_from_combined_str(tpos_str)
|
|
424
420
|
if unified_metadata_key == UnifiedMetadataKey.DISC_TOTAL:
|
|
425
421
|
tpos_key = self.Id3TextFrame.DISC_NUMBER
|
|
426
422
|
if tpos_key not in raw_clean_metadata:
|
|
@@ -429,12 +425,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
|
|
|
429
425
|
if tpos_value is None or len(tpos_value) == 0:
|
|
430
426
|
return None
|
|
431
427
|
tpos_str = str(tpos_value[0])
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
match = re.match(r"^(\d+)/(\d+)$", tpos_str)
|
|
435
|
-
if match:
|
|
436
|
-
return int(match.group(2))
|
|
437
|
-
return None
|
|
428
|
+
return parse_disc_total_from_combined_str(tpos_str)
|
|
438
429
|
msg = f"Metadata key not handled: {unified_metadata_key}"
|
|
439
430
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
440
431
|
|
|
@@ -6,6 +6,11 @@ from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
7
|
from ...._audio_file import _AudioFile
|
|
8
8
|
from ....exceptions import FileCorruptedError, InvalidRatingValueError, MetadataFieldNotSupportedByMetadataFormatError
|
|
9
|
+
from ....utils.disc_number_read import (
|
|
10
|
+
parse_disc_number_from_combined_str,
|
|
11
|
+
parse_disc_total_from_combined_str,
|
|
12
|
+
parse_explicit_non_negative_disctotal,
|
|
13
|
+
)
|
|
9
14
|
from ....utils.rating_profiles import RatingWriteProfile
|
|
10
15
|
from ....utils.raw_metadata_sanitizer import sanitize_vorbis_raw_info
|
|
11
16
|
from ....utils.tool_path_resolver import get_tool_path
|
|
@@ -260,6 +265,49 @@ class _VorbisManager(_RatingSupportingMetadataManager):
|
|
|
260
265
|
# Cast to RawMetadataDict since RawMetadataKey is str, Enum and string keys work
|
|
261
266
|
self.raw_clean_metadata_uppercase_keys = cast(RawMetadataDict, result_dict)
|
|
262
267
|
|
|
268
|
+
def get_unified_metadata_field(self, unified_metadata_key: UnifiedMetadataKey) -> UnifiedMetadataValue:
|
|
269
|
+
if unified_metadata_key not in (
|
|
270
|
+
UnifiedMetadataKey.DISC_NUMBER,
|
|
271
|
+
UnifiedMetadataKey.DISC_TOTAL,
|
|
272
|
+
):
|
|
273
|
+
return super().get_unified_metadata_field(unified_metadata_key)
|
|
274
|
+
|
|
275
|
+
if self.raw_clean_metadata_uppercase_keys is None:
|
|
276
|
+
self._extract_raw_clean_metadata_uppercase_keys_from_file()
|
|
277
|
+
keys = self.raw_clean_metadata_uppercase_keys
|
|
278
|
+
if keys is None:
|
|
279
|
+
return None
|
|
280
|
+
|
|
281
|
+
disc_number_key = self.VorbisKey.DISC_NUMBER
|
|
282
|
+
disc_total_key = self.VorbisKey.DISC_TOTAL
|
|
283
|
+
|
|
284
|
+
def _first_string(raw_key: RawMetadataKey) -> str | None:
|
|
285
|
+
if raw_key not in keys:
|
|
286
|
+
return None
|
|
287
|
+
vals = keys[raw_key]
|
|
288
|
+
if not vals or len(vals) == 0:
|
|
289
|
+
return None
|
|
290
|
+
v = vals[0]
|
|
291
|
+
if v is None or v == "":
|
|
292
|
+
return None
|
|
293
|
+
return str(v)
|
|
294
|
+
|
|
295
|
+
d = _first_string(disc_number_key)
|
|
296
|
+
t = _first_string(disc_total_key)
|
|
297
|
+
|
|
298
|
+
if unified_metadata_key == UnifiedMetadataKey.DISC_NUMBER:
|
|
299
|
+
if d is None:
|
|
300
|
+
return None
|
|
301
|
+
return parse_disc_number_from_combined_str(d)
|
|
302
|
+
|
|
303
|
+
if t is not None:
|
|
304
|
+
explicit = parse_explicit_non_negative_disctotal(t)
|
|
305
|
+
if explicit is not None:
|
|
306
|
+
return explicit
|
|
307
|
+
if d is None:
|
|
308
|
+
return None
|
|
309
|
+
return parse_disc_total_from_combined_str(d)
|
|
310
|
+
|
|
263
311
|
def _get_raw_rating_by_traktor_or_not(self, raw_clean_metadata: RawMetadataDict) -> tuple[int | None, bool]:
|
|
264
312
|
if self.VorbisKey.RATING in raw_clean_metadata:
|
|
265
313
|
rating_list = raw_clean_metadata[self.VorbisKey.RATING]
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
-
from audiometa import get_full_metadata
|
|
7
|
+
from audiometa import UnifiedMetadataKey, get_full_metadata, get_unified_metadata_field_schema
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@pytest.mark.integration
|
|
@@ -20,6 +20,8 @@ class TestGetFullMetadata:
|
|
|
20
20
|
assert "headers" in result
|
|
21
21
|
assert "raw_metadata" in result
|
|
22
22
|
assert "format_priorities" in result
|
|
23
|
+
assert "unified_metadata_field_schema" in result
|
|
24
|
+
assert "supported_unified_metadata_field_ids" in result
|
|
23
25
|
|
|
24
26
|
# Check that each section is a dictionary
|
|
25
27
|
assert isinstance(result["unified_metadata"], dict)
|
|
@@ -28,6 +30,16 @@ class TestGetFullMetadata:
|
|
|
28
30
|
assert isinstance(result["headers"], dict)
|
|
29
31
|
assert isinstance(result["raw_metadata"], dict)
|
|
30
32
|
assert isinstance(result["format_priorities"], dict)
|
|
33
|
+
schema = result["unified_metadata_field_schema"]
|
|
34
|
+
assert isinstance(schema, list)
|
|
35
|
+
assert len(schema) == len(UnifiedMetadataKey)
|
|
36
|
+
assert {item["id"] for item in schema} == {k.value for k in UnifiedMetadataKey}
|
|
37
|
+
supported = result["supported_unified_metadata_field_ids"]
|
|
38
|
+
assert isinstance(supported, list)
|
|
39
|
+
assert all(isinstance(x, str) for x in supported)
|
|
40
|
+
assert supported == sorted(supported)
|
|
41
|
+
assert set(supported) <= {k.value for k in UnifiedMetadataKey}
|
|
42
|
+
assert schema == get_unified_metadata_field_schema()
|
|
31
43
|
|
|
32
44
|
def test_get_full_metadata_format_priorities_structure(self, sample_mp3_file: Path):
|
|
33
45
|
"""Test that format_priorities has the expected structure."""
|
audiometa_python-1.4.0/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata_field
|
|
4
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
|
|
5
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
6
|
+
from audiometa.test.helpers.vorbis.vorbis_metadata_setter import VorbisMetadataSetter
|
|
7
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.integration
|
|
11
|
+
class TestDiscNumberReading:
|
|
12
|
+
def test_id3v2_with_total(self):
|
|
13
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
14
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1/2"})
|
|
15
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
16
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
17
|
+
assert disc_number == 1
|
|
18
|
+
assert disc_total == 2
|
|
19
|
+
|
|
20
|
+
def test_id3v2_without_total(self):
|
|
21
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
22
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1"})
|
|
23
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
24
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
25
|
+
assert disc_number == 1
|
|
26
|
+
assert disc_total is None
|
|
27
|
+
|
|
28
|
+
def test_id3v2_max_value(self):
|
|
29
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
30
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "99/99"})
|
|
31
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
32
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
33
|
+
assert disc_number == 99
|
|
34
|
+
assert disc_total == 99
|
|
35
|
+
|
|
36
|
+
def test_id3v2_hyphen_separator_read(self):
|
|
37
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
38
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1-2"})
|
|
39
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
40
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
41
|
+
assert disc_number == 1
|
|
42
|
+
assert disc_total == 2
|
|
43
|
+
|
|
44
|
+
def test_id3v2_invalid_tpos_multiple_slashes_returns_none(self):
|
|
45
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
46
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1/2/3"})
|
|
47
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
48
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
49
|
+
assert disc_number is None
|
|
50
|
+
assert disc_total is None
|
|
51
|
+
|
|
52
|
+
def test_id3v2_read_tpos_above_255_not_clamped(self):
|
|
53
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
54
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "256/300"})
|
|
55
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
56
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
57
|
+
assert disc_number == 256
|
|
58
|
+
assert disc_total == 300
|
|
59
|
+
|
|
60
|
+
def test_vorbis_with_total(self):
|
|
61
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
62
|
+
VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1", "disc_total": "2"})
|
|
63
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
64
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
65
|
+
assert disc_number == 1
|
|
66
|
+
assert disc_total == 2
|
|
67
|
+
|
|
68
|
+
def test_vorbis_without_total(self):
|
|
69
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
70
|
+
VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "2"})
|
|
71
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
72
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
73
|
+
assert disc_number == 2
|
|
74
|
+
assert disc_total is None
|
|
75
|
+
|
|
76
|
+
def test_vorbis_disc_number_combined_slash_form(self):
|
|
77
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
78
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "3/5")
|
|
79
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
80
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
81
|
+
assert disc_number == 3
|
|
82
|
+
assert disc_total == 5
|
|
83
|
+
|
|
84
|
+
def test_vorbis_discnumber_combined_slash_via_set_metadata(self):
|
|
85
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
86
|
+
VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1/2"})
|
|
87
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
88
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
89
|
+
assert disc_number == 1
|
|
90
|
+
assert disc_total == 2
|
|
91
|
+
|
|
92
|
+
def test_vorbis_disc_number_hyphen_form(self):
|
|
93
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
94
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1-2")
|
|
95
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
96
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
97
|
+
assert disc_number == 1
|
|
98
|
+
assert disc_total == 2
|
|
99
|
+
|
|
100
|
+
def test_vorbis_disctotal_overrides_embedded_total(self):
|
|
101
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
102
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/3")
|
|
103
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "2")
|
|
104
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
105
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
106
|
+
assert disc_number == 1
|
|
107
|
+
assert disc_total == 2
|
|
108
|
+
|
|
109
|
+
def test_vorbis_discnumber_slash_with_matching_disctotal(self):
|
|
110
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
111
|
+
VorbisMetadataSetter.set_metadata(test_file, {"disc_number": "1/2", "disc_total": "2"})
|
|
112
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
113
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
114
|
+
assert disc_number == 1
|
|
115
|
+
assert disc_total == 2
|
|
116
|
+
|
|
117
|
+
def test_vorbis_invalid_disctotal_falls_back_to_discnumber_slash(self):
|
|
118
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
119
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2")
|
|
120
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "bogus")
|
|
121
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
122
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
123
|
+
assert disc_number == 1
|
|
124
|
+
assert disc_total == 2
|
|
125
|
+
|
|
126
|
+
def test_vorbis_negative_disctotal_falls_back_to_discnumber_slash(self):
|
|
127
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
128
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2")
|
|
129
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "-1")
|
|
130
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
131
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
132
|
+
assert disc_number == 1
|
|
133
|
+
assert disc_total == 2
|
|
134
|
+
|
|
135
|
+
def test_vorbis_invalid_combined_discnumber(self):
|
|
136
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
137
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2/3")
|
|
138
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
139
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
140
|
+
assert disc_number is None
|
|
141
|
+
assert disc_total is None
|
|
142
|
+
|
|
143
|
+
def test_vorbis_disctotal_only(self):
|
|
144
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
145
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "2")
|
|
146
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
147
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
148
|
+
assert disc_number is None
|
|
149
|
+
assert disc_total == 2
|
|
150
|
+
|
|
151
|
+
def test_id3v1_not_supported(self):
|
|
152
|
+
from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
|
|
153
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
154
|
+
|
|
155
|
+
with temp_file_with_metadata({}, "id3v1") as test_file:
|
|
156
|
+
with pytest.raises(
|
|
157
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
158
|
+
match="UnifiedMetadataKey.DISC_NUMBER metadata not supported by ID3v1 format",
|
|
159
|
+
):
|
|
160
|
+
get_unified_metadata_field(
|
|
161
|
+
test_file, UnifiedMetadataKey.DISC_NUMBER, metadata_format=MetadataFormat.ID3V1
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
with pytest.raises(
|
|
165
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
166
|
+
match="UnifiedMetadataKey.DISC_TOTAL metadata not supported by ID3v1 format",
|
|
167
|
+
):
|
|
168
|
+
get_unified_metadata_field(
|
|
169
|
+
test_file, UnifiedMetadataKey.DISC_TOTAL, metadata_format=MetadataFormat.ID3V1
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def test_riff_not_supported(self):
|
|
173
|
+
from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
|
|
174
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
175
|
+
|
|
176
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
177
|
+
with pytest.raises(
|
|
178
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
179
|
+
match="UnifiedMetadataKey.DISC_NUMBER metadata not supported by RIFF format",
|
|
180
|
+
):
|
|
181
|
+
get_unified_metadata_field(
|
|
182
|
+
test_file, UnifiedMetadataKey.DISC_NUMBER, metadata_format=MetadataFormat.RIFF
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
with pytest.raises(
|
|
186
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
187
|
+
match="UnifiedMetadataKey.DISC_TOTAL metadata not supported by RIFF format",
|
|
188
|
+
):
|
|
189
|
+
get_unified_metadata_field(
|
|
190
|
+
test_file, UnifiedMetadataKey.DISC_TOTAL, metadata_format=MetadataFormat.RIFF
|
|
191
|
+
)
|