diff --git a/db.py b/db.py index 93c9c24..9c31114 100755 --- a/db.py +++ b/db.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.types import TypeDecorator -from sqlalchemy import BINARY +from sqlalchemy.types import BINARY import uuid, datetime import os.path @@ -39,6 +39,9 @@ class UUID(TypeDecorator): def gen_id_column(): return Column(UUID, primary_key = True, default = uuid.uuid4) +def now(): + return datetime.datetime.now().replace(microsecond = 0) + engine = create_engine(config.get('DATABASE_URI'), convert_unicode = True) session = scoped_session(sessionmaker(autocommit = False, autoflush = False, bind = engine)) @@ -64,6 +67,7 @@ class Folder(Base): root = Column(Boolean, default = False) name = Column(String) path = Column(String, unique = True) + created = Column(DateTime, default = now) has_cover_art = Column(Boolean, default = False) last_scan = Column(DateTime, default = datetime.datetime.min) @@ -75,6 +79,7 @@ class Folder(Base): 'id': str(self.id), 'isDir': True, 'title': self.name, + 'created': self.created.isoformat() } if not self.root: info['parent'] = str(self.parent_id) @@ -110,9 +115,12 @@ class Track(Base): genre = Column(String, nullable = True) duration = Column(Integer) album_id = Column(UUID, ForeignKey('album.id')) - path = Column(String, unique = True) bitrate = Column(Integer) + path = Column(String, unique = True) + created = Column(DateTime, default = now) + last_modification = Column(Integer) + root_folder_id = Column(UUID, ForeignKey('folder.id')) root_folder = relationship('Folder', primaryjoin = Folder.id == root_folder_id) folder_id = Column(UUID, ForeignKey('folder.id')) @@ -135,6 +143,7 @@ class Track(Base): 'path': self.path[len(self.root_folder.path) + 1:], 'isVideo': False, 'discNumber': self.disc, + 'created': self.created.isoformat(), 'albumId': str(self.album.id), 'artistId': str(self.album.artist.id), 'type': 'music' @@ -151,7 +160,6 @@ class Track(Base): # transcodedSuffix # userRating # averageRating - # created # starred return info diff --git a/scanner.py b/scanner.py index cfd9893..cf2fb17 100755 --- a/scanner.py +++ b/scanner.py @@ -9,15 +9,16 @@ import db class Scanner: def __init__(self, session): self.__session = session + self.__tracks = db.Track.query.all() self.__artists = db.Artist.query.all() self.__folders = db.Folder.query.all() self.__added_artists = 0 - self.__added_albums = 0 - self.__added_tracks = 0 + self.__added_albums = 0 + self.__added_tracks = 0 self.__deleted_artists = 0 - self.__deleted_albums = 0 - self.__deleted_tracks = 0 + self.__deleted_albums = 0 + self.__deleted_tracks = 0 def scan(self, folder): for root, subfolders, files in os.walk(folder.path): @@ -27,21 +28,20 @@ class Scanner: folder.last_scan = datetime.datetime.now() def prune(self, folder): - for artist in db.Artist.query.all(): - for album in artist.albums[:]: - for track in filter(lambda t: t.root_folder.id == folder.id, album.tracks): - if not os.path.exists(track.path): - album.tracks.remove(track) - track.folder.tracks.remove(track) - self.__session.delete(track) - self.__deleted_tracks += 1 - if len(album.tracks) == 0: - artist.albums.remove(album) - self.__session.delete(album) - self.__deleted_albums += 1 - if len(artist.albums) == 0: - self.__session.delete(artist) - self.__deleted_artists += 1 + for track in [ t for t in self.__tracks if t.root_folder.id == folder.id and not os.path.exists(t.path) ]: + track.album.tracks.remove(track) + track.folder.tracks.remove(track) + self.__session.delete(track) + self.__deleted_tracks += 1 + + for album in [ album for artist in self.__artists for album in artist.albums if len(album.tracks) == 0 ]: + album.artist.albums.remove(album) + self.__session.delete(album) + self.__deleted_albums += 1 + + for artist in [ a for a in self.__artists if len(a.albums) == 0 ]: + self.__session.delete(artist) + self.__deleted_artists += 1 self.__cleanup_folder(folder) @@ -51,17 +51,19 @@ class Scanner: self.check_cover_art(f) def __scan_file(self, path, folder): - tag = eyeD3.Tag() - tag.link(path) - audio_file = eyeD3.Mp3AudioFile(path) - - al = self.__find_album(tag.getArtist(), tag.getAlbum()) - tr = filter(lambda t: t.path == path, al.tracks) + tr = filter(lambda t: t.path == path, self.__tracks) if not tr: tr = db.Track(path = path, root_folder = folder, folder = self.__find_folder(path, folder)) + self.__tracks.append(tr) self.__added_tracks += 1 else: tr = tr[0] + if not os.path.getmtime(path) > tr.last_modification: + return + + tag = eyeD3.Tag() + tag.link(path) + audio_file = eyeD3.Mp3AudioFile(path) tr.disc = tag.getDiscNum()[0] or 1 tr.number = tag.getTrackNum()[0] or 1 @@ -69,8 +71,9 @@ class Scanner: tr.year = tag.getYear() tr.genre = tag.getGenre().name if tag.getGenre() else None tr.duration = audio_file.getPlayTime() - tr.album = al + tr.album = self.__find_album(tag.getArtist(), tag.getAlbum()) tr.bitrate = audio_file.getBitRate()[1] + tr.last_modification = os.path.getmtime(path) def __find_album(self, artist, album): ar = self.__find_artist(artist)