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,39 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.id3v1 import ID3v1MetadataSetter
5
+ from audiometa.test.helpers.id3v2 import ID3v2MetadataSetter
6
+ from audiometa.test.helpers.riff import RIFFMetadataSetter
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.test.helpers.vorbis import VorbisMetadataSetter
10
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
11
+
12
+
13
+ @pytest.mark.integration
14
+ class TestLanguageReading:
15
+ def test_id3v1(self):
16
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v1") as test_file:
17
+ ID3v1MetadataSetter.set_max_metadata(test_file)
18
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
19
+ assert language is None
20
+
21
+ def test_id3v2(self):
22
+ with temp_file_with_metadata({"title": "Test Song"}, "mp3") as test_file:
23
+ ID3v2MetadataSetter.set_max_metadata(test_file)
24
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
25
+ assert language == "a" * 1000
26
+
27
+ def test_vorbis(self):
28
+ with temp_file_with_metadata({"title": "Test Song"}, "flac") as test_file:
29
+ VorbisMetadataSetter.set_max_metadata(test_file)
30
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
31
+ assert language == "a" * 1000
32
+
33
+ def test_riff(self):
34
+ with temp_file_with_metadata({"title": "Test Song"}, "wav") as test_file:
35
+ RIFFMetadataSetter.set_language(test_file, "en")
36
+ assert "TAG:language=en" in RIFFMetadataGetter.get_raw_metadata(test_file)
37
+
38
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
39
+ assert language == "en"
@@ -0,0 +1,43 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field, update_metadata
4
+ from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
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 TestLanguageWriting:
12
+ def test_id3v2(self):
13
+ with temp_file_with_metadata({}, "mp3") as test_file:
14
+ test_language = "en"
15
+ test_metadata = {UnifiedMetadataKey.LANGUAGE: test_language}
16
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
17
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
18
+ assert language == test_language
19
+
20
+ def test_riff(self):
21
+ with temp_file_with_metadata({}, "wav") as test_file:
22
+ test_language = "fr"
23
+ test_metadata = {UnifiedMetadataKey.LANGUAGE: test_language}
24
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.RIFF)
25
+
26
+ raw_metadata = RIFFMetadataGetter.get_raw_metadata(test_file)
27
+ assert "TAG:language=fr" in raw_metadata
28
+
29
+ def test_vorbis(self):
30
+ with temp_file_with_metadata({}, "flac") as test_file:
31
+ test_language = "de"
32
+ test_metadata = {UnifiedMetadataKey.LANGUAGE: test_language}
33
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.VORBIS)
34
+ language = get_unified_metadata_field(test_file, UnifiedMetadataKey.LANGUAGE)
35
+ assert language == test_language
36
+
37
+ def test_invalid_type_raises(self):
38
+ from audiometa.exceptions import InvalidMetadataFieldTypeError
39
+
40
+ with temp_file_with_metadata({}, "mp3") as test_file:
41
+ bad_metadata = {UnifiedMetadataKey.LANGUAGE: 123}
42
+ with pytest.raises(InvalidMetadataFieldTypeError):
43
+ update_metadata(test_file, bad_metadata)
@@ -0,0 +1,129 @@
1
+ import pytest
2
+
3
+ from audiometa import update_metadata
4
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
5
+ from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
6
+ from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.test.helpers.vorbis.vorbis_metadata_getter import VorbisMetadataGetter
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 TestLyricsDeleting:
15
+ def test_delete_lyrics_id3v1(self):
16
+ with (
17
+ temp_file_with_metadata({}, "mp3") as test_file,
18
+ pytest.raises(
19
+ MetadataFieldNotSupportedByMetadataFormatError,
20
+ match="UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS metadata not supported by ID3v1 format",
21
+ ),
22
+ ):
23
+ update_metadata(
24
+ test_file,
25
+ {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: "Test lyrics"},
26
+ metadata_format=MetadataFormat.ID3V1,
27
+ )
28
+
29
+ def test_delete_lyrics_id3v2_3(self):
30
+ with temp_file_with_metadata({}, "id3v2.3") as test_file:
31
+ ID3v2MetadataSetter.set_lyrics(test_file, "Test lyrics", version="2.3")
32
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
33
+ # 4 null bytes because of missing language
34
+ assert raw_metadata["USLT"] == ["\x00\x00\x00\x00Test lyrics"]
35
+
36
+ update_metadata(
37
+ test_file,
38
+ {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None},
39
+ metadata_format=MetadataFormat.ID3V2,
40
+ id3v2_version=(2, 3, 0),
41
+ )
42
+
43
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
44
+ assert raw_metadata.get("USLT") is None
45
+
46
+ def test_delete_lyrics_id3v2_4(self):
47
+ with temp_file_with_metadata({}, "id3v2.4") as test_file:
48
+ ID3v2MetadataSetter.set_lyrics(test_file, "Test lyrics", version="2.4")
49
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.4")
50
+ assert raw_metadata["USLT"] == ["eng\x00Test lyrics"]
51
+
52
+ update_metadata(
53
+ test_file,
54
+ {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None},
55
+ metadata_format=MetadataFormat.ID3V2,
56
+ id3v2_version=(2, 4, 0),
57
+ )
58
+
59
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.4")
60
+ assert raw_metadata.get("USLT") is None
61
+
62
+ def test_delete_lyrics_riff(self):
63
+ with temp_file_with_metadata({}, "wav") as test_file:
64
+ from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
65
+ from audiometa.test.helpers.riff.riff_metadata_setter import RIFFMetadataSetter
66
+
67
+ RIFFMetadataSetter.set_lyrics(test_file, "Test lyrics")
68
+ raw_metadata = RIFFMetadataGetter.get_raw_metadata(test_file)
69
+ assert "TAG:lyrics=Test lyrics" in raw_metadata
70
+
71
+ update_metadata(
72
+ test_file, {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None}, metadata_format=MetadataFormat.RIFF
73
+ )
74
+
75
+ raw_metadata = RIFFMetadataGetter.get_raw_metadata(test_file)
76
+ assert "TAG:lyrics=" not in raw_metadata
77
+
78
+ def test_delete_lyrics_vorbis(self):
79
+ with temp_file_with_metadata({}, "flac") as test_file:
80
+ from audiometa.test.helpers.vorbis.vorbis_metadata_setter import VorbisMetadataSetter
81
+
82
+ VorbisMetadataSetter.set_lyrics(test_file, "Test lyrics")
83
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
84
+ assert "LYRICS=Test lyrics" in raw_metadata
85
+
86
+ update_metadata(
87
+ test_file, {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None}, metadata_format=MetadataFormat.VORBIS
88
+ )
89
+
90
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
91
+ assert "LYRICS=" not in raw_metadata
92
+
93
+ def test_delete_lyrics_preserves_other_fields(self):
94
+ with temp_file_with_metadata({}, "mp3") as test_file:
95
+ # Set multiple metadata fields using helper methods
96
+ ID3v2MetadataSetter.set_lyrics(test_file, "Test lyrics")
97
+ ID3v2MetadataSetter.set_title(test_file, "Test Title")
98
+ ID3v2MetadataSetter.set_artists(test_file, "Test Artist")
99
+
100
+ # Delete only lyrics using library API
101
+ update_metadata(
102
+ test_file, {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None}, metadata_format=MetadataFormat.ID3V2
103
+ )
104
+
105
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file)
106
+ assert raw_metadata is None
107
+
108
+ def test_delete_lyrics_already_none(self):
109
+ with temp_file_with_metadata({}, "flac") as test_file:
110
+ # Try to delete lyrics that don't exist
111
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
112
+ assert "LYRICS=" not in raw_metadata
113
+
114
+ update_metadata(
115
+ test_file, {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: None}, metadata_format=MetadataFormat.VORBIS
116
+ )
117
+
118
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
119
+ assert "LYRICS=" not in raw_metadata
120
+
121
+ def test_delete_lyrics_empty_string(self):
122
+ from audiometa import get_unified_metadata_field
123
+
124
+ with temp_file_with_metadata({}, "mp3") as test_file:
125
+ update_metadata(
126
+ test_file, {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: ""}, metadata_format=MetadataFormat.ID3V2
127
+ )
128
+ lyrics = get_unified_metadata_field(test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS)
129
+ assert lyrics is None
@@ -0,0 +1,57 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
5
+ from audiometa.test.helpers.id3v2.id3v2_metadata_setter import ID3v2MetadataSetter
6
+ from audiometa.test.helpers.riff.riff_metadata_setter import RIFFMetadataSetter
7
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
8
+ from audiometa.test.helpers.vorbis.vorbis_metadata_setter import VorbisMetadataSetter
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 TestLyricsReading:
15
+ def test_id3v1(self):
16
+ with (
17
+ temp_file_with_metadata({"title": "Test Song"}, "id3v1") as test_file,
18
+ pytest.raises(
19
+ MetadataFieldNotSupportedByMetadataFormatError,
20
+ match="UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS metadata not supported by ID3v1 format",
21
+ ),
22
+ ):
23
+ get_unified_metadata_field(
24
+ test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS, metadata_format=MetadataFormat.ID3V1
25
+ )
26
+
27
+ def test_id3v2_3(self):
28
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v2.3") as test_file:
29
+ ID3v2MetadataSetter.set_lyrics(test_file, "a" * 4000, version="2.3")
30
+ lyrics = get_unified_metadata_field(
31
+ test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS, metadata_format=MetadataFormat.ID3V2
32
+ )
33
+ assert lyrics == "a" * 4000
34
+
35
+ def test_id3v2_4(self):
36
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v2.4") as test_file:
37
+ ID3v2MetadataSetter.set_lyrics(test_file, "a" * 4000, version="2.4")
38
+ lyrics = get_unified_metadata_field(
39
+ test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS, metadata_format=MetadataFormat.ID3V2
40
+ )
41
+ assert lyrics == "a" * 4000
42
+
43
+ def test_vorbis(self):
44
+ with temp_file_with_metadata({"title": "Test Song"}, "flac") as test_file:
45
+ VorbisMetadataSetter.set_lyrics(test_file, "a" * 4000)
46
+ lyrics = get_unified_metadata_field(
47
+ test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS, metadata_format=MetadataFormat.VORBIS
48
+ )
49
+ assert lyrics == "a" * 4000
50
+
51
+ def test_riff(self):
52
+ with temp_file_with_metadata({"title": "Test Song"}, "wav") as test_file:
53
+ RIFFMetadataSetter.set_lyrics(test_file, "a" * 4000)
54
+ lyrics = get_unified_metadata_field(
55
+ test_file, UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS, metadata_format=MetadataFormat.RIFF
56
+ )
57
+ assert lyrics == "a" * 4000
@@ -0,0 +1,59 @@
1
+ import pytest
2
+
3
+ from audiometa import update_metadata
4
+ from audiometa.test.helpers.id3v2.id3v2_header_verifier import ID3v2HeaderVerifier
5
+ from audiometa.test.helpers.id3v2.id3v2_metadata_getter import ID3v2MetadataGetter
6
+ from audiometa.test.helpers.riff.riff_metadata_getter import RIFFMetadataGetter
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 TestLyricsWriting:
14
+ def test_id3v2_3_default_en(self):
15
+ with temp_file_with_metadata({}, "mp3") as test_file:
16
+ test_lyrics = "These are test lyrics\nWith multiple lines\nFor testing purposes"
17
+ test_metadata = {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: test_lyrics}
18
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 3, 0))
19
+
20
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.3")
21
+ assert [f"eng\x00{test_lyrics}"] == raw_metadata["USLT"]
22
+
23
+ def test_id3v2_4_default_en(self):
24
+ with temp_file_with_metadata({}, "mp3") as test_file:
25
+ test_lyrics = "These are test lyrics\nWith multiple lines\nFor testing purposes"
26
+ test_metadata = {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: test_lyrics}
27
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2, id3v2_version=(2, 4, 0))
28
+
29
+ assert ID3v2HeaderVerifier.get_id3v2_version(test_file) == (2, 4, 0)
30
+ raw_metadata = ID3v2MetadataGetter.get_raw_metadata(test_file, version="2.4")
31
+ assert [f"eng\x00{test_lyrics}"] == raw_metadata["USLT"]
32
+
33
+ def test_riff(self):
34
+ with temp_file_with_metadata({}, "wav") as test_file:
35
+ test_lyrics = "RIFF test lyrics\nWith multiple lines\nFor testing purposes"
36
+ test_metadata = {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: test_lyrics}
37
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.RIFF)
38
+
39
+ raw_metadata = RIFFMetadataGetter.get_raw_metadata(test_file)
40
+ assert f"TAG:lyrics={test_lyrics}" in raw_metadata
41
+
42
+ def test_vorbis(self):
43
+ from audiometa.test.helpers.vorbis.vorbis_metadata_getter import VorbisMetadataGetter
44
+
45
+ with temp_file_with_metadata({}, "flac") as test_file:
46
+ test_lyrics = "Vorbis test lyrics\nWith multiple lines\nFor testing purposes"
47
+ test_metadata = {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: test_lyrics}
48
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.VORBIS)
49
+
50
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
51
+ assert f"LYRICS={test_lyrics}" in raw_metadata
52
+
53
+ def test_invalid_type_raises(self):
54
+ from audiometa.exceptions import InvalidMetadataFieldTypeError
55
+
56
+ with temp_file_with_metadata({}, "mp3") as test_file:
57
+ bad_metadata = {UnifiedMetadataKey.UNSYNCHRONIZED_LYRICS: 12345}
58
+ with pytest.raises(InvalidMetadataFieldTypeError):
59
+ update_metadata(test_file, bad_metadata)
@@ -0,0 +1,88 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field, update_metadata
4
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
5
+ from audiometa.utils.metadata_format import MetadataFormat
6
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
+
8
+
9
+ @pytest.mark.integration
10
+ class TestPublisherDeleting:
11
+ def test_delete_publisher_id3v2(self):
12
+ with temp_file_with_metadata({}, "mp3") as test_file:
13
+ update_metadata(
14
+ test_file, {UnifiedMetadataKey.PUBLISHER: "Test Publisher"}, metadata_format=MetadataFormat.ID3V2
15
+ )
16
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) == "Test Publisher"
17
+
18
+ update_metadata(test_file, {UnifiedMetadataKey.PUBLISHER: None}, metadata_format=MetadataFormat.ID3V2)
19
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) is None
20
+
21
+ def test_delete_publisher_id3v1(self):
22
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
23
+
24
+ with (
25
+ temp_file_with_metadata({}, "mp3") as test_file,
26
+ pytest.raises(
27
+ MetadataFieldNotSupportedByMetadataFormatError,
28
+ match="UnifiedMetadataKey.PUBLISHER metadata not supported by ID3v1 format",
29
+ ),
30
+ ):
31
+ update_metadata(
32
+ test_file,
33
+ {UnifiedMetadataKey.PUBLISHER: "Test Publisher"},
34
+ metadata_format=MetadataFormat.ID3V1,
35
+ )
36
+
37
+ def test_delete_publisher_riff(self):
38
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
39
+
40
+ with (
41
+ temp_file_with_metadata({}, "wav") as test_file,
42
+ pytest.raises(
43
+ MetadataFieldNotSupportedByMetadataFormatError,
44
+ match="UnifiedMetadataKey.PUBLISHER metadata not supported by RIFF format",
45
+ ),
46
+ ):
47
+ update_metadata(
48
+ test_file,
49
+ {UnifiedMetadataKey.PUBLISHER: "Test Publisher"},
50
+ metadata_format=MetadataFormat.RIFF,
51
+ )
52
+
53
+ def test_delete_publisher_vorbis(self):
54
+ with temp_file_with_metadata({}, "flac") as test_file:
55
+ update_metadata(
56
+ test_file, {UnifiedMetadataKey.PUBLISHER: "Test Publisher"}, metadata_format=MetadataFormat.VORBIS
57
+ )
58
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) == "Test Publisher"
59
+
60
+ update_metadata(test_file, {UnifiedMetadataKey.PUBLISHER: None}, metadata_format=MetadataFormat.VORBIS)
61
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) is None
62
+
63
+ def test_delete_publisher_preserves_other_fields(self):
64
+ with temp_file_with_metadata({}, "mp3") as test_file:
65
+ update_metadata(
66
+ test_file,
67
+ {
68
+ UnifiedMetadataKey.PUBLISHER: "Test Publisher",
69
+ UnifiedMetadataKey.TITLE: "Test Title",
70
+ UnifiedMetadataKey.ARTISTS: ["Test Artist"],
71
+ },
72
+ )
73
+
74
+ update_metadata(test_file, {UnifiedMetadataKey.PUBLISHER: None})
75
+
76
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) is None
77
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.TITLE) == "Test Title"
78
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.ARTISTS) == ["Test Artist"]
79
+
80
+ def test_delete_publisher_already_none(self):
81
+ with temp_file_with_metadata({}, "mp3") as test_file:
82
+ update_metadata(test_file, {UnifiedMetadataKey.PUBLISHER: None})
83
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) is None
84
+
85
+ def test_delete_publisher_empty_string(self):
86
+ with temp_file_with_metadata({}, "mp3") as test_file:
87
+ update_metadata(test_file, {UnifiedMetadataKey.PUBLISHER: ""}, metadata_format=MetadataFormat.ID3V2)
88
+ assert get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER) is None
@@ -0,0 +1,32 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field
4
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
5
+ from audiometa.test.helpers.vorbis.vorbis_metadata_getter import VorbisMetadataGetter
6
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
+
8
+
9
+ @pytest.mark.integration
10
+ class TestPublisherReading:
11
+ def test_id3v1(self):
12
+ with temp_file_with_metadata({"title": "Test Song"}, "id3v1") as test_file:
13
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
14
+ assert publisher is None
15
+
16
+ def test_id3v2(self):
17
+ with temp_file_with_metadata({"title": "Test Song", "publisher": "Test Publisher"}, "mp3") as test_file:
18
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
19
+ assert publisher == "Test Publisher"
20
+
21
+ def test_vorbis(self):
22
+ with temp_file_with_metadata({"title": "Test Song", "publisher": "Test Publisher"}, "flac") as test_file:
23
+ raw_metadata = VorbisMetadataGetter.get_raw_metadata(test_file)
24
+ assert "PUBLISHER=Test Publisher" in raw_metadata
25
+
26
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
27
+ assert publisher == "Test Publisher"
28
+
29
+ def test_riff(self):
30
+ with temp_file_with_metadata({"title": "Test Song"}, "wav") as test_file:
31
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
32
+ assert publisher is None
@@ -0,0 +1,47 @@
1
+ import pytest
2
+
3
+ from audiometa import get_unified_metadata_field, update_metadata
4
+ from audiometa.test.helpers.temp_file_with_metadata import temp_file_with_metadata
5
+ from audiometa.utils.metadata_format import MetadataFormat
6
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
+
8
+
9
+ @pytest.mark.integration
10
+ class TestPublisherWriting:
11
+ def test_id3v2(self):
12
+ with temp_file_with_metadata({}, "mp3") as test_file:
13
+ test_publisher = "Test Publisher ID3v2"
14
+ test_metadata = {UnifiedMetadataKey.PUBLISHER: test_publisher}
15
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.ID3V2)
16
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
17
+ assert publisher == test_publisher
18
+
19
+ def test_riff(self):
20
+ from audiometa.exceptions import MetadataFieldNotSupportedByMetadataFormatError
21
+
22
+ with temp_file_with_metadata({}, "wav") as test_file:
23
+ test_publisher = "Test Publisher RIFF"
24
+ test_metadata = {UnifiedMetadataKey.PUBLISHER: test_publisher}
25
+
26
+ # RIFF format raises exception for unsupported metadata
27
+ with pytest.raises(
28
+ MetadataFieldNotSupportedByMetadataFormatError,
29
+ match="UnifiedMetadataKey.PUBLISHER metadata not supported by RIFF format",
30
+ ):
31
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.RIFF)
32
+
33
+ def test_vorbis(self):
34
+ with temp_file_with_metadata({}, "flac") as test_file:
35
+ test_publisher = "Test Publisher Vorbis"
36
+ test_metadata = {UnifiedMetadataKey.PUBLISHER: test_publisher}
37
+ update_metadata(test_file, test_metadata, metadata_format=MetadataFormat.VORBIS)
38
+ publisher = get_unified_metadata_field(test_file, UnifiedMetadataKey.PUBLISHER)
39
+ assert publisher == test_publisher
40
+
41
+ def test_invalid_type_raises(self):
42
+ from audiometa.exceptions import InvalidMetadataFieldTypeError
43
+
44
+ with temp_file_with_metadata({}, "mp3") as test_file:
45
+ bad_metadata = {UnifiedMetadataKey.PUBLISHER: 123}
46
+ with pytest.raises(InvalidMetadataFieldTypeError):
47
+ update_metadata(test_file, bad_metadata)
@@ -0,0 +1,81 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+ from audiometa import get_unified_metadata
6
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
+
8
+
9
+ @pytest.mark.integration
10
+ class TestBase100Proportional:
11
+ @pytest.mark.parametrize(
12
+ ("star_rating", "expected_normalized_rating"),
13
+ [
14
+ (0, 0),
15
+ (0.5, 10),
16
+ (1, 20),
17
+ (1.5, 30),
18
+ (2, 40),
19
+ (2.5, 50),
20
+ (3, 60),
21
+ (3.5, 70),
22
+ (4, 80),
23
+ (4.5, 90),
24
+ (5, 100),
25
+ ],
26
+ )
27
+ def test_vorbis(self, assets_dir: Path, star_rating, expected_normalized_rating):
28
+ file_path = assets_dir / f"rating_vorbis={star_rating} star.flac"
29
+ metadata = get_unified_metadata(file_path, normalized_rating_max_value=100)
30
+ rating = metadata.get(UnifiedMetadataKey.RATING)
31
+ assert rating is not None
32
+ assert isinstance(rating, int | float)
33
+ assert rating == expected_normalized_rating
34
+
35
+ @pytest.mark.parametrize(
36
+ ("star_rating", "expected_normalized_rating"),
37
+ [
38
+ (0, 0),
39
+ (0.5, 10),
40
+ (1, 20),
41
+ (1.5, 30),
42
+ (2, 40),
43
+ (2.5, 50),
44
+ (3, 60),
45
+ (3.5, 70),
46
+ (4, 80),
47
+ (4.5, 90),
48
+ (5, 100),
49
+ ],
50
+ )
51
+ def test_id3v2(self, assets_dir: Path, star_rating, expected_normalized_rating):
52
+ file_path = assets_dir / f"rating_id3v2_base 100={star_rating} star.wav"
53
+ metadata = get_unified_metadata(file_path, normalized_rating_max_value=100)
54
+ rating = metadata.get(UnifiedMetadataKey.RATING)
55
+ assert rating is not None
56
+ assert isinstance(rating, int | float)
57
+ assert rating == expected_normalized_rating
58
+
59
+ @pytest.mark.parametrize(
60
+ ("star_rating", "expected_normalized_rating"),
61
+ [
62
+ (1, 20),
63
+ (2, 40),
64
+ (3, 60),
65
+ (4, 80),
66
+ (5, 100),
67
+ ],
68
+ )
69
+ def test_wav_riff(self, assets_dir: Path, star_rating, expected_normalized_rating):
70
+ file_path = assets_dir / f"rating_riff_base 100_kid3={star_rating} star.wav"
71
+ metadata = get_unified_metadata(file_path, normalized_rating_max_value=100)
72
+ rating = metadata.get(UnifiedMetadataKey.RATING)
73
+ assert rating is not None
74
+ assert isinstance(rating, int | float)
75
+ assert rating == expected_normalized_rating
76
+
77
+ def test_none_rating_wav_riff(self, assets_dir: Path):
78
+ file_path = assets_dir / "rating_riff_kid3=none.wav"
79
+ metadata = get_unified_metadata(file_path, normalized_rating_max_value=100)
80
+ rating = metadata.get(UnifiedMetadataKey.RATING)
81
+ assert rating is None
@@ -0,0 +1,33 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+
5
+ from audiometa import get_unified_metadata
6
+ from audiometa.utils.unified_metadata_key import UnifiedMetadataKey
7
+
8
+
9
+ @pytest.mark.integration
10
+ class TestBase255NonProportional:
11
+ @pytest.mark.parametrize(
12
+ ("star_rating", "expected_normalized_rating"),
13
+ [
14
+ (0, 0),
15
+ (0.5, 10),
16
+ (1, 20),
17
+ (1.5, 30),
18
+ (2, 40),
19
+ (2.5, 50),
20
+ (3, 60),
21
+ (3.5, 70),
22
+ (4, 80),
23
+ (4.5, 90),
24
+ (5, 100),
25
+ ],
26
+ )
27
+ def test_id3v2_mp3(self, assets_dir: Path, star_rating, expected_normalized_rating):
28
+ file_path = assets_dir / f"rating_id3v2={star_rating} star.mp3"
29
+ metadata = get_unified_metadata(file_path, normalized_rating_max_value=100)
30
+ rating = metadata.get(UnifiedMetadataKey.RATING)
31
+ assert rating is not None
32
+ assert isinstance(rating, int | float)
33
+ assert rating == expected_normalized_rating