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:
parent
77becdb655
commit
deba8aeee4
@ -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"
|
||||||
|
@ -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)
|
||||||
|
@ -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]))
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user