From 2c4ec6c0e8969257b01fd6ba18e2162c643d04db Mon Sep 17 00:00:00 2001 From: Taizo Simpson Date: Wed, 10 Oct 2018 12:58:47 -0400 Subject: [PATCH] Whether or not a track has embeded art is tracked just like any other metadata, to reduce disk r/w and mem usage and a lot of other things. WARNING: This needs migrations before being merged to master --- supysonic/db.py | 12 ++++++++---- supysonic/scanner.py | 1 + supysonic/schema/mysql.sql | 1 + supysonic/schema/postgres.sql | 1 + supysonic/schema/sqlite.sql | 1 + tests/base/test_db.py | 2 ++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/supysonic/db.py b/supysonic/db.py index 1db68a3..969f6cf 100644 --- a/supysonic/db.py +++ b/supysonic/db.py @@ -105,7 +105,7 @@ class Folder(PathMixin, db.Entity): info['coverArt'] = str(self.id) else: for track in self.tracks: - if track.extract_cover_art(): + if track.has_art: info['coverArt'] = str(track.id) break @@ -216,6 +216,7 @@ class Track(PathMixin, db.Entity): year = Optional(int) genre = Optional(str, nullable = True) duration = Required(int) + has_art = Required(bool, default=False) album = Required(Album, column = 'album_id') artist = Required(Artist, column = 'artist_id') @@ -266,7 +267,7 @@ class Track(PathMixin, db.Entity): info['year'] = self.year if self.genre: info['genre'] = self.genre - if self.extract_cover_art(): + if self.has_art: info['coverArt'] = str(self.id) elif self.folder.cover_art: info['coverArt'] = str(self.folder.id) @@ -304,8 +305,11 @@ class Track(PathMixin, db.Entity): 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) + return Track._extract_cover_art(self.path) + + def _extract_cover_art(path): + if os.path.exists(path): + metadata = mutagen.File(path) data = None if metadata: if isinstance(metadata.tags, mutagen.id3.ID3Tags) and len(metadata.tags.getall('APIC')) > 0: diff --git a/supysonic/scanner.py b/supysonic/scanner.py index 99b5527..ae5061b 100644 --- a/supysonic/scanner.py +++ b/supysonic/scanner.py @@ -140,6 +140,7 @@ class Scanner: trdict['year'] = self.__try_read_tag(tag, 'date', None, lambda x: int(x[0].split('-')[0])) trdict['genre'] = self.__try_read_tag(tag, 'genre') trdict['duration'] = int(tag.info.length) + trdict['has_art'] = bool(Track._extract_cover_art(path)) trdict['bitrate'] = (tag.info.bitrate if hasattr(tag.info, 'bitrate') else int(os.path.getsize(path) * 8 / tag.info.length)) // 1000 trdict['content_type'] = mimetypes.guess_type(path, False)[0] or 'application/octet-stream' diff --git a/supysonic/schema/mysql.sql b/supysonic/schema/mysql.sql index 9787df2..68571b4 100644 --- a/supysonic/schema/mysql.sql +++ b/supysonic/schema/mysql.sql @@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS track ( year INTEGER, genre VARCHAR(256), duration INTEGER NOT NULL, + has_art BOOLEAN NOT NULL, album_id BINARY(16) NOT NULL REFERENCES album, artist_id BINARY(16) NOT NULL REFERENCES artist, bitrate INTEGER NOT NULL, diff --git a/supysonic/schema/postgres.sql b/supysonic/schema/postgres.sql index 9339f55..5f447c1 100644 --- a/supysonic/schema/postgres.sql +++ b/supysonic/schema/postgres.sql @@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS track ( year INTEGER, genre VARCHAR(256), duration INTEGER NOT NULL, + has_art BOOLEAN NOT NULL, album_id UUID NOT NULL REFERENCES album, artist_id UUID NOT NULL REFERENCES artist, bitrate INTEGER NOT NULL, diff --git a/supysonic/schema/sqlite.sql b/supysonic/schema/sqlite.sql index bf8e567..c7781b4 100644 --- a/supysonic/schema/sqlite.sql +++ b/supysonic/schema/sqlite.sql @@ -31,6 +31,7 @@ CREATE TABLE IF NOT EXISTS track ( year INTEGER, genre VARCHAR(256), duration INTEGER NOT NULL, + has_art BOOLEAN NOT NULL, album_id CHAR(36) NOT NULL REFERENCES album, artist_id CHAR(36) NOT NULL REFERENCES artist, bitrate INTEGER NOT NULL, diff --git a/tests/base/test_db.py b/tests/base/test_db.py index 8365196..c3bc600 100644 --- a/tests/base/test_db.py +++ b/tests/base/test_db.py @@ -71,6 +71,7 @@ class DbTestCase(unittest.TestCase): disc = 1, number = 1, duration = 3, + has_art = True, bitrate = 320, path = 'tests/assets/formats/silence.ogg', content_type = 'audio/ogg', @@ -106,6 +107,7 @@ class DbTestCase(unittest.TestCase): disc = 1, number = 1, duration = 5, + has_art = True, bitrate = 96, path = 'tests/assets/formats/silence.flac', content_type = 'audio/flac',