audiometa-python 1.2.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {audiometa_python-1.2.0/audiometa_python.egg-info → audiometa_python-1.3.0}/PKG-INFO +9 -4
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/README.md +5 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/cli.py +110 -9
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_comprehensive.py +80 -74
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_options.py +25 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_unified.py +20 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/test_formatting.py +21 -0
- audiometa_python-1.3.0/audiometa/test/tests/unit/cli/test_cli_colorize.py +90 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0/audiometa_python.egg-info}/PKG-INFO +9 -4
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa_python.egg-info/SOURCES.txt +1 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/pyproject.toml +7 -4
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/LICENSE +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/__main__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/_audio_file.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/exceptions.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_MetadataManager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_id3v1_preserver.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_flac_handler.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_reader.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/id3v2/_id3v2_writer.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/_RiffManager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/_riff_bext_chunk.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/_riff_constants.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/_riff_file_structure.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/riff/_riff_info_chunk.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/vorbis/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/id3v1/_Id3v1Manager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/id3v1/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/id3v1/_constants.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/id3v1/id3v1_raw_metadata.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/manager/id3v1/id3v1_raw_metadata_key.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/assets/create_test_files.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/common/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/common/audio_file_creator.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/common/external_tool_runner.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v1/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v1/id3v1_header_verifier.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/id3v2_header_verifier.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/riff_header_verifier.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/riff_manual_metadata_creator.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/riff_metadata_deleter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/riff_metadata_getter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/riff/riff_metadata_setter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/scripts/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/technical_info_inspector.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/temp_file_with_metadata.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/vorbis/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/vorbis/vorbis_header_verifier.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/conftest.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_basic.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_formats.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_metadata_content.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_multiple_files.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/test_delete.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/test_help.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_basic.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_comprehensive.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_force_format.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_integer_fields.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_list_fields.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_rating.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_string_fields.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/write/test_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/test_core_workflows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/workflows/test_rating_workflows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/conftest.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/delete_all_metadata/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/encoding/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/encoding/test_encoding.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/options/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/options/test_include_headers.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/options/test_include_technical.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_consistency.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_performance.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_raw_metadata_includes_unsupported_tags.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/get_full_metadata/test_structure.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/artists/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/artists/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/comment/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/comment/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/composer/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/composer/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/description/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/description/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/description/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/description/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/genre/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/language/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/language/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/language/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_artistid/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/musicbrainz_trackid/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/originator/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/originator/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/originator/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/originator/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/title/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/title/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/title/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/reading/test_reading_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/real_audio_files/test_reading.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/real_audio_files/test_writing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_audio_data_corruption.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_file.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_invalid_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_invalid_with_metadata_combinations.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_state_precedence.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_unset_with_metadata_combinations.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_fails_with_id3v1.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_with_id3v2_only.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_validation_works_without_id3v1.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_metadata_combinations/test_md5_with_metadata_combinations.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_checking/test_unset_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_delete_original.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_flipped_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_partial_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_invalid_md5/test_random_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_md5_repair_with_metadata.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_non_flac_error.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/flac_md5/md5_repair/test_unset_md5.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/test_bitrate.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/test_channels.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/test_audio_file.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/test_forced_format.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/test_partial_update.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_flac_sync.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_mp3_sync.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/sync_strategy/test_wav_sync.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/test_context_manager.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/test_file_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/test_is_audio_file.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/test_operations.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/audio_file/test_path_handling.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/cli/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/cli/test_expand_file_patterns.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/conftest.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_riff_info_chunk_fourcc.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/disc_number/test_disc_number_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_format_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/isrc/test_isrc_type_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_format_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_artistid/test_musicbrainz_artistid_type_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_format_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_trackid/test_musicbrainz_trackid_type_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/musicbrainz_uuid/test_uuid_format_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/release_date/test_date_format_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/metadata_field/track_number/test_track_number_validation.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/utils/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/unit/utils/test_raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/flac_md5_state.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/id3v1_genre_code_map.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/metadata_format.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/metadata_writing_strategy.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/mutagen_exception_handler.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/__init__.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/base.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/config.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/macos.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/ubuntu.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/os_dependencies_checker/windows.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/rating_profiles.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/raw_metadata_sanitizer.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/tool_path_resolver.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/types.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/utils/unified_metadata_key.py +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa_python.egg-info/dependency_links.txt +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa_python.egg-info/entry_points.txt +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa_python.egg-info/requires.txt +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa_python.egg-info/top_level.txt +0 -0
- {audiometa_python-1.2.0 → audiometa_python-1.3.0}/setup.cfg +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: audiometa-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A comprehensive Python library for reading and writing audio metadata across multiple formats
|
|
5
5
|
Author: AudioMeta Python Contributors
|
|
6
6
|
Author-email: Andreas Garcia <garcia.andreas.1991@gmail.com>
|
|
7
7
|
License: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://github.com/
|
|
9
|
-
Project-URL: Repository, https://github.com/
|
|
10
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
+
Project-URL: Homepage, https://github.com/BehindTheMusicTree/audiometa
|
|
9
|
+
Project-URL: Repository, https://github.com/BehindTheMusicTree/audiometa
|
|
10
|
+
Project-URL: Issues, https://github.com/BehindTheMusicTree/audiometa/issues
|
|
11
11
|
Keywords: audio,metadata,mp3,flac,wav,id3,vorbis,riff
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -1518,6 +1518,9 @@ audiometa read song.mp3 --include-raw-binary-data
|
|
|
1518
1518
|
|
|
1519
1519
|
# Save to file
|
|
1520
1520
|
audiometa read song.mp3 --output metadata.json
|
|
1521
|
+
|
|
1522
|
+
# Colorize output (headers, keys, values) for terminal or demos
|
|
1523
|
+
audiometa read song.mp3 --format table --color
|
|
1521
1524
|
```
|
|
1522
1525
|
|
|
1523
1526
|
#### Error Handling {#cli-error-handling}
|
|
@@ -1543,6 +1546,8 @@ audiometa read "**/*.mp3" --recursive
|
|
|
1543
1546
|
- **YAML**: Human-readable structured format (requires PyYAML)
|
|
1544
1547
|
- **Table**: Simple text table format
|
|
1545
1548
|
|
|
1549
|
+
Use `--color` to colorize headers, keys, and values for terminal or demo videos (plain output by default; disabled when writing to a file). Respects the `NO_COLOR` environment variable.
|
|
1550
|
+
|
|
1546
1551
|
### Examples
|
|
1547
1552
|
|
|
1548
1553
|
```bash
|
|
@@ -1476,6 +1476,9 @@ audiometa read song.mp3 --include-raw-binary-data
|
|
|
1476
1476
|
|
|
1477
1477
|
# Save to file
|
|
1478
1478
|
audiometa read song.mp3 --output metadata.json
|
|
1479
|
+
|
|
1480
|
+
# Colorize output (headers, keys, values) for terminal or demos
|
|
1481
|
+
audiometa read song.mp3 --format table --color
|
|
1479
1482
|
```
|
|
1480
1483
|
|
|
1481
1484
|
#### Error Handling {#cli-error-handling}
|
|
@@ -1501,6 +1504,8 @@ audiometa read "**/*.mp3" --recursive
|
|
|
1501
1504
|
- **YAML**: Human-readable structured format (requires PyYAML)
|
|
1502
1505
|
- **Table**: Simple text table format
|
|
1503
1506
|
|
|
1507
|
+
Use `--color` to colorize headers, keys, and values for terminal or demo videos (plain output by default; disabled when writing to a file). Respects the `NO_COLOR` environment variable.
|
|
1508
|
+
|
|
1504
1509
|
### Examples
|
|
1505
1510
|
|
|
1506
1511
|
```bash
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
6
8
|
import sys
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
from typing import Any
|
|
@@ -23,20 +25,95 @@ from audiometa.exceptions import (
|
|
|
23
25
|
from audiometa.utils.metadata_format import MetadataFormat
|
|
24
26
|
from audiometa.utils.types import UnifiedMetadata
|
|
25
27
|
|
|
28
|
+
_ANSI_RESET = "\033[0m"
|
|
29
|
+
_ANSI_KEY = "\033[32m" # green
|
|
30
|
+
_ANSI_STR = "\033[33m" # yellow
|
|
31
|
+
_ANSI_NUM = "\033[36m" # cyan
|
|
32
|
+
_ANSI_LITERAL = "\033[2m" # dim
|
|
33
|
+
_ANSI_SECTION = "\033[1;36m" # bold cyan
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _data_for_serialization(data: Any) -> Any:
|
|
37
|
+
"""Convert data to a form suitable for YAML/JSON (UnifiedMetadataKey keys as strings)."""
|
|
38
|
+
if isinstance(data, dict):
|
|
39
|
+
return {
|
|
40
|
+
(k.value if isinstance(k, UnifiedMetadataKey) else k): _data_for_serialization(v) for k, v in data.items()
|
|
41
|
+
}
|
|
42
|
+
if isinstance(data, list):
|
|
43
|
+
return [_data_for_serialization(item) for item in data]
|
|
44
|
+
return data
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _colorize_json(raw: str) -> str:
|
|
48
|
+
"""Add ANSI colors to JSON: keys green, string values yellow, numbers cyan, literals dim."""
|
|
49
|
+
raw = re.sub(r'("[^"]*")\s*:', rf"{_ANSI_KEY}\1{_ANSI_RESET}:", raw)
|
|
50
|
+
raw = re.sub(r':\s*("(?:[^"\\]|\\.)*")', rf": {_ANSI_STR}\1{_ANSI_RESET}", raw)
|
|
51
|
+
raw = re.sub(r":\s*(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)", rf": {_ANSI_NUM}\1{_ANSI_RESET}", raw)
|
|
52
|
+
return re.sub(r"\b(true|false|null)\b", rf"{_ANSI_LITERAL}\1{_ANSI_RESET}", raw)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _colorize_table(raw: str) -> str:
|
|
56
|
+
"""Colorize table: section headers bold cyan, keys green, values yellow (incl. multiline)."""
|
|
57
|
+
lines = raw.split("\n")
|
|
58
|
+
out = []
|
|
59
|
+
key_val_re = re.compile(r"^(\s*)(.*?)\s*:\s*(.*)$")
|
|
60
|
+
for line in lines:
|
|
61
|
+
if line.strip().startswith("===") and line.strip().endswith("==="):
|
|
62
|
+
out.append(f"{_ANSI_SECTION}{line}{_ANSI_RESET}")
|
|
63
|
+
elif ":" in line and not line.strip().startswith("=="):
|
|
64
|
+
match = key_val_re.match(line)
|
|
65
|
+
if match:
|
|
66
|
+
pre, key_part, val_part = match.groups()
|
|
67
|
+
out.append(f"{pre}{_ANSI_KEY}{key_part}{_ANSI_RESET}: {_ANSI_STR}{val_part}{_ANSI_RESET}")
|
|
68
|
+
else:
|
|
69
|
+
out.append(line)
|
|
70
|
+
elif line.strip():
|
|
71
|
+
# Continuation line (e.g. multiline lyrics in table), color as value
|
|
72
|
+
indent = line[: len(line) - len(line.lstrip())]
|
|
73
|
+
rest = line.lstrip()
|
|
74
|
+
out.append(f"{indent}{_ANSI_STR}{rest}{_ANSI_RESET}")
|
|
75
|
+
else:
|
|
76
|
+
out.append(line)
|
|
77
|
+
return "\n".join(out)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _colorize_yaml(raw: str) -> str:
|
|
81
|
+
"""Colorize YAML: keys green, values yellow (including multiline continuation lines)."""
|
|
82
|
+
lines = raw.split("\n")
|
|
83
|
+
out = []
|
|
84
|
+
key_line_re = re.compile(r"^(\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$")
|
|
85
|
+
for line in lines:
|
|
86
|
+
match = key_line_re.match(line)
|
|
87
|
+
if match:
|
|
88
|
+
pre, key, val = match.groups()
|
|
89
|
+
if val.strip():
|
|
90
|
+
out.append(f"{pre}{_ANSI_KEY}{key}{_ANSI_RESET}: {_ANSI_STR}{val}{_ANSI_RESET}")
|
|
91
|
+
else:
|
|
92
|
+
out.append(f"{pre}{_ANSI_KEY}{key}{_ANSI_RESET}:{val}")
|
|
93
|
+
elif line.strip():
|
|
94
|
+
# Continuation line (e.g. multiline lyrics); not a key line, color as value
|
|
95
|
+
indent = line[: len(line) - len(line.lstrip())]
|
|
96
|
+
rest = line.lstrip()
|
|
97
|
+
out.append(f"{indent}{_ANSI_STR}{rest}{_ANSI_RESET}")
|
|
98
|
+
else:
|
|
99
|
+
out.append(line)
|
|
100
|
+
return "\n".join(out)
|
|
101
|
+
|
|
26
102
|
|
|
27
103
|
def format_output(data: Any, output_format: str) -> str:
|
|
28
104
|
"""Format output data according to specified format."""
|
|
105
|
+
serializable = _data_for_serialization(data)
|
|
29
106
|
if output_format == "json":
|
|
30
|
-
return json.dumps(
|
|
107
|
+
return json.dumps(serializable, indent=2)
|
|
31
108
|
if output_format == "yaml":
|
|
32
109
|
try:
|
|
33
110
|
import yaml # type: ignore[import-untyped]
|
|
34
111
|
|
|
35
|
-
result = yaml.dump(
|
|
112
|
+
result = yaml.dump(serializable, default_flow_style=False)
|
|
36
113
|
return str(result) if result is not None else ""
|
|
37
114
|
except ImportError:
|
|
38
115
|
sys.stderr.write("Warning: PyYAML not installed, falling back to JSON\n")
|
|
39
|
-
return json.dumps(
|
|
116
|
+
return json.dumps(serializable, indent=2)
|
|
40
117
|
elif output_format == "table":
|
|
41
118
|
return format_as_table(data)
|
|
42
119
|
else:
|
|
@@ -107,7 +184,8 @@ def format_as_table(data: dict[str, Any]) -> str:
|
|
|
107
184
|
lines.append("=== UNIFIED METADATA ===")
|
|
108
185
|
for key, value in data["unified_metadata"].items():
|
|
109
186
|
if value is not None:
|
|
110
|
-
|
|
187
|
+
label = key.value if isinstance(key, UnifiedMetadataKey) else str(key)
|
|
188
|
+
lines.append(f"{label:20}: {value}")
|
|
111
189
|
lines.append("")
|
|
112
190
|
|
|
113
191
|
if "technical_info" in data:
|
|
@@ -124,7 +202,8 @@ def format_as_table(data: dict[str, Any]) -> str:
|
|
|
124
202
|
lines.append(f"\n{metadata_format_name.upper()}:")
|
|
125
203
|
for key, value in format_data.items():
|
|
126
204
|
if value is not None:
|
|
127
|
-
|
|
205
|
+
label = key.value if isinstance(key, UnifiedMetadataKey) else str(key)
|
|
206
|
+
lines.append(f" {label:18}: {value}")
|
|
128
207
|
|
|
129
208
|
return "\n".join(lines)
|
|
130
209
|
|
|
@@ -150,17 +229,27 @@ def _read_metadata(args: argparse.Namespace) -> None:
|
|
|
150
229
|
include_raw_binary_data=getattr(args, "include_raw_binary_data", False),
|
|
151
230
|
)
|
|
152
231
|
|
|
153
|
-
|
|
232
|
+
plain = format_output(metadata, args.output_format)
|
|
233
|
+
use_color = getattr(args, "color", False) and not args.output
|
|
234
|
+
if os.environ.get("NO_COLOR"):
|
|
235
|
+
use_color = False
|
|
236
|
+
out = plain
|
|
237
|
+
if use_color and args.output_format == "json":
|
|
238
|
+
out = _colorize_json(plain)
|
|
239
|
+
elif use_color and args.output_format == "table":
|
|
240
|
+
out = _colorize_table(plain)
|
|
241
|
+
elif use_color and args.output_format == "yaml":
|
|
242
|
+
out = _colorize_yaml(plain)
|
|
154
243
|
|
|
155
244
|
if args.output:
|
|
156
245
|
try:
|
|
157
246
|
with Path(args.output).open("w") as f:
|
|
158
|
-
f.write(
|
|
247
|
+
f.write(plain)
|
|
159
248
|
except (PermissionError, OSError) as e:
|
|
160
249
|
_handle_file_operation_error(e, args.output, args.continue_on_error)
|
|
161
250
|
else:
|
|
162
|
-
sys.stdout.write(
|
|
163
|
-
if not
|
|
251
|
+
sys.stdout.write(out)
|
|
252
|
+
if not out.endswith("\n"):
|
|
164
253
|
sys.stdout.write("\n")
|
|
165
254
|
|
|
166
255
|
except (FileTypeNotSupportedError, FileNotFoundError, PermissionError, OSError, Exception) as e:
|
|
@@ -409,6 +498,12 @@ Examples:
|
|
|
409
498
|
read_parser.add_argument(
|
|
410
499
|
"--continue-on-error", action="store_true", help="Continue processing other files on error"
|
|
411
500
|
)
|
|
501
|
+
read_parser.add_argument(
|
|
502
|
+
"--color",
|
|
503
|
+
action="store_true",
|
|
504
|
+
dest="color",
|
|
505
|
+
help="Colorize output (headers, keys, values) for JSON, YAML, and table.",
|
|
506
|
+
)
|
|
412
507
|
read_parser.set_defaults(func=_read_metadata)
|
|
413
508
|
|
|
414
509
|
# Unified command
|
|
@@ -426,6 +521,12 @@ Examples:
|
|
|
426
521
|
unified_parser.add_argument(
|
|
427
522
|
"--continue-on-error", action="store_true", help="Continue processing other files on error"
|
|
428
523
|
)
|
|
524
|
+
unified_parser.add_argument(
|
|
525
|
+
"--color",
|
|
526
|
+
action="store_true",
|
|
527
|
+
dest="color",
|
|
528
|
+
help="Colorize output (headers, keys, values) for JSON, YAML, and table.",
|
|
529
|
+
)
|
|
429
530
|
unified_parser.set_defaults(func=_read_metadata, format_type="unified")
|
|
430
531
|
|
|
431
532
|
# Write command
|
|
@@ -49,26 +49,26 @@ class TestCLIReadComprehensive:
|
|
|
49
49
|
data = json.loads(result.stdout)
|
|
50
50
|
unified = data.get("unified_metadata", {})
|
|
51
51
|
|
|
52
|
-
assert unified.get(UnifiedMetadataKey.TITLE) == "Comprehensive Test Title"
|
|
53
|
-
assert unified.get(UnifiedMetadataKey.ARTISTS) == ["Artist One", "Artist Two"]
|
|
54
|
-
assert unified.get(UnifiedMetadataKey.ALBUM) == "Test Album"
|
|
55
|
-
assert unified.get(UnifiedMetadataKey.ALBUM_ARTISTS) == ["Album Artist"]
|
|
56
|
-
assert unified.get(UnifiedMetadataKey.RELEASE_DATE) == "2024"
|
|
57
|
-
assert unified.get(UnifiedMetadataKey.GENRES_NAMES) == ["Rock", "Blues"]
|
|
58
|
-
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER) == "5/12"
|
|
59
|
-
assert unified.get(UnifiedMetadataKey.DISC_NUMBER) == 1
|
|
60
|
-
assert unified.get(UnifiedMetadataKey.DISC_TOTAL) == 2
|
|
61
|
-
assert unified.get(UnifiedMetadataKey.RATING) == 85
|
|
62
|
-
assert unified.get(UnifiedMetadataKey.BPM) == 120
|
|
63
|
-
assert unified.get(UnifiedMetadataKey.LANGUAGE) == "eng"
|
|
64
|
-
assert unified.get(UnifiedMetadataKey.COMPOSERS) == ["Composer One", "Composer Two"]
|
|
65
|
-
assert unified.get(UnifiedMetadataKey.PUBLISHER) == "Test Publisher"
|
|
66
|
-
assert unified.get(UnifiedMetadataKey.COPYRIGHT) == "© 2024"
|
|
67
|
-
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS) == "Test lyrics"
|
|
68
|
-
assert unified.get(UnifiedMetadataKey.COMMENT) == "Test comment"
|
|
69
|
-
assert unified.get(UnifiedMetadataKey.ISRC) == "USRC17607839"
|
|
70
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID) == "9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6"
|
|
71
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS) == [
|
|
52
|
+
assert unified.get(UnifiedMetadataKey.TITLE.value) == "Comprehensive Test Title"
|
|
53
|
+
assert unified.get(UnifiedMetadataKey.ARTISTS.value) == ["Artist One", "Artist Two"]
|
|
54
|
+
assert unified.get(UnifiedMetadataKey.ALBUM.value) == "Test Album"
|
|
55
|
+
assert unified.get(UnifiedMetadataKey.ALBUM_ARTISTS.value) == ["Album Artist"]
|
|
56
|
+
assert unified.get(UnifiedMetadataKey.RELEASE_DATE.value) == "2024"
|
|
57
|
+
assert unified.get(UnifiedMetadataKey.GENRES_NAMES.value) == ["Rock", "Blues"]
|
|
58
|
+
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER.value) == "5/12"
|
|
59
|
+
assert unified.get(UnifiedMetadataKey.DISC_NUMBER.value) == 1
|
|
60
|
+
assert unified.get(UnifiedMetadataKey.DISC_TOTAL.value) == 2
|
|
61
|
+
assert unified.get(UnifiedMetadataKey.RATING.value) == 85
|
|
62
|
+
assert unified.get(UnifiedMetadataKey.BPM.value) == 120
|
|
63
|
+
assert unified.get(UnifiedMetadataKey.LANGUAGE.value) == "eng"
|
|
64
|
+
assert unified.get(UnifiedMetadataKey.COMPOSERS.value) == ["Composer One", "Composer Two"]
|
|
65
|
+
assert unified.get(UnifiedMetadataKey.PUBLISHER.value) == "Test Publisher"
|
|
66
|
+
assert unified.get(UnifiedMetadataKey.COPYRIGHT.value) == "© 2024"
|
|
67
|
+
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS.value) == "Test lyrics"
|
|
68
|
+
assert unified.get(UnifiedMetadataKey.COMMENT.value) == "Test comment"
|
|
69
|
+
assert unified.get(UnifiedMetadataKey.ISRC.value) == "USRC17607839"
|
|
70
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID.value) == "9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6"
|
|
71
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS.value) == [
|
|
72
72
|
"9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6",
|
|
73
73
|
"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
|
|
74
74
|
]
|
|
@@ -108,24 +108,26 @@ class TestCLIReadComprehensive:
|
|
|
108
108
|
data = json.loads(result.stdout)
|
|
109
109
|
unified = data.get("unified_metadata", {})
|
|
110
110
|
|
|
111
|
-
assert unified.get(UnifiedMetadataKey.TITLE) == "FLAC Comprehensive Test"
|
|
112
|
-
assert unified.get(UnifiedMetadataKey.ARTISTS) == ["FLAC Artist"]
|
|
113
|
-
assert unified.get(UnifiedMetadataKey.ALBUM) == "FLAC Album"
|
|
114
|
-
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER) == "3/10"
|
|
115
|
-
assert unified.get(UnifiedMetadataKey.DISC_NUMBER) == 1
|
|
116
|
-
assert unified.get(UnifiedMetadataKey.DISC_TOTAL) == 2
|
|
117
|
-
assert unified.get(UnifiedMetadataKey.BPM) == 140
|
|
118
|
-
assert unified.get(UnifiedMetadataKey.LANGUAGE) == "eng"
|
|
119
|
-
assert unified.get(UnifiedMetadataKey.COMPOSERS) == ["FLAC Composer"]
|
|
120
|
-
assert unified.get(UnifiedMetadataKey.PUBLISHER) == "FLAC Publisher"
|
|
121
|
-
assert unified.get(UnifiedMetadataKey.COPYRIGHT) == "© FLAC"
|
|
122
|
-
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS) == "FLAC lyrics"
|
|
123
|
-
assert unified.get(UnifiedMetadataKey.COMMENT) == "FLAC comment"
|
|
124
|
-
assert unified.get(UnifiedMetadataKey.DESCRIPTION) == "FLAC description"
|
|
125
|
-
assert unified.get(UnifiedMetadataKey.REPLAYGAIN) == "+2.5 dB"
|
|
126
|
-
assert unified.get(UnifiedMetadataKey.ISRC) == "FRXXX1800001"
|
|
127
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID) == "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
128
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS) == [
|
|
111
|
+
assert unified.get(UnifiedMetadataKey.TITLE.value) == "FLAC Comprehensive Test"
|
|
112
|
+
assert unified.get(UnifiedMetadataKey.ARTISTS.value) == ["FLAC Artist"]
|
|
113
|
+
assert unified.get(UnifiedMetadataKey.ALBUM.value) == "FLAC Album"
|
|
114
|
+
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER.value) == "3/10"
|
|
115
|
+
assert unified.get(UnifiedMetadataKey.DISC_NUMBER.value) == 1
|
|
116
|
+
assert unified.get(UnifiedMetadataKey.DISC_TOTAL.value) == 2
|
|
117
|
+
assert unified.get(UnifiedMetadataKey.BPM.value) == 140
|
|
118
|
+
assert unified.get(UnifiedMetadataKey.LANGUAGE.value) == "eng"
|
|
119
|
+
assert unified.get(UnifiedMetadataKey.COMPOSERS.value) == ["FLAC Composer"]
|
|
120
|
+
assert unified.get(UnifiedMetadataKey.PUBLISHER.value) == "FLAC Publisher"
|
|
121
|
+
assert unified.get(UnifiedMetadataKey.COPYRIGHT.value) == "© FLAC"
|
|
122
|
+
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS.value) == "FLAC lyrics"
|
|
123
|
+
assert unified.get(UnifiedMetadataKey.COMMENT.value) == "FLAC comment"
|
|
124
|
+
assert unified.get(UnifiedMetadataKey.DESCRIPTION.value) == "FLAC description"
|
|
125
|
+
assert unified.get(UnifiedMetadataKey.REPLAYGAIN.value) == "+2.5 dB"
|
|
126
|
+
assert unified.get(UnifiedMetadataKey.ISRC.value) == "FRXXX1800001"
|
|
127
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID.value) == "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
128
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS.value) == [
|
|
129
|
+
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
130
|
+
]
|
|
129
131
|
# ARCHIVAL_LOCATION is not supported by Vorbis format (FLAC)
|
|
130
132
|
|
|
131
133
|
def test_cli_read_all_fields_comprehensive_wav(self):
|
|
@@ -160,22 +162,24 @@ class TestCLIReadComprehensive:
|
|
|
160
162
|
data = json.loads(result.stdout)
|
|
161
163
|
unified = data.get("unified_metadata", {})
|
|
162
164
|
|
|
163
|
-
assert unified.get(UnifiedMetadataKey.TITLE) == "WAV Comprehensive Test"
|
|
164
|
-
assert unified.get(UnifiedMetadataKey.ARTISTS) == ["WAV Artist"]
|
|
165
|
-
assert unified.get(UnifiedMetadataKey.ALBUM) == "WAV Album"
|
|
166
|
-
assert unified.get(UnifiedMetadataKey.RELEASE_DATE) == "2024"
|
|
167
|
-
assert unified.get(UnifiedMetadataKey.GENRES_NAMES) == ["Rock"]
|
|
168
|
-
assert unified.get(UnifiedMetadataKey.RATING) == 100
|
|
169
|
-
assert unified.get(UnifiedMetadataKey.BPM) == 120
|
|
170
|
-
assert unified.get(UnifiedMetadataKey.LANGUAGE) == "eng"
|
|
171
|
-
assert unified.get(UnifiedMetadataKey.COMPOSERS) == ["WAV Composer"]
|
|
172
|
-
assert unified.get(UnifiedMetadataKey.COPYRIGHT) == "© WAV"
|
|
173
|
-
assert unified.get(UnifiedMetadataKey.COMMENT) == "WAV comment"
|
|
174
|
-
assert unified.get(UnifiedMetadataKey.DESCRIPTION) == "WAV description"
|
|
175
|
-
assert unified.get(UnifiedMetadataKey.ORIGINATOR) == "WAV originator"
|
|
176
|
-
assert unified.get(UnifiedMetadataKey.ISRC) == "GBUM71505078"
|
|
177
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID) == "12345678-1234-5678-9abc-def123456789"
|
|
178
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS) == [
|
|
165
|
+
assert unified.get(UnifiedMetadataKey.TITLE.value) == "WAV Comprehensive Test"
|
|
166
|
+
assert unified.get(UnifiedMetadataKey.ARTISTS.value) == ["WAV Artist"]
|
|
167
|
+
assert unified.get(UnifiedMetadataKey.ALBUM.value) == "WAV Album"
|
|
168
|
+
assert unified.get(UnifiedMetadataKey.RELEASE_DATE.value) == "2024"
|
|
169
|
+
assert unified.get(UnifiedMetadataKey.GENRES_NAMES.value) == ["Rock"]
|
|
170
|
+
assert unified.get(UnifiedMetadataKey.RATING.value) == 100
|
|
171
|
+
assert unified.get(UnifiedMetadataKey.BPM.value) == 120
|
|
172
|
+
assert unified.get(UnifiedMetadataKey.LANGUAGE.value) == "eng"
|
|
173
|
+
assert unified.get(UnifiedMetadataKey.COMPOSERS.value) == ["WAV Composer"]
|
|
174
|
+
assert unified.get(UnifiedMetadataKey.COPYRIGHT.value) == "© WAV"
|
|
175
|
+
assert unified.get(UnifiedMetadataKey.COMMENT.value) == "WAV comment"
|
|
176
|
+
assert unified.get(UnifiedMetadataKey.DESCRIPTION.value) == "WAV description"
|
|
177
|
+
assert unified.get(UnifiedMetadataKey.ORIGINATOR.value) == "WAV originator"
|
|
178
|
+
assert unified.get(UnifiedMetadataKey.ISRC.value) == "GBUM71505078"
|
|
179
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID.value) == "12345678-1234-5678-9abc-def123456789"
|
|
180
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS.value) == [
|
|
181
|
+
"12345678-1234-5678-9abc-def123456789"
|
|
182
|
+
]
|
|
179
183
|
|
|
180
184
|
def test_cli_read_comprehensive_roundtrip(self):
|
|
181
185
|
"""Test that we can write all fields via CLI and read them back correctly."""
|
|
@@ -248,23 +252,25 @@ class TestCLIReadComprehensive:
|
|
|
248
252
|
data = json.loads(read_result.stdout)
|
|
249
253
|
unified = data.get("unified_metadata", {})
|
|
250
254
|
|
|
251
|
-
assert unified.get(UnifiedMetadataKey.TITLE) == "Roundtrip Test"
|
|
252
|
-
assert unified.get(UnifiedMetadataKey.ARTISTS) == ["Roundtrip Artist One", "Roundtrip Artist Two"]
|
|
253
|
-
assert unified.get(UnifiedMetadataKey.ALBUM) == "Roundtrip Album"
|
|
254
|
-
assert unified.get(UnifiedMetadataKey.ALBUM_ARTISTS) == ["Roundtrip Album Artist"]
|
|
255
|
-
assert unified.get(UnifiedMetadataKey.RELEASE_DATE) == "2024"
|
|
256
|
-
assert unified.get(UnifiedMetadataKey.GENRES_NAMES) == ["Rock", "Blues"]
|
|
257
|
-
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER) == "5/12"
|
|
258
|
-
assert unified.get(UnifiedMetadataKey.DISC_NUMBER) == 1
|
|
259
|
-
assert unified.get(UnifiedMetadataKey.DISC_TOTAL) == 2
|
|
260
|
-
assert unified.get(UnifiedMetadataKey.RATING) == 85
|
|
261
|
-
assert unified.get(UnifiedMetadataKey.BPM) == 120
|
|
262
|
-
assert unified.get(UnifiedMetadataKey.LANGUAGE) == "eng"
|
|
263
|
-
assert unified.get(UnifiedMetadataKey.COMPOSERS) == ["Roundtrip Composer"]
|
|
264
|
-
assert unified.get(UnifiedMetadataKey.PUBLISHER) == "Roundtrip Publisher"
|
|
265
|
-
assert unified.get(UnifiedMetadataKey.COPYRIGHT) == "© Roundtrip"
|
|
266
|
-
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS) == "Roundtrip lyrics"
|
|
267
|
-
assert unified.get(UnifiedMetadataKey.COMMENT) == "Roundtrip comment"
|
|
268
|
-
assert unified.get(UnifiedMetadataKey.ISRC) == "USRC17607839"
|
|
269
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID) == "9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6"
|
|
270
|
-
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS) == [
|
|
255
|
+
assert unified.get(UnifiedMetadataKey.TITLE.value) == "Roundtrip Test"
|
|
256
|
+
assert unified.get(UnifiedMetadataKey.ARTISTS.value) == ["Roundtrip Artist One", "Roundtrip Artist Two"]
|
|
257
|
+
assert unified.get(UnifiedMetadataKey.ALBUM.value) == "Roundtrip Album"
|
|
258
|
+
assert unified.get(UnifiedMetadataKey.ALBUM_ARTISTS.value) == ["Roundtrip Album Artist"]
|
|
259
|
+
assert unified.get(UnifiedMetadataKey.RELEASE_DATE.value) == "2024"
|
|
260
|
+
assert unified.get(UnifiedMetadataKey.GENRES_NAMES.value) == ["Rock", "Blues"]
|
|
261
|
+
assert unified.get(UnifiedMetadataKey.TRACK_NUMBER.value) == "5/12"
|
|
262
|
+
assert unified.get(UnifiedMetadataKey.DISC_NUMBER.value) == 1
|
|
263
|
+
assert unified.get(UnifiedMetadataKey.DISC_TOTAL.value) == 2
|
|
264
|
+
assert unified.get(UnifiedMetadataKey.RATING.value) == 85
|
|
265
|
+
assert unified.get(UnifiedMetadataKey.BPM.value) == 120
|
|
266
|
+
assert unified.get(UnifiedMetadataKey.LANGUAGE.value) == "eng"
|
|
267
|
+
assert unified.get(UnifiedMetadataKey.COMPOSERS.value) == ["Roundtrip Composer"]
|
|
268
|
+
assert unified.get(UnifiedMetadataKey.PUBLISHER.value) == "Roundtrip Publisher"
|
|
269
|
+
assert unified.get(UnifiedMetadataKey.COPYRIGHT.value) == "© Roundtrip"
|
|
270
|
+
assert unified.get(UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS.value) == "Roundtrip lyrics"
|
|
271
|
+
assert unified.get(UnifiedMetadataKey.COMMENT.value) == "Roundtrip comment"
|
|
272
|
+
assert unified.get(UnifiedMetadataKey.ISRC.value) == "USRC17607839"
|
|
273
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_TRACKID.value) == "9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6"
|
|
274
|
+
assert unified.get(UnifiedMetadataKey.MUSICBRAINZ_ARTISTIDS.value) == [
|
|
275
|
+
"9d6f6f7c-9d52-4c76-8f9e-01d18d8f8ec6"
|
|
276
|
+
]
|
{audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_options.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
2
3
|
import subprocess
|
|
3
4
|
import sys
|
|
4
5
|
|
|
@@ -86,3 +87,27 @@ class TestCLIReadOptions:
|
|
|
86
87
|
)
|
|
87
88
|
assert result.returncode == 0
|
|
88
89
|
assert "UNIFIED METADATA" in result.stdout
|
|
90
|
+
|
|
91
|
+
def test_cli_read_with_color_produces_ansi(self):
|
|
92
|
+
env = {k: v for k, v in os.environ.items() if k != "NO_COLOR"}
|
|
93
|
+
with temp_file_with_metadata({"title": "Test"}, "mp3") as test_file:
|
|
94
|
+
result = subprocess.run(
|
|
95
|
+
[sys.executable, "-m", "audiometa", "read", str(test_file), "--color", "--format", "json"],
|
|
96
|
+
capture_output=True,
|
|
97
|
+
text=True,
|
|
98
|
+
check=False,
|
|
99
|
+
env=env,
|
|
100
|
+
)
|
|
101
|
+
assert result.returncode == 0
|
|
102
|
+
assert "\033[" in result.stdout
|
|
103
|
+
|
|
104
|
+
def test_cli_read_without_color_no_ansi(self):
|
|
105
|
+
with temp_file_with_metadata({"title": "Test"}, "mp3") as test_file:
|
|
106
|
+
result = subprocess.run(
|
|
107
|
+
[sys.executable, "-m", "audiometa", "read", str(test_file), "--format", "json"],
|
|
108
|
+
capture_output=True,
|
|
109
|
+
text=True,
|
|
110
|
+
check=False,
|
|
111
|
+
)
|
|
112
|
+
assert result.returncode == 0
|
|
113
|
+
assert "\033[" not in result.stdout
|
{audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/read/test_unified.py
RENAMED
|
@@ -37,6 +37,26 @@ class TestCLIReadUnified:
|
|
|
37
37
|
assert data.get("title") == "Unified Test"
|
|
38
38
|
assert data.get("artists") == ["Unified Artist"]
|
|
39
39
|
|
|
40
|
+
def test_cli_unified_yaml_uses_plain_string_keys(self):
|
|
41
|
+
with temp_file_with_metadata({"title": "YAML Key Test", "artist": "YAML Artist"}, "mp3") as test_file:
|
|
42
|
+
result = subprocess.run(
|
|
43
|
+
[sys.executable, "-m", "audiometa", "unified", str(test_file), "--format", "yaml"],
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
check=False,
|
|
47
|
+
)
|
|
48
|
+
assert result.returncode == 0
|
|
49
|
+
assert "!!python" not in result.stdout
|
|
50
|
+
try:
|
|
51
|
+
import yaml
|
|
52
|
+
|
|
53
|
+
data = yaml.safe_load(result.stdout)
|
|
54
|
+
assert isinstance(data, dict)
|
|
55
|
+
assert data.get("title") == "YAML Key Test"
|
|
56
|
+
assert data.get("artists") == ["YAML Artist"]
|
|
57
|
+
except ImportError:
|
|
58
|
+
pass
|
|
59
|
+
|
|
40
60
|
def test_cli_unified_table_format(self):
|
|
41
61
|
with temp_file_with_metadata({"title": "Table Test", "artist": "Table Artist"}, "mp3") as test_file:
|
|
42
62
|
result = subprocess.run(
|
{audiometa_python-1.2.0 → audiometa_python-1.3.0}/audiometa/test/tests/e2e/cli/test_formatting.py
RENAMED
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
+
from audiometa import UnifiedMetadataKey
|
|
5
6
|
from audiometa.cli import format_as_table, format_output
|
|
6
7
|
|
|
7
8
|
|
|
@@ -29,3 +30,23 @@ class TestCLIFormatting:
|
|
|
29
30
|
assert "Test Artist" in result
|
|
30
31
|
assert "180" in result
|
|
31
32
|
assert "320" in result
|
|
33
|
+
|
|
34
|
+
def test_format_output_table_displays_key_labels_not_enum_repr(self):
|
|
35
|
+
data = {
|
|
36
|
+
"unified_metadata": {
|
|
37
|
+
UnifiedMetadataKey.TITLE: "Song Title",
|
|
38
|
+
UnifiedMetadataKey.ALBUM_ARTISTS: ["Album Artist"],
|
|
39
|
+
},
|
|
40
|
+
"metadata_format": {
|
|
41
|
+
"id3v2": {
|
|
42
|
+
UnifiedMetadataKey.TITLE: "Song Title",
|
|
43
|
+
UnifiedMetadataKey.ALBUM_ARTISTS: ["Album Artist"],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
result = format_as_table(data)
|
|
48
|
+
assert "UnifiedMetadataKey." not in result
|
|
49
|
+
assert "title" in result
|
|
50
|
+
assert "album_artists" in result
|
|
51
|
+
assert "Song Title" in result
|
|
52
|
+
assert "Album Artist" in result or "['Album Artist']" in result
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from audiometa.cli import _colorize_json, _colorize_table, _colorize_yaml
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _strip_ansi(text: str) -> str:
|
|
9
|
+
return re.sub(r"\033\[[0-9;]*m", "", text)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.mark.unit
|
|
13
|
+
class TestColorizeJson:
|
|
14
|
+
def test_keys_green(self):
|
|
15
|
+
raw = '"title": "Hello"'
|
|
16
|
+
out = _colorize_json(raw)
|
|
17
|
+
assert "\033[32m" in out
|
|
18
|
+
assert "title" in out
|
|
19
|
+
assert _strip_ansi(out) == raw
|
|
20
|
+
|
|
21
|
+
def test_string_values_yellow(self):
|
|
22
|
+
raw = '"title": "Hello"'
|
|
23
|
+
out = _colorize_json(raw)
|
|
24
|
+
assert "\033[33m" in out
|
|
25
|
+
assert "Hello" in out
|
|
26
|
+
|
|
27
|
+
def test_numbers_cyan(self):
|
|
28
|
+
raw = '"duration": 180'
|
|
29
|
+
out = _colorize_json(raw)
|
|
30
|
+
assert "\033[36m" in out
|
|
31
|
+
assert "180" in out
|
|
32
|
+
|
|
33
|
+
def test_literals_dim(self):
|
|
34
|
+
raw = '"enabled": true'
|
|
35
|
+
out = _colorize_json(raw)
|
|
36
|
+
assert "\033[2m" in out
|
|
37
|
+
assert "true" in out
|
|
38
|
+
|
|
39
|
+
def test_reset_present(self):
|
|
40
|
+
raw = '{"key": "val"}'
|
|
41
|
+
out = _colorize_json(raw)
|
|
42
|
+
assert "\033[0m" in out
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.unit
|
|
46
|
+
class TestColorizeTable:
|
|
47
|
+
def test_section_headers_bold_cyan(self):
|
|
48
|
+
raw = "=== UNIFIED METADATA ==="
|
|
49
|
+
out = _colorize_table(raw)
|
|
50
|
+
assert "\033[1;36m" in out
|
|
51
|
+
assert "UNIFIED METADATA" in out
|
|
52
|
+
|
|
53
|
+
def test_key_value_line(self):
|
|
54
|
+
raw = "title : My Song"
|
|
55
|
+
out = _colorize_table(raw)
|
|
56
|
+
assert "\033[32m" in out
|
|
57
|
+
assert "\033[33m" in out
|
|
58
|
+
assert "title" in out
|
|
59
|
+
assert "My Song" in out
|
|
60
|
+
|
|
61
|
+
def test_continuation_line_colored_as_value(self):
|
|
62
|
+
raw = "title : Line one\nLine two"
|
|
63
|
+
out = _colorize_table(raw)
|
|
64
|
+
assert "\033[33m" in out
|
|
65
|
+
assert "Line one" in out
|
|
66
|
+
assert "Line two" in out
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pytest.mark.unit
|
|
70
|
+
class TestColorizeYaml:
|
|
71
|
+
def test_key_green_value_yellow(self):
|
|
72
|
+
raw = "title: My Album"
|
|
73
|
+
out = _colorize_yaml(raw)
|
|
74
|
+
assert "\033[32m" in out
|
|
75
|
+
assert "\033[33m" in out
|
|
76
|
+
assert "title" in out
|
|
77
|
+
assert "My Album" in out
|
|
78
|
+
|
|
79
|
+
def test_continuation_line_colored(self):
|
|
80
|
+
raw = "lyrics: First line\nSecond line"
|
|
81
|
+
out = _colorize_yaml(raw)
|
|
82
|
+
assert "\033[33m" in out
|
|
83
|
+
assert "First line" in out
|
|
84
|
+
assert "Second line" in out
|
|
85
|
+
|
|
86
|
+
def test_empty_value_key_only_colored(self):
|
|
87
|
+
raw = "empty:"
|
|
88
|
+
out = _colorize_yaml(raw)
|
|
89
|
+
assert "\033[32m" in out
|
|
90
|
+
assert "empty" in out
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: audiometa-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A comprehensive Python library for reading and writing audio metadata across multiple formats
|
|
5
5
|
Author: AudioMeta Python Contributors
|
|
6
6
|
Author-email: Andreas Garcia <garcia.andreas.1991@gmail.com>
|
|
7
7
|
License: Apache-2.0
|
|
8
|
-
Project-URL: Homepage, https://github.com/
|
|
9
|
-
Project-URL: Repository, https://github.com/
|
|
10
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
+
Project-URL: Homepage, https://github.com/BehindTheMusicTree/audiometa
|
|
9
|
+
Project-URL: Repository, https://github.com/BehindTheMusicTree/audiometa
|
|
10
|
+
Project-URL: Issues, https://github.com/BehindTheMusicTree/audiometa/issues
|
|
11
11
|
Keywords: audio,metadata,mp3,flac,wav,id3,vorbis,riff
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -1518,6 +1518,9 @@ audiometa read song.mp3 --include-raw-binary-data
|
|
|
1518
1518
|
|
|
1519
1519
|
# Save to file
|
|
1520
1520
|
audiometa read song.mp3 --output metadata.json
|
|
1521
|
+
|
|
1522
|
+
# Colorize output (headers, keys, values) for terminal or demos
|
|
1523
|
+
audiometa read song.mp3 --format table --color
|
|
1521
1524
|
```
|
|
1522
1525
|
|
|
1523
1526
|
#### Error Handling {#cli-error-handling}
|
|
@@ -1543,6 +1546,8 @@ audiometa read "**/*.mp3" --recursive
|
|
|
1543
1546
|
- **YAML**: Human-readable structured format (requires PyYAML)
|
|
1544
1547
|
- **Table**: Simple text table format
|
|
1545
1548
|
|
|
1549
|
+
Use `--color` to colorize headers, keys, and values for terminal or demo videos (plain output by default; disabled when writing to a file). Respects the `NO_COLOR` environment variable.
|
|
1550
|
+
|
|
1546
1551
|
### Examples
|
|
1547
1552
|
|
|
1548
1553
|
```bash
|
|
@@ -341,6 +341,7 @@ audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py
|
|
|
341
341
|
audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py
|
|
342
342
|
audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py
|
|
343
343
|
audiometa/test/tests/unit/cli/__init__.py
|
|
344
|
+
audiometa/test/tests/unit/cli/test_cli_colorize.py
|
|
344
345
|
audiometa/test/tests/unit/cli/test_expand_file_patterns.py
|
|
345
346
|
audiometa/test/tests/unit/metadata_managers/__init__.py
|
|
346
347
|
audiometa/test/tests/unit/metadata_managers/conftest.py
|