diff --git a/api/funkwhale_api/music/metadata.py b/api/funkwhale_api/music/metadata.py index 4084dccd7..d74511be3 100644 --- a/api/funkwhale_api/music/metadata.py +++ b/api/funkwhale_api/music/metadata.py @@ -4,6 +4,7 @@ import logging from collections.abc import Mapping import arrow +import magic import mutagen._util import mutagen.flac import mutagen.oggtheora @@ -131,6 +132,28 @@ def clean_flac_pictures(apic): return pictures +def clean_ogg_coverart(metadata_block_picture): + pictures = [] + for b64_data in [metadata_block_picture]: + try: + data = base64.b64decode(b64_data) + except (TypeError, ValueError): + continue + + mime = magic.Magic(mime=True) + mime.from_buffer(data) + + pictures.append( + { + "mimetype": mime.from_buffer(data), + "content": data, + "description": "", + "type": mutagen.id3.PictureType.COVER_FRONT, + } + ) + return pictures + + def clean_ogg_pictures(metadata_block_picture): pictures = [] for b64_data in [metadata_block_picture]: @@ -196,10 +219,16 @@ CONF = { "license": {}, "copyright": {}, "genre": {}, - "pictures": { - "field": "metadata_block_picture", - "to_application": clean_ogg_pictures, - }, + "pictures": [ + { + "field": "metadata_block_picture", + "to_application": clean_ogg_pictures, + }, + { + "field": "coverart", + "to_application": clean_ogg_coverart, + }, + ], "comment": {"field": "comment"}, }, }, @@ -221,10 +250,16 @@ CONF = { "license": {}, "copyright": {}, "genre": {}, - "pictures": { - "field": "metadata_block_picture", - "to_application": clean_ogg_pictures, - }, + "pictures": [ + { + "field": "metadata_block_picture", + "to_application": clean_ogg_pictures, + }, + { + "field": "coverart", + "to_application": clean_ogg_coverart, + }, + ], "comment": {"field": "comment"}, }, }, @@ -415,25 +450,30 @@ class Metadata(Mapping): def _get_from_self(self, key, default=NODEFAULT): try: - field_conf = self._conf["fields"][key] + field_confs = self._conf["fields"][key] except KeyError: raise UnsupportedTag(f"{key} is not supported for this file format") - real_key = field_conf.get("field", key) - try: - getter = field_conf.get("getter", self._conf["getter"]) - v = getter(self._file, real_key) - except KeyError: - if default == NODEFAULT: - raise TagNotFound(real_key) - return default + if not isinstance(field_confs, list): + field_confs = [field_confs] - converter = field_conf.get("to_application") - if converter: - v = converter(v) - field = VALIDATION.get(key) - if field: - v = field.to_python(v) - return v + for field_conf in field_confs: + real_key = field_conf.get("field", key) + try: + getter = field_conf.get("getter", self._conf["getter"]) + v = getter(self._file, real_key) + except KeyError: + continue + + converter = field_conf.get("to_application") + if converter: + v = converter(v) + field = VALIDATION.get(key) + if field: + v = field.to_python(v) + return v + if default == NODEFAULT: + raise TagNotFound(real_key) + return default def get_picture(self, *picture_types): if not picture_types: diff --git a/api/tests/music/test_coverart.ogg b/api/tests/music/test_coverart.ogg new file mode 100644 index 000000000..485175e77 Binary files /dev/null and b/api/tests/music/test_coverart.ogg differ diff --git a/api/tests/music/test_metadata.py b/api/tests/music/test_metadata.py index 29eb27e24..62a5489c5 100644 --- a/api/tests/music/test_metadata.py +++ b/api/tests/music/test_metadata.py @@ -187,6 +187,7 @@ def test_can_get_metadata_from_id3_aiff_file(field, value): "with_cover.ogg", "with_cover.opus", "test.m4a", + "test_coverart.ogg", ], ) def test_can_get_pictures(name): diff --git a/changes/changelog.d/2376.feature b/changes/changelog.d/2376.feature new file mode 100644 index 000000000..04f86d54b --- /dev/null +++ b/changes/changelog.d/2376.feature @@ -0,0 +1 @@ +Add support for deprecated COVERART fields in ogg files. diff --git a/docs/administrator/import.md b/docs/administrator/import.md index 6273d5aa5..39fa4d510 100644 --- a/docs/administrator/import.md +++ b/docs/administrator/import.md @@ -200,7 +200,7 @@ Funkwhale imports the music in your storage directory into the specified library Funkwhale attempts to import album art for your music library. The import process checks for the following. -1. The cover embedded in the audio files (works with FLAC and MP3 files). +1. The cover embedded in the audio files (works with FLAC, OGG, MP3 and MP4 files, possibly others). 2. A `cover.jpg` or `cover.png` in the the track's directory. 3. An `mbid` in the file's tags. If there is an `mbid`, the import process tries to fetch cover art from Musicbrainz.