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,47 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import delete_all_metadata
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.integration
|
|
8
|
+
class TestDeleteAllMetadataBasic:
|
|
9
|
+
def test_delete_all_metadata_file_with_no_metadata(self):
|
|
10
|
+
with temp_file_with_metadata({}, "mp3") as test_file:
|
|
11
|
+
# Delete metadata from file that has no metadata
|
|
12
|
+
result = delete_all_metadata(test_file)
|
|
13
|
+
assert result is True
|
|
14
|
+
|
|
15
|
+
def test_delete_all_metadata_id3v2_version_specific(self):
|
|
16
|
+
# First add some metadata using external script
|
|
17
|
+
test_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
18
|
+
with temp_file_with_metadata(test_metadata, "mp3") as test_file:
|
|
19
|
+
# Delete metadata with specific ID3v2 version
|
|
20
|
+
result = delete_all_metadata(test_file, id3v2_version=(2, 3, 0))
|
|
21
|
+
assert result is True
|
|
22
|
+
|
|
23
|
+
def test_delete_all_metadata_return_value_success(self):
|
|
24
|
+
# First add some metadata using external script
|
|
25
|
+
test_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
26
|
+
with temp_file_with_metadata(test_metadata, "mp3") as test_file:
|
|
27
|
+
result = delete_all_metadata(test_file)
|
|
28
|
+
assert result is True
|
|
29
|
+
assert isinstance(result, bool)
|
|
30
|
+
|
|
31
|
+
def test_delete_all_metadata_preserves_audio_data(self):
|
|
32
|
+
# First add some metadata using external script
|
|
33
|
+
test_metadata = {"title": "Test Title", "artist": "Test Artist"}
|
|
34
|
+
with temp_file_with_metadata(test_metadata, "mp3") as test_file:
|
|
35
|
+
# Get file size with metadata
|
|
36
|
+
with_metadata_size = test_file.stat().st_size
|
|
37
|
+
|
|
38
|
+
# Delete all metadata
|
|
39
|
+
result = delete_all_metadata(test_file)
|
|
40
|
+
assert result is True
|
|
41
|
+
|
|
42
|
+
# Verify file size decreased (metadata headers removed)
|
|
43
|
+
after_deletion_size = test_file.stat().st_size
|
|
44
|
+
assert after_deletion_size < with_metadata_size
|
|
45
|
+
|
|
46
|
+
# Verify the file is still valid (not corrupted)
|
|
47
|
+
assert after_deletion_size > 0
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import delete_all_metadata
|
|
4
|
+
from audiometa.exceptions import FileTypeNotSupportedError
|
|
5
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.mark.integration
|
|
9
|
+
class TestDeleteAllMetadataErrorHandling:
|
|
10
|
+
def test_delete_all_metadata_unsupported_file_type(self):
|
|
11
|
+
# Create a file with unsupported extension
|
|
12
|
+
with temp_file_with_metadata({}, "mp3") as temp_audio_file_path:
|
|
13
|
+
temp_audio_file_path.write_bytes(b"fake audio content")
|
|
14
|
+
txt_file_path = temp_audio_file_path.with_suffix(".txt")
|
|
15
|
+
txt_file_path.write_bytes(b"fake audio content")
|
|
16
|
+
|
|
17
|
+
with pytest.raises(FileTypeNotSupportedError):
|
|
18
|
+
delete_all_metadata(str(txt_file_path))
|
|
19
|
+
|
|
20
|
+
def test_delete_all_metadata_nonexistent_file(self):
|
|
21
|
+
nonexistent_file = "nonexistent_file.mp3"
|
|
22
|
+
|
|
23
|
+
with pytest.raises(FileNotFoundError):
|
|
24
|
+
delete_all_metadata(nonexistent_file)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Integration tests for reading metadata."""
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from audiometa import get_unified_metadata, update_metadata
|
|
4
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
5
|
+
from audiometa.utils.metadata_format import MetadataFormat
|
|
6
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.integration
|
|
10
|
+
class TestEncoding:
|
|
11
|
+
def test_id3v2_3_encoding_support(self):
|
|
12
|
+
with temp_file_with_metadata({}, "id3v2.3") as test_file:
|
|
13
|
+
metadata_dict = {
|
|
14
|
+
UnifiedMetadataKey.TITLE: "Test Title with ASCII",
|
|
15
|
+
UnifiedMetadataKey.ARTISTS: ["Artist Name"],
|
|
16
|
+
UnifiedMetadataKey.ALBUM: "Album Name",
|
|
17
|
+
}
|
|
18
|
+
update_metadata(test_file, metadata_dict, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0))
|
|
19
|
+
|
|
20
|
+
metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
|
|
21
|
+
assert metadata.get(UnifiedMetadataKey.TITLE) == "Test Title with ASCII"
|
|
22
|
+
assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Artist Name"]
|
|
23
|
+
assert metadata.get(UnifiedMetadataKey.ALBUM) == "Album Name"
|
|
24
|
+
|
|
25
|
+
def test_id3v2_4_utf8_encoding_support(self):
|
|
26
|
+
with temp_file_with_metadata({}, "id3v2.4") as test_file:
|
|
27
|
+
# Test with Unicode characters that require UTF-8
|
|
28
|
+
unicode_metadata = {
|
|
29
|
+
UnifiedMetadataKey.TITLE: "Test 中文 العربية русский 🎵",
|
|
30
|
+
UnifiedMetadataKey.ARTISTS: ["Artist 日本語 한국어"],
|
|
31
|
+
UnifiedMetadataKey.ALBUM: "Album Ελληνικά ภาษาไทย",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
update_metadata(test_file, unicode_metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0))
|
|
35
|
+
|
|
36
|
+
# Verify the Unicode characters are preserved
|
|
37
|
+
metadata = get_unified_metadata(test_file)
|
|
38
|
+
assert metadata.get(UnifiedMetadataKey.TITLE) == "Test 中文 العربية русский 🎵"
|
|
39
|
+
assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Artist 日本語 한국어"]
|
|
40
|
+
assert metadata.get(UnifiedMetadataKey.ALBUM) == "Album Ελληνικά ภาษาไทย"
|
|
41
|
+
|
|
42
|
+
def test_id3v1_encoding_support(self):
|
|
43
|
+
with temp_file_with_metadata({}, "id3v1") as test_file:
|
|
44
|
+
metadata_dict = {
|
|
45
|
+
UnifiedMetadataKey.TITLE: "Test Title with ASCII",
|
|
46
|
+
UnifiedMetadataKey.ARTISTS: ["Artist Name"],
|
|
47
|
+
UnifiedMetadataKey.ALBUM: "Album Name",
|
|
48
|
+
}
|
|
49
|
+
update_metadata(test_file, metadata_dict, metadata_format=MetadataFormat.ID3V1)
|
|
50
|
+
|
|
51
|
+
metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
|
|
52
|
+
assert metadata.get(UnifiedMetadataKey.TITLE) == "Test Title with ASCII"
|
|
53
|
+
assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Artist Name"]
|
|
54
|
+
assert metadata.get(UnifiedMetadataKey.ALBUM) == "Album Name"
|
|
55
|
+
|
|
56
|
+
def test_riff_utf8_encoding_support(self):
|
|
57
|
+
with temp_file_with_metadata({}, "wav") as test_file:
|
|
58
|
+
# Test with Unicode characters that require UTF-8
|
|
59
|
+
unicode_metadata = {
|
|
60
|
+
UnifiedMetadataKey.TITLE: "Test 中文 العربية русский 🎵",
|
|
61
|
+
UnifiedMetadataKey.ARTISTS: ["Artist 日本語 한국어"],
|
|
62
|
+
UnifiedMetadataKey.ALBUM: "Album Ελληνικά ภาษาไทย",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
update_metadata(test_file, unicode_metadata, metadata_format=MetadataFormat.RIFF)
|
|
66
|
+
|
|
67
|
+
# Verify the Unicode characters are preserved
|
|
68
|
+
metadata = get_unified_metadata(test_file)
|
|
69
|
+
assert metadata.get(UnifiedMetadataKey.TITLE) == "Test 中文 العربية русский 🎵"
|
|
70
|
+
assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Artist 日本語 한국어"]
|
|
71
|
+
assert metadata.get(UnifiedMetadataKey.ALBUM) == "Album Ελληνικά ภาษาไทย"
|
|
72
|
+
|
|
73
|
+
def test_vorbis_utf8_encoding_support(self):
|
|
74
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
75
|
+
# Test with Unicode characters that require UTF-8
|
|
76
|
+
unicode_metadata = {
|
|
77
|
+
UnifiedMetadataKey.TITLE: "Test 中文 العربية русский 🎵",
|
|
78
|
+
UnifiedMetadataKey.ARTISTS: ["Artist 日本語 한국어"],
|
|
79
|
+
UnifiedMetadataKey.ALBUM: "Album Ελληνικά ภาษาไทย",
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
update_metadata(test_file, unicode_metadata, metadata_format=MetadataFormat.VORBIS)
|
|
83
|
+
|
|
84
|
+
# Verify the Unicode characters are preserved
|
|
85
|
+
metadata = get_unified_metadata(test_file)
|
|
86
|
+
assert metadata.get(UnifiedMetadataKey.TITLE) == "Test 中文 العربية русский 🎵"
|
|
87
|
+
assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Artist 日本語 한국어"]
|
|
88
|
+
assert metadata.get(UnifiedMetadataKey.ALBUM) == "Album Ελληνικά ภาษาไทย"
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa import get_unified_metadata
|
|
6
|
+
from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
|
|
7
|
+
from audiometa.test.helpers.vorbis import VorbisMetadataSetter
|
|
8
|
+
from audiometa.test.helpers.vorbis.vorbis_metadata_getter import VorbisMetadataGetter
|
|
9
|
+
from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.mark.integration
|
|
13
|
+
class TestSpecialCharactersEdgeCases:
|
|
14
|
+
def test_read_unicode_characters(self):
|
|
15
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
16
|
+
VorbisMetadataSetter.set_artists(test_file, ["François", "José", "Müller", "北京"])
|
|
17
|
+
VorbisMetadataSetter.add_title(test_file, "Café Music 音乐")
|
|
18
|
+
metadata_title = VorbisMetadataGetter.get_title(test_file)
|
|
19
|
+
assert metadata_title == "Café Music 音乐"
|
|
20
|
+
|
|
21
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
22
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
23
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
24
|
+
|
|
25
|
+
assert isinstance(artists, list)
|
|
26
|
+
assert len(artists) == 4
|
|
27
|
+
assert "François" in artists
|
|
28
|
+
assert "José" in artists
|
|
29
|
+
assert "Müller" in artists
|
|
30
|
+
assert "北京" in artists
|
|
31
|
+
|
|
32
|
+
assert isinstance(title, str)
|
|
33
|
+
assert title == "Café Music 音乐"
|
|
34
|
+
|
|
35
|
+
def test_read_special_punctuation(self):
|
|
36
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
37
|
+
VorbisMetadataSetter.set_artists(test_file, ["Artist & Co.", "Band (feat. Singer)", "Group - The Band"])
|
|
38
|
+
VorbisMetadataSetter.add_title(test_file, "Song (Remix) - Special Edition")
|
|
39
|
+
|
|
40
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
41
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
42
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
43
|
+
|
|
44
|
+
assert isinstance(artists, list)
|
|
45
|
+
assert len(artists) == 3
|
|
46
|
+
assert "Artist & Co." in artists
|
|
47
|
+
assert "Band (feat. Singer)" in artists
|
|
48
|
+
assert "Group - The Band" in artists
|
|
49
|
+
|
|
50
|
+
assert isinstance(title, str)
|
|
51
|
+
assert title == "Song (Remix) - Special Edition"
|
|
52
|
+
|
|
53
|
+
def test_read_quotes_and_apostrophes(self):
|
|
54
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
55
|
+
VorbisMetadataSetter.set_artists(test_file, ["Artist's Band", 'The "Quoted" Band', "It's a Band"])
|
|
56
|
+
VorbisMetadataSetter.add_title(test_file, 'Don\'t Stop "Believing"')
|
|
57
|
+
|
|
58
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
59
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
60
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
61
|
+
|
|
62
|
+
assert isinstance(artists, list)
|
|
63
|
+
assert len(artists) == 3
|
|
64
|
+
assert "Artist's Band" in artists
|
|
65
|
+
assert 'The "Quoted" Band' in artists
|
|
66
|
+
assert "It's a Band" in artists
|
|
67
|
+
|
|
68
|
+
assert isinstance(title, str)
|
|
69
|
+
assert title == 'Don\'t Stop "Believing"'
|
|
70
|
+
|
|
71
|
+
def test_read_control_characters(self):
|
|
72
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
73
|
+
VorbisMetadataSetter.set_artists(
|
|
74
|
+
test_file, ["Artist\twith\ttabs", "Band\nwith\nnewlines", "Group\rwith\rcarriage"]
|
|
75
|
+
)
|
|
76
|
+
VorbisMetadataSetter.add_title(test_file, "Song\twith\ttabs")
|
|
77
|
+
|
|
78
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
79
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
80
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
81
|
+
|
|
82
|
+
assert isinstance(artists, list)
|
|
83
|
+
assert len(artists) == 3
|
|
84
|
+
assert "Artist\twith\ttabs" in artists
|
|
85
|
+
assert "Band\nwith\nnewlines" in artists
|
|
86
|
+
assert "Group\rwith\rcarriage" in artists
|
|
87
|
+
|
|
88
|
+
assert isinstance(title, str)
|
|
89
|
+
assert title == "Song\twith\ttabs"
|
|
90
|
+
|
|
91
|
+
def test_read_very_long_strings(self):
|
|
92
|
+
long_string = "A" * 1000
|
|
93
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
94
|
+
VorbisMetadataSetter.set_artists(test_file, [long_string, "Short Artist"])
|
|
95
|
+
VorbisMetadataSetter.add_title(test_file, "B" * 500)
|
|
96
|
+
|
|
97
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
98
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
99
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
100
|
+
|
|
101
|
+
assert isinstance(artists, list)
|
|
102
|
+
assert len(artists) == 2
|
|
103
|
+
assert long_string in artists
|
|
104
|
+
assert "Short Artist" in artists
|
|
105
|
+
|
|
106
|
+
assert isinstance(title, str)
|
|
107
|
+
assert title == "B" * 500
|
|
108
|
+
|
|
109
|
+
def test_read_mixed_encodings(self):
|
|
110
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
111
|
+
VorbisMetadataSetter.set_artists(test_file, ["ASCII Artist", "Français", "Русский", "العربية", "中文"])
|
|
112
|
+
VorbisMetadataSetter.add_title(test_file, "Mixed 编码 Title")
|
|
113
|
+
|
|
114
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
115
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
116
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
117
|
+
|
|
118
|
+
assert isinstance(artists, list)
|
|
119
|
+
assert len(artists) == 5
|
|
120
|
+
assert "ASCII Artist" in artists
|
|
121
|
+
assert "Français" in artists
|
|
122
|
+
assert "Русский" in artists
|
|
123
|
+
assert "العربية" in artists
|
|
124
|
+
assert "中文" in artists
|
|
125
|
+
|
|
126
|
+
assert isinstance(title, str)
|
|
127
|
+
assert title == "Mixed 编码 Title"
|
|
128
|
+
|
|
129
|
+
def test_read_special_separator_characters(self):
|
|
130
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
131
|
+
VorbisMetadataSetter.set_artists(
|
|
132
|
+
test_file, ["Artist; with; semicolons", "Band, with, commas", "Group|with|pipes"]
|
|
133
|
+
)
|
|
134
|
+
VorbisMetadataSetter.add_title(test_file, "Song; with; separators")
|
|
135
|
+
|
|
136
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
137
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
138
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
139
|
+
|
|
140
|
+
assert isinstance(artists, list)
|
|
141
|
+
assert len(artists) == 3
|
|
142
|
+
assert "Artist; with; semicolons" in artists
|
|
143
|
+
assert "Band, with, commas" in artists
|
|
144
|
+
assert "Group|with|pipes" in artists
|
|
145
|
+
|
|
146
|
+
assert isinstance(title, str)
|
|
147
|
+
assert title == "Song; with; separators"
|
|
148
|
+
|
|
149
|
+
def test_read_html_xml_characters(self):
|
|
150
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
151
|
+
VorbisMetadataSetter.set_artists(test_file, ["Artist <tag>", "Band & Co.", "Group <test>"])
|
|
152
|
+
VorbisMetadataSetter.add_title(test_file, "Song & Title")
|
|
153
|
+
|
|
154
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
155
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
156
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
157
|
+
|
|
158
|
+
assert isinstance(artists, list)
|
|
159
|
+
assert len(artists) == 3
|
|
160
|
+
assert "Artist <tag>" in artists
|
|
161
|
+
assert "Band & Co." in artists
|
|
162
|
+
assert "Group <test>" in artists
|
|
163
|
+
|
|
164
|
+
assert isinstance(title, str)
|
|
165
|
+
assert title == "Song & Title"
|
|
166
|
+
|
|
167
|
+
def test_read_emoji_characters(self):
|
|
168
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
169
|
+
VorbisMetadataSetter.set_artists(test_file, ["Artist 🎵", "Band 🎸", "Group 🎤"])
|
|
170
|
+
VorbisMetadataSetter.add_title(test_file, "Song 🎶 with 🎵 emojis")
|
|
171
|
+
|
|
172
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
173
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
174
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
175
|
+
|
|
176
|
+
assert isinstance(artists, list)
|
|
177
|
+
assert len(artists) == 3
|
|
178
|
+
assert "Artist 🎵" in artists
|
|
179
|
+
assert "Band 🎸" in artists
|
|
180
|
+
assert "Group 🎤" in artists
|
|
181
|
+
|
|
182
|
+
assert isinstance(title, str)
|
|
183
|
+
assert title == "Song 🎶 with 🎵 emojis"
|
|
184
|
+
|
|
185
|
+
def test_read_mixed_special_characters(self):
|
|
186
|
+
with temp_file_with_metadata({}, "flac") as test_file:
|
|
187
|
+
VorbisMetadataSetter.set_artists(
|
|
188
|
+
test_file,
|
|
189
|
+
[
|
|
190
|
+
"François & Co. (feat. Müller) 🎵",
|
|
191
|
+
'The "Quoted" Band - Special Characters',
|
|
192
|
+
"Artist with\nnewlines\tand\ttabs",
|
|
193
|
+
],
|
|
194
|
+
)
|
|
195
|
+
VorbisMetadataSetter.add_title(test_file, 'Mixed Special 🎵 Characters & "Quotes"')
|
|
196
|
+
|
|
197
|
+
unified_metadata = get_unified_metadata(test_file)
|
|
198
|
+
artists = unified_metadata.get(UnifiedMetadataKey.ARTISTS)
|
|
199
|
+
title = unified_metadata.get(UnifiedMetadataKey.TITLE)
|
|
200
|
+
|
|
201
|
+
assert isinstance(artists, list)
|
|
202
|
+
assert len(artists) == 3
|
|
203
|
+
assert "François & Co. (feat. Müller) 🎵" in artists
|
|
204
|
+
assert 'The "Quoted" Band - Special Characters' in artists
|
|
205
|
+
assert "Artist with\nnewlines\tand\ttabs" in artists
|
|
206
|
+
|
|
207
|
+
assert isinstance(title, str)
|
|
208
|
+
assert title == 'Mixed Special 🎵 Characters & "Quotes"'
|
|
209
|
+
|
|
210
|
+
def test_read_special_characters_from_existing_file(self, sample_mp3_file: Path):
|
|
211
|
+
# Test reading special characters from a file that already has them
|
|
212
|
+
# This tests the reading functionality without writing first
|
|
213
|
+
unified_metadata = get_unified_metadata(sample_mp3_file)
|
|
214
|
+
|
|
215
|
+
# Should handle any special characters that might be in the sample file
|
|
216
|
+
for _key, value in unified_metadata.items():
|
|
217
|
+
if isinstance(value, str):
|
|
218
|
+
# Should be able to handle unicode and special characters
|
|
219
|
+
assert isinstance(value, str)
|
|
220
|
+
elif isinstance(value, list):
|
|
221
|
+
for item in value:
|
|
222
|
+
if isinstance(item, str):
|
|
223
|
+
assert isinstance(item, str)
|
|
File without changes
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Tests for get_full_metadata function with different audio formats."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from audiometa import get_full_metadata
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.integration
|
|
11
|
+
class TestGetFullMetadataAudioFormats:
|
|
12
|
+
def test_get_full_metadata_mp3_with_metadata(self, sample_mp3_file: Path):
|
|
13
|
+
result = get_full_metadata(sample_mp3_file)
|
|
14
|
+
|
|
15
|
+
# Check structure
|
|
16
|
+
assert "unified_metadata" in result
|
|
17
|
+
assert "technical_info" in result
|
|
18
|
+
assert "metadata_format" in result
|
|
19
|
+
assert "headers" in result
|
|
20
|
+
assert "raw_metadata" in result
|
|
21
|
+
assert "format_priorities" in result
|
|
22
|
+
|
|
23
|
+
# Check format priorities
|
|
24
|
+
assert result["format_priorities"]["file_extension"] == ".mp3"
|
|
25
|
+
assert "id3v2" in result["format_priorities"]["reading_order"]
|
|
26
|
+
assert "id3v1" in result["format_priorities"]["reading_order"]
|
|
27
|
+
assert result["format_priorities"]["writing_format"] == "id3v2"
|
|
28
|
+
|
|
29
|
+
# Check technical info
|
|
30
|
+
tech_info = result["technical_info"]
|
|
31
|
+
assert "duration_seconds" in tech_info
|
|
32
|
+
assert "bitrate_bps" in tech_info
|
|
33
|
+
assert "sample_rate_hz" in tech_info
|
|
34
|
+
assert "channels" in tech_info
|
|
35
|
+
assert "file_size_bytes" in tech_info
|
|
36
|
+
assert "file_extension" in tech_info
|
|
37
|
+
assert "audio_format_name" in tech_info
|
|
38
|
+
assert tech_info["file_extension"] == ".mp3"
|
|
39
|
+
assert tech_info["audio_format_name"] == "MP3"
|
|
40
|
+
assert tech_info["is_flac_md5_valid"] is None # Not a FLAC file
|
|
41
|
+
|
|
42
|
+
# Check format metadata
|
|
43
|
+
assert "id3v2" in result["metadata_format"]
|
|
44
|
+
assert "id3v1" in result["metadata_format"]
|
|
45
|
+
|
|
46
|
+
# Check headers
|
|
47
|
+
assert "id3v2" in result["headers"]
|
|
48
|
+
assert "id3v1" in result["headers"]
|
|
49
|
+
|
|
50
|
+
# Check raw metadata
|
|
51
|
+
assert "id3v2" in result["raw_metadata"]
|
|
52
|
+
assert "id3v1" in result["raw_metadata"]
|
|
53
|
+
|
|
54
|
+
def test_get_full_metadata_flac_with_metadata(self, sample_flac_file: Path):
|
|
55
|
+
result = get_full_metadata(sample_flac_file)
|
|
56
|
+
|
|
57
|
+
# Check format priorities
|
|
58
|
+
assert result["format_priorities"]["file_extension"] == ".flac"
|
|
59
|
+
assert "vorbis" in result["format_priorities"]["reading_order"]
|
|
60
|
+
assert "id3v2" in result["format_priorities"]["reading_order"]
|
|
61
|
+
assert "id3v1" in result["format_priorities"]["reading_order"]
|
|
62
|
+
assert result["format_priorities"]["writing_format"] == "vorbis"
|
|
63
|
+
|
|
64
|
+
# Check technical info
|
|
65
|
+
tech_info = result["technical_info"]
|
|
66
|
+
assert tech_info["file_extension"] == ".flac"
|
|
67
|
+
assert tech_info["audio_format_name"] == "FLAC"
|
|
68
|
+
assert "is_flac_md5_valid" in tech_info # Should be present for FLAC
|
|
69
|
+
|
|
70
|
+
# Check format metadata
|
|
71
|
+
assert "vorbis" in result["metadata_format"]
|
|
72
|
+
assert "id3v2" in result["metadata_format"]
|
|
73
|
+
assert "id3v1" in result["metadata_format"]
|
|
74
|
+
|
|
75
|
+
# Check headers
|
|
76
|
+
assert "vorbis" in result["headers"]
|
|
77
|
+
assert "id3v2" in result["headers"]
|
|
78
|
+
assert "id3v1" in result["headers"]
|
|
79
|
+
|
|
80
|
+
def test_get_full_metadata_wav_with_metadata(self, sample_wav_file: Path):
|
|
81
|
+
result = get_full_metadata(sample_wav_file)
|
|
82
|
+
|
|
83
|
+
# Check format priorities
|
|
84
|
+
assert result["format_priorities"]["file_extension"] == ".wav"
|
|
85
|
+
assert "riff" in result["format_priorities"]["reading_order"]
|
|
86
|
+
assert "id3v2" in result["format_priorities"]["reading_order"]
|
|
87
|
+
assert "id3v1" in result["format_priorities"]["reading_order"]
|
|
88
|
+
assert result["format_priorities"]["writing_format"] == "riff"
|
|
89
|
+
|
|
90
|
+
# Check technical info
|
|
91
|
+
tech_info = result["technical_info"]
|
|
92
|
+
assert tech_info["file_extension"] == ".wav"
|
|
93
|
+
assert tech_info["audio_format_name"] == "WAV"
|
|
94
|
+
assert tech_info["is_flac_md5_valid"] is None # Not a FLAC file
|
|
95
|
+
|
|
96
|
+
# Check format metadata
|
|
97
|
+
assert "riff" in result["metadata_format"]
|
|
98
|
+
assert "id3v2" in result["metadata_format"]
|
|
99
|
+
assert "id3v1" in result["metadata_format"]
|
|
100
|
+
|
|
101
|
+
# Check headers
|
|
102
|
+
assert "riff" in result["headers"]
|
|
103
|
+
assert "id3v2" in result["headers"]
|
|
104
|
+
assert "id3v1" in result["headers"]
|
|
105
|
+
|
|
106
|
+
def test_get_full_metadata_format_specific_metadata_isolation(self, sample_mp3_file: Path):
|
|
107
|
+
result = get_full_metadata(sample_mp3_file)
|
|
108
|
+
|
|
109
|
+
# Each format should have its own metadata section
|
|
110
|
+
metadata_format = result["metadata_format"]
|
|
111
|
+
|
|
112
|
+
# ID3v2 metadata should be separate from ID3v1
|
|
113
|
+
if "id3v2" in metadata_format and "id3v1" in metadata_format:
|
|
114
|
+
id3v2_metadata = metadata_format["id3v2"]
|
|
115
|
+
id3v1_metadata = metadata_format["id3v1"]
|
|
116
|
+
|
|
117
|
+
# They should be separate dictionaries
|
|
118
|
+
assert isinstance(id3v2_metadata, dict)
|
|
119
|
+
assert isinstance(id3v1_metadata, dict)
|
|
120
|
+
|
|
121
|
+
# They might have different content or structure
|
|
122
|
+
# This is expected and correct behavior
|