mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Adding support for track artist vs album artist. Scanner only
This commit is contained in:
parent
074a0dc026
commit
104c9ffbb6
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
.*.sw[a-z]
|
||||||
*~
|
*~
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
|
@ -135,3 +135,10 @@ Instead of manually running a scan every time your library changes, you can run
|
|||||||
listen to any library change and update the database accordingly. The daemon is `bin/supysonic-watcher`
|
listen to any library change and update the database accordingly. The daemon is `bin/supysonic-watcher`
|
||||||
and can be run as an *init.d* script.
|
and can be run as an *init.d* script.
|
||||||
|
|
||||||
|
Upgrading
|
||||||
|
---------
|
||||||
|
|
||||||
|
Some commits might introduce changes in the database schema. When that's the case migration scripts will
|
||||||
|
be provided in the *schema/migration* folder, prefixed by the date of commit that introduced the changes.
|
||||||
|
Those scripts shouldn't be used when initializing a new database, only when upgrading from a previous schema.
|
||||||
|
|
||||||
|
9
schema/migration/20161030.mysql.sql
Normal file
9
schema/migration/20161030.mysql.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE track ADD artist_id CHAR(36) AFTER album_id;
|
||||||
|
UPDATE track SET artist_id = (SELECT artist_id FROM album WHERE id = track.album_id);
|
||||||
|
ALTER TABLE track MODIFY artist_id CHAR(36) NOT NULL;
|
||||||
|
ALTER TABLE track ADD FOREIGN KEY (artist_id) REFERENCES artist;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
9
schema/migration/20161030.postgresql.sql
Normal file
9
schema/migration/20161030.postgresql.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE track ADD artist_id UUID;
|
||||||
|
UPDATE track SET artist_id = (SELECT artist_id FROM album WHERE id = track.album_id);
|
||||||
|
ALTER TABLE track ALTER artist_id SET NOT NULL;
|
||||||
|
ALTER TABLE track ADD FOREIGN KEY (artist_id) REFERENCES artist;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
35
schema/migration/20161030.sqlite.sql
Executable file
35
schema/migration/20161030.sqlite.sql
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
-- PRAGMA foreign_keys = OFF;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE track RENAME TO track_old;
|
||||||
|
CREATE TABLE track (
|
||||||
|
id CHAR(36) PRIMARY KEY,
|
||||||
|
disc INTEGER NOT NULL,
|
||||||
|
number INTEGER NOT NULL,
|
||||||
|
title VARCHAR(256) NOT NULL,
|
||||||
|
year INTEGER,
|
||||||
|
genre VARCHAR(256),
|
||||||
|
duration INTEGER NOT NULL,
|
||||||
|
album_id CHAR(36) NOT NULL REFERENCES album,
|
||||||
|
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
||||||
|
bitrate INTEGER NOT NULL,
|
||||||
|
path VARCHAR(4096) NOT NULL,
|
||||||
|
content_type VARCHAR(32) NOT NULL,
|
||||||
|
created DATETIME NOT NULL,
|
||||||
|
last_modification INTEGER NOT NULL,
|
||||||
|
play_count INTEGER NOT NULL,
|
||||||
|
last_play DATETIME,
|
||||||
|
root_folder_id CHAR(36) NOT NULL REFERENCES folder,
|
||||||
|
folder_id CHAR(36) NOT NULL REFERENCES folder
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO track(id, disc, number, title, year, genre, duration, album_id, artist_id, bitrate, path, content_type, created, last_modification, play_count, last_play, root_folder_id, folder_id)
|
||||||
|
SELECT t.id, disc, number, title, year, genre, duration, album_id, artist_id, bitrate, path, content_type, created, last_modification, play_count, last_play, root_folder_id, folder_id
|
||||||
|
FROM track_old t, album a
|
||||||
|
WHERE album_id = a.id;
|
||||||
|
|
||||||
|
DROP TABLE track_old;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
-- PRAGMA foreign_keys = ON;
|
||||||
|
|
@ -29,6 +29,7 @@ CREATE TABLE track (
|
|||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
album_id CHAR(36) NOT NULL REFERENCES album,
|
album_id CHAR(36) NOT NULL REFERENCES album,
|
||||||
|
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
content_type VARCHAR(32) NOT NULL,
|
||||||
|
@ -29,6 +29,7 @@ CREATE TABLE track (
|
|||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
album_id UUID NOT NULL REFERENCES album,
|
album_id UUID NOT NULL REFERENCES album,
|
||||||
|
artist_id UUID NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
content_type VARCHAR(32) NOT NULL,
|
||||||
|
@ -29,6 +29,7 @@ CREATE TABLE track (
|
|||||||
genre VARCHAR(256),
|
genre VARCHAR(256),
|
||||||
duration INTEGER NOT NULL,
|
duration INTEGER NOT NULL,
|
||||||
album_id CHAR(36) NOT NULL REFERENCES album,
|
album_id CHAR(36) NOT NULL REFERENCES album,
|
||||||
|
artist_id CHAR(36) NOT NULL REFERENCES artist,
|
||||||
bitrate INTEGER NOT NULL,
|
bitrate INTEGER NOT NULL,
|
||||||
path VARCHAR(4096) NOT NULL,
|
path VARCHAR(4096) NOT NULL,
|
||||||
content_type VARCHAR(32) NOT NULL,
|
content_type VARCHAR(32) NOT NULL,
|
||||||
|
@ -151,6 +151,8 @@ class Track(object):
|
|||||||
duration = Int()
|
duration = Int()
|
||||||
album_id = UUID()
|
album_id = UUID()
|
||||||
album = Reference(album_id, Album.id)
|
album = Reference(album_id, Album.id)
|
||||||
|
artist_id = UUID()
|
||||||
|
artist = Reference(artist_id, Artist.id)
|
||||||
bitrate = Int()
|
bitrate = Int()
|
||||||
|
|
||||||
path = Unicode() # unique
|
path = Unicode() # unique
|
||||||
@ -173,7 +175,7 @@ class Track(object):
|
|||||||
'isDir': False,
|
'isDir': False,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'album': self.album.name,
|
'album': self.album.name,
|
||||||
'artist': self.album.artist.name,
|
'artist': self.artist.name,
|
||||||
'track': self.number,
|
'track': self.number,
|
||||||
'size': os.path.getsize(self.path),
|
'size': os.path.getsize(self.path),
|
||||||
'contentType': self.content_type,
|
'contentType': self.content_type,
|
||||||
@ -185,7 +187,7 @@ class Track(object):
|
|||||||
'discNumber': self.disc,
|
'discNumber': self.disc,
|
||||||
'created': self.created.isoformat(),
|
'created': self.created.isoformat(),
|
||||||
'albumId': str(self.album_id),
|
'albumId': str(self.album_id),
|
||||||
'artistId': str(self.album.artist_id),
|
'artistId': str(self.artist_id),
|
||||||
'type': 'music'
|
'type': 'music'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +228,7 @@ class Track(object):
|
|||||||
|
|
||||||
Folder.tracks = ReferenceSet(Folder.id, Track.folder_id)
|
Folder.tracks = ReferenceSet(Folder.id, Track.folder_id)
|
||||||
Album.tracks = ReferenceSet(Album.id, Track.album_id)
|
Album.tracks = ReferenceSet(Album.id, Track.album_id)
|
||||||
|
Artist.tracks = ReferenceSet(Artist.id, Track.artist_id)
|
||||||
|
|
||||||
class User(object):
|
class User(object):
|
||||||
__storm_table__ = 'user'
|
__storm_table__ = 'user'
|
||||||
|
@ -107,7 +107,7 @@ class Scanner:
|
|||||||
self.__deleted_albums += 1
|
self.__deleted_albums += 1
|
||||||
self.__albums_to_check.clear()
|
self.__albums_to_check.clear()
|
||||||
|
|
||||||
for artist in [ a for a in self.__artists_to_check if not a.albums.count() ]:
|
for artist in [ a for a in self.__artists_to_check if not a.albums.count() and not a.tracks.count() ]:
|
||||||
self.__store.remove(artist)
|
self.__store.remove(artist)
|
||||||
self.__deleted_artists += 1
|
self.__deleted_artists += 1
|
||||||
self.__artists_to_check.clear()
|
self.__artists_to_check.clear()
|
||||||
@ -148,35 +148,45 @@ class Scanner:
|
|||||||
tr.path = path
|
tr.path = path
|
||||||
add = True
|
add = True
|
||||||
|
|
||||||
|
artist = self.__try_read_tag(tag, 'artist', '')
|
||||||
|
album = self.__try_read_tag(tag, 'album', '')
|
||||||
|
albumartist = self.__try_read_tag(tag, 'albumartist', artist)
|
||||||
|
|
||||||
tr.disc = self.__try_read_tag(tag, 'discnumber', 1, lambda x: int(x[0].split('/')[0]))
|
tr.disc = self.__try_read_tag(tag, 'discnumber', 1, lambda x: int(x[0].split('/')[0]))
|
||||||
tr.number = self.__try_read_tag(tag, 'tracknumber', 1, lambda x: int(x[0].split('/')[0]))
|
tr.number = self.__try_read_tag(tag, 'tracknumber', 1, lambda x: int(x[0].split('/')[0]))
|
||||||
tr.title = self.__try_read_tag(tag, 'title', '')
|
tr.title = self.__try_read_tag(tag, 'title', '')
|
||||||
tr.year = self.__try_read_tag(tag, 'date', None, lambda x: int(x[0].split('-')[0]))
|
tr.year = self.__try_read_tag(tag, 'date', None, lambda x: int(x[0].split('-')[0]))
|
||||||
tr.genre = self.__try_read_tag(tag, 'genre')
|
tr.genre = self.__try_read_tag(tag, 'genre')
|
||||||
tr.duration = int(tag.info.length)
|
tr.duration = int(tag.info.length)
|
||||||
if not add:
|
|
||||||
old_album = tr.album
|
|
||||||
new_album = self.__find_album(self.__try_read_tag(tag, 'artist', ''), self.__try_read_tag(tag, 'album', ''))
|
|
||||||
if old_album.id != new_album.id:
|
|
||||||
tr.album = new_album
|
|
||||||
self.__albums_to_check.add(old_album)
|
|
||||||
tr.bitrate = (tag.info.bitrate if hasattr(tag.info, 'bitrate') else int(os.path.getsize(path) * 8 / tag.info.length)) / 1000
|
tr.bitrate = (tag.info.bitrate if hasattr(tag.info, 'bitrate') else int(os.path.getsize(path) * 8 / tag.info.length)) / 1000
|
||||||
tr.content_type = get_mime(os.path.splitext(path)[1][1:])
|
tr.content_type = get_mime(os.path.splitext(path)[1][1:])
|
||||||
tr.last_modification = os.path.getmtime(path)
|
tr.last_modification = os.path.getmtime(path)
|
||||||
|
|
||||||
|
tralbum = self.__find_album(albumartist, album)
|
||||||
|
trartist = self.__find_artist(artist)
|
||||||
|
|
||||||
if add:
|
if add:
|
||||||
tralbum = self.__find_album(self.__try_read_tag(tag, 'artist', ''), self.__try_read_tag(tag, 'album', ''))
|
|
||||||
trroot = self.__find_root_folder(path)
|
trroot = self.__find_root_folder(path)
|
||||||
trfolder = self.__find_folder(path)
|
trfolder = self.__find_folder(path)
|
||||||
|
|
||||||
# Set the references at the very last as searching for them will cause the added track to be flushed, even if
|
# Set the references at the very last as searching for them will cause the added track to be flushed, even if
|
||||||
# it is incomplete, causing not null constraints errors.
|
# it is incomplete, causing not null constraints errors.
|
||||||
tr.album = tralbum
|
tr.album = tralbum
|
||||||
|
tr.artist = trartist
|
||||||
tr.folder = trfolder
|
tr.folder = trfolder
|
||||||
tr.root_folder = trroot
|
tr.root_folder = trroot
|
||||||
|
|
||||||
self.__store.add(tr)
|
self.__store.add(tr)
|
||||||
self.__added_tracks += 1
|
self.__added_tracks += 1
|
||||||
|
else:
|
||||||
|
if tr.album.id != tralbum.id:
|
||||||
|
self.__albums_to_check.add(tr.album)
|
||||||
|
tr.album = tralbum
|
||||||
|
|
||||||
|
if tr.artist.id != trartist.id:
|
||||||
|
self.__artists_to_check.add(tr.artist)
|
||||||
|
tr.artist = trartist
|
||||||
|
|
||||||
def remove_file(self, path):
|
def remove_file(self, path):
|
||||||
tr = self.__store.find(Track, Track.path == path).one()
|
tr = self.__store.find(Track, Track.path == path).one()
|
||||||
@ -185,6 +195,7 @@ class Scanner:
|
|||||||
|
|
||||||
self.__folders_to_check.add(tr.folder)
|
self.__folders_to_check.add(tr.folder)
|
||||||
self.__albums_to_check.add(tr.album)
|
self.__albums_to_check.add(tr.album)
|
||||||
|
self.__artists_to_check.add(tr.artist)
|
||||||
self.__store.remove(tr)
|
self.__store.remove(tr)
|
||||||
self.__deleted_tracks += 1
|
self.__deleted_tracks += 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user