1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-11-09 19:52:16 +00:00

Art extraction is now done as a method of Track; cover_art() only extracts cover art if given a track ID; Cache embeded art

This commit is contained in:
Taizo Simpson 2018-10-08 20:05:45 -04:00
parent 7106d95cee
commit 4bbcbd0acf
No known key found for this signature in database
GPG Key ID: D197B1197B2D4D68
3 changed files with 47 additions and 34 deletions

View File

@ -7,15 +7,12 @@
#
# Distributed under terms of the GNU AGPLv3 license.
import base64
import codecs
import mimetypes
import mutagen
import os.path
import requests
import shlex
import subprocess
import tempfile
from flask import request, Response, send_file
from flask import current_app
@ -134,27 +131,27 @@ def download_media():
@api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ])
def cover_art():
res = get_entity(Folder)
if not res.cover_art or not os.path.isfile(os.path.join(res.path, res.cover_art)):
# Check for embeded metadata in songs
temp_cover = tempfile.NamedTemporaryFile()
cover_path = temp_cover.name
for track in res.tracks:
song = mutagen.File(track.path)
if isinstance(song.tags, mutagen.id3.ID3Tags) and len(song.tags.getall('APIC')) > 0:
temp_cover.write(song.tags.getall('APIC')[0].data)
break
elif isinstance(song, mutagen.flac.FLAC) and len(song.pictures):
temp_cover.write(song.pictures[0].data)
break
elif isinstance(song.tags, mutagen._vorbis.VCommentDict) and 'METADATA_BLOCK_PICTURE' in song.tags and len(song.tags['METADATA_BLOCK_PICTURE']) > 0:
picture = mutagen.flac.Picture(base64.b64decode(song.tags['METADATA_BLOCK_PICTURE'][0]))
temp_cover.write(picture.data)
break
else:
eid = request.values['id']
if Folder.exists(id=eid):
res = get_entity(Folder)
if not res.cover_art or not os.path.isfile(os.path.join(res.path, res.cover_art)):
raise NotFound('Cover art')
else:
cover_path = os.path.join(res.path, res.cover_art)
elif Track.exists(id=eid):
embed_cache = os.path.join(current_app.config['WEBAPP']['cache_dir'], 'embeded_art')
cover_path = os.path.join(embed_cache, eid)
if not os.path.exists(cover_path):
res = get_entity(Track)
art = res.extract_cover_art()
if not art:
raise NotFound('Cover art')
#Art found, save to cache
os.makedirs(embed_cache, exist_ok=True)
with open(cover_path, 'wb') as cover_file:
cover_file.write(art)
else:
raise NotFound('Entity')
size = request.values.get('size')
if size:
size = int(size)
@ -234,4 +231,3 @@ def read_file_as_unicode(path):
# Fallback to ASCII
current_app.logger.debug('Reading file {} with ascii encoding'.format(path))
return unicode(open(path, 'r').read())

View File

@ -7,8 +7,10 @@
#
# Distributed under terms of the GNU AGPLv3 license.
import base64
import importlib
import mimetypes
import mutagen
import os.path
import pkg_resources
import time
@ -101,6 +103,11 @@ class Folder(PathMixin, db.Entity):
info['artist'] = self.parent.name
if self.cover_art:
info['coverArt'] = str(self.id)
else:
for track in self.tracks:
if track.extract_cover_art():
info['coverArt'] = str(track.id)
break
try:
starred = StarredFolder[user.id, self.id]
@ -259,7 +266,9 @@ class Track(PathMixin, db.Entity):
info['year'] = self.year
if self.genre:
info['genre'] = self.genre
if self.folder.cover_art:
if self.extract_cover_art():
info['coverArt'] = str(self.id)
elif self.folder.cover_art:
info['coverArt'] = str(self.folder.id)
try:
@ -293,6 +302,20 @@ class Track(PathMixin, db.Entity):
def sort_key(self):
return (self.album.artist.name + self.album.name + ("%02i" % self.disc) + ("%02i" % self.number) + self.title).lower()
def extract_cover_art(self):
if os.path.exists(self.path):
metadata = mutagen.File(self.path)
data = None
if metadata:
if isinstance(metadata.tags, mutagen.id3.ID3Tags) and len(metadata.tags.getall('APIC')) > 0:
return metadata.tags.getall('APIC')[0].data
elif isinstance(metadata, mutagen.flac.FLAC) and len(metadata.pictures):
return metadata.pictures[0].data
elif isinstance(metadata.tags, mutagen._vorbis.VCommentDict) and 'METADATA_BLOCK_PICTURE' in metadata.tags and len(metadata.tags['METADATA_BLOCK_PICTURE']) > 0:
picture = mutagen.flac.Picture(base64.b64decode(metadata.tags['METADATA_BLOCK_PICTURE'][0]))
return picture.data
return None
class User(db.Entity):
_table_ = 'user'

View File

@ -32,13 +32,6 @@ class MediaTestCase(ApiTestBase):
)
self.folderid = folder.id
folder_embeded_art = Folder(
name = 'Root',
path = os.path.abspath('tests/assets/folder'),
root = True,
)
self.folderid_embeded = folder_embeded_art.id
artist = Artist(name = 'Artist')
album = Album(artist = artist, name = 'Album')
@ -64,13 +57,14 @@ class MediaTestCase(ApiTestBase):
artist = artist,
album = album,
path = os.path.abspath('tests/assets/folder/silence.mp3'),
root_folder = folder_embeded_art,
folder = folder_embeded_art,
root_folder = folder,
folder = folder,
duration = 2,
bitrate = 320,
content_type = 'audio/mpeg',
last_modification = 0
)
self.trackid_embeded_art = track_embeded_art.id
def test_stream(self):
self._make_request('stream', error = 10)
@ -143,7 +137,7 @@ class MediaTestCase(ApiTestBase):
# TODO test non square covers
# Test extracting cover art from embeded media
args['id'] = str(self.folderid_embeded)
args['id'] = str(self.trackid_embeded_art)
rv = self.client.get('/rest/getCoverArt.view', query_string = args)
self.assertEqual(rv.status_code, 200)
self.assertEqual(rv.mimetype, 'image/png')