audiometa-python 0.6.0__py3-none-any.whl
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/__init__.py +1297 -0
- audiometa/__main__.py +6 -0
- audiometa/_audio_file.py +607 -0
- audiometa/cli.py +476 -0
- audiometa/exceptions.py +167 -0
- audiometa/manager/_MetadataManager.py +768 -0
- audiometa/manager/__init__.py +1 -0
- audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +250 -0
- audiometa/manager/_rating_supporting/__init__.py +1 -0
- audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +1032 -0
- audiometa/manager/_rating_supporting/id3v2/__init__.py +25 -0
- audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +11 -0
- audiometa/manager/_rating_supporting/riff/_RiffManager.py +1002 -0
- audiometa/manager/_rating_supporting/riff/__init__.py +25 -0
- audiometa/manager/_rating_supporting/riff/_riff_constants.py +17 -0
- audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +542 -0
- audiometa/manager/_rating_supporting/vorbis/__init__.py +17 -0
- audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +6 -0
- audiometa/manager/id3v1/_Id3v1Manager.py +512 -0
- audiometa/manager/id3v1/__init__.py +1 -0
- audiometa/manager/id3v1/_constants.py +8 -0
- audiometa/manager/id3v1/id3v1_raw_metadata.py +242 -0
- audiometa/manager/id3v1/id3v1_raw_metadata_key.py +13 -0
- audiometa/test/__init__.py +1 -0
- audiometa/test/assets/create_test_files.py +72 -0
- audiometa/test/helpers/__init__.py +51 -0
- audiometa/test/helpers/common/__init__.py +6 -0
- audiometa/test/helpers/common/audio_file_creator.py +68 -0
- audiometa/test/helpers/common/external_tool_runner.py +74 -0
- audiometa/test/helpers/id3v1/__init__.py +8 -0
- audiometa/test/helpers/id3v1/id3v1_header_verifier.py +18 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +37 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +61 -0
- audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +82 -0
- audiometa/test/helpers/id3v2/__init__.py +28 -0
- audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +349 -0
- audiometa/test/helpers/id3v2/id3v2_header_verifier.py +38 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +56 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +189 -0
- audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +506 -0
- audiometa/test/helpers/riff/__init__.py +8 -0
- audiometa/test/helpers/riff/riff_header_verifier.py +85 -0
- audiometa/test/helpers/riff/riff_manual_metadata_creator.py +298 -0
- audiometa/test/helpers/riff/riff_metadata_deleter.py +56 -0
- audiometa/test/helpers/riff/riff_metadata_getter.py +219 -0
- audiometa/test/helpers/riff/riff_metadata_setter.py +374 -0
- audiometa/test/helpers/scripts/__init__.py +0 -0
- audiometa/test/helpers/technical_info_inspector.py +115 -0
- audiometa/test/helpers/temp_file_with_metadata.py +82 -0
- audiometa/test/helpers/vorbis/__init__.py +8 -0
- audiometa/test/helpers/vorbis/vorbis_header_verifier.py +31 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +49 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +67 -0
- audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +221 -0
- audiometa/test/tests/__init__.py +0 -0
- audiometa/test/tests/conftest.py +276 -0
- audiometa/test/tests/e2e/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/error_handling/__init__.py +1 -0
- audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +77 -0
- audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +130 -0
- audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +118 -0
- audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +172 -0
- audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +49 -0
- audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +160 -0
- audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +90 -0
- audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +51 -0
- audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/read/test_basic.py +58 -0
- audiometa/test/tests/e2e/cli/read/test_comprehensive.py +240 -0
- audiometa/test/tests/e2e/cli/read/test_formats.py +55 -0
- audiometa/test/tests/e2e/cli/read/test_metadata_content.py +164 -0
- audiometa/test/tests/e2e/cli/read/test_multiple_files.py +149 -0
- audiometa/test/tests/e2e/cli/read/test_options.py +88 -0
- audiometa/test/tests/e2e/cli/read/test_unified.py +84 -0
- audiometa/test/tests/e2e/cli/test_delete.py +20 -0
- audiometa/test/tests/e2e/cli/test_formatting.py +31 -0
- audiometa/test/tests/e2e/cli/test_help.py +41 -0
- audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- audiometa/test/tests/e2e/cli/write/test_basic.py +51 -0
- audiometa/test/tests/e2e/cli/write/test_comprehensive.py +210 -0
- audiometa/test/tests/e2e/cli/write/test_force_format.py +336 -0
- audiometa/test/tests/e2e/cli/write/test_integer_fields.py +145 -0
- audiometa/test/tests/e2e/cli/write/test_list_fields.py +107 -0
- audiometa/test/tests/e2e/cli/write/test_rating.py +74 -0
- audiometa/test/tests/e2e/cli/write/test_string_fields.py +54 -0
- audiometa/test/tests/e2e/cli/write/test_validation.py +85 -0
- audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +166 -0
- audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- audiometa/test/tests/e2e/workflows/test_core_workflows.py +166 -0
- audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +318 -0
- audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +165 -0
- audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +129 -0
- audiometa/test/tests/e2e/workflows/test_rating_workflows.py +124 -0
- audiometa/test/tests/integration/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +108 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +61 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +65 -0
- audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +69 -0
- audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +79 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +61 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +67 -0
- audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +60 -0
- audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +87 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +62 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +57 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_with_id3v2_tags.py +83 -0
- audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +62 -0
- audiometa/test/tests/integration/conftest.py +29 -0
- audiometa/test/tests/integration/delete_all_metadata/__init__.py +1 -0
- audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +102 -0
- audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +77 -0
- audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +47 -0
- audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +24 -0
- audiometa/test/tests/integration/encoding/__init__.py +1 -0
- audiometa/test/tests/integration/encoding/test_encoding.py +88 -0
- audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +223 -0
- audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
- audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +250 -0
- audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
- audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
- audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
- audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
- audiometa/test/tests/integration/get_full_metadata/test_options.py +207 -0
- audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
- audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
- audiometa/test/tests/integration/get_full_metadata/test_structure.py +161 -0
- audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album/test_deleting.py +73 -0
- audiometa/test/tests/integration/metadata_field/album/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/album/test_writing.py +50 -0
- audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +83 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +38 -0
- audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +52 -0
- audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +68 -0
- audiometa/test/tests/integration/metadata_field/artists/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/artists/test_writing.py +46 -0
- audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +32 -0
- audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +56 -0
- audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +68 -0
- audiometa/test/tests/integration/metadata_field/comment/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/comment/test_writing.py +49 -0
- audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/composer/test_reading.py +34 -0
- audiometa/test/tests/integration/metadata_field/composer/test_writing.py +41 -0
- audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +81 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +35 -0
- audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +41 -0
- audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +97 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +92 -0
- audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +153 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +56 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +54 -0
- audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +61 -0
- audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +65 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +25 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +58 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +61 -0
- audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +191 -0
- audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +62 -0
- audiometa/test/tests/integration/metadata_field/genre/test_writing.py +64 -0
- audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
- audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
- audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/language/test_deleting.py +75 -0
- audiometa/test/tests/integration/metadata_field/language/test_reading.py +39 -0
- audiometa/test/tests/integration/metadata_field/language/test_writing.py +43 -0
- audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +129 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +57 -0
- audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +59 -0
- audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +88 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +32 -0
- audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +47 -0
- audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +81 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +33 -0
- audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +58 -0
- audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +117 -0
- audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +137 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +77 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +55 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +57 -0
- audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +192 -0
- audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +74 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +82 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +59 -0
- audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +49 -0
- audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +135 -0
- audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/title/test_deleting.py +73 -0
- audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +47 -0
- audiometa/test/tests/integration/metadata_field/title/test_reading.py +36 -0
- audiometa/test/tests/integration/metadata_field/title/test_writing.py +64 -0
- audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +43 -0
- audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +32 -0
- audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +59 -0
- audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +73 -0
- audiometa/test/tests/integration/multiple_values/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +23 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +92 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +216 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +84 -0
- audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +169 -0
- audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +209 -0
- audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +198 -0
- audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +24 -0
- audiometa/test/tests/integration/multiple_values/writing/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +1 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +62 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +36 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +34 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +32 -0
- audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +54 -0
- audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +42 -0
- audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +98 -0
- audiometa/test/tests/integration/reading/__init__.py +1 -0
- audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +80 -0
- audiometa/test/tests/integration/reading/test_reading_error_handling.py +36 -0
- audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- audiometa/test/tests/integration/real_audio_files/test_reading.py +146 -0
- audiometa/test/tests/integration/real_audio_files/test_writing.py +198 -0
- audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +103 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/__init__.py +0 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_audio_data_corruption.py +21 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_flipped_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_non_flac_error.py +13 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_partial_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_random_md5.py +29 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_unset_md5.py +56 -0
- audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +21 -0
- audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
- audiometa/test/tests/integration/technical_info/test_channels.py +38 -0
- audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +38 -0
- audiometa/test/tests/integration/technical_info/test_sample_rate.py +40 -0
- audiometa/test/tests/integration/test_audio_file.py +35 -0
- audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +95 -0
- audiometa/test/tests/integration/writing/__init__.py +0 -0
- audiometa/test/tests/integration/writing/test_error_handling.py +44 -0
- audiometa/test/tests/integration/writing/test_forced_format.py +224 -0
- audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +223 -0
- audiometa/test/tests/integration/writing/test_partial_update.py +36 -0
- audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +79 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +76 -0
- audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +215 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +42 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +93 -0
- audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +99 -0
- audiometa/test/tests/unit/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +26 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +31 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +38 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +190 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +51 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +28 -0
- audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +31 -0
- audiometa/test/tests/unit/audio_file/test_context_manager.py +30 -0
- audiometa/test/tests/unit/audio_file/test_file_validation.py +40 -0
- audiometa/test/tests/unit/audio_file/test_is_audio_file.py +49 -0
- audiometa/test/tests/unit/audio_file/test_operations.py +20 -0
- audiometa/test/tests/unit/audio_file/test_path_handling.py +23 -0
- audiometa/test/tests/unit/cli/__init__.py +0 -0
- audiometa/test/tests/unit/cli/test_expand_file_patterns.py +234 -0
- audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/conftest.py +142 -0
- audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +49 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +66 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
- audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +53 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +186 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +142 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +76 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +152 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +23 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +77 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +43 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +151 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +61 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_date_format_validation.py +135 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_disc_number_validation.py +75 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_track_number_validation.py +46 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +22 -0
- audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +83 -0
- audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +74 -0
- audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +26 -0
- audiometa/utils/__init__.py +1 -0
- audiometa/utils/id3v1_genre_code_map.py +205 -0
- audiometa/utils/metadata_format.py +31 -0
- audiometa/utils/metadata_writing_strategy.py +16 -0
- audiometa/utils/mutagen_exception_handler.py +24 -0
- audiometa/utils/os_dependencies_checker/__init__.py +24 -0
- audiometa/utils/os_dependencies_checker/base.py +62 -0
- audiometa/utils/os_dependencies_checker/config.py +77 -0
- audiometa/utils/os_dependencies_checker/macos.py +236 -0
- audiometa/utils/os_dependencies_checker/ubuntu.py +95 -0
- audiometa/utils/os_dependencies_checker/windows.py +227 -0
- audiometa/utils/rating_profiles.py +110 -0
- audiometa/utils/tool_path_resolver.py +135 -0
- audiometa/utils/types.py +82 -0
- audiometa/utils/unified_metadata_key.py +87 -0
- audiometa_python-0.6.0.dist-info/METADATA +1593 -0
- audiometa_python-0.6.0.dist-info/RECORD +352 -0
- audiometa_python-0.6.0.dist-info/WHEEL +5 -0
- audiometa_python-0.6.0.dist-info/entry_points.txt +2 -0
- audiometa_python-0.6.0.dist-info/licenses/LICENSE +202 -0
- audiometa_python-0.6.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""Tests for forced format parameter functionality.
|
|
2
|
+
|
|
3
|
+
This module tests the behavior when a specific metadata format is forced using the metadata_format parameter in
|
|
4
|
+
update_metadata.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
10
|
+
from audiometa.exceptions import (
|
|
11
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
12
|
+
MetadataFormatNotSupportedByAudioFormatError,
|
|
13
|
+
MetadataWritingConflictParametersError,
|
|
14
|
+
)
|
|
15
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
16
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
17
|
+
from audiometa.utils.metadata_writing_strategy import MetadataWritingStrategy
|
|
18
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.integration
|
|
22
|
+
class TestForcedFormat:
|
|
23
|
+
def test_forced_format_writes_only_to_specified_format(self):
|
|
24
|
+
# Create WAV file with initial RIFF metadata
|
|
25
|
+
initial_metadata = {"title": "Original RIFF Title", "artist": "Original RIFF Artist"}
|
|
26
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
27
|
+
# Add ID3v2 metadata using the library directly
|
|
28
|
+
id3v2_metadata = {
|
|
29
|
+
UnifiedMetadataKey.TITLE: "Original ID3v2 Title",
|
|
30
|
+
UnifiedMetadataKey.ARTISTS: ["Original ID3v2 Artist"],
|
|
31
|
+
}
|
|
32
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
33
|
+
|
|
34
|
+
# Verify both formats have their respective metadata
|
|
35
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
36
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
37
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) == "Original RIFF Title"
|
|
38
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "Original ID3v2 Title"
|
|
39
|
+
|
|
40
|
+
# Force ID3v2 format (should write only to ID3v2, leave RIFF untouched)
|
|
41
|
+
new_metadata = {
|
|
42
|
+
UnifiedMetadataKey.TITLE: "New ID3v2 Title",
|
|
43
|
+
UnifiedMetadataKey.ARTISTS: ["New ID3v2 Artist"],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# This should write only to ID3v2 format, leaving RIFF unchanged
|
|
47
|
+
update_metadata(test_file, new_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
48
|
+
|
|
49
|
+
# Verify ID3v2 has new metadata
|
|
50
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
51
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "New ID3v2 Title"
|
|
52
|
+
assert id3v2_after.get(UnifiedMetadataKey.ARTISTS) == ["New ID3v2 Artist"]
|
|
53
|
+
|
|
54
|
+
# Verify RIFF still has original metadata (forced format doesn't affect other formats)
|
|
55
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
56
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "Original RIFF Title"
|
|
57
|
+
assert riff_after.get(UnifiedMetadataKey.ARTISTS) == ["Original RIFF Artist"]
|
|
58
|
+
|
|
59
|
+
def test_forced_format_fails_fast_on_unsupported_fields(self):
|
|
60
|
+
# Create WAV file with basic metadata
|
|
61
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
62
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
63
|
+
# Try to write ARCHIVAL_LOCATION to RIFF format (not supported)
|
|
64
|
+
unsupported_metadata = {
|
|
65
|
+
UnifiedMetadataKey.TITLE: "Test Title",
|
|
66
|
+
UnifiedMetadataKey.ARCHIVAL_LOCATION: "some location", # ARCHIVAL_LOCATION not supported by RIFF format
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# This should raise MetadataFieldNotSupportedByMetadataFormatError because format is forced
|
|
70
|
+
with pytest.raises(
|
|
71
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
72
|
+
match="UnifiedMetadataKey.ARCHIVAL_LOCATION metadata not supported by RIFF format",
|
|
73
|
+
):
|
|
74
|
+
update_metadata(test_file, unsupported_metadata, metadata_format=MetadataFormat.RIFF)
|
|
75
|
+
|
|
76
|
+
def test_forced_format_succeeds_with_supported_fields(self):
|
|
77
|
+
# Create WAV file with basic metadata
|
|
78
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
79
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
80
|
+
# Write supported fields to RIFF format
|
|
81
|
+
supported_metadata = {
|
|
82
|
+
UnifiedMetadataKey.TITLE: "New RIFF Title",
|
|
83
|
+
UnifiedMetadataKey.ARTISTS: ["New RIFF Artist"],
|
|
84
|
+
UnifiedMetadataKey.ALBUM: "New RIFF Album",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# This should succeed because all fields are supported by RIFF
|
|
88
|
+
update_metadata(test_file, supported_metadata, metadata_format=MetadataFormat.RIFF)
|
|
89
|
+
|
|
90
|
+
# Verify RIFF has new metadata
|
|
91
|
+
riff_metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
92
|
+
assert riff_metadata.get(UnifiedMetadataKey.TITLE) == "New RIFF Title"
|
|
93
|
+
assert riff_metadata.get(UnifiedMetadataKey.ARTISTS) == ["New RIFF Artist"]
|
|
94
|
+
assert riff_metadata.get(UnifiedMetadataKey.ALBUM) == "New RIFF Album"
|
|
95
|
+
|
|
96
|
+
def test_forced_format_parameter_conflict_error(self):
|
|
97
|
+
# Create WAV file with basic metadata
|
|
98
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
99
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
100
|
+
metadata = {UnifiedMetadataKey.TITLE: "Test Title", UnifiedMetadataKey.ARTISTS: ["Test Artist"]}
|
|
101
|
+
|
|
102
|
+
# This should raise error because both parameters are specified
|
|
103
|
+
with pytest.raises(
|
|
104
|
+
MetadataWritingConflictParametersError,
|
|
105
|
+
match="Cannot specify both metadata_strategy and metadata_format",
|
|
106
|
+
):
|
|
107
|
+
update_metadata(
|
|
108
|
+
test_file,
|
|
109
|
+
metadata,
|
|
110
|
+
metadata_format=MetadataFormat.RIFF,
|
|
111
|
+
metadata_strategy=MetadataWritingStrategy.SYNC,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def test_forced_format_with_unsupported_file_type(self):
|
|
115
|
+
# Create MP3 file
|
|
116
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
117
|
+
with temp_file_with_metadata(initial_metadata, "mp3") as test_file:
|
|
118
|
+
metadata = {UnifiedMetadataKey.TITLE: "Test Title", UnifiedMetadataKey.ARTISTS: ["Test Artist"]}
|
|
119
|
+
|
|
120
|
+
# Try to force Vorbis format on MP3 file (not supported)
|
|
121
|
+
with pytest.raises(
|
|
122
|
+
MetadataFormatNotSupportedByAudioFormatError,
|
|
123
|
+
match="Tag format MetadataFormat.VORBIS not supported for file extension .mp3",
|
|
124
|
+
):
|
|
125
|
+
update_metadata(test_file, metadata, metadata_format=MetadataFormat.VORBIS)
|
|
126
|
+
|
|
127
|
+
def test_forced_format_id3v1_writing_support(self):
|
|
128
|
+
# Create MP3 file with basic metadata
|
|
129
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
130
|
+
with temp_file_with_metadata(initial_metadata, "mp3") as test_file:
|
|
131
|
+
metadata = {UnifiedMetadataKey.TITLE: "New ID3v1 Title", UnifiedMetadataKey.ARTISTS: ["New ID3v1 Artist"]}
|
|
132
|
+
|
|
133
|
+
update_metadata(test_file, metadata, metadata_format=MetadataFormat.ID3V1)
|
|
134
|
+
|
|
135
|
+
# Verify the metadata was written
|
|
136
|
+
from audiometa import get_unified_metadata
|
|
137
|
+
|
|
138
|
+
result = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
139
|
+
assert result.get(UnifiedMetadataKey.TITLE) == "New ID3v1 Title"
|
|
140
|
+
assert result.get(UnifiedMetadataKey.ARTISTS) == ["New ID3v1 Artist"]
|
|
141
|
+
|
|
142
|
+
def test_forced_format_multiple_formats_present(self):
|
|
143
|
+
# Create WAV file with both RIFF and ID3v2 metadata
|
|
144
|
+
initial_metadata = {"title": "Original RIFF Title", "artist": "Original RIFF Artist"}
|
|
145
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
146
|
+
# Add ID3v2 metadata using the library directly
|
|
147
|
+
id3v2_metadata = {
|
|
148
|
+
UnifiedMetadataKey.TITLE: "Original ID3v2 Title",
|
|
149
|
+
UnifiedMetadataKey.ARTISTS: ["Original ID3v2 Artist"],
|
|
150
|
+
}
|
|
151
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
152
|
+
|
|
153
|
+
# Verify both formats have original metadata
|
|
154
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
155
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
156
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) == "Original RIFF Title"
|
|
157
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "Original ID3v2 Title"
|
|
158
|
+
|
|
159
|
+
# Force ID3v2 format - should only update ID3v2
|
|
160
|
+
new_metadata = {
|
|
161
|
+
UnifiedMetadataKey.TITLE: "New ID3v2 Title",
|
|
162
|
+
UnifiedMetadataKey.ARTISTS: ["New ID3v2 Artist"],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
update_metadata(test_file, new_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
166
|
+
|
|
167
|
+
# Verify ID3v2 was updated
|
|
168
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
169
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "New ID3v2 Title"
|
|
170
|
+
assert id3v2_after.get(UnifiedMetadataKey.ARTISTS) == ["New ID3v2 Artist"]
|
|
171
|
+
|
|
172
|
+
# Verify RIFF was NOT updated (forced format only affects specified format)
|
|
173
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
174
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "Original RIFF Title"
|
|
175
|
+
assert riff_after.get(UnifiedMetadataKey.ARTISTS) == ["Original RIFF Artist"]
|
|
176
|
+
|
|
177
|
+
def test_forced_format_with_rating_field(self):
|
|
178
|
+
# Create MP3 file with basic metadata
|
|
179
|
+
initial_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
180
|
+
with temp_file_with_metadata(initial_metadata, "mp3") as test_file:
|
|
181
|
+
# Write rating to ID3v2 format with proper configuration
|
|
182
|
+
metadata_with_rating = {UnifiedMetadataKey.TITLE: "Test Title", UnifiedMetadataKey.RATING: 80}
|
|
183
|
+
|
|
184
|
+
# This should succeed with proper configuration
|
|
185
|
+
update_metadata(
|
|
186
|
+
test_file,
|
|
187
|
+
metadata_with_rating,
|
|
188
|
+
metadata_format=MetadataFormat.ID3V2,
|
|
189
|
+
normalized_rating_max_value=100,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Verify rating was written (converted from 0-100 to 0-255 scale)
|
|
193
|
+
id3v2_metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
194
|
+
assert id3v2_metadata.get(UnifiedMetadataKey.TITLE) == "Test Title"
|
|
195
|
+
# Rating 85 on 0-100 scale becomes 196 on 0-255 scale (85 * 255 / 100 = 216.75, rounded to 196)
|
|
196
|
+
assert id3v2_metadata.get(UnifiedMetadataKey.RATING) == 196
|
|
197
|
+
|
|
198
|
+
# Note: delete_all_metadata tests have been moved to test_delete_all_metadata.py
|
|
199
|
+
|
|
200
|
+
def test_forced_format_validation_before_writing(self):
|
|
201
|
+
# Create WAV file with initial metadata
|
|
202
|
+
initial_metadata = {"title": "Original Title", "artist": "Original Artist"}
|
|
203
|
+
with temp_file_with_metadata(initial_metadata, "wav") as test_file:
|
|
204
|
+
# Try to write mixed supported/unsupported fields to RIFF format
|
|
205
|
+
mixed_metadata = {
|
|
206
|
+
UnifiedMetadataKey.TITLE: "New Title", # Supported
|
|
207
|
+
UnifiedMetadataKey.ARTISTS: ["New Artist"], # Supported
|
|
208
|
+
UnifiedMetadataKey.ARCHIVAL_LOCATION: "some location", # NOT supported by RIFF
|
|
209
|
+
UnifiedMetadataKey.ALBUM: "New Album", # Supported
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# This should fail because ARCHIVAL_LOCATION is not supported by RIFF
|
|
213
|
+
with pytest.raises(
|
|
214
|
+
MetadataFieldNotSupportedByMetadataFormatError,
|
|
215
|
+
match="UnifiedMetadataKey.ARCHIVAL_LOCATION metadata not supported by RIFF format",
|
|
216
|
+
):
|
|
217
|
+
update_metadata(test_file, mixed_metadata, metadata_format=MetadataFormat.RIFF)
|
|
218
|
+
|
|
219
|
+
# Verify NO changes were made to the file (validation happens before writing)
|
|
220
|
+
final_metadata = get_unified_metadata(test_file)
|
|
221
|
+
assert final_metadata.get(UnifiedMetadataKey.TITLE) == "Original Title"
|
|
222
|
+
assert final_metadata.get(UnifiedMetadataKey.ARTISTS) == ["Original Artist"]
|
|
223
|
+
assert final_metadata.get(UnifiedMetadataKey.BPM) is None
|
|
224
|
+
assert final_metadata.get(UnifiedMetadataKey.ALBUM) is None
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""Tests for multiple format preservation when updating metadata.
|
|
2
|
+
|
|
3
|
+
This module tests that updating fields in one format with the PRESERVE strategy does not affect other formats. It covers
|
|
4
|
+
the main working combinations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
10
|
+
from audiometa.test.helpers.id3v1 import ID3v1MetadataSetter
|
|
11
|
+
from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
|
|
12
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
13
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
14
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.integration
|
|
18
|
+
class TestMultipleFormatPreservation:
|
|
19
|
+
def test_id3v1_preserves_id3v2(self):
|
|
20
|
+
with temp_file_with_metadata({"title": "ID3v2 Title", "artist": "ID3v2 Artist"}, "mp3") as test_file:
|
|
21
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title"})
|
|
22
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"artist": "ID3v2 Artist"})
|
|
23
|
+
|
|
24
|
+
# Verify initial state
|
|
25
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
26
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
27
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
28
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) is None
|
|
29
|
+
|
|
30
|
+
# Update ID3v1 with PRESERVE strategy (specify ID3v1 format)
|
|
31
|
+
id3v1_metadata = {UnifiedMetadataKey.TITLE: "ID3v1 Title", UnifiedMetadataKey.ARTISTS: ["ID3v1 Artist"]}
|
|
32
|
+
update_metadata(test_file, id3v1_metadata, metadata_format=MetadataFormat.ID3V1)
|
|
33
|
+
|
|
34
|
+
# Verify ID3v1 was updated and ID3v2 was preserved
|
|
35
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
36
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
37
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
38
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
39
|
+
|
|
40
|
+
def test_id3v2_preserves_id3v1(self):
|
|
41
|
+
with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
|
|
42
|
+
# Verify initial state
|
|
43
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
44
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
45
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
46
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) is None
|
|
47
|
+
|
|
48
|
+
id3v2_metadata = {UnifiedMetadataKey.TITLE: "ID3v2 Title", UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"]}
|
|
49
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
50
|
+
|
|
51
|
+
# Verify ID3v2 was updated and ID3v1 was preserved
|
|
52
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
53
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
54
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
55
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
56
|
+
|
|
57
|
+
def test_riff_preserves_id3v1(self):
|
|
58
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
59
|
+
ID3v1MetadataSetter.set_title(test_file, "ID3v1 Title")
|
|
60
|
+
ID3v1MetadataSetter.set_artist(test_file, "ID3v1 Artist")
|
|
61
|
+
|
|
62
|
+
# Verify initial state
|
|
63
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
64
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
65
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
66
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) is None
|
|
67
|
+
|
|
68
|
+
riff_metadata = {UnifiedMetadataKey.TITLE: "RIFF Title", UnifiedMetadataKey.ARTISTS: ["RIFF Artist"]}
|
|
69
|
+
update_metadata(test_file, riff_metadata, metadata_format=MetadataFormat.RIFF)
|
|
70
|
+
|
|
71
|
+
# Verify RIFF was updated and ID3v1 was preserved
|
|
72
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
73
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
74
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
75
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
76
|
+
|
|
77
|
+
def test_id3v1_preserves_riff(self):
|
|
78
|
+
with temp_file_with_metadata({"title": "RIFF Title", "artist": "RIFF Artist"}, "wav") as test_file:
|
|
79
|
+
# Verify initial state
|
|
80
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
81
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
82
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
83
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) is None
|
|
84
|
+
|
|
85
|
+
# Update ID3v1 with PRESERVE strategy (specify ID3v1 format)
|
|
86
|
+
id3v1_metadata = {UnifiedMetadataKey.TITLE: "ID3v1 Title", UnifiedMetadataKey.ARTISTS: ["ID3v1 Artist"]}
|
|
87
|
+
update_metadata(test_file, id3v1_metadata, metadata_format=MetadataFormat.ID3V1)
|
|
88
|
+
|
|
89
|
+
# Verify ID3v1 was updated and RIFF was preserved
|
|
90
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
91
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
92
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
93
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
94
|
+
|
|
95
|
+
def test_riff_preserves_id3v2(self):
|
|
96
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
97
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title"})
|
|
98
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"artist": "ID3v2 Artist"})
|
|
99
|
+
|
|
100
|
+
# Verify initial state
|
|
101
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
102
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
103
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
104
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) is None
|
|
105
|
+
|
|
106
|
+
# Update RIFF with PRESERVE strategy (specify RIFF format)
|
|
107
|
+
riff_metadata = {UnifiedMetadataKey.TITLE: "RIFF Title", UnifiedMetadataKey.ARTISTS: ["RIFF Artist"]}
|
|
108
|
+
update_metadata(test_file, riff_metadata, metadata_format=MetadataFormat.RIFF)
|
|
109
|
+
|
|
110
|
+
# Verify RIFF was updated and ID3v2 was preserved
|
|
111
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
112
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
113
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
114
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
115
|
+
|
|
116
|
+
def test_id3v2_preserves_riff(self):
|
|
117
|
+
with temp_file_with_metadata({"title": "RIFF Title", "artist": "RIFF Artist"}, "wav") as test_file:
|
|
118
|
+
# Verify initial state
|
|
119
|
+
riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
120
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
121
|
+
assert riff_before.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
122
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) is None
|
|
123
|
+
|
|
124
|
+
# Update ID3v2 with PRESERVE strategy (specify ID3v2 format)
|
|
125
|
+
id3v2_metadata = {UnifiedMetadataKey.TITLE: "ID3v2 Title", UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"]}
|
|
126
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
127
|
+
|
|
128
|
+
# Verify ID3v2 was updated and RIFF was preserved
|
|
129
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
130
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
131
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
132
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
133
|
+
|
|
134
|
+
def test_vorbis_preserves_id3v2(self):
|
|
135
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
136
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title"})
|
|
137
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"artist": "ID3v2 Artist"})
|
|
138
|
+
|
|
139
|
+
# Verify initial state
|
|
140
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
141
|
+
vorbis_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
|
|
142
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
143
|
+
assert vorbis_before.get(UnifiedMetadataKey.TITLE) is None
|
|
144
|
+
|
|
145
|
+
# Update Vorbis with PRESERVE strategy (specify Vorbis format)
|
|
146
|
+
vorbis_metadata = {UnifiedMetadataKey.TITLE: "Vorbis Title", UnifiedMetadataKey.ARTISTS: ["Vorbis Artist"]}
|
|
147
|
+
update_metadata(test_file, vorbis_metadata, metadata_format=MetadataFormat.VORBIS)
|
|
148
|
+
|
|
149
|
+
# Verify Vorbis was updated and ID3v2 was preserved
|
|
150
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
151
|
+
vorbis_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
|
|
152
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
153
|
+
assert vorbis_after.get(UnifiedMetadataKey.TITLE) == "Vorbis Title"
|
|
154
|
+
|
|
155
|
+
def test_id3v2_preserves_vorbis(self):
|
|
156
|
+
with temp_file_with_metadata({"title": "Vorbis Title", "artist": "Vorbis Artist"}, "flac") as test_file:
|
|
157
|
+
# Verify initial state
|
|
158
|
+
vorbis_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
|
|
159
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
160
|
+
assert vorbis_before.get(UnifiedMetadataKey.TITLE) == "Vorbis Title"
|
|
161
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) is None
|
|
162
|
+
|
|
163
|
+
# Update ID3v2 with PRESERVE strategy (specify ID3v2 format)
|
|
164
|
+
id3v2_metadata = {UnifiedMetadataKey.TITLE: "ID3v2 Title", UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"]}
|
|
165
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
166
|
+
|
|
167
|
+
# Verify ID3v2 was updated and Vorbis was preserved
|
|
168
|
+
vorbis_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
|
|
169
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
170
|
+
assert vorbis_after.get(UnifiedMetadataKey.TITLE) == "Vorbis Title"
|
|
171
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
172
|
+
|
|
173
|
+
def test_multiple_fields_preservation(self):
|
|
174
|
+
with temp_file_with_metadata({"title": "Original Title", "artist": "Original Artist"}, "mp3") as test_file:
|
|
175
|
+
ID3v1MetadataSetter.set_title(test_file, "ID3v1 Title")
|
|
176
|
+
ID3v1MetadataSetter.set_artist(test_file, "ID3v1 Artist")
|
|
177
|
+
# Use ID3v2.3 instead of ID3v2.4 to preserve ID3v1 metadata
|
|
178
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title"}, version="2.3")
|
|
179
|
+
ID3v2MetadataSetter.set_metadata(test_file, {"artist": "ID3v2 Artist"}, version="2.3")
|
|
180
|
+
|
|
181
|
+
# Verify initial state
|
|
182
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
183
|
+
id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
184
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
185
|
+
assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
186
|
+
|
|
187
|
+
# Update only ID3v2 with multiple fields
|
|
188
|
+
id3v2_metadata = {
|
|
189
|
+
UnifiedMetadataKey.TITLE: "Updated ID3v2 Title",
|
|
190
|
+
UnifiedMetadataKey.ARTISTS: ["Updated ID3v2 Artist"],
|
|
191
|
+
UnifiedMetadataKey.ALBUM: "ID3v2 Album",
|
|
192
|
+
}
|
|
193
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
194
|
+
|
|
195
|
+
# Verify ID3v2 was updated and ID3v1 was preserved
|
|
196
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
197
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
198
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
199
|
+
assert id3v1_after.get(UnifiedMetadataKey.ARTISTS) == ["ID3v1 Artist"]
|
|
200
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "Updated ID3v2 Title"
|
|
201
|
+
assert id3v2_after.get(UnifiedMetadataKey.ARTISTS) == ["Updated ID3v2 Artist"]
|
|
202
|
+
assert id3v2_after.get(UnifiedMetadataKey.ALBUM) == "ID3v2 Album"
|
|
203
|
+
|
|
204
|
+
def test_preserve_strategy_with_none_values(self):
|
|
205
|
+
with temp_file_with_metadata({"title": "Original Title", "artist": "Original Artist"}, "mp3") as test_file:
|
|
206
|
+
ID3v1MetadataSetter.set_title(test_file, "ID3v1 Title")
|
|
207
|
+
ID3v1MetadataSetter.set_artist(test_file, "ID3v1 Artist")
|
|
208
|
+
|
|
209
|
+
# Verify initial state
|
|
210
|
+
id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
211
|
+
assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
212
|
+
|
|
213
|
+
# Update ID3v2 with None values (should not affect ID3v1)
|
|
214
|
+
id3v2_metadata = {
|
|
215
|
+
UnifiedMetadataKey.TITLE: None, # This should not affect ID3v1
|
|
216
|
+
UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"],
|
|
217
|
+
}
|
|
218
|
+
update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
|
|
219
|
+
|
|
220
|
+
# Verify ID3v1 was preserved
|
|
221
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
222
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
223
|
+
assert id3v1_after.get(UnifiedMetadataKey.ARTISTS) == ["ID3v1 Artist"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Tests for general metadata writing functionality using external scripts.
|
|
2
|
+
|
|
3
|
+
This refactored version uses external scripts to set up test data instead of the app's update functions, preventing
|
|
4
|
+
circular dependencies.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
10
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
11
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.mark.integration
|
|
15
|
+
class TestMetadataWriting:
|
|
16
|
+
# Note: delete_all_metadata tests have been moved to test_delete_all_metadata.py
|
|
17
|
+
|
|
18
|
+
def test_write_metadata_partial_update(self):
|
|
19
|
+
# Use external script to set initial metadata
|
|
20
|
+
initial_metadata = {"title": "Original Title", "artist": "Original Artist", "album": "Original Album"}
|
|
21
|
+
|
|
22
|
+
with temp_file_with_metadata(initial_metadata, "mp3") as test_file:
|
|
23
|
+
# Get original metadata
|
|
24
|
+
original_metadata = get_unified_metadata(test_file)
|
|
25
|
+
original_album = original_metadata.get(UnifiedMetadataKey.ALBUM)
|
|
26
|
+
|
|
27
|
+
# Update only title using app's function (this is what we're testing)
|
|
28
|
+
test_metadata = {UnifiedMetadataKey.TITLE: "Partial Update Title"}
|
|
29
|
+
|
|
30
|
+
update_metadata(test_file, test_metadata)
|
|
31
|
+
updated_metadata = get_unified_metadata(test_file)
|
|
32
|
+
|
|
33
|
+
# Title should be updated
|
|
34
|
+
assert updated_metadata.get(UnifiedMetadataKey.TITLE) == "Partial Update Title"
|
|
35
|
+
# Other fields should remain unchanged
|
|
36
|
+
assert updated_metadata.get(UnifiedMetadataKey.ALBUM) == original_album
|
|
File without changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Tests for CLEANUP metadata writing strategy.
|
|
2
|
+
|
|
3
|
+
This module tests the CLEANUP strategy which writes to native format and removes all non-native metadata formats.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
9
|
+
from audiometa.test.helpers.id3v1.id3v1_metadata_setter import ID3v1MetadataSetter
|
|
10
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
|
|
11
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
12
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
13
|
+
from audiometa.utils.metadata_writing_strategy import MetadataWritingStrategy
|
|
14
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.integration
|
|
18
|
+
class TestCleanupStrategy:
|
|
19
|
+
def test_cleanup_strategy_wav(self):
|
|
20
|
+
with temp_file_with_metadata(
|
|
21
|
+
{"title": "Basic Title", "artist": "Basic Artist", "album": "Basic Album"}, "wav"
|
|
22
|
+
) as test_file:
|
|
23
|
+
ID3v2MetadataSetter.set_metadata(
|
|
24
|
+
test_file,
|
|
25
|
+
{"title": "ID3v2 Title", "artist": "ID3v2 Artist", "album": "ID3v2 Album"},
|
|
26
|
+
version="2.3",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
metadata = {
|
|
30
|
+
UnifiedMetadataKey.TITLE: "RIFF Title",
|
|
31
|
+
UnifiedMetadataKey.ARTISTS: ["RIFF Artist"],
|
|
32
|
+
UnifiedMetadataKey.ALBUM: "RIFF Album",
|
|
33
|
+
}
|
|
34
|
+
update_metadata(test_file, metadata, metadata_strategy=MetadataWritingStrategy.CLEANUP)
|
|
35
|
+
|
|
36
|
+
# Verify ID3v2 was removed
|
|
37
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
38
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
|
|
39
|
+
|
|
40
|
+
# Verify RIFF has new metadata
|
|
41
|
+
riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
|
|
42
|
+
assert riff_after.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
43
|
+
|
|
44
|
+
# Merged metadata should only have RIFF (ID3v2 was cleaned up)
|
|
45
|
+
merged = get_unified_metadata(test_file)
|
|
46
|
+
assert merged.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
47
|
+
|
|
48
|
+
def test_cleanup_strategy_mp3_id3v1_not_preserved(self):
|
|
49
|
+
# Create test file with ID3v1 metadata using external script
|
|
50
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
51
|
+
# Add ID3v1 metadata using temp_file_with_metadata
|
|
52
|
+
ID3v1MetadataSetter.set_metadata(
|
|
53
|
+
test_file, {"title": "ID3v1 Title", "artist": "ID3v1 Artist", "album": "ID3v1 Album"}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Verify ID3v1 metadata was written
|
|
57
|
+
id3v1_result = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
58
|
+
assert id3v1_result.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
59
|
+
|
|
60
|
+
# Now write ID3v2 metadata with CLEANUP strategy
|
|
61
|
+
id3v2_metadata = {
|
|
62
|
+
UnifiedMetadataKey.TITLE: "ID3v2 Title",
|
|
63
|
+
UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"],
|
|
64
|
+
UnifiedMetadataKey.ALBUM: "ID3v2 Album",
|
|
65
|
+
}
|
|
66
|
+
update_metadata(test_file, id3v2_metadata, metadata_strategy=MetadataWritingStrategy.CLEANUP)
|
|
67
|
+
|
|
68
|
+
# Verify ID3v1 metadata behavior with CLEANUP strategy
|
|
69
|
+
# ID3v1 should be removed (cleaned up) with CLEANUP strategy
|
|
70
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
71
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None # ID3v1 was cleaned up
|
|
72
|
+
|
|
73
|
+
# Verify ID3v2 metadata was written
|
|
74
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
75
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
76
|
+
|
|
77
|
+
# Merged metadata should prefer ID3v2 (higher precedence)
|
|
78
|
+
merged = get_unified_metadata(test_file)
|
|
79
|
+
assert merged.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Tests for PRESERVE metadata writing strategy.
|
|
2
|
+
|
|
3
|
+
This module tests the PRESERVE strategy which writes to native format only and preserves existing metadata in other
|
|
4
|
+
formats.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
10
|
+
from audiometa.test.helpers.id3v1.id3v1_metadata_setter import ID3v1MetadataSetter
|
|
11
|
+
from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
|
|
12
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
13
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
14
|
+
from audiometa.utils.metadata_writing_strategy import MetadataWritingStrategy
|
|
15
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.integration
|
|
19
|
+
class TestPreserveStrategy:
|
|
20
|
+
def test_preserve_strategy_wav(self):
|
|
21
|
+
with temp_file_with_metadata(
|
|
22
|
+
{"title": "ID3v2 Title", "artist": "ID3v2 Artist", "album": "ID3v2 Album"}, "wav"
|
|
23
|
+
) as test_file:
|
|
24
|
+
ID3v2MetadataSetter.set_metadata(
|
|
25
|
+
test_file,
|
|
26
|
+
{"title": "ID3v2 Title", "artist": "ID3v2 Artist", "album": "ID3v2 Album"},
|
|
27
|
+
version="2.3",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Verify ID3v2 metadata was written
|
|
31
|
+
id3v2_result = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
32
|
+
assert id3v2_result.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
33
|
+
|
|
34
|
+
# Now write RIFF metadata with PRESERVE strategy (default)
|
|
35
|
+
# This part still uses the app's function since we're testing the strategy
|
|
36
|
+
riff_metadata = {
|
|
37
|
+
UnifiedMetadataKey.TITLE: "RIFF Title",
|
|
38
|
+
UnifiedMetadataKey.ARTISTS: ["RIFF Artist"],
|
|
39
|
+
UnifiedMetadataKey.ALBUM: "RIFF Album",
|
|
40
|
+
}
|
|
41
|
+
update_metadata(test_file, riff_metadata, metadata_strategy=MetadataWritingStrategy.PRESERVE)
|
|
42
|
+
|
|
43
|
+
# Merged metadata should prefer RIFF (WAV native format has higher precedence)
|
|
44
|
+
merged = get_unified_metadata(test_file)
|
|
45
|
+
assert merged.get(UnifiedMetadataKey.TITLE) == "RIFF Title"
|
|
46
|
+
|
|
47
|
+
def test_preserve_strategy_mp3_id3v1_not_preserved(self):
|
|
48
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
49
|
+
ID3v1MetadataSetter.set_metadata(
|
|
50
|
+
test_file, {"title": "ID3v1 Title", "artist": "ID3v1 Artist", "album": "ID3v1 Album"}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Verify ID3v1 metadata was written
|
|
54
|
+
id3v1_result = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
55
|
+
assert id3v1_result.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
|
|
56
|
+
|
|
57
|
+
# Now write ID3v2 metadata with PRESERVE strategy
|
|
58
|
+
metadata = {
|
|
59
|
+
UnifiedMetadataKey.TITLE: "ID3v2 Title",
|
|
60
|
+
UnifiedMetadataKey.ARTISTS: ["ID3v2 Artist"],
|
|
61
|
+
UnifiedMetadataKey.ALBUM: "ID3v2 Album",
|
|
62
|
+
}
|
|
63
|
+
update_metadata(test_file, metadata, metadata_strategy=MetadataWritingStrategy.PRESERVE)
|
|
64
|
+
|
|
65
|
+
# Verify ID3v1 metadata behavior with PRESERVE strategy
|
|
66
|
+
# ID3v1 should be preserved (not overwritten) with PRESERVE strategy
|
|
67
|
+
id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
68
|
+
assert id3v1_after.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title" # ID3v1 was preserved
|
|
69
|
+
|
|
70
|
+
# Verify ID3v2 metadata was written
|
|
71
|
+
id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
72
|
+
assert id3v2_after.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|
|
73
|
+
|
|
74
|
+
# Merged metadata should prefer ID3v2 (higher precedence)
|
|
75
|
+
merged = get_unified_metadata(test_file)
|
|
76
|
+
assert merged.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
|