1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-23 01:16:18 +00:00

Changing which methods are available from Scanner and what they do

This commit is contained in:
spl0k 2014-08-04 19:56:45 +02:00
parent 77becdb655
commit deba8aeee4
5 changed files with 63 additions and 63 deletions

View File

@ -141,18 +141,19 @@ class CLI(cmd.Cmd):
print "Scanning '{0}': {1}% ({2}/{3})".format(self.__name, (scanned * 100) / total, scanned, total) print "Scanning '{0}': {1}% ({2}/{3})".format(self.__name, (scanned * 100) / total, scanned, total)
self.__last_display = time.time() self.__last_display = time.time()
s = Scanner(self.__store) scanner = Scanner(self.__store)
if folders: if folders:
folders = map(lambda n: self.__store.find(Folder, Folder.name == n, Folder.root == True).one() or n, folders) folders = map(lambda n: self.__store.find(Folder, Folder.name == n, Folder.root == True).one() or n, folders)
if any(map(lambda f: isinstance(f, basestring), folders)): if any(map(lambda f: isinstance(f, basestring), folders)):
print "No such folder(s): " + ' '.join(f for f in folders if isinstance(f, basestring)) print "No such folder(s): " + ' '.join(f for f in folders if isinstance(f, basestring))
for folder in filter(lambda f: isinstance(f, Folder), folders): for folder in filter(lambda f: isinstance(f, Folder), folders):
FolderManager.scan(self.__store, folder.id, s, TimedProgressDisplay(folder.name)) scanner.scan(folder, TimedProgressDisplay(folder.name))
else: else:
for folder in self.__store.find(Folder, Folder.root == True): for folder in self.__store.find(Folder, Folder.root == True):
FolderManager.scan(self.__store, folder.id, s, TimedProgressDisplay(folder.name)) scanner.scan(folder, TimedProgressDisplay(folder.name))
added, deleted = s.stats() scanner.finish()
added, deleted = scanner.stats()
self.__store.commit() self.__store.commit()
print "Scanning done" print "Scanning done"

View File

@ -47,8 +47,9 @@ class SupysonicWatcherEventHandler(PatternMatchingEventHandler):
store = db.get_store(config.get('base', 'database_uri')) store = db.get_store(config.get('base', 'database_uri'))
track = store.find(db.Track, db.Track.path == event.src_path).one() track = store.find(db.Track, db.Track.path == event.src_path).one()
if track: if track:
folder = track.root_folder scanner = Scanner(store)
Scanner(store).prune(folder) scanner.remove_file(track.path)
scanner.finish()
store.commit() store.commit()
else: else:
self.__logger.debug("Deleted file %s not in the database", event.src_path) self.__logger.debug("Deleted file %s not in the database", event.src_path)

View File

@ -84,17 +84,19 @@ def del_folder(id):
@app.route('/folder/scan') @app.route('/folder/scan')
@app.route('/folder/scan/<id>') @app.route('/folder/scan/<id>')
def scan_folder(id = None): def scan_folder(id = None):
s = Scanner(store) scanner = Scanner(store)
if id is None: if id is None:
for folder in store.find(Folder, Folder.root == True): for folder in store.find(Folder, Folder.root == True):
FolderManager.scan(store, folder.id, s) scanner.scan(folder)
else: else:
status = FolderManager.scan(store, id, s) status, folder = FolderManager.get(store, id)
if status != FolderManager.SUCCESS: if status != FolderManager.SUCCESS:
flash(FolderManager.error_str(status)) flash(FolderManager.error_str(status))
return redirect(url_for('folder_index')) return redirect(url_for('folder_index'))
scanner.scan(folder)
added, deleted = s.stats() scanner.finish()
added, deleted = scanner.stats()
store.commit() store.commit()
flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2])) flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2]))

View File

@ -20,6 +20,7 @@
import os.path, uuid import os.path, uuid
from supysonic.db import Folder, Artist, Album, Track from supysonic.db import Folder, Artist, Album, Track
from supysonic.scanner import Scanner
class FolderManager: class FolderManager:
SUCCESS = 0 SUCCESS = 0
@ -77,24 +78,11 @@ class FolderManager:
if not folder.root: if not folder.root:
return FolderManager.NO_SUCH_FOLDER return FolderManager.NO_SUCH_FOLDER
# delete associated tracks and prune empty albums/artists scanner = Scanner(store)
potentially_removed_albums = set()
for track in store.find(Track, Track.root_folder_id == folder.id): for track in store.find(Track, Track.root_folder_id == folder.id):
potentially_removed_albums.add(track.album) scanner.remove_file(track.path)
store.remove(track) scanner.finish()
potentially_removed_artists = set()
for album in filter(lambda album: album.tracks.count() == 0, potentially_removed_albums):
potentially_removed_artists.add(album.artist)
store.remove(album)
for artist in filter(lambda artist: artist.albums.count() == 0, potentially_removed_artists):
store.remove(artist)
def cleanup_folder(folder):
for f in folder.children:
cleanup_folder(f)
store.remove(folder) store.remove(folder)
cleanup_folder(folder)
store.commit() store.commit()
return FolderManager.SUCCESS return FolderManager.SUCCESS
@ -106,17 +94,6 @@ class FolderManager:
return FolderManager.NO_SUCH_FOLDER return FolderManager.NO_SUCH_FOLDER
return FolderManager.delete(store, folder.id) return FolderManager.delete(store, folder.id)
@staticmethod
def scan(store, uid, scanner, progress_callback = None):
status, folder = FolderManager.get(store, uid)
if status != FolderManager.SUCCESS:
return status
scanner.scan(folder, progress_callback)
scanner.prune(folder)
scanner.check_cover_art(folder)
return FolderManager.SUCCESS
@staticmethod @staticmethod
def error_str(err): def error_str(err):
if err == FolderManager.SUCCESS: if err == FolderManager.SUCCESS:

View File

@ -42,7 +42,16 @@ class Scanner:
extensions = config.get('base', 'scanner_extensions') extensions = config.get('base', 'scanner_extensions')
self.__extensions = map(str.lower, extensions.split()) if extensions else None self.__extensions = map(str.lower, extensions.split()) if extensions else None
self.__folders_to_check = set()
self.__artists_to_check = set()
self.__albums_to_check = set()
def __del__(self):
if self.__folders_to_check or self.__artists_to_check or self.__albums_to_check:
raise Exception("There's still something to check. Did you run Scanner.finish()?")
def scan(self, folder, progress_callback = None): def scan(self, folder, progress_callback = None):
# Scan new/updated files
files = [ os.path.join(root, f) for root, _, fs in os.walk(folder.path) for f in fs if self.__is_valid_path(os.path.join(root, f)) ] files = [ os.path.join(root, f) for root, _, fs in os.walk(folder.path) for f in fs if self.__is_valid_path(os.path.join(root, f)) ]
total = len(files) total = len(files)
current = 0 current = 0
@ -53,32 +62,39 @@ class Scanner:
if progress_callback: if progress_callback:
progress_callback(current, total) progress_callback(current, total)
# Remove files that have been deleted
for track in [ t for t in self.__store.find(Track, Track.root_folder_id == folder.id) if not self.__is_valid_path(t.path) ]:
self.remove_file(track.path)
# Update cover art info
folders = [ folder ]
while folders:
f = folders.pop()
f.has_cover_art = os.path.isfile(os.path.join(f.path, 'cover.jpg'))
folders += f.children
folder.last_scan = int(time.time()) folder.last_scan = int(time.time())
self.__store.flush() def finish(self):
for album in [ a for a in self.__albums_to_check if not a.tracks.count() ]:
def prune(self, folder): self.__artists_to_check.add(album.artist)
for track in [ t for t in self.__store.find(Track, Track.root_folder_id == folder.id) if not self.__is_valid_path(t.path) ]:
self.__store.remove(track)
self.__deleted_tracks += 1
# TODO execute the conditional part on SQL
for album in [ a for a in self.__store.find(Album) if a.tracks.count() == 0 ]:
self.__store.remove(album) self.__store.remove(album)
self.__deleted_albums += 1 self.__deleted_albums += 1
self.__albums_to_check.clear()
# TODO execute the conditional part on SQL for artist in [ a for a in self.__artists_to_check if not a.albums.count() ]:
for artist in [ a for a in self.__store.find(Artist) if a.albums.count() == 0 ]:
self.__store.remove(artist) self.__store.remove(artist)
self.__deleted_artists += 1 self.__deleted_artists += 1
self.__artists_to_check.clear()
self.__cleanup_folder(folder) while self.__folders_to_check:
self.__store.flush() folder = self.__folders_to_check.pop()
if folder.root:
continue
def check_cover_art(self, folder): if not folder.tracks.count() and not folder.children.count():
folder.has_cover_art = os.path.isfile(os.path.join(folder.path, 'cover.jpg')) self.__folders_to_check.add(folder.parent)
for f in folder.children: self.__store.remove(folder)
self.check_cover_art(f)
def __is_valid_path(self, path): def __is_valid_path(self, path):
if not os.path.exists(path): if not os.path.exists(path):
@ -96,8 +112,7 @@ class Scanner:
tag = self.__try_load_tag(path) tag = self.__try_load_tag(path)
if not tag: if not tag:
self.__store.remove(tr) self.remove_file(path)
self.__deleted_tracks += 1
return return
else: else:
tag = self.__try_load_tag(path) tag = self.__try_load_tag(path)
@ -134,6 +149,16 @@ class Scanner:
self.__store.add(tr) self.__store.add(tr)
self.__added_tracks += 1 self.__added_tracks += 1
def remove_file(self, path):
tr = self.__store.find(Track, Track.path == path).one()
if not tr:
return
self.__folders_to_check.add(tr.folder)
self.__albums_to_check.add(tr.album)
self.__store.remove(tr)
self.__deleted_tracks += 1
def __find_album(self, artist, album): def __find_album(self, artist, album):
ar = self.__find_artist(artist) ar = self.__find_artist(artist)
al = ar.albums.find(name = album).one() al = ar.albums.find(name = album).one()
@ -218,12 +243,6 @@ class Scanner:
except: except:
return default return default
def __cleanup_folder(self, folder):
for f in folder.children:
self.__cleanup_folder(f)
if folder.children.count() == 0 and folder.tracks.count() == 0 and not folder.root:
self.__store.remove(folder)
def stats(self): def stats(self):
return (self.__added_artists, self.__added_albums, self.__added_tracks), (self.__deleted_artists, self.__deleted_albums, self.__deleted_tracks) return (self.__added_artists, self.__added_albums, self.__added_tracks), (self.__deleted_artists, self.__deleted_albums, self.__deleted_tracks)