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.
Files changed (352) hide show
  1. audiometa/__init__.py +1297 -0
  2. audiometa/__main__.py +6 -0
  3. audiometa/_audio_file.py +607 -0
  4. audiometa/cli.py +476 -0
  5. audiometa/exceptions.py +167 -0
  6. audiometa/manager/_MetadataManager.py +768 -0
  7. audiometa/manager/__init__.py +1 -0
  8. audiometa/manager/_rating_supporting/_RatingSupportingMetadataManager.py +250 -0
  9. audiometa/manager/_rating_supporting/__init__.py +1 -0
  10. audiometa/manager/_rating_supporting/id3v2/_Id3v2Manager.py +1032 -0
  11. audiometa/manager/_rating_supporting/id3v2/__init__.py +25 -0
  12. audiometa/manager/_rating_supporting/id3v2/_id3v2_constants.py +11 -0
  13. audiometa/manager/_rating_supporting/riff/_RiffManager.py +1002 -0
  14. audiometa/manager/_rating_supporting/riff/__init__.py +25 -0
  15. audiometa/manager/_rating_supporting/riff/_riff_constants.py +17 -0
  16. audiometa/manager/_rating_supporting/vorbis/_VorbisManager.py +542 -0
  17. audiometa/manager/_rating_supporting/vorbis/__init__.py +17 -0
  18. audiometa/manager/_rating_supporting/vorbis/_vorbis_constants.py +6 -0
  19. audiometa/manager/id3v1/_Id3v1Manager.py +512 -0
  20. audiometa/manager/id3v1/__init__.py +1 -0
  21. audiometa/manager/id3v1/_constants.py +8 -0
  22. audiometa/manager/id3v1/id3v1_raw_metadata.py +242 -0
  23. audiometa/manager/id3v1/id3v1_raw_metadata_key.py +13 -0
  24. audiometa/test/__init__.py +1 -0
  25. audiometa/test/assets/create_test_files.py +72 -0
  26. audiometa/test/helpers/__init__.py +51 -0
  27. audiometa/test/helpers/common/__init__.py +6 -0
  28. audiometa/test/helpers/common/audio_file_creator.py +68 -0
  29. audiometa/test/helpers/common/external_tool_runner.py +74 -0
  30. audiometa/test/helpers/id3v1/__init__.py +8 -0
  31. audiometa/test/helpers/id3v1/id3v1_header_verifier.py +18 -0
  32. audiometa/test/helpers/id3v1/id3v1_metadata_deleter.py +37 -0
  33. audiometa/test/helpers/id3v1/id3v1_metadata_getter.py +61 -0
  34. audiometa/test/helpers/id3v1/id3v1_metadata_setter.py +82 -0
  35. audiometa/test/helpers/id3v2/__init__.py +28 -0
  36. audiometa/test/helpers/id3v2/id3v2_frame_manual_creator.py +349 -0
  37. audiometa/test/helpers/id3v2/id3v2_header_verifier.py +38 -0
  38. audiometa/test/helpers/id3v2/id3v2_metadata_deleter.py +56 -0
  39. audiometa/test/helpers/id3v2/id3v2_metadata_getter.py +189 -0
  40. audiometa/test/helpers/id3v2/id3v2_metadata_setter.py +506 -0
  41. audiometa/test/helpers/riff/__init__.py +8 -0
  42. audiometa/test/helpers/riff/riff_header_verifier.py +85 -0
  43. audiometa/test/helpers/riff/riff_manual_metadata_creator.py +298 -0
  44. audiometa/test/helpers/riff/riff_metadata_deleter.py +56 -0
  45. audiometa/test/helpers/riff/riff_metadata_getter.py +219 -0
  46. audiometa/test/helpers/riff/riff_metadata_setter.py +374 -0
  47. audiometa/test/helpers/scripts/__init__.py +0 -0
  48. audiometa/test/helpers/technical_info_inspector.py +115 -0
  49. audiometa/test/helpers/temp_file_with_metadata.py +82 -0
  50. audiometa/test/helpers/vorbis/__init__.py +8 -0
  51. audiometa/test/helpers/vorbis/vorbis_header_verifier.py +31 -0
  52. audiometa/test/helpers/vorbis/vorbis_metadata_deleter.py +49 -0
  53. audiometa/test/helpers/vorbis/vorbis_metadata_getter.py +67 -0
  54. audiometa/test/helpers/vorbis/vorbis_metadata_setter.py +221 -0
  55. audiometa/test/tests/__init__.py +0 -0
  56. audiometa/test/tests/conftest.py +276 -0
  57. audiometa/test/tests/e2e/__init__.py +0 -0
  58. audiometa/test/tests/e2e/cli/__init__.py +0 -0
  59. audiometa/test/tests/e2e/cli/error_handling/__init__.py +1 -0
  60. audiometa/test/tests/e2e/cli/error_handling/test_command_structure_errors.py +77 -0
  61. audiometa/test/tests/e2e/cli/error_handling/test_file_access_errors.py +130 -0
  62. audiometa/test/tests/e2e/cli/error_handling/test_format_output_errors.py +118 -0
  63. audiometa/test/tests/e2e/cli/error_handling/test_input_validation_errors.py +172 -0
  64. audiometa/test/tests/e2e/cli/error_handling/test_missing_fields_validation.py +49 -0
  65. audiometa/test/tests/e2e/cli/error_handling/test_multiple_files_errors.py +160 -0
  66. audiometa/test/tests/e2e/cli/error_handling/test_rating_validation.py +90 -0
  67. audiometa/test/tests/e2e/cli/error_handling/test_year_validation.py +51 -0
  68. audiometa/test/tests/e2e/cli/read/__init__.py +0 -0
  69. audiometa/test/tests/e2e/cli/read/test_basic.py +58 -0
  70. audiometa/test/tests/e2e/cli/read/test_comprehensive.py +240 -0
  71. audiometa/test/tests/e2e/cli/read/test_formats.py +55 -0
  72. audiometa/test/tests/e2e/cli/read/test_metadata_content.py +164 -0
  73. audiometa/test/tests/e2e/cli/read/test_multiple_files.py +149 -0
  74. audiometa/test/tests/e2e/cli/read/test_options.py +88 -0
  75. audiometa/test/tests/e2e/cli/read/test_unified.py +84 -0
  76. audiometa/test/tests/e2e/cli/test_delete.py +20 -0
  77. audiometa/test/tests/e2e/cli/test_formatting.py +31 -0
  78. audiometa/test/tests/e2e/cli/test_help.py +41 -0
  79. audiometa/test/tests/e2e/cli/write/__init__.py +0 -0
  80. audiometa/test/tests/e2e/cli/write/test_basic.py +51 -0
  81. audiometa/test/tests/e2e/cli/write/test_comprehensive.py +210 -0
  82. audiometa/test/tests/e2e/cli/write/test_force_format.py +336 -0
  83. audiometa/test/tests/e2e/cli/write/test_integer_fields.py +145 -0
  84. audiometa/test/tests/e2e/cli/write/test_list_fields.py +107 -0
  85. audiometa/test/tests/e2e/cli/write/test_rating.py +74 -0
  86. audiometa/test/tests/e2e/cli/write/test_string_fields.py +54 -0
  87. audiometa/test/tests/e2e/cli/write/test_validation.py +85 -0
  88. audiometa/test/tests/e2e/scenarios/__init__.py +0 -0
  89. audiometa/test/tests/e2e/scenarios/test_user_scenarios.py +166 -0
  90. audiometa/test/tests/e2e/workflows/__init__.py +0 -0
  91. audiometa/test/tests/e2e/workflows/test_core_workflows.py +166 -0
  92. audiometa/test/tests/e2e/workflows/test_deletion_workflows.py +318 -0
  93. audiometa/test/tests/e2e/workflows/test_error_handling_workflows.py +165 -0
  94. audiometa/test/tests/e2e/workflows/test_format_specific_workflows.py +129 -0
  95. audiometa/test/tests/e2e/workflows/test_rating_workflows.py +124 -0
  96. audiometa/test/tests/integration/__init__.py +0 -0
  97. audiometa/test/tests/integration/audio_format/__init__.py +0 -0
  98. audiometa/test/tests/integration/audio_format/flac/__init__.py +0 -0
  99. audiometa/test/tests/integration/audio_format/flac/test_flac_delete_all.py +108 -0
  100. audiometa/test/tests/integration/audio_format/flac/test_flac_reading_all.py +61 -0
  101. audiometa/test/tests/integration/audio_format/flac/test_flac_reading_field.py +65 -0
  102. audiometa/test/tests/integration/audio_format/flac/test_flac_writing.py +69 -0
  103. audiometa/test/tests/integration/audio_format/mp3/__init__.py +0 -0
  104. audiometa/test/tests/integration/audio_format/mp3/test_mp3_delete_all.py +79 -0
  105. audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_all.py +61 -0
  106. audiometa/test/tests/integration/audio_format/mp3/test_mp3_reading_field.py +67 -0
  107. audiometa/test/tests/integration/audio_format/mp3/test_mp3_writing.py +60 -0
  108. audiometa/test/tests/integration/audio_format/wav/__init__.py +0 -0
  109. audiometa/test/tests/integration/audio_format/wav/test_wav_delete_all.py +87 -0
  110. audiometa/test/tests/integration/audio_format/wav/test_wav_reading_all.py +62 -0
  111. audiometa/test/tests/integration/audio_format/wav/test_wav_reading_field.py +57 -0
  112. audiometa/test/tests/integration/audio_format/wav/test_wav_with_id3v2_tags.py +83 -0
  113. audiometa/test/tests/integration/audio_format/wav/test_wav_writing.py +62 -0
  114. audiometa/test/tests/integration/conftest.py +29 -0
  115. audiometa/test/tests/integration/delete_all_metadata/__init__.py +1 -0
  116. audiometa/test/tests/integration/delete_all_metadata/test_audio_format_all.py +102 -0
  117. audiometa/test/tests/integration/delete_all_metadata/test_audio_format_header_deletion.py +77 -0
  118. audiometa/test/tests/integration/delete_all_metadata/test_basic_functionality.py +47 -0
  119. audiometa/test/tests/integration/delete_all_metadata/test_error_handling.py +24 -0
  120. audiometa/test/tests/integration/encoding/__init__.py +1 -0
  121. audiometa/test/tests/integration/encoding/test_encoding.py +88 -0
  122. audiometa/test/tests/integration/encoding/test_special_characters_edge_cases.py +223 -0
  123. audiometa/test/tests/integration/get_full_metadata/__init__.py +0 -0
  124. audiometa/test/tests/integration/get_full_metadata/test_audio_formats.py +122 -0
  125. audiometa/test/tests/integration/get_full_metadata/test_binary_data_filtering.py +250 -0
  126. audiometa/test/tests/integration/get_full_metadata/test_consistency.py +67 -0
  127. audiometa/test/tests/integration/get_full_metadata/test_edge_cases.py +123 -0
  128. audiometa/test/tests/integration/get_full_metadata/test_error_handling.py +40 -0
  129. audiometa/test/tests/integration/get_full_metadata/test_get_full_metadata.py +43 -0
  130. audiometa/test/tests/integration/get_full_metadata/test_options.py +207 -0
  131. audiometa/test/tests/integration/get_full_metadata/test_performance.py +95 -0
  132. audiometa/test/tests/integration/get_full_metadata/test_riff_bext.py +128 -0
  133. audiometa/test/tests/integration/get_full_metadata/test_structure.py +161 -0
  134. audiometa/test/tests/integration/metadata_field/__init__.py +0 -0
  135. audiometa/test/tests/integration/metadata_field/album/__init__.py +0 -0
  136. audiometa/test/tests/integration/metadata_field/album/test_deleting.py +73 -0
  137. audiometa/test/tests/integration/metadata_field/album/test_reading.py +36 -0
  138. audiometa/test/tests/integration/metadata_field/album/test_writing.py +50 -0
  139. audiometa/test/tests/integration/metadata_field/album_artists/__init__.py +0 -0
  140. audiometa/test/tests/integration/metadata_field/album_artists/test_deleting.py +83 -0
  141. audiometa/test/tests/integration/metadata_field/album_artists/test_reading.py +38 -0
  142. audiometa/test/tests/integration/metadata_field/album_artists/test_writing.py +52 -0
  143. audiometa/test/tests/integration/metadata_field/artists/__init__.py +0 -0
  144. audiometa/test/tests/integration/metadata_field/artists/test_deleting.py +68 -0
  145. audiometa/test/tests/integration/metadata_field/artists/test_reading.py +36 -0
  146. audiometa/test/tests/integration/metadata_field/artists/test_writing.py +46 -0
  147. audiometa/test/tests/integration/metadata_field/bpm/__init__.py +0 -0
  148. audiometa/test/tests/integration/metadata_field/bpm/test_deleting.py +75 -0
  149. audiometa/test/tests/integration/metadata_field/bpm/test_reading.py +32 -0
  150. audiometa/test/tests/integration/metadata_field/bpm/test_writing.py +56 -0
  151. audiometa/test/tests/integration/metadata_field/comment/__init__.py +0 -0
  152. audiometa/test/tests/integration/metadata_field/comment/test_deleting.py +68 -0
  153. audiometa/test/tests/integration/metadata_field/comment/test_reading.py +36 -0
  154. audiometa/test/tests/integration/metadata_field/comment/test_writing.py +49 -0
  155. audiometa/test/tests/integration/metadata_field/composer/__init__.py +0 -0
  156. audiometa/test/tests/integration/metadata_field/composer/test_deleting.py +75 -0
  157. audiometa/test/tests/integration/metadata_field/composer/test_reading.py +34 -0
  158. audiometa/test/tests/integration/metadata_field/composer/test_writing.py +41 -0
  159. audiometa/test/tests/integration/metadata_field/copyright/__init__.py +0 -0
  160. audiometa/test/tests/integration/metadata_field/copyright/test_deleting.py +81 -0
  161. audiometa/test/tests/integration/metadata_field/copyright/test_reading.py +35 -0
  162. audiometa/test/tests/integration/metadata_field/copyright/test_writing.py +41 -0
  163. audiometa/test/tests/integration/metadata_field/disc_number/__init__.py +0 -0
  164. audiometa/test/tests/integration/metadata_field/disc_number/test_deleting.py +97 -0
  165. audiometa/test/tests/integration/metadata_field/disc_number/test_reading.py +92 -0
  166. audiometa/test/tests/integration/metadata_field/disc_number/test_writing.py +153 -0
  167. audiometa/test/tests/integration/metadata_field/field_not_supported/__init__.py +0 -0
  168. audiometa/test/tests/integration/metadata_field/field_not_supported/test_deleting.py +56 -0
  169. audiometa/test/tests/integration/metadata_field/field_not_supported/test_reading.py +54 -0
  170. audiometa/test/tests/integration/metadata_field/field_not_supported/test_writing.py +61 -0
  171. audiometa/test/tests/integration/metadata_field/genre/__init__.py +0 -0
  172. audiometa/test/tests/integration/metadata_field/genre/reading/__init__.py +0 -0
  173. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/__init__.py +0 -0
  174. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v1_reading.py +65 -0
  175. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_id3v2_reading.py +25 -0
  176. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_riff_reading.py +58 -0
  177. audiometa/test/tests/integration/metadata_field/genre/reading/metadata_format/test_vorbis_reading.py +61 -0
  178. audiometa/test/tests/integration/metadata_field/genre/reading/test_smart_reading.py +191 -0
  179. audiometa/test/tests/integration/metadata_field/genre/test_deleting.py +62 -0
  180. audiometa/test/tests/integration/metadata_field/genre/test_writing.py +64 -0
  181. audiometa/test/tests/integration/metadata_field/isrc/__init__.py +1 -0
  182. audiometa/test/tests/integration/metadata_field/isrc/test_deleting.py +31 -0
  183. audiometa/test/tests/integration/metadata_field/isrc/test_reading.py +35 -0
  184. audiometa/test/tests/integration/metadata_field/isrc/test_writing.py +165 -0
  185. audiometa/test/tests/integration/metadata_field/language/__init__.py +0 -0
  186. audiometa/test/tests/integration/metadata_field/language/test_deleting.py +75 -0
  187. audiometa/test/tests/integration/metadata_field/language/test_reading.py +39 -0
  188. audiometa/test/tests/integration/metadata_field/language/test_writing.py +43 -0
  189. audiometa/test/tests/integration/metadata_field/lyrics/__init__.py +0 -0
  190. audiometa/test/tests/integration/metadata_field/lyrics/test_deleting.py +129 -0
  191. audiometa/test/tests/integration/metadata_field/lyrics/test_reading.py +57 -0
  192. audiometa/test/tests/integration/metadata_field/lyrics/test_writing.py +59 -0
  193. audiometa/test/tests/integration/metadata_field/publisher/__init__.py +0 -0
  194. audiometa/test/tests/integration/metadata_field/publisher/test_deleting.py +88 -0
  195. audiometa/test/tests/integration/metadata_field/publisher/test_reading.py +32 -0
  196. audiometa/test/tests/integration/metadata_field/publisher/test_writing.py +47 -0
  197. audiometa/test/tests/integration/metadata_field/rating/__init__.py +0 -0
  198. audiometa/test/tests/integration/metadata_field/rating/reading/__init__.py +0 -0
  199. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_100_proportional.py +81 -0
  200. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_non_proportional.py +33 -0
  201. audiometa/test/tests/integration/metadata_field/rating/reading/test_base_255_proportional.py +58 -0
  202. audiometa/test/tests/integration/metadata_field/rating/test_deleting.py +117 -0
  203. audiometa/test/tests/integration/metadata_field/rating/test_error_handling.py +137 -0
  204. audiometa/test/tests/integration/metadata_field/rating/writing/__init__.py +0 -0
  205. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/__init__.py +0 -0
  206. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_id3v2.py +77 -0
  207. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_riff.py +55 -0
  208. audiometa/test/tests/integration/metadata_field/rating/writing/metadata_format/test_vorbis.py +57 -0
  209. audiometa/test/tests/integration/metadata_field/rating/writing/test_comprehensive.py +192 -0
  210. audiometa/test/tests/integration/metadata_field/release_date/__init__.py +0 -0
  211. audiometa/test/tests/integration/metadata_field/release_date/test_deleting.py +74 -0
  212. audiometa/test/tests/integration/metadata_field/release_date/test_error_handling.py +82 -0
  213. audiometa/test/tests/integration/metadata_field/release_date/test_reading.py +59 -0
  214. audiometa/test/tests/integration/metadata_field/release_date/test_writing.py +49 -0
  215. audiometa/test/tests/integration/metadata_field/test_metadata_field_validation.py +135 -0
  216. audiometa/test/tests/integration/metadata_field/title/__init__.py +0 -0
  217. audiometa/test/tests/integration/metadata_field/title/test_deleting.py +73 -0
  218. audiometa/test/tests/integration/metadata_field/title/test_error_handling.py +47 -0
  219. audiometa/test/tests/integration/metadata_field/title/test_reading.py +36 -0
  220. audiometa/test/tests/integration/metadata_field/title/test_writing.py +64 -0
  221. audiometa/test/tests/integration/metadata_field/track_number/__init__.py +0 -0
  222. audiometa/test/tests/integration/metadata_field/track_number/reading/__init__.py +0 -0
  223. audiometa/test/tests/integration/metadata_field/track_number/reading/test_edge_cases.py +43 -0
  224. audiometa/test/tests/integration/metadata_field/track_number/reading/test_metadata_format.py +32 -0
  225. audiometa/test/tests/integration/metadata_field/track_number/test_deleting.py +59 -0
  226. audiometa/test/tests/integration/metadata_field/track_number/test_writing.py +73 -0
  227. audiometa/test/tests/integration/multiple_values/__init__.py +1 -0
  228. audiometa/test/tests/integration/multiple_values/reading/__init__.py +1 -0
  229. audiometa/test/tests/integration/multiple_values/reading/metadata_format/__init__.py +1 -0
  230. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v1.py +23 -0
  231. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_3.py +92 -0
  232. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_id3v2_4.py +216 -0
  233. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_riff.py +84 -0
  234. audiometa/test/tests/integration/multiple_values/reading/metadata_format/test_vorbis.py +169 -0
  235. audiometa/test/tests/integration/multiple_values/reading/test_performance_large_data.py +209 -0
  236. audiometa/test/tests/integration/multiple_values/reading/test_smart_parsing_scenarios.py +198 -0
  237. audiometa/test/tests/integration/multiple_values/reading/test_unicode_handling.py +24 -0
  238. audiometa/test/tests/integration/multiple_values/writing/__init__.py +1 -0
  239. audiometa/test/tests/integration/multiple_values/writing/metadata_format/__init__.py +1 -0
  240. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v1.py +62 -0
  241. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_3.py +36 -0
  242. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_id3v2_4.py +34 -0
  243. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_riff.py +32 -0
  244. audiometa/test/tests/integration/multiple_values/writing/metadata_format/test_vorbis.py +54 -0
  245. audiometa/test/tests/integration/multiple_values/writing/test_error_handling.py +42 -0
  246. audiometa/test/tests/integration/multiple_values/writing/test_large_values.py +98 -0
  247. audiometa/test/tests/integration/reading/__init__.py +1 -0
  248. audiometa/test/tests/integration/reading/test_read_multiple_metadata.py +80 -0
  249. audiometa/test/tests/integration/reading/test_reading_error_handling.py +36 -0
  250. audiometa/test/tests/integration/real_audio_files/__init__.py +0 -0
  251. audiometa/test/tests/integration/real_audio_files/test_reading.py +146 -0
  252. audiometa/test/tests/integration/real_audio_files/test_writing.py +198 -0
  253. audiometa/test/tests/integration/technical_info/__init__.py +0 -0
  254. audiometa/test/tests/integration/technical_info/flac_md5/__init__.py +0 -0
  255. audiometa/test/tests/integration/technical_info/flac_md5/conftest.py +103 -0
  256. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/__init__.py +0 -0
  257. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_audio_data_corruption.py +21 -0
  258. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_flipped_md5.py +29 -0
  259. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_non_flac_error.py +13 -0
  260. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_partial_md5.py +29 -0
  261. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_random_md5.py +29 -0
  262. audiometa/test/tests/integration/technical_info/flac_md5/test_invalid_md5/test_unset_md5.py +56 -0
  263. audiometa/test/tests/integration/technical_info/flac_md5/test_valid_md5.py +21 -0
  264. audiometa/test/tests/integration/technical_info/test_bitrate.py +79 -0
  265. audiometa/test/tests/integration/technical_info/test_channels.py +38 -0
  266. audiometa/test/tests/integration/technical_info/test_duration_in_sec.py +38 -0
  267. audiometa/test/tests/integration/technical_info/test_sample_rate.py +40 -0
  268. audiometa/test/tests/integration/test_audio_file.py +35 -0
  269. audiometa/test/tests/integration/test_audio_format_readable_after_update_all_metadata_formats.py +95 -0
  270. audiometa/test/tests/integration/writing/__init__.py +0 -0
  271. audiometa/test/tests/integration/writing/test_error_handling.py +44 -0
  272. audiometa/test/tests/integration/writing/test_forced_format.py +224 -0
  273. audiometa/test/tests/integration/writing/test_multiple_format_preservation.py +223 -0
  274. audiometa/test/tests/integration/writing/test_partial_update.py +36 -0
  275. audiometa/test/tests/integration/writing/writing_strategies/__init__.py +0 -0
  276. audiometa/test/tests/integration/writing/writing_strategies/test_cleanup_strategy.py +79 -0
  277. audiometa/test/tests/integration/writing/writing_strategies/test_preserve_strategy.py +76 -0
  278. audiometa/test/tests/integration/writing/writing_strategies/test_sync_strategy.py +215 -0
  279. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/__init__.py +0 -0
  280. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_fail_behavior.py +42 -0
  281. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_no_writing_on_failure.py +93 -0
  282. audiometa/test/tests/integration/writing/writing_strategies/unsupported_fields/test_strategy_specific.py +99 -0
  283. audiometa/test/tests/unit/__init__.py +0 -0
  284. audiometa/test/tests/unit/audio_file/__init__.py +0 -0
  285. audiometa/test/tests/unit/audio_file/technical_info/__init__.py +0 -0
  286. audiometa/test/tests/unit/audio_file/technical_info/test_bitrate.py +26 -0
  287. audiometa/test/tests/unit/audio_file/technical_info/test_channels.py +31 -0
  288. audiometa/test/tests/unit/audio_file/technical_info/test_duration_in_sec.py +38 -0
  289. audiometa/test/tests/unit/audio_file/technical_info/test_error_handling.py +190 -0
  290. audiometa/test/tests/unit/audio_file/technical_info/test_file_size.py +51 -0
  291. audiometa/test/tests/unit/audio_file/technical_info/test_format_name.py +28 -0
  292. audiometa/test/tests/unit/audio_file/technical_info/test_sample_rate.py +31 -0
  293. audiometa/test/tests/unit/audio_file/test_context_manager.py +30 -0
  294. audiometa/test/tests/unit/audio_file/test_file_validation.py +40 -0
  295. audiometa/test/tests/unit/audio_file/test_is_audio_file.py +49 -0
  296. audiometa/test/tests/unit/audio_file/test_operations.py +20 -0
  297. audiometa/test/tests/unit/audio_file/test_path_handling.py +23 -0
  298. audiometa/test/tests/unit/cli/__init__.py +0 -0
  299. audiometa/test/tests/unit/cli/test_expand_file_patterns.py +234 -0
  300. audiometa/test/tests/unit/metadata_managers/__init__.py +0 -0
  301. audiometa/test/tests/unit/metadata_managers/conftest.py +142 -0
  302. audiometa/test/tests/unit/metadata_managers/header_info/__init__.py +0 -0
  303. audiometa/test/tests/unit/metadata_managers/header_info/test_id3v1.py +49 -0
  304. audiometa/test/tests/unit/metadata_managers/header_info/test_id3v2.py +66 -0
  305. audiometa/test/tests/unit/metadata_managers/header_info/test_riff.py +343 -0
  306. audiometa/test/tests/unit/metadata_managers/header_info/test_vorbis.py +53 -0
  307. audiometa/test/tests/unit/metadata_managers/metadata_field/__init__.py +0 -0
  308. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/__init__.py +0 -0
  309. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/__init__.py +0 -0
  310. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/reading/test_smart_parsing.py +186 -0
  311. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/__init__.py +0 -0
  312. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_separator_selection.py +142 -0
  313. audiometa/test/tests/unit/metadata_managers/metadata_field/multiple_values/writing/test_value_filtering.py +76 -0
  314. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/__init__.py +0 -0
  315. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/__init__.py +0 -0
  316. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_normalization.py +152 -0
  317. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/reading/test_profiles_values.py +23 -0
  318. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/test_rating_validation.py +77 -0
  319. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/__init__.py +0 -0
  320. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_configuration_error.py +43 -0
  321. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_validation.py +151 -0
  322. audiometa/test/tests/unit/metadata_managers/metadata_field/rating/writing/test_writing_profiles.py +61 -0
  323. audiometa/test/tests/unit/metadata_managers/metadata_field/test_date_format_validation.py +135 -0
  324. audiometa/test/tests/unit/metadata_managers/metadata_field/test_disc_number_validation.py +75 -0
  325. audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_format_validation.py +121 -0
  326. audiometa/test/tests/unit/metadata_managers/metadata_field/test_isrc_type_validation.py +30 -0
  327. audiometa/test/tests/unit/metadata_managers/metadata_field/test_track_number_validation.py +46 -0
  328. audiometa/test/tests/unit/metadata_managers/metadata_field/test_type_validation_exception.py +22 -0
  329. audiometa/test/tests/unit/metadata_managers/metadata_field/test_validation.py +83 -0
  330. audiometa/test/tests/unit/metadata_managers/test_metadata_format_managers_write_and_read.py +74 -0
  331. audiometa/test/tests/unit/metadata_managers/test_riff_configuration_error.py +26 -0
  332. audiometa/utils/__init__.py +1 -0
  333. audiometa/utils/id3v1_genre_code_map.py +205 -0
  334. audiometa/utils/metadata_format.py +31 -0
  335. audiometa/utils/metadata_writing_strategy.py +16 -0
  336. audiometa/utils/mutagen_exception_handler.py +24 -0
  337. audiometa/utils/os_dependencies_checker/__init__.py +24 -0
  338. audiometa/utils/os_dependencies_checker/base.py +62 -0
  339. audiometa/utils/os_dependencies_checker/config.py +77 -0
  340. audiometa/utils/os_dependencies_checker/macos.py +236 -0
  341. audiometa/utils/os_dependencies_checker/ubuntu.py +95 -0
  342. audiometa/utils/os_dependencies_checker/windows.py +227 -0
  343. audiometa/utils/rating_profiles.py +110 -0
  344. audiometa/utils/tool_path_resolver.py +135 -0
  345. audiometa/utils/types.py +82 -0
  346. audiometa/utils/unified_metadata_key.py +87 -0
  347. audiometa_python-0.6.0.dist-info/METADATA +1593 -0
  348. audiometa_python-0.6.0.dist-info/RECORD +352 -0
  349. audiometa_python-0.6.0.dist-info/WHEEL +5 -0
  350. audiometa_python-0.6.0.dist-info/entry_points.txt +2 -0
  351. audiometa_python-0.6.0.dist-info/licenses/LICENSE +202 -0
  352. audiometa_python-0.6.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,60 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata, update_metadata
4
+ from audiometa.exceptions import MetadataFormatNotSupportedByAudioFormatError
5
+ from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
6
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
7
+ from audiometa.utils.metadata_format import MetadataFormat
8
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
9
+
10
+
11
+ @pytest.mark.integration
12
+ class TestMp3Writing:
13
+ def test_writing_default_format_mp3(self):
14
+ with temp_file_with_metadata({}, "mp3") as temp_mp3_file_path:
15
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title Default"}
16
+ update_metadata(temp_mp3_file_path, metadata)
17
+
18
+ id3v2_title = ID3v2MetadataGetter.get_title(temp_mp3_file_path)
19
+ assert id3v2_title == "Test Title Default"
20
+
21
+ def test_id3v1_metadata_writing_mp3(self):
22
+ with temp_file_with_metadata({}, "mp3") as temp_audio_file_path:
23
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title ID3v1"}
24
+ update_metadata(temp_audio_file_path, metadata, metadata_format=MetadataFormat.ID3V1)
25
+ read_metadata = get_unified_metadata(temp_audio_file_path, metadata_format=MetadataFormat.ID3V1)
26
+ assert read_metadata[UnifiedMetadataKey.TITLE] == "Test Title ID3v1"
27
+
28
+ def test_id3v2_3_metadata_writing_mp3(self):
29
+ with temp_file_with_metadata({}, "id3v2.3") as test_file:
30
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title ID3v2.3"}
31
+ update_metadata(test_file, metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0))
32
+ read_metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
33
+ assert read_metadata[UnifiedMetadataKey.TITLE] == "Test Title ID3v2.3"
34
+
35
+ def test_id3v2_4_metadata_writing_mp3(self):
36
+ with temp_file_with_metadata({}, "id3v2.4") as test_file:
37
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title ID3v2.4"}
38
+ update_metadata(test_file, metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0))
39
+ read_metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
40
+ assert read_metadata[UnifiedMetadataKey.TITLE] == "Test Title ID3v2.4"
41
+
42
+ def test_riff_metadata_writing_mp3(self):
43
+ with (
44
+ temp_file_with_metadata({}, "mp3") as test_file,
45
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
46
+ ):
47
+ update_metadata(
48
+ test_file, {UnifiedMetadataKey.TITLE: "Test Title RIFF"}, metadata_format=MetadataFormat.RIFF
49
+ )
50
+
51
+ def test_vorbis_metadata_writing_mp3(self):
52
+ with (
53
+ temp_file_with_metadata({}, "mp3") as test_file,
54
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
55
+ ):
56
+ update_metadata(
57
+ test_file,
58
+ {UnifiedMetadataKey.TITLE: "Test Title Vorbis"},
59
+ metadata_format=MetadataFormat.VORBIS,
60
+ )
@@ -0,0 +1,87 @@
1
+ import pytest
2
+
3
+ from audiometa import delete_all_metadata, get_unified_metadata
4
+ from audiometa.exceptions import MetadataFormatNotSupportedByAudioFormatError
5
+ from audiometa.test.helpers.id3v1 import ID3v1MetadataSetter
6
+ from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.utils.metadata_format import MetadataFormat
9
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
10
+
11
+
12
+ @pytest.mark.integration
13
+ class TestDeleteAllMetadataFormatSpecificWAV:
14
+ def test_delete_all_metadata_formats_wav(self):
15
+ with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
16
+ # Verify ID3v1 has metadata before adding ID3v2
17
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
18
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
19
+
20
+ # Add ID3v2 metadata using external tools for proper test isolation
21
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title", "artist": "ID3V2 Artist"})
22
+
23
+ # Verify ID3v2 has metadata
24
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
25
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
26
+
27
+ # Delete all metadata
28
+ result = delete_all_metadata(test_file)
29
+ assert result is True
30
+
31
+ # Verify both formats were deleted
32
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
33
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
34
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
35
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
36
+
37
+ def test_riff(self):
38
+ with temp_file_with_metadata({"title": "Test RIFF Title", "artist": "Test RIFF Artist"}, "wav") as test_file:
39
+ # Verify RIFF metadata is set
40
+ riff_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
41
+ assert riff_before.get(UnifiedMetadataKey.TITLE) == "Test RIFF Title"
42
+
43
+ result = delete_all_metadata(test_file, metadata_format=MetadataFormat.RIFF)
44
+ assert result is True
45
+
46
+ # Verify RIFF metadata is deleted
47
+ riff_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
48
+ assert riff_after.get(UnifiedMetadataKey.TITLE) is None
49
+
50
+ def test_id3v2(self):
51
+ with temp_file_with_metadata({"title": "Test RIFF Title", "artist": "Test RIFF Artist"}, "wav") as test_file:
52
+ # Add ID3V2 metadata
53
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3V2 Title", "artist": "ID3V2 Artist"})
54
+
55
+ # Verify ID3V2 metadata is set
56
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
57
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3V2 Title"
58
+
59
+ result = delete_all_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
60
+ assert result is True
61
+
62
+ # Verify ID3V2 metadata is deleted
63
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
64
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
65
+
66
+ def test_id3v1(self):
67
+ with temp_file_with_metadata({"title": "Test RIFF Title", "artist": "Test RIFF Artist"}, "wav") as test_file:
68
+ # Add ID3V1 metadata
69
+ ID3v1MetadataSetter.set_metadata(test_file, {"title": "ID3V1 Title", "artist": "ID3V1 Artist"})
70
+
71
+ # Verify ID3V1 metadata is set
72
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
73
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3V1 Title"
74
+
75
+ result = delete_all_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
76
+ assert result is True
77
+
78
+ # Verify ID3V1 metadata is deleted
79
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
80
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
81
+
82
+ def test_vorbis(self):
83
+ with (
84
+ temp_file_with_metadata({"title": "Test RIFF Title", "artist": "Test RIFF Artist"}, "wav") as test_file,
85
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
86
+ ):
87
+ delete_all_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
@@ -0,0 +1,62 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata
4
+ from audiometa.exceptions import MetadataFormatNotSupportedByAudioFormatError
5
+ from audiometa.test.helpers.id3v1.id3v1_metadata_getter import ID3v1MetadataGetter
6
+ from audiometa.test.helpers.id3v1.id3v1_metadata_setter import ID3v1MetadataSetter
7
+ from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
8
+ from audiometa.test.helpers.riff.riff_metadata_setter import RIFFMetadataSetter
9
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
10
+ from audiometa.utils.metadata_format import MetadataFormat
11
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
12
+
13
+
14
+ @pytest.mark.integration
15
+ class TestWavReading:
16
+ def test_all_metadata_reading_wav(self):
17
+ with temp_file_with_metadata({}, "wav") as test_file:
18
+ ID3v1MetadataSetter.set_metadata(test_file, {"title": "a" * 30})
19
+ assert ID3v1MetadataGetter.get_title(test_file) == "a" * 30
20
+
21
+ metadata = get_unified_metadata(test_file)
22
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "a" * 30
23
+
24
+ def test_id3v2_3_metadata_reading_wav(self):
25
+ with temp_file_with_metadata({}, "wav") as test_file:
26
+ ID3v2MetadataSetter.set_metadata(
27
+ test_file, {"title": "ID3v2.3 Long Title That Exceeds ID3v1 Limits"}, version="2.3"
28
+ )
29
+
30
+ metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0))
31
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "ID3v2.3 Long Title That Exceeds ID3v1 Limits"
32
+
33
+ def test_id3v2_4_metadata_reading_wav(self):
34
+ with temp_file_with_metadata({}, "wav") as test_file:
35
+ ID3v2MetadataSetter.set_metadata(
36
+ test_file, {"title": "ID3v2.4 Long Title That Exceeds ID3v1 Limits"}, version="2.4"
37
+ )
38
+
39
+ metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0))
40
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "ID3v2.4 Long Title That Exceeds ID3v1 Limits"
41
+
42
+ def test_id3v1_metadata_reading_wav(self):
43
+ with temp_file_with_metadata({}, "wav") as test_file:
44
+ ID3v1MetadataSetter.set_metadata(test_file, {"title": "a" * 30})
45
+ assert ID3v1MetadataGetter.get_title(test_file) == "a" * 30
46
+
47
+ metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
48
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "a" * 30
49
+
50
+ def test_riff_metadata_reading_wav(self):
51
+ with temp_file_with_metadata({}, "wav") as test_file:
52
+ RIFFMetadataSetter.set_title(test_file, "a" * 30)
53
+
54
+ metadata = get_unified_metadata(test_file, metadata_format=MetadataFormat.RIFF)
55
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "a" * 30
56
+
57
+ def test_vorbis_metadata_reading_wav(self):
58
+ with (
59
+ temp_file_with_metadata({}, "wav") as test_file,
60
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
61
+ ):
62
+ get_unified_metadata(test_file, metadata_format=MetadataFormat.VORBIS)
@@ -0,0 +1,57 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.exceptions import MetadataFormatNotSupportedByAudioFormatError
5
+ from audiometa.test.helpers.id3v1.id3v1_metadata_setter import ID3v1MetadataSetter
6
+ from audiometa.test.helpers.id3v2.id3v2_header_verifier import ID3v2HeaderVerifier
7
+ from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
8
+ from audiometa.test.helpers.riff.riff_metadata_setter import RIFFMetadataSetter
9
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
10
+ from audiometa.utils.metadata_format import MetadataFormat
11
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
12
+
13
+
14
+ @pytest.mark.integration
15
+ class TestWavReading:
16
+ def test_all_metadata_format_reading_wav(self):
17
+ with temp_file_with_metadata({}, "wav") as test_file:
18
+ ID3v1MetadataSetter.set_metadata(test_file, {"title": "Title ID3v1"})
19
+
20
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE)
21
+ assert title == "Title ID3v1"
22
+
23
+ def test_riff_metadata_reading_wav(self):
24
+ with temp_file_with_metadata({}, "wav") as test_file:
25
+ RIFFMetadataSetter.set_title(test_file, "RIFF Small Title")
26
+
27
+ title = get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.RIFF)
28
+ assert title == "RIFF Small Title"
29
+
30
+ def test_id3v2_3_metadata_reading_wav(self):
31
+ with temp_file_with_metadata({}, "id3v2.3") as test_file:
32
+ ID3v2MetadataSetter.set_title(test_file, "ID3v2.3 Long Title That Exceeds RIFF Limits", version="2.3")
33
+
34
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
35
+
36
+ title = get_unified_metadata_field(
37
+ test_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0)
38
+ )
39
+ assert title == "ID3v2.3 Long Title That Exceeds RIFF Limits"
40
+
41
+ def test_id3v2_4_metadata_reading_wav(self):
42
+ with temp_file_with_metadata({}, "id3v2.4") as test_file:
43
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2.4 Long Title That Exceeds RIFF Limits"})
44
+
45
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 4, 0)
46
+
47
+ title = get_unified_metadata_field(
48
+ test_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0)
49
+ )
50
+ assert title == "ID3v2.4 Long Title That Exceeds RIFF Limits"
51
+
52
+ def test_vorbis_metadata_reading_wav(self):
53
+ with (
54
+ temp_file_with_metadata({}, "wav") as test_file,
55
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
56
+ ):
57
+ get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE, metadata_format=MetadataFormat.VORBIS)
@@ -0,0 +1,83 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata, update_metadata
4
+ from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
5
+ from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
6
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
7
+ from audiometa.utils.metadata_format import MetadataFormat
8
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
9
+
10
+
11
+ @pytest.mark.integration
12
+ class TestWavWithId3v2Tags:
13
+ """Test WAV files that have ID3v2 tags, which are placed at the beginning of the file."""
14
+
15
+ def test_wav_with_id3v2_tags_audiofile_instantiation(self):
16
+ # Create a WAV file and add ID3v2 metadata (which places ID3v2 tags at the start)
17
+ with temp_file_with_metadata({}, "wav") as test_file:
18
+ # Write ID3v2 metadata to create the problematic file structure
19
+ id3v2_metadata = {UnifiedMetadataKey.TITLE: "ID3v2 Title"}
20
+ update_metadata(test_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
21
+
22
+ # The key test: _AudioFile instantiation should not fail
23
+ from audiometa._audio_file import _AudioFile
24
+
25
+ audio_file = _AudioFile(test_file) # Should not raise FileCorruptedError
26
+
27
+ # Verify the file is properly recognized as a WAV
28
+ assert audio_file.file_extension == ".wav"
29
+ assert audio_file.get_audio_format_name() == "WAV"
30
+
31
+ def test_wav_with_id3v2_tags_validation_and_reading(self):
32
+ # Create a WAV file with some initial RIFF metadata
33
+ with temp_file_with_metadata(
34
+ {"title": "Original RIFF Title", "artist": "Original RIFF Artist"}, "wav"
35
+ ) as test_file:
36
+ # Verify initial RIFF metadata
37
+ initial_metadata = get_unified_metadata(test_file)
38
+ assert initial_metadata.get(UnifiedMetadataKey.TITLE) == "Original RIFF Title"
39
+ assert initial_metadata.get(UnifiedMetadataKey.ARTISTS) == ["Original RIFF Artist"]
40
+
41
+ # Now write metadata using SYNC strategy (writes to all formats including ID3v2)
42
+ # This will add ID3v2 tags at the beginning of the file while preserving RIFF
43
+ sync_metadata = {
44
+ UnifiedMetadataKey.TITLE: "Sync Title",
45
+ UnifiedMetadataKey.ARTISTS: ["Sync Artist"],
46
+ UnifiedMetadataKey.ALBUM: "Sync Album",
47
+ }
48
+ update_metadata(test_file, sync_metadata)
49
+
50
+ # Verify that the file can still be validated (_AudioFile creation doesn't fail)
51
+ # and that metadata can be read
52
+ final_metadata = get_unified_metadata(test_file)
53
+ assert final_metadata.get(UnifiedMetadataKey.TITLE) == "Sync Title"
54
+ assert final_metadata.get(UnifiedMetadataKey.ARTISTS) == ["Sync Artist"]
55
+ assert final_metadata.get(UnifiedMetadataKey.ALBUM) == "Sync Album"
56
+
57
+ # Verify both ID3v2 and RIFF metadata exist
58
+ id3v2_title = ID3v2MetadataGetter.get_title(test_file)
59
+ riff_title = RIFFMetadataGetter.get_title(test_file)
60
+ assert id3v2_title == "Sync Title"
61
+ assert riff_title == "Sync Title"
62
+
63
+ def test_wav_sync_strategy_with_id3v2_and_riff(self):
64
+ with temp_file_with_metadata({}, "wav") as test_file:
65
+ # Use SYNC strategy (default) to write to all supported formats
66
+ sync_metadata = {
67
+ UnifiedMetadataKey.TITLE: "Sync Title",
68
+ UnifiedMetadataKey.ARTISTS: ["Sync Artist"],
69
+ UnifiedMetadataKey.ALBUM: "Sync Album",
70
+ }
71
+ update_metadata(test_file, sync_metadata)
72
+
73
+ # File should be valid and readable
74
+ metadata = get_unified_metadata(test_file)
75
+ assert metadata.get(UnifiedMetadataKey.TITLE) == "Sync Title"
76
+ assert metadata.get(UnifiedMetadataKey.ARTISTS) == ["Sync Artist"]
77
+ assert metadata.get(UnifiedMetadataKey.ALBUM) == "Sync Album"
78
+
79
+ # Both formats should have the metadata
80
+ id3v2_title = ID3v2MetadataGetter.get_title(test_file)
81
+ riff_title = RIFFMetadataGetter.get_title(test_file)
82
+ assert id3v2_title == "Sync Title"
83
+ assert riff_title == "Sync Title"
@@ -0,0 +1,62 @@
1
+ import pytest
2
+
3
+ from audiometa import update_metadata
4
+ from audiometa.exceptions import MetadataFormatNotSupportedByAudioFormatError
5
+ from audiometa.test.helpers.id3v2.id3v2_header_verifier import ID3v2HeaderVerifier
6
+ from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
7
+ from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
8
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
9
+ from audiometa.utils.metadata_format import MetadataFormat
10
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
11
+
12
+
13
+ @pytest.mark.integration
14
+ class TestWavWriting:
15
+ def test_writing_default_format_wav(self):
16
+ with temp_file_with_metadata({}, "wav") as test_file:
17
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title Default"}
18
+ update_metadata(test_file, metadata)
19
+
20
+ title = RIFFMetadataGetter.get_title(test_file)
21
+ assert title == "Test Title Default"
22
+
23
+ def test_riff_metadata_writing_wav(self):
24
+ with temp_file_with_metadata({}, "wav") as test_file:
25
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title RIFF"}
26
+ update_metadata(test_file, metadata, metadata_format=MetadataFormat.RIFF)
27
+
28
+ title = RIFFMetadataGetter.get_title(test_file)
29
+ assert title == "Test Title RIFF"
30
+
31
+ def test_id3v2_3_metadata_writing_wav(self):
32
+ with temp_file_with_metadata({}, "id3v2.3") as test_file:
33
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title ID3v2.3"}
34
+ update_metadata(
35
+ test_file, unified_metadata=metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0)
36
+ )
37
+
38
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 3, 0)
39
+
40
+ title = ID3v2MetadataGetter.get_title(test_file)
41
+ assert title == "Test Title ID3v2.3"
42
+
43
+ def test_id3v2_4_metadata_writing_wav(self):
44
+ with temp_file_with_metadata({}, "id3v2.4") as test_file:
45
+ metadata = {UnifiedMetadataKey.TITLE: "Test Title ID3v2.4"}
46
+ update_metadata(test_file, metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0))
47
+
48
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 4, 0)
49
+
50
+ title = ID3v2MetadataGetter.get_title(test_file)
51
+ assert title == "Test Title ID3v2.4"
52
+
53
+ def test_vorbis_metadata_writing_wav(self):
54
+ with (
55
+ temp_file_with_metadata({}, "wav") as test_file,
56
+ pytest.raises(MetadataFormatNotSupportedByAudioFormatError),
57
+ ):
58
+ update_metadata(
59
+ test_file,
60
+ {UnifiedMetadataKey.TITLE: "Test Title Vorbis"},
61
+ metadata_format=MetadataFormat.VORBIS,
62
+ )
@@ -0,0 +1,29 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+
6
+ # Test tracks with rating
7
+ @pytest.fixture
8
+ def rating_id3v2_base_100_0_star_wav(assets_dir: Path) -> Path:
9
+ return assets_dir / "rating_id3v2_base 100=0 star.wav"
10
+
11
+
12
+ @pytest.fixture
13
+ def rating_id3v2_base_100_5_star_wav(assets_dir: Path) -> Path:
14
+ return assets_dir / "rating_id3v2_base 100=5 star.wav"
15
+
16
+
17
+ @pytest.fixture
18
+ def rating_id3v2_base_255_5_star_mp3(assets_dir: Path) -> Path:
19
+ return assets_dir / "rating_id3v2_base 255_kid3=5 star.mp3"
20
+
21
+
22
+ @pytest.fixture
23
+ def rating_riff_base_100_5_star_wav(assets_dir: Path) -> Path:
24
+ return assets_dir / "rating_riff_base 100_kid3=5 star.wav"
25
+
26
+
27
+ @pytest.fixture
28
+ def rating_vorbis_base_100_5_star_flac(assets_dir: Path) -> Path:
29
+ return assets_dir / "rating_vorbis=5 star.flac"
@@ -0,0 +1 @@
1
+ """Tests for delete_all_metadata functionality."""
@@ -0,0 +1,102 @@
1
+ import pytest
2
+
3
+ from audiometa import delete_all_metadata, get_unified_metadata
4
+ from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
5
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
6
+ from audiometa.utils.metadata_format import MetadataFormat
7
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
8
+
9
+
10
+ @pytest.mark.integration
11
+ class TestDeleteAllMetadataAllFormats:
12
+ def test_delete_all_metadata_formats_mp3(self):
13
+ with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
14
+ # Verify ID3v1 has metadata before adding ID3v2
15
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
16
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
17
+
18
+ # Add ID3v2 metadata using external tools for proper test isolation
19
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title", "artist": "ID3v2 Artist"})
20
+
21
+ # Verify ID3v2 has metadata
22
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
23
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
24
+
25
+ # Delete all metadata
26
+ result = delete_all_metadata(test_file)
27
+ assert result is True
28
+
29
+ # Verify both formats were deleted
30
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
31
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
32
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
33
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
34
+
35
+ def test_delete_all_metadata_formats_flac(self):
36
+ with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
37
+ # Verify ID3v1 has metadata before adding ID3v2
38
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
39
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
40
+
41
+ # Add ID3v2 metadata using external tools for proper test isolation
42
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title", "artist": "ID3v2 Artist"})
43
+
44
+ # Verify ID3v2 has metadata
45
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
46
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
47
+
48
+ # Delete all metadata
49
+ result = delete_all_metadata(test_file)
50
+ assert result is True
51
+
52
+ # Verify both formats were deleted
53
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
54
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
55
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
56
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
57
+
58
+ def test_delete_all_metadata_formats_wav(self):
59
+ with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
60
+ # Verify ID3v1 has metadata before adding ID3v2
61
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
62
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
63
+
64
+ # Add ID3v2 metadata using external tools for proper test isolation
65
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title", "artist": "ID3v2 Artist"})
66
+
67
+ # Verify ID3v2 has metadata
68
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
69
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
70
+
71
+ # Delete all metadata
72
+ result = delete_all_metadata(test_file)
73
+ assert result is True
74
+
75
+ # Verify both formats were deleted
76
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
77
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
78
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
79
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
80
+
81
+ def test_delete_all_metadata_removes_all_formats(self):
82
+ with temp_file_with_metadata({"title": "ID3v1 Title", "artist": "ID3v1 Artist"}, "id3v1") as test_file:
83
+ # Verify ID3v1 has metadata before adding ID3v2
84
+ id3v1_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
85
+ assert id3v1_before.get(UnifiedMetadataKey.TITLE) == "ID3v1 Title"
86
+
87
+ # Add ID3v2 metadata using external tools for proper test isolation
88
+ ID3v2MetadataSetter.set_metadata(test_file, {"title": "ID3v2 Title", "artist": "ID3v2 Artist"})
89
+
90
+ # Verify ID3v2 has metadata
91
+ id3v2_before = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
92
+ assert id3v2_before.get(UnifiedMetadataKey.TITLE) == "ID3v2 Title"
93
+
94
+ # Delete all metadata
95
+ result = delete_all_metadata(test_file)
96
+ assert result is True
97
+
98
+ # Verify both formats were deleted
99
+ id3v2_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V2)
100
+ id3v1_after = get_unified_metadata(test_file, metadata_format=MetadataFormat.ID3V1)
101
+ assert id3v2_after.get(UnifiedMetadataKey.TITLE) is None
102
+ assert id3v1_after.get(UnifiedMetadataKey.TITLE) is None
@@ -0,0 +1,77 @@
1
+ import pytest
2
+
3
+ from audiometa import delete_all_metadata, update_metadata
4
+ from audiometa.test.helpers.id3v1.id3v1_header_verifier import ID3v1HeaderVerifier
5
+ from audiometa.test.helpers.id3v2.id3v2_header_verifier import ID3v2HeaderVerifier
6
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
7
+ from audiometa.test.helpers.vorbis.vorbis_header_verifier import VorbisHeaderVerifier
8
+ from audiometa.utils.metadata_format import MetadataFormat
9
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
10
+
11
+
12
+ @pytest.mark.integration
13
+ class TestAudioFormatHeaderDeletion:
14
+ def test_header_detection_flac(self):
15
+ with temp_file_with_metadata({"title": "FLAC Test"}, "flac") as flac_file:
16
+ vorbis_metadata = {UnifiedMetadataKey.TITLE: "FLAC Vorbis Title"}
17
+ update_metadata(flac_file, vorbis_metadata, metadata_format=MetadataFormat.VORBIS)
18
+
19
+ id3v2_metadata = {UnifiedMetadataKey.ARTISTS: ["FLAC ID3v2 Artist"]}
20
+ update_metadata(flac_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
21
+
22
+ id3v1_metadata = {UnifiedMetadataKey.ALBUM: "FLAC ID3v1 Album"}
23
+ update_metadata(flac_file, id3v1_metadata, metadata_format=MetadataFormat.ID3V1)
24
+
25
+ assert VorbisHeaderVerifier.has_vorbis_comments(flac_file)
26
+ assert ID3v1HeaderVerifier.has_id3v1_header(flac_file)
27
+ assert ID3v2HeaderVerifier.has_id3v2_header(flac_file)
28
+
29
+ # Test header removal
30
+ result = delete_all_metadata(flac_file)
31
+ assert result is True
32
+
33
+ # After deletion, headers should be removed
34
+ assert not VorbisHeaderVerifier.has_vorbis_comments(flac_file)
35
+ assert not ID3v1HeaderVerifier.has_id3v1_header(flac_file)
36
+ assert not ID3v2HeaderVerifier.has_id3v2_header(flac_file)
37
+
38
+ def test_header_detection_wav(self):
39
+ with temp_file_with_metadata({"title": "WAV Test"}, "wav") as wav_file:
40
+ riff_metadata = {UnifiedMetadataKey.TITLE: "WAV RIFF Title"}
41
+ update_metadata(wav_file, riff_metadata, metadata_format=MetadataFormat.RIFF)
42
+
43
+ id3v2_metadata = {UnifiedMetadataKey.ARTISTS: ["WAV ID3v2 Artist"]}
44
+ update_metadata(wav_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
45
+
46
+ id3v1_metadata = {UnifiedMetadataKey.ALBUM: "WAV ID3v1 Album"}
47
+ update_metadata(wav_file, id3v1_metadata, metadata_format=MetadataFormat.ID3V1)
48
+
49
+ assert ID3v1HeaderVerifier.has_id3v1_header(wav_file)
50
+ assert ID3v2HeaderVerifier.has_id3v2_header(wav_file)
51
+
52
+ # Test header removal
53
+ result = delete_all_metadata(wav_file)
54
+ assert result is True
55
+
56
+ # After deletion, headers should be removed
57
+ assert not ID3v1HeaderVerifier.has_id3v1_header(wav_file)
58
+ assert not ID3v2HeaderVerifier.has_id3v2_header(wav_file)
59
+
60
+ def test_header_detection_mp3(self):
61
+ with temp_file_with_metadata({"title": "MP3 Test"}, "mp3") as mp3_file:
62
+ id3v2_metadata = {UnifiedMetadataKey.TITLE: "MP3 ID3v2 Title"}
63
+ update_metadata(mp3_file, id3v2_metadata, metadata_format=MetadataFormat.ID3V2)
64
+
65
+ id3v1_metadata = {UnifiedMetadataKey.ALBUM: "MP3 ID3v1 Album"}
66
+ update_metadata(mp3_file, id3v1_metadata, metadata_format=MetadataFormat.ID3V1)
67
+
68
+ assert ID3v1HeaderVerifier.has_id3v1_header(mp3_file)
69
+ assert ID3v2HeaderVerifier.has_id3v2_header(mp3_file)
70
+
71
+ # Test header removal
72
+ result = delete_all_metadata(mp3_file)
73
+ assert result is True
74
+
75
+ # After deletion, headers should be removed
76
+ assert not ID3v1HeaderVerifier.has_id3v1_header(mp3_file)
77
+ assert not ID3v2HeaderVerifier.has_id3v2_header(mp3_file)