mirror of
https://github.com/spl0k/supysonic.git
synced 2024-11-10 04:02:17 +00:00
Merge branch 'embed_as_metadata'
This commit is contained in:
commit
25cb354f78
@ -31,7 +31,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from urlparse import urlparse, parse_qsl
|
from urlparse import urlparse, parse_qsl
|
||||||
|
|
||||||
SCHEMA_VERSION = '20180829'
|
SCHEMA_VERSION = '20181010'
|
||||||
|
|
||||||
def now():
|
def now():
|
||||||
return datetime.now().replace(microsecond = 0)
|
return datetime.now().replace(microsecond = 0)
|
||||||
@ -105,7 +105,7 @@ class Folder(PathMixin, db.Entity):
|
|||||||
info['coverArt'] = str(self.id)
|
info['coverArt'] = str(self.id)
|
||||||
else:
|
else:
|
||||||
for track in self.tracks:
|
for track in self.tracks:
|
||||||
if track.extract_cover_art():
|
if track.has_art:
|
||||||
info['coverArt'] = str(track.id)
|
info['coverArt'] = str(track.id)
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -190,6 +190,10 @@ class Album(db.Entity):
|
|||||||
track_with_cover = self.tracks.select(lambda t: t.folder.cover_art is not None).first()
|
track_with_cover = self.tracks.select(lambda t: t.folder.cover_art is not None).first()
|
||||||
if track_with_cover is not None:
|
if track_with_cover is not None:
|
||||||
info['coverArt'] = str(track_with_cover.folder.id)
|
info['coverArt'] = str(track_with_cover.folder.id)
|
||||||
|
else:
|
||||||
|
track_with_cover = self.tracks.select(lambda t: t.has_art).first()
|
||||||
|
if track_with_cover is not None:
|
||||||
|
info['coverArt'] = str(track_with_cover.id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
starred = StarredAlbum[user.id, self.id]
|
starred = StarredAlbum[user.id, self.id]
|
||||||
@ -216,6 +220,7 @@ class Track(PathMixin, db.Entity):
|
|||||||
year = Optional(int)
|
year = Optional(int)
|
||||||
genre = Optional(str, nullable = True)
|
genre = Optional(str, nullable = True)
|
||||||
duration = Required(int)
|
duration = Required(int)
|
||||||
|
has_art = Required(bool, default=False)
|
||||||
|
|
||||||
album = Required(Album, column = 'album_id')
|
album = Required(Album, column = 'album_id')
|
||||||
artist = Required(Artist, column = 'artist_id')
|
artist = Required(Artist, column = 'artist_id')
|
||||||
@ -266,7 +271,7 @@ class Track(PathMixin, db.Entity):
|
|||||||
info['year'] = self.year
|
info['year'] = self.year
|
||||||
if self.genre:
|
if self.genre:
|
||||||
info['genre'] = self.genre
|
info['genre'] = self.genre
|
||||||
if self.extract_cover_art():
|
if self.has_art:
|
||||||
info['coverArt'] = str(self.id)
|
info['coverArt'] = str(self.id)
|
||||||
elif self.folder.cover_art:
|
elif self.folder.cover_art:
|
||||||
info['coverArt'] = str(self.folder.id)
|
info['coverArt'] = str(self.folder.id)
|
||||||
@ -304,8 +309,12 @@ class Track(PathMixin, db.Entity):
|
|||||||
return (self.album.artist.name + self.album.name + ("%02i" % self.disc) + ("%02i" % self.number) + self.title).lower()
|
return (self.album.artist.name + self.album.name + ("%02i" % self.disc) + ("%02i" % self.number) + self.title).lower()
|
||||||
|
|
||||||
def extract_cover_art(self):
|
def extract_cover_art(self):
|
||||||
if os.path.exists(self.path):
|
return Track._extract_cover_art(self.path)
|
||||||
metadata = mutagen.File(self.path)
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_cover_art(path):
|
||||||
|
if os.path.exists(path):
|
||||||
|
metadata = mutagen.File(path)
|
||||||
if metadata:
|
if metadata:
|
||||||
if isinstance(metadata.tags, mutagen.id3.ID3Tags) and len(metadata.tags.getall('APIC')) > 0:
|
if isinstance(metadata.tags, mutagen.id3.ID3Tags) and len(metadata.tags.getall('APIC')) > 0:
|
||||||
return metadata.tags.getall('APIC')[0].data
|
return metadata.tags.getall('APIC')[0].data
|
||||||
|
@ -140,6 +140,7 @@ class Scanner:
|
|||||||
trdict['year'] = self.__try_read_tag(tag, 'date', None, lambda x: int(x[0].split('-')[0]))
|
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['genre'] = self.__try_read_tag(tag, 'genre')
|
||||||
trdict['duration'] = int(tag.info.length)
|
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['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'
|
trdict['content_type'] = mimetypes.guess_type(path, False)[0] or 'application/octet-stream'
|
||||||
|
6
supysonic/schema/migration/mysql/20181010.sql
Normal file
6
supysonic/schema/migration/mysql/20181010.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE track ADD has_art BOOLEAN DEFAULT false NOT NULL;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
6
supysonic/schema/migration/postgres/20181010.sql
Normal file
6
supysonic/schema/migration/postgres/20181010.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE track ADD has_art BOOLEAN DEFAULT false NOT NULL;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
3
supysonic/schema/migration/sqlite/20181010.sql
Normal file
3
supysonic/schema/migration/sqlite/20181010.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE track ADD has_art BOOLEAN DEFAULT false NOT NULL;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
year INTEGER,
|
year INTEGER,
|
||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
|
has_art BOOLEAN NOT NULL DEFAULT false,
|
||||||
album_id BINARY(16) NOT NULL REFERENCES album,
|
album_id BINARY(16) NOT NULL REFERENCES album,
|
||||||
artist_id BINARY(16) NOT NULL REFERENCES artist,
|
artist_id BINARY(16) NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
|
@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
year INTEGER,
|
year INTEGER,
|
||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
|
has_art BOOLEAN NOT NULL DEFAULT false,
|
||||||
album_id UUID NOT NULL REFERENCES album,
|
album_id UUID NOT NULL REFERENCES album,
|
||||||
artist_id UUID NOT NULL REFERENCES artist,
|
artist_id UUID NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
|
@ -31,6 +31,7 @@ CREATE TABLE IF NOT EXISTS track (
|
|||||||
year INTEGER,
|
year INTEGER,
|
||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
|
has_art BOOLEAN NOT NULL DEFAULT false,
|
||||||
album_id CHAR(36) NOT NULL REFERENCES album,
|
album_id CHAR(36) NOT NULL REFERENCES album,
|
||||||
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
|
@ -71,6 +71,7 @@ class DbTestCase(unittest.TestCase):
|
|||||||
disc = 1,
|
disc = 1,
|
||||||
number = 1,
|
number = 1,
|
||||||
duration = 3,
|
duration = 3,
|
||||||
|
has_art = True,
|
||||||
bitrate = 320,
|
bitrate = 320,
|
||||||
path = 'tests/assets/formats/silence.ogg',
|
path = 'tests/assets/formats/silence.ogg',
|
||||||
content_type = 'audio/ogg',
|
content_type = 'audio/ogg',
|
||||||
@ -96,9 +97,9 @@ class DbTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
return track1, track2
|
return track1, track2
|
||||||
|
|
||||||
def create_track_in(self, folder, root):
|
def create_track_in(self, folder, root, artist = None, album = None, has_art = True):
|
||||||
artist = db.Artist(name = 'Snazzy Artist')
|
artist = artist or db.Artist(name = 'Snazzy Artist')
|
||||||
album = db.Album(artist = artist, name = 'Rockin\' Album')
|
album = album or db.Album(artist = artist, name = 'Rockin\' Album')
|
||||||
return db.Track(
|
return db.Track(
|
||||||
title = 'Nifty Number',
|
title = 'Nifty Number',
|
||||||
album = album,
|
album = album,
|
||||||
@ -106,6 +107,7 @@ class DbTestCase(unittest.TestCase):
|
|||||||
disc = 1,
|
disc = 1,
|
||||||
number = 1,
|
number = 1,
|
||||||
duration = 5,
|
duration = 5,
|
||||||
|
has_art = has_art,
|
||||||
bitrate = 96,
|
bitrate = 96,
|
||||||
path = 'tests/assets/formats/silence.flac',
|
path = 'tests/assets/formats/silence.flac',
|
||||||
content_type = 'audio/flac',
|
content_type = 'audio/flac',
|
||||||
@ -232,7 +234,8 @@ class DbTestCase(unittest.TestCase):
|
|||||||
# No tracks, shouldn't be stored under normal circumstances
|
# No tracks, shouldn't be stored under normal circumstances
|
||||||
self.assertRaises(ValueError, album.as_subsonic_album, user)
|
self.assertRaises(ValueError, album.as_subsonic_album, user)
|
||||||
|
|
||||||
self.create_some_tracks(artist, album)
|
root_folder, folder_art, folder_noart = self.create_some_folders()
|
||||||
|
track1 = self.create_track_in(root_folder, folder_noart, artist = artist, album = album)
|
||||||
|
|
||||||
album_dict = album.as_subsonic_album(user)
|
album_dict = album.as_subsonic_album(user)
|
||||||
self.assertIsInstance(album_dict, dict)
|
self.assertIsInstance(album_dict, dict)
|
||||||
@ -244,11 +247,13 @@ class DbTestCase(unittest.TestCase):
|
|||||||
self.assertIn('duration', album_dict)
|
self.assertIn('duration', album_dict)
|
||||||
self.assertIn('created', album_dict)
|
self.assertIn('created', album_dict)
|
||||||
self.assertIn('starred', album_dict)
|
self.assertIn('starred', album_dict)
|
||||||
|
self.assertIn('coverArt', album_dict)
|
||||||
self.assertEqual(album_dict['name'], album.name)
|
self.assertEqual(album_dict['name'], album.name)
|
||||||
self.assertEqual(album_dict['artist'], artist.name)
|
self.assertEqual(album_dict['artist'], artist.name)
|
||||||
self.assertEqual(album_dict['artistId'], str(artist.id))
|
self.assertEqual(album_dict['artistId'], str(artist.id))
|
||||||
self.assertEqual(album_dict['songCount'], 2)
|
self.assertEqual(album_dict['songCount'], 1)
|
||||||
self.assertEqual(album_dict['duration'], 8)
|
self.assertEqual(album_dict['duration'], 5)
|
||||||
|
self.assertEqual(album_dict['coverArt'], str(track1.id))
|
||||||
self.assertRegex(album_dict['created'], date_regex)
|
self.assertRegex(album_dict['created'], date_regex)
|
||||||
self.assertRegex(album_dict['starred'], date_regex)
|
self.assertRegex(album_dict['starred'], date_regex)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user