1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Don't open files twice when scanning

This commit is contained in:
Alban Féron 2019-07-07 16:35:33 +02:00
parent f3a12c78b4
commit e0cd49d67b
No known key found for this signature in database
GPG Key ID: 8CE0313646D16165
4 changed files with 56 additions and 32 deletions

View File

@ -31,6 +31,7 @@ from zipstream import ZipFile
from .. import scanner
from ..cache import CacheMiss
from ..covers import get_embedded_cover
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
from ..py23 import dict
@ -227,7 +228,7 @@ def cover_art():
cover_path = cache.get(cache_key)
except CacheMiss:
res = get_entity(Track)
art = res.extract_cover_art()
art = get_embedded_cover(res.path)
if not art:
raise NotFound("Cover art")
cover_path = cache.set(cache_key, art)

View File

@ -10,9 +10,14 @@
import os.path
import re
from base64 import b64decode
from mutagen import File, FileType
from mutagen.easyid3 import EasyID3
from mutagen.flac import FLAC, Picture
from mutagen._vorbis import VCommentDict
from PIL import Image
from .py23 import scandir
from .py23 import scandir, strtype
EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp")
NAMING_SCORE_RULES = (
@ -82,3 +87,48 @@ def find_cover_in_folder(path, album_name=None):
return candidates[0]
return sorted(candidates, key=lambda c: c.score, reverse=True)[0]
def get_embedded_cover(path):
if not isinstance(path, strtype): # pragma: nocover
raise TypeError("Expecting string, got " + str(type(path)))
if not os.path.exists(path):
return None
metadata = File(path, easy=True)
if not metadata:
return None
if isinstance(metadata.tags, EasyID3):
picture = metadata["pictures"][0]
elif isinstance(metadata, FLAC):
picture = metadata.pictures[0]
elif isinstance(metadata.tags, VCommentDict):
picture = Picture(b64decode(metadata.tags["METADATA_BLOCK_PICTURE"][0]))
else:
return None
return picture.data
def has_embedded_cover(metadata):
if not isinstance(metadata, FileType): # pragma: nocover
raise TypeError("Expecting mutagen.FileType, got " + str(type(metadata)))
pictures = []
if isinstance(metadata.tags, EasyID3):
pictures = metadata.get("pictures", [])
elif isinstance(metadata, FLAC):
pictures = metadata.pictures
elif isinstance(metadata.tags, VCommentDict):
pictures = metadata.tags.get("METADATA_BLOCK_PICTURE", [])
return len(pictures) > 0
def _get_id3_apic(id3, key):
return id3.getall("APIC")
EasyID3.RegisterKey("pictures", _get_id3_apic)

View File

@ -7,10 +7,8 @@
#
# Distributed under terms of the GNU AGPLv3 license.
import base64
import importlib
import mimetypes
import mutagen
import os.path
import pkg_resources
import time
@ -353,32 +351,6 @@ class Track(PathMixin, db.Entity):
+ self.title
).lower()
def extract_cover_art(self):
return Track._extract_cover_art(self.path)
@staticmethod
def _extract_cover_art(path):
if os.path.exists(path):
metadata = mutagen.File(path)
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

@ -16,12 +16,13 @@ from datetime import datetime
from pony.orm import db_session
from threading import Thread, Event
from .covers import find_cover_in_folder, CoverFile
from .covers import find_cover_in_folder, has_embedded_cover, CoverFile
from .db import Folder, Artist, Album, Track, User
from .db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack
from .db import RatingFolder, RatingTrack
from .py23 import scandir, strtype, DirEntry, Queue, QueueEmpty
logger = logging.getLogger(__name__)
@ -247,7 +248,7 @@ class Scanner(Thread):
)
trdict["genre"] = self.__try_read_tag(tag, "genre")
trdict["duration"] = int(tag.info.length)
trdict["has_art"] = bool(Track._extract_cover_art(path))
trdict["has_art"] = has_embedded_cover(tag)
trdict["bitrate"] = (
int(