audiometa-python 1.4.1__tar.gz → 1.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {audiometa_python-1.4.1/audiometa_python.egg-info → audiometa_python-1.4.3}/PKG-INFO +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/__init__.py +22 -17
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/_audio_file.py +3 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_MetadataManager.py +6 -4
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +3 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_reader.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_writer.py +3 -10
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +29 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/id3v1/_Id3v1Manager.py +4 -5
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v1/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/__init__.py +2 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/vorbis/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +6 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +18 -18
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_structure.py +12 -12
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +82 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_invalid_md5.py +6 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_invalid_with_metadata_combinations.py +15 -15
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_state_precedence.py +6 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_unset_with_metadata_combinations.py +12 -12
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_fails_with_id3v1.py +9 -9
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_with_id3v2_only.py +6 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_with_metadata_combinations.py +12 -12
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_flipped_md5.py +3 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_md5_repair_with_metadata.py +6 -6
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/test_bitrate.py +3 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff_info_chunk_fourcc.py +9 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/flac_md5_state.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/metadata_format.py +5 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/metadata_writing_strategy.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/base.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/ubuntu.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/types.py +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/unified_metadata_key.py +5 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3/audiometa_python.egg-info}/PKG-INFO +2 -2
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa_python.egg-info/requires.txt +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/pyproject.toml +14 -3
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/LICENSE +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/README.md +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/__main__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/cli.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/exceptions.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_id3v1_preserver.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/id3v2/_id3v2_flac_handler.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/_riff_bext_chunk.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/_riff_file_structure.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/riff/_riff_info_chunk.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/vorbis/__init__.py +1 -1
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/id3v1/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/id3v1/_constants.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/assets/create_test_files.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/common/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/riff_metadata_getter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/riff/riff_metadata_setter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/scripts/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/technical_info_inspector.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/conftest.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_options.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/read/test_unified.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/test_formatting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/conftest.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/options/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/options/test_include_headers.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/options/test_include_technical.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_performance.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_raw_metadata_includes_unsupported_tags.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/description/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/description/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/description/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/description/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/originator/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/originator/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/originator/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/originator/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_audio_data_corruption.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_file.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/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.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_unset_md5.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_delete_original.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_partial_md5.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_random_md5.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_non_flac_error.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_unset_md5.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/test_audio_file.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_flac_sync.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_mp3_sync.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_wav_sync.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/cli/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/cli/test_cli_colorize.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/test_disc_number_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_format_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_type_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_format_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_type_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_format_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_type_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/test_uuid_format_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/test_date_format_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/test_track_number_validation.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/test_get_supported_unified_metadata_field_ids.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/utils/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/utils/test_disc_number_read.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/utils/test_raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/test/tests/unit/utils/test_unified_metadata_field_schema.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/disc_number_read.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/id3v1_genre_code_map.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/mutagen_exception_handler.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/config.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/rating_profiles.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/tool_path_resolver.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa/utils/unified_metadata_field_schema.py +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa_python.egg-info/SOURCES.txt +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa_python.egg-info/dependency_links.txt +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa_python.egg-info/entry_points.txt +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/audiometa_python.egg-info/top_level.txt +0 -0
- {audiometa_python-1.4.1 → audiometa_python-1.4.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: audiometa-python
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.3
|
|
4
4
|
Summary: A comprehensive Python library for reading and writing audio metadata across multiple formats
|
|
5
5
|
Author: AudioMeta Python Contributors
|
|
6
6
|
Author-email: Andreas Garcia <garcia.andreas.1991@gmail.com>
|
|
@@ -27,7 +27,7 @@ Provides-Extra: dev
|
|
|
27
27
|
Requires-Dist: pytest==9.0.1; extra == "dev"
|
|
28
28
|
Requires-Dist: pytest-cov==4.0.0; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest-mock==3.15.1; extra == "dev"
|
|
30
|
-
Requires-Dist: ruff==0.
|
|
30
|
+
Requires-Dist: ruff==0.15.9; extra == "dev"
|
|
31
31
|
Requires-Dist: isort==5.13.2; extra == "dev"
|
|
32
32
|
Requires-Dist: mypy==1.18.2; extra == "dev"
|
|
33
33
|
Requires-Dist: pre-commit==3.0.0; extra == "dev"
|
|
@@ -38,35 +38,35 @@ from .utils.unified_metadata_field_schema import get_unified_metadata_field_sche
|
|
|
38
38
|
from .utils.unified_metadata_key import UnifiedMetadataKey
|
|
39
39
|
|
|
40
40
|
__all__ = [
|
|
41
|
-
"UnifiedMetadataKey",
|
|
42
|
-
"get_unified_metadata_field_schema",
|
|
43
|
-
"get_supported_unified_metadata_field_ids",
|
|
44
|
-
"FlacMd5State",
|
|
45
|
-
"MetadataFormat",
|
|
46
|
-
"MetadataWritingStrategy",
|
|
47
|
-
"UnifiedMetadata",
|
|
48
|
-
"UnifiedMetadataValue",
|
|
49
41
|
"FileCorruptedError",
|
|
50
42
|
"FileTypeNotSupportedError",
|
|
43
|
+
"FlacMd5State",
|
|
51
44
|
"InvalidMetadataFieldTypeError",
|
|
52
45
|
"MetadataFieldNotSupportedByLibError",
|
|
53
46
|
"MetadataFieldNotSupportedByMetadataFormatError",
|
|
47
|
+
"MetadataFormat",
|
|
54
48
|
"MetadataFormatNotSupportedByAudioFormatError",
|
|
55
49
|
"MetadataWritingConflictParametersError",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
50
|
+
"MetadataWritingStrategy",
|
|
51
|
+
"UnifiedMetadata",
|
|
52
|
+
"UnifiedMetadataKey",
|
|
53
|
+
"UnifiedMetadataValue",
|
|
60
54
|
"delete_all_metadata",
|
|
55
|
+
"fix_md5_checking",
|
|
61
56
|
"get_bitrate",
|
|
62
57
|
"get_channels",
|
|
58
|
+
"get_duration_in_sec",
|
|
63
59
|
"get_file_size",
|
|
60
|
+
"get_full_metadata",
|
|
64
61
|
"get_sample_rate",
|
|
62
|
+
"get_supported_unified_metadata_field_ids",
|
|
63
|
+
"get_unified_metadata",
|
|
64
|
+
"get_unified_metadata_field",
|
|
65
|
+
"get_unified_metadata_field_schema",
|
|
65
66
|
"is_audio_file",
|
|
66
|
-
"get_duration_in_sec",
|
|
67
67
|
"is_flac_md5_valid",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
68
|
+
"update_metadata",
|
|
69
|
+
"validate_metadata_for_update",
|
|
70
70
|
]
|
|
71
71
|
|
|
72
72
|
FILE_EXTENSION_NOT_HANDLED_MESSAGE = "The file's format is not handled by the service."
|
|
@@ -124,7 +124,10 @@ def _get_metadata_manager(
|
|
|
124
124
|
if not metadata_format:
|
|
125
125
|
metadata_format = audio_file_prioritized_tag_formats[0]
|
|
126
126
|
elif metadata_format not in audio_file_prioritized_tag_formats:
|
|
127
|
-
msg =
|
|
127
|
+
msg = (
|
|
128
|
+
f"Tag format {metadata_format.qualified_name()} not supported for file extension "
|
|
129
|
+
f"{audio_file.file_extension}"
|
|
130
|
+
)
|
|
128
131
|
raise MetadataFormatNotSupportedByAudioFormatError(msg)
|
|
129
132
|
|
|
130
133
|
manager_class: type[_MetadataManager] = cast(Any, METADATA_FORMAT_MANAGER_CLASS_MAP[metadata_format])
|
|
@@ -901,7 +904,9 @@ def _handle_metadata_strategy(
|
|
|
901
904
|
except MetadataFieldNotSupportedByMetadataFormatError as e:
|
|
902
905
|
# For SYNC strategy, log warning but continue with other formats
|
|
903
906
|
if warn_on_unsupported_field:
|
|
904
|
-
format_warn_msg =
|
|
907
|
+
format_warn_msg = (
|
|
908
|
+
f"Format {target_format_actual.qualified_name()} doesn't support some metadata fields: {e}"
|
|
909
|
+
)
|
|
905
910
|
warnings.warn(format_warn_msg, stacklevel=2)
|
|
906
911
|
except Exception as e:
|
|
907
912
|
# Re-raise user errors (like InvalidRatingValueError) immediately
|
|
@@ -7,7 +7,7 @@ import tempfile
|
|
|
7
7
|
import types
|
|
8
8
|
import warnings
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import cast
|
|
10
|
+
from typing import Self, cast
|
|
11
11
|
|
|
12
12
|
from mutagen.flac import FLAC, StreamInfo
|
|
13
13
|
from mutagen.mp3 import MP3
|
|
@@ -251,7 +251,7 @@ class _AudioFile:
|
|
|
251
251
|
if hasattr(self.file, "close"):
|
|
252
252
|
self.file.close()
|
|
253
253
|
|
|
254
|
-
def __enter__(self) ->
|
|
254
|
+
def __enter__(self) -> Self:
|
|
255
255
|
return self
|
|
256
256
|
|
|
257
257
|
def __exit__(
|
|
@@ -368,7 +368,7 @@ class _AudioFile:
|
|
|
368
368
|
)
|
|
369
369
|
|
|
370
370
|
# Create a temporary file to store the corrected FLAC content
|
|
371
|
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".flac")
|
|
371
|
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".flac") # noqa: SIM115
|
|
372
372
|
temp_path = temp_file.name
|
|
373
373
|
temp_file.close() # Close but don't delete yet
|
|
374
374
|
|
|
@@ -251,8 +251,7 @@ class _MetadataManager:
|
|
|
251
251
|
|
|
252
252
|
raise InvalidMetadataFieldFormatError(
|
|
253
253
|
UnifiedMetadataKey.ISRC.value,
|
|
254
|
-
"12 alphanumeric characters (e.g., 'USRC17607839') or 15 characters with hyphens "
|
|
255
|
-
"(e.g., 'US-RC1-76-07839')",
|
|
254
|
+
"12 alphanumeric characters (e.g., 'USRC17607839') or 15 characters with hyphens (e.g., 'US-RC1-76-07839')",
|
|
256
255
|
isrc,
|
|
257
256
|
)
|
|
258
257
|
|
|
@@ -660,7 +659,7 @@ class _MetadataManager:
|
|
|
660
659
|
def get_unified_metadata_field(self, unified_metadata_key: UnifiedMetadataKey) -> UnifiedMetadataValue:
|
|
661
660
|
if unified_metadata_key not in self.metadata_keys_direct_map_read:
|
|
662
661
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
663
|
-
msg = f"{unified_metadata_key} metadata not supported by {metadata_format_name} format"
|
|
662
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata not supported by {metadata_format_name} format"
|
|
664
663
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
665
664
|
|
|
666
665
|
if self.raw_clean_metadata_uppercase_keys is None:
|
|
@@ -852,7 +851,10 @@ class _MetadataManager:
|
|
|
852
851
|
|
|
853
852
|
if unified_metadata_key not in self.metadata_keys_direct_map_write:
|
|
854
853
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
855
|
-
msg =
|
|
854
|
+
msg = (
|
|
855
|
+
f"{unified_metadata_key.qualified_name()} metadata not supported by "
|
|
856
|
+
f"{metadata_format_name} format"
|
|
857
|
+
)
|
|
856
858
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
857
859
|
raw_metadata_key = self.metadata_keys_direct_map_write[unified_metadata_key]
|
|
858
860
|
if raw_metadata_key:
|
|
@@ -212,7 +212,9 @@ class _RatingSupportingMetadataManager(_MetadataManager):
|
|
|
212
212
|
or UnifiedMetadataKey.RATING not in self.metadata_keys_direct_map_write
|
|
213
213
|
):
|
|
214
214
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
215
|
-
msg =
|
|
215
|
+
msg = (
|
|
216
|
+
f"{UnifiedMetadataKey.RATING.qualified_name()} metadata not supported by {metadata_format_name} format"
|
|
217
|
+
)
|
|
216
218
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
217
219
|
|
|
218
220
|
# Validate rating value before processing
|
|
@@ -426,7 +426,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
|
|
|
426
426
|
return None
|
|
427
427
|
tpos_str = str(tpos_value[0])
|
|
428
428
|
return parse_disc_total_from_combined_str(tpos_str)
|
|
429
|
-
msg = f"Metadata key not handled: {unified_metadata_key}"
|
|
429
|
+
msg = f"Metadata key not handled: {unified_metadata_key.qualified_name()}"
|
|
430
430
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
431
431
|
|
|
432
432
|
def _update_formatted_value_in_raw_mutagen_metadata(
|
|
@@ -510,7 +510,7 @@ class _Id3v2Manager(_RatingSupportingMetadataManager):
|
|
|
510
510
|
app_metadata_value = unified_metadata[unified_metadata_key]
|
|
511
511
|
if unified_metadata_key not in self.metadata_keys_direct_map_write:
|
|
512
512
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
513
|
-
msg = f"{unified_metadata_key} metadata not supported by {metadata_format_name} format"
|
|
513
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata not supported by {metadata_format_name} format"
|
|
514
514
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
515
515
|
raw_metadata_key = self.metadata_keys_direct_map_write[unified_metadata_key]
|
|
516
516
|
if raw_metadata_key:
|
|
@@ -254,5 +254,5 @@ class _Id3v2Reader:
|
|
|
254
254
|
"""
|
|
255
255
|
uuid_hex_length = 32
|
|
256
256
|
if len(uuid_str) == uuid_hex_length and all(c in "0123456789abcdefABCDEF" for c in uuid_str):
|
|
257
|
-
return f"{uuid_str[:8]}-{uuid_str[8:12]}-
|
|
257
|
+
return f"{uuid_str[:8]}-{uuid_str[8:12]}-{uuid_str[12:16]}-{uuid_str[16:20]}-{uuid_str[20:32]}"
|
|
258
258
|
return uuid_str
|
|
@@ -6,6 +6,7 @@ from mutagen.id3 import ID3
|
|
|
6
6
|
from mutagen.id3._frames import TPOS, TXXX, UFID
|
|
7
7
|
|
|
8
8
|
from audiometa.manager._MetadataManager import _MetadataManager as MetadataManager
|
|
9
|
+
from audiometa.utils.disc_number_read import parse_disc_number_from_combined_str, parse_disc_total_from_combined_str
|
|
9
10
|
from audiometa.utils.types import RawMetadataKey, UnifiedMetadataValue
|
|
10
11
|
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
11
12
|
|
|
@@ -285,11 +286,7 @@ class _Id3v2Writer:
|
|
|
285
286
|
current_total = None
|
|
286
287
|
if current_tpos and len(current_tpos.text) > 0:
|
|
287
288
|
tpos_str = str(current_tpos.text[0])
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
match = re.match(r"^(\d+)/(\d+)$", tpos_str)
|
|
291
|
-
if match:
|
|
292
|
-
current_total = int(match.group(2))
|
|
289
|
+
current_total = parse_disc_total_from_combined_str(tpos_str)
|
|
293
290
|
|
|
294
291
|
raw_mutagen_metadata.delall(tpos_key)
|
|
295
292
|
if app_metadata_value is not None:
|
|
@@ -304,11 +301,7 @@ class _Id3v2Writer:
|
|
|
304
301
|
current_disc_number = None
|
|
305
302
|
if current_tpos and len(current_tpos.text) > 0:
|
|
306
303
|
tpos_str = str(current_tpos.text[0])
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
match = re.match(r"^(\d+)(?:/(\d+))?$", tpos_str)
|
|
310
|
-
if match:
|
|
311
|
-
current_disc_number = int(match.group(1))
|
|
304
|
+
current_disc_number = parse_disc_number_from_combined_str(tpos_str)
|
|
312
305
|
|
|
313
306
|
raw_mutagen_metadata.delall(tpos_key)
|
|
314
307
|
if app_metadata_value is not None:
|
|
@@ -307,7 +307,7 @@ class _RiffManager(_RatingSupportingMetadataManager):
|
|
|
307
307
|
except Exception:
|
|
308
308
|
pass
|
|
309
309
|
return None
|
|
310
|
-
msg = f"Metadata key not handled: {unified_metadata_key}"
|
|
310
|
+
msg = f"Metadata key not handled: {unified_metadata_key.qualified_name()}"
|
|
311
311
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
312
312
|
|
|
313
313
|
def _update_not_using_mutagen_metadata(self, unified_metadata: UnifiedMetadata) -> None:
|
|
@@ -344,7 +344,7 @@ class _RiffManager(_RatingSupportingMetadataManager):
|
|
|
344
344
|
|
|
345
345
|
for unified_metadata_key in unified_metadata:
|
|
346
346
|
if unified_metadata_key not in self.metadata_keys_direct_map_write:
|
|
347
|
-
msg = f"{unified_metadata_key} metadata not supported by RIFF format"
|
|
347
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata not supported by RIFF format"
|
|
348
348
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
349
349
|
|
|
350
350
|
def _read_file_data_for_update(self) -> tuple[bytearray, bool]:
|
|
@@ -388,6 +388,32 @@ class _VorbisManager(_RatingSupportingMetadataManager):
|
|
|
388
388
|
# Get current metadata
|
|
389
389
|
current_metadata = self._extract_mutagen_metadata()
|
|
390
390
|
|
|
391
|
+
# Preserve total when existing DISCNUMBER is stored as combined n/m or n-m and only DISC_NUMBER is updated.
|
|
392
|
+
if (
|
|
393
|
+
UnifiedMetadataKey.DISC_NUMBER in unified_metadata
|
|
394
|
+
and UnifiedMetadataKey.DISC_TOTAL not in unified_metadata
|
|
395
|
+
and unified_metadata[UnifiedMetadataKey.DISC_NUMBER] is not None
|
|
396
|
+
):
|
|
397
|
+
explicit_total = None
|
|
398
|
+
combined_discnumber = None
|
|
399
|
+
for raw_key, raw_values in current_metadata.items():
|
|
400
|
+
key_name = str(raw_key).upper()
|
|
401
|
+
if raw_values is None or len(raw_values) == 0 or raw_values[0] in (None, ""):
|
|
402
|
+
continue
|
|
403
|
+
if key_name == self.VorbisKey.DISC_TOTAL.value:
|
|
404
|
+
explicit_total = str(raw_values[0])
|
|
405
|
+
elif key_name == self.VorbisKey.DISC_NUMBER.value:
|
|
406
|
+
combined_discnumber = str(raw_values[0])
|
|
407
|
+
|
|
408
|
+
explicit_total_is_usable = (
|
|
409
|
+
explicit_total is not None and parse_explicit_non_negative_disctotal(explicit_total) is not None
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if not explicit_total_is_usable and combined_discnumber is not None:
|
|
413
|
+
parsed_total = parse_disc_total_from_combined_str(combined_discnumber)
|
|
414
|
+
if parsed_total is not None:
|
|
415
|
+
unified_metadata[UnifiedMetadataKey.DISC_TOTAL] = parsed_total
|
|
416
|
+
|
|
391
417
|
# Update metadata dict
|
|
392
418
|
for unified_metadata_key in list(unified_metadata.keys()):
|
|
393
419
|
app_metadata_value = unified_metadata[unified_metadata_key]
|
|
@@ -401,7 +427,7 @@ class _VorbisManager(_RatingSupportingMetadataManager):
|
|
|
401
427
|
|
|
402
428
|
if unified_metadata_key not in self.metadata_keys_direct_map_write:
|
|
403
429
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
404
|
-
msg = f"{unified_metadata_key} metadata not supported by {metadata_format_name} format"
|
|
430
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata not supported by {metadata_format_name} format"
|
|
405
431
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
406
432
|
raw_metadata_key = self.metadata_keys_direct_map_write[unified_metadata_key]
|
|
407
433
|
if raw_metadata_key:
|
|
@@ -563,7 +589,7 @@ class _VorbisManager(_RatingSupportingMetadataManager):
|
|
|
563
589
|
def _get_undirectly_mapped_metadata_value_other_than_rating_from_raw_clean_metadata(
|
|
564
590
|
self, _raw_clean_metadata: RawMetadataDict, unified_metadata_key: UnifiedMetadataKey
|
|
565
591
|
) -> UnifiedMetadataValue:
|
|
566
|
-
msg = f"Metadata key not handled: {unified_metadata_key}"
|
|
592
|
+
msg = f"Metadata key not handled: {unified_metadata_key.qualified_name()}"
|
|
567
593
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
568
594
|
|
|
569
595
|
def _update_undirectly_mapped_metadata(
|
|
@@ -600,5 +626,5 @@ class _VorbisManager(_RatingSupportingMetadataManager):
|
|
|
600
626
|
if self.VorbisKey.RATING_TRAKTOR in raw_mutagen_metadata:
|
|
601
627
|
del raw_mutagen_metadata[self.VorbisKey.RATING_TRAKTOR]
|
|
602
628
|
else:
|
|
603
|
-
msg = f"Metadata key not handled: {unified_metadata_key}"
|
|
629
|
+
msg = f"Metadata key not handled: {unified_metadata_key.qualified_name()}"
|
|
604
630
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
@@ -161,7 +161,7 @@ class _Id3v1Manager(_MetadataManager):
|
|
|
161
161
|
raw_clean_metadata=raw_clean_metadata_uppercase_keys,
|
|
162
162
|
raw_metadata_ket=Id3v1RawMetadataKey.GENRE_CODE_OR_NAME,
|
|
163
163
|
)
|
|
164
|
-
msg = f"{unified_metadata_key} metadata is not undirectly handled"
|
|
164
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata is not undirectly handled"
|
|
165
165
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
166
166
|
|
|
167
167
|
def _update_undirectly_mapped_metadata(
|
|
@@ -187,7 +187,7 @@ class _Id3v1Manager(_MetadataManager):
|
|
|
187
187
|
if genre_code is not None:
|
|
188
188
|
tags[Id3v1RawMetadataKey.GENRE_CODE_OR_NAME] = [str(genre_code)]
|
|
189
189
|
else:
|
|
190
|
-
msg = f"{unified_metadata_key} metadata is not undirectly handled"
|
|
190
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata is not undirectly handled"
|
|
191
191
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
192
192
|
|
|
193
193
|
def _update_formatted_value_in_raw_mutagen_metadata(
|
|
@@ -204,8 +204,7 @@ class _Id3v1Manager(_MetadataManager):
|
|
|
204
204
|
|
|
205
205
|
# If value is None, remove the field (delete from tags)
|
|
206
206
|
if app_metadata_value is None:
|
|
207
|
-
|
|
208
|
-
del tags[raw_metadata_key]
|
|
207
|
+
tags.pop(raw_metadata_key, None)
|
|
209
208
|
return
|
|
210
209
|
|
|
211
210
|
# Convert and truncate the value according to ID3v1 constraints
|
|
@@ -258,7 +257,7 @@ class _Id3v1Manager(_MetadataManager):
|
|
|
258
257
|
for unified_metadata_key in unified_metadata:
|
|
259
258
|
if unified_metadata_key not in self.metadata_keys_direct_map_write:
|
|
260
259
|
metadata_format_name = self._get_formatted_metadata_format_name()
|
|
261
|
-
msg = f"{unified_metadata_key} metadata not supported by {metadata_format_name} format"
|
|
260
|
+
msg = f"{unified_metadata_key.qualified_name()} metadata not supported by {metadata_format_name} format"
|
|
262
261
|
raise MetadataFieldNotSupportedByMetadataFormatError(msg)
|
|
263
262
|
|
|
264
263
|
# Read the entire file
|
|
@@ -5,4 +5,4 @@ from .id3v1_metadata_deleter import ID3v1MetadataDeleter
|
|
|
5
5
|
from .id3v1_metadata_getter import ID3v1MetadataGetter
|
|
6
6
|
from .id3v1_metadata_setter import ID3v1MetadataSetter
|
|
7
7
|
|
|
8
|
-
__all__ = ["
|
|
8
|
+
__all__ = ["ID3v1HeaderVerifier", "ID3v1MetadataDeleter", "ID3v1MetadataGetter", "ID3v1MetadataSetter"]
|
|
@@ -15,14 +15,10 @@ from .id3v2_metadata_setter import ID3v2MetadataSetter
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
__all__ = [
|
|
18
|
-
|
|
18
|
+
"ExternalMetadataToolError",
|
|
19
19
|
"ID3v2HeaderVerifier",
|
|
20
20
|
"ID3v2MetadataDeleter",
|
|
21
|
-
"ID3v2MetadataSetter",
|
|
22
21
|
"ID3v2MetadataGetter",
|
|
23
|
-
|
|
24
|
-
# Advanced tools
|
|
22
|
+
"ID3v2MetadataSetter",
|
|
25
23
|
"ManualID3v2FrameCreator",
|
|
26
|
-
# External tool wrappers
|
|
27
|
-
"ExternalMetadataToolError",
|
|
28
24
|
]
|
|
@@ -5,4 +5,4 @@ from .riff_metadata_deleter import RIFFMetadataDeleter
|
|
|
5
5
|
from .riff_metadata_getter import RIFFMetadataGetter
|
|
6
6
|
from .riff_metadata_setter import RIFFMetadataSetter
|
|
7
7
|
|
|
8
|
-
__all__ = ["
|
|
8
|
+
__all__ = ["RIFFHeaderVerifier", "RIFFMetadataDeleter", "RIFFMetadataGetter", "RIFFMetadataSetter"]
|
|
@@ -5,4 +5,4 @@ from .vorbis_metadata_deleter import VorbisMetadataDeleter
|
|
|
5
5
|
from .vorbis_metadata_getter import VorbisMetadataGetter
|
|
6
6
|
from .vorbis_metadata_setter import VorbisMetadataSetter
|
|
7
7
|
|
|
8
|
-
__all__ = ["
|
|
8
|
+
__all__ = ["VorbisHeaderVerifier", "VorbisMetadataDeleter", "VorbisMetadataGetter", "VorbisMetadataSetter"]
|
|
@@ -115,9 +115,9 @@ class TestCLIMultipleFilesErrors:
|
|
|
115
115
|
|
|
116
116
|
# Should contain success messages for valid files
|
|
117
117
|
stdout_output = result.stdout.lower()
|
|
118
|
-
assert (
|
|
119
|
-
"
|
|
120
|
-
)
|
|
118
|
+
assert "updated metadata for" in stdout_output, (
|
|
119
|
+
f"Expected success message in stdout but got:\nSTDOUT: {result.stdout}\nSTDERR: {result.stderr}"
|
|
120
|
+
)
|
|
121
121
|
|
|
122
122
|
# Should contain error message for unsupported file
|
|
123
123
|
stderr_output = result.stderr.lower()
|
|
@@ -151,9 +151,9 @@ class TestCLIMultipleFilesErrors:
|
|
|
151
151
|
|
|
152
152
|
# Should contain messages for processed files
|
|
153
153
|
stdout_output = result.stdout.lower()
|
|
154
|
-
assert (
|
|
155
|
-
"
|
|
156
|
-
)
|
|
154
|
+
assert "deleted" in stdout_output or "found" in stdout_output, (
|
|
155
|
+
f"Expected success message in stdout but got:\nSTDOUT: {result.stdout}\nSTDERR: {result.stderr}"
|
|
156
|
+
)
|
|
157
157
|
|
|
158
158
|
# Should contain error message for unsupported file
|
|
159
159
|
stderr_output = result.stderr.lower()
|
|
@@ -51,14 +51,14 @@ class TestGetFullMetadataBinaryDataFiltering:
|
|
|
51
51
|
for frame_id, frame_data in id3v2_frames.items():
|
|
52
52
|
text = frame_data.get("text", "")
|
|
53
53
|
|
|
54
|
-
assert not any(
|
|
55
|
-
|
|
56
|
-
)
|
|
54
|
+
assert not any(ord(c) < 32 and c not in "\t\n\r" for c in text), (
|
|
55
|
+
f"Frame {frame_id} contains binary data in text: {text[:50]!r}"
|
|
56
|
+
)
|
|
57
57
|
|
|
58
58
|
if _is_binary_frame(frame_id):
|
|
59
|
-
assert text.startswith(
|
|
60
|
-
"
|
|
61
|
-
)
|
|
59
|
+
assert text.startswith("<Binary data:"), (
|
|
60
|
+
f"Binary frame {frame_id} should have placeholder text, got: {text}"
|
|
61
|
+
)
|
|
62
62
|
assert text.endswith(" bytes>"), f"Binary frame {frame_id} should end with ' bytes>', got: {text}"
|
|
63
63
|
|
|
64
64
|
def test_get_full_metadata_id3v2_binary_frames_sanitized(self, sample_mp3_file):
|
|
@@ -72,9 +72,9 @@ class TestGetFullMetadataBinaryDataFiltering:
|
|
|
72
72
|
assert text.startswith("<Binary data:"), f"Binary frame {frame_id} should have placeholder text"
|
|
73
73
|
assert text.endswith(" bytes>"), f"Binary frame {frame_id} should end with ' bytes>'"
|
|
74
74
|
else:
|
|
75
|
-
assert not any(
|
|
76
|
-
|
|
77
|
-
)
|
|
75
|
+
assert not any(ord(c) < 32 and c not in "\t\n\r" for c in text), (
|
|
76
|
+
f"Text frame {frame_id} contains binary data: {text[:50]!r}"
|
|
77
|
+
)
|
|
78
78
|
|
|
79
79
|
def test_get_full_metadata_vorbis_no_binary_data(self, sample_flac_file):
|
|
80
80
|
"""Test that get_full_metadata Vorbis comments don't contain binary data."""
|
|
@@ -86,9 +86,9 @@ class TestGetFullMetadataBinaryDataFiltering:
|
|
|
86
86
|
assert isinstance(values, list), f"Vorbis comment {key} should be a list"
|
|
87
87
|
for value in values:
|
|
88
88
|
assert isinstance(value, str), f"Vorbis comment {key} value should be string"
|
|
89
|
-
assert not any(
|
|
90
|
-
|
|
91
|
-
)
|
|
89
|
+
assert not any(ord(c) < 32 and c not in "\t\n\r" for c in value), (
|
|
90
|
+
f"Vorbis comment {key} contains binary data: {value[:50]!r}"
|
|
91
|
+
)
|
|
92
92
|
|
|
93
93
|
def test_get_full_metadata_vorbis_opaque_comment_sanitized(self):
|
|
94
94
|
"""TRAKTOR4 and other opaque Vorbis comment keys are replaced with size placeholder."""
|
|
@@ -133,9 +133,9 @@ class TestGetFullMetadataBinaryDataFiltering:
|
|
|
133
133
|
for key, value in riff_fields.items():
|
|
134
134
|
assert isinstance(value, str), f"RIFF field {key} should be string"
|
|
135
135
|
# Check for binary data patterns
|
|
136
|
-
assert not any(
|
|
137
|
-
|
|
138
|
-
)
|
|
136
|
+
assert not any(ord(c) < 32 and c not in "\t\n\r" for c in value), (
|
|
137
|
+
f"RIFF field {key} contains binary data: {value[:50]!r}"
|
|
138
|
+
)
|
|
139
139
|
|
|
140
140
|
def test_get_full_metadata_id3v1_no_binary_data(self, sample_mp3_file):
|
|
141
141
|
"""Test that get_full_metadata ID3v1 metadata doesn't contain binary data."""
|
|
@@ -147,9 +147,9 @@ class TestGetFullMetadataBinaryDataFiltering:
|
|
|
147
147
|
for key, value in id3v1_fields.items():
|
|
148
148
|
assert isinstance(value, str), f"ID3v1 field {key} should be string"
|
|
149
149
|
# Check for binary data patterns
|
|
150
|
-
assert not any(
|
|
151
|
-
|
|
152
|
-
)
|
|
150
|
+
assert not any(ord(c) < 32 and c not in "\t\n\r" for c in value), (
|
|
151
|
+
f"ID3v1 field {key} contains binary data: {value[:50]!r}"
|
|
152
|
+
)
|
|
153
153
|
|
|
154
154
|
def test_cli_output_no_binary_data(self, sample_mp3_file):
|
|
155
155
|
"""Test that CLI output doesn't contain binary data."""
|
|
@@ -92,9 +92,9 @@ class TestGetFullMetadataStructure:
|
|
|
92
92
|
|
|
93
93
|
# If there are parsed fields, they should use UnifiedMetadataKey enum values as keys
|
|
94
94
|
for key in parsed_fields:
|
|
95
|
-
assert isinstance(
|
|
96
|
-
key,
|
|
97
|
-
)
|
|
95
|
+
assert isinstance(key, UnifiedMetadataKey), (
|
|
96
|
+
f"ID3v1 parsed_fields key {key} should be UnifiedMetadataKey enum, got {type(key)}"
|
|
97
|
+
)
|
|
98
98
|
# Verify it's a valid UnifiedMetadataKey value
|
|
99
99
|
assert key in UnifiedMetadataKey, f"ID3v1 parsed_fields key {key} is not a valid UnifiedMetadataKey"
|
|
100
100
|
|
|
@@ -138,9 +138,9 @@ class TestGetFullMetadataStructure:
|
|
|
138
138
|
assert isinstance(key, str), f"ID3v1 parsed_fields key in CLI output should be string, got: {type(key)}"
|
|
139
139
|
|
|
140
140
|
# Verify it's a valid UnifiedMetadataKey value
|
|
141
|
-
assert key in [
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
assert key in [e.value for e in UnifiedMetadataKey], (
|
|
142
|
+
f"ID3v1 parsed_fields key {key} is not a valid UnifiedMetadataKey value"
|
|
143
|
+
)
|
|
144
144
|
|
|
145
145
|
def test_parsed_fields_consistency_across_formats(self, sample_mp3_file: Path):
|
|
146
146
|
result = get_full_metadata(sample_mp3_file)
|
|
@@ -150,12 +150,12 @@ class TestGetFullMetadataStructure:
|
|
|
150
150
|
# Check that all formats have the expected structure
|
|
151
151
|
for metadata_format_name, format_data in raw_metadata.items():
|
|
152
152
|
assert "parsed_fields" in format_data, f"Format {metadata_format_name} should have parsed_fields"
|
|
153
|
-
assert isinstance(
|
|
154
|
-
|
|
155
|
-
)
|
|
153
|
+
assert isinstance(format_data["parsed_fields"], dict), (
|
|
154
|
+
f"Format {metadata_format_name} parsed_fields should be a dictionary"
|
|
155
|
+
)
|
|
156
156
|
|
|
157
157
|
# Check that parsed_fields values are strings (no binary data)
|
|
158
158
|
for key, value in format_data["parsed_fields"].items():
|
|
159
|
-
assert isinstance(
|
|
160
|
-
value,
|
|
161
|
-
)
|
|
159
|
+
assert isinstance(value, str), (
|
|
160
|
+
f"Format {metadata_format_name} parsed_fields value for {key} should be string, got {type(value)}"
|
|
161
|
+
)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
3
|
from audiometa import get_unified_metadata_field, update_metadata
|
|
4
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
|
|
4
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
|
|
5
7
|
from audiometa.utils.metadata_format import MetadataFormat
|
|
6
8
|
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
9
|
|
|
@@ -68,6 +70,34 @@ class TestDiscNumberWriting:
|
|
|
68
70
|
assert disc_number == 1
|
|
69
71
|
assert disc_total is None
|
|
70
72
|
|
|
73
|
+
def test_id3v2_update_disc_number_preserves_total_from_hyphen_tpos(self):
|
|
74
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
75
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1-2"})
|
|
76
|
+
|
|
77
|
+
update_metadata(
|
|
78
|
+
test_file,
|
|
79
|
+
{UnifiedMetadataKey.DISC_NUMBER: 5},
|
|
80
|
+
metadata_format=MetadataFormat.ID3V2,
|
|
81
|
+
)
|
|
82
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
83
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
84
|
+
assert disc_number == 5
|
|
85
|
+
assert disc_total == 2
|
|
86
|
+
|
|
87
|
+
def test_id3v2_update_disc_total_preserves_disc_number_from_hyphen_tpos(self):
|
|
88
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
89
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"disc_number": "1-2"})
|
|
90
|
+
|
|
91
|
+
update_metadata(
|
|
92
|
+
test_file,
|
|
93
|
+
{UnifiedMetadataKey.DISC_TOTAL: 4},
|
|
94
|
+
metadata_format=MetadataFormat.ID3V2,
|
|
95
|
+
)
|
|
96
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
97
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
98
|
+
assert disc_number == 1
|
|
99
|
+
assert disc_total == 4
|
|
100
|
+
|
|
71
101
|
def test_vorbis_disc_number_writes_separate_fields(self):
|
|
72
102
|
with temp_file_with_metadata({}, "flac") as test_file:
|
|
73
103
|
update_metadata(
|
|
@@ -80,6 +110,58 @@ class TestDiscNumberWriting:
|
|
|
80
110
|
assert disc_number == 1
|
|
81
111
|
assert disc_total == 2
|
|
82
112
|
|
|
113
|
+
@pytest.mark.parametrize(
|
|
114
|
+
"initial_disc_number",
|
|
115
|
+
["1/2", "1-2"],
|
|
116
|
+
)
|
|
117
|
+
def test_vorbis_update_disc_number_preserves_total_from_combined_discnumber(self, initial_disc_number):
|
|
118
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
119
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", initial_disc_number)
|
|
120
|
+
|
|
121
|
+
update_metadata(
|
|
122
|
+
test_file,
|
|
123
|
+
{UnifiedMetadataKey.DISC_NUMBER: 5},
|
|
124
|
+
metadata_format=MetadataFormat.VORBIS,
|
|
125
|
+
)
|
|
126
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
127
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
128
|
+
assert disc_number == 5
|
|
129
|
+
assert disc_total == 2
|
|
130
|
+
|
|
131
|
+
def test_vorbis_update_disc_number_preserves_explicit_total_when_conflicting(self):
|
|
132
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
133
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/3")
|
|
134
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", "2")
|
|
135
|
+
|
|
136
|
+
update_metadata(
|
|
137
|
+
test_file,
|
|
138
|
+
{UnifiedMetadataKey.DISC_NUMBER: 5},
|
|
139
|
+
metadata_format=MetadataFormat.VORBIS,
|
|
140
|
+
)
|
|
141
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
142
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
143
|
+
assert disc_number == 5
|
|
144
|
+
assert disc_total == 2
|
|
145
|
+
|
|
146
|
+
@pytest.mark.parametrize(
|
|
147
|
+
"invalid_total",
|
|
148
|
+
["bogus", "-1"],
|
|
149
|
+
)
|
|
150
|
+
def test_vorbis_update_disc_number_ignores_invalid_explicit_total_and_preserves_embedded(self, invalid_total):
|
|
151
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
152
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCNUMBER", "1/2")
|
|
153
|
+
VorbisMetadataSetter.set_tag(test_file, "DISCTOTAL", invalid_total)
|
|
154
|
+
|
|
155
|
+
update_metadata(
|
|
156
|
+
test_file,
|
|
157
|
+
{UnifiedMetadataKey.DISC_NUMBER: 5},
|
|
158
|
+
metadata_format=MetadataFormat.VORBIS,
|
|
159
|
+
)
|
|
160
|
+
disc_number = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_NUMBER)
|
|
161
|
+
disc_total = get_unified_metadata_field(test_file, UnifiedMetadataKey.DISC_TOTAL)
|
|
162
|
+
assert disc_number == 5
|
|
163
|
+
assert disc_total == 2
|
|
164
|
+
|
|
83
165
|
def test_id3v2_disc_number_max_value_truncated(self):
|
|
84
166
|
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
85
167
|
update_metadata(
|