1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Thighter DB session scoping in scanner

Should prevent 'database is locked' issues
Also helps reducing memory usage (#144)
This commit is contained in:
spl0k 2019-05-10 17:58:01 +02:00
parent e354f99d69
commit 58b7888ba9
2 changed files with 31 additions and 19 deletions

View File

@ -110,8 +110,6 @@ class SupysonicCLI(cmd.Cmd):
self.write_line('Unknown command %s' % line.split()[0]) self.write_line('Unknown command %s' % line.split()[0])
self.do_help(None) self.do_help(None)
onecmd = db_session(cmd.Cmd.onecmd)
def postloop(self): def postloop(self):
self.write_line() self.write_line()
@ -141,10 +139,12 @@ class SupysonicCLI(cmd.Cmd):
folder_scan_target_group.add_argument('--background', action = 'store_true', help = 'Scan the folder(s) in the background. Requires the daemon to be running.') folder_scan_target_group.add_argument('--background', action = 'store_true', help = 'Scan the folder(s) in the background. Requires the daemon to be running.')
folder_scan_target_group.add_argument('--foreground', action = 'store_true', help = 'Scan the folder(s) in the foreground, blocking the processus while the scan is running.') folder_scan_target_group.add_argument('--foreground', action = 'store_true', help = 'Scan the folder(s) in the foreground, blocking the processus while the scan is running.')
@db_session
def folder_list(self): def folder_list(self):
self.write_line('Name\t\tPath\n----\t\t----') self.write_line('Name\t\tPath\n----\t\t----')
self.write_line('\n'.join('{0: <16}{1}'.format(f.name, f.path) for f in Folder.select(lambda f: f.root))) self.write_line('\n'.join('{0: <16}{1}'.format(f.name, f.path) for f in Folder.select(lambda f: f.root)))
@db_session
def folder_add(self, name, path): def folder_add(self, name, path):
try: try:
FolderManager.add(name, path) FolderManager.add(name, path)
@ -152,6 +152,7 @@ class SupysonicCLI(cmd.Cmd):
except ValueError as e: except ValueError as e:
self.write_error_line(str(e)) self.write_error_line(str(e))
@db_session
def folder_delete(self, name): def folder_delete(self, name):
try: try:
FolderManager.delete_by_name(name) FolderManager.delete_by_name(name)
@ -196,15 +197,17 @@ class SupysonicCLI(cmd.Cmd):
if folders: if folders:
fstrs = folders fstrs = folders
folders = select(f.name for f in Folder if f.root and f.name in fstrs)[:] with db_session:
folders = select(f.name for f in Folder if f.root and f.name in fstrs)[:]
notfound = set(fstrs) - set(folders) notfound = set(fstrs) - set(folders)
if notfound: if notfound:
self.write_line("No such folder(s): " + ' '.join(notfound)) self.write_line("No such folder(s): " + ' '.join(notfound))
for folder in folders: for folder in folders:
scanner.queue_folder(folder) scanner.queue_folder(folder)
else: else:
for folder in select(f.name for f in Folder if f.root): with db_session:
scanner.queue_folder(folder) for folder in select(f.name for f in Folder if f.root):
scanner.queue_folder(folder)
scanner.run() scanner.run()
stats = scanner.stats() stats = scanner.stats()
@ -242,6 +245,7 @@ class SupysonicCLI(cmd.Cmd):
user_pass_parser.add_argument('name', help = 'Name/login of the user to which change the password') user_pass_parser.add_argument('name', help = 'Name/login of the user to which change the password')
user_pass_parser.add_argument('password', nargs = '?', help = 'New password') user_pass_parser.add_argument('password', nargs = '?', help = 'New password')
@db_session
def user_list(self): def user_list(self):
self.write_line('Name\t\tAdmin\tEmail\n----\t\t-----\t-----') self.write_line('Name\t\tAdmin\tEmail\n----\t\t-----\t-----')
self.write_line('\n'.join('{0: <16}{1}\t{2}'.format(u.name, '*' if u.admin else '', u.mail) for u in User.select())) self.write_line('\n'.join('{0: <16}{1}\t{2}'.format(u.name, '*' if u.admin else '', u.mail) for u in User.select()))
@ -253,6 +257,7 @@ class SupysonicCLI(cmd.Cmd):
raise ValueError("Passwords don't match") raise ValueError("Passwords don't match")
return password return password
@db_session
def user_add(self, name, admin, password, email): def user_add(self, name, admin, password, email):
try: try:
if not password: if not password:
@ -261,6 +266,7 @@ class SupysonicCLI(cmd.Cmd):
except ValueError as e: except ValueError as e:
self.write_error_line(str(e)) self.write_error_line(str(e))
@db_session
def user_delete(self, name): def user_delete(self, name):
try: try:
UserManager.delete_by_name(name) UserManager.delete_by_name(name)
@ -268,6 +274,7 @@ class SupysonicCLI(cmd.Cmd):
except ObjectNotFound as e: except ObjectNotFound as e:
self.write_error_line(str(e)) self.write_error_line(str(e))
@db_session
def user_setadmin(self, name, off): def user_setadmin(self, name, off):
user = User.get(name = name) user = User.get(name = name)
if user is None: if user is None:
@ -276,6 +283,7 @@ class SupysonicCLI(cmd.Cmd):
user.admin = not off user.admin = not off
self.write_line("{0} '{1}' admin rights".format('Revoked' if off else 'Granted', name)) self.write_line("{0} '{1}' admin rights".format('Revoked' if off else 'Granted', name))
@db_session
def user_changepass(self, name, password): def user_changepass(self, name, password):
try: try:
if not password: if not password:

View File

@ -82,7 +82,6 @@ class Scanner(Thread):
self.__queue.put(folder_name) self.__queue.put(folder_name)
@db_session
def run(self): def run(self):
while not self.__stopped.is_set(): while not self.__stopped.is_set():
try: try:
@ -90,9 +89,10 @@ class Scanner(Thread):
except QueueEmpty: except QueueEmpty:
break break
folder = Folder.get(name = folder_name, root = True) with db_session:
if folder is None: folder = Folder.get(name = folder_name, root = True)
continue if folder is None:
continue
self.__scan_folder(folder) self.__scan_folder(folder)
@ -140,9 +140,10 @@ class Scanner(Thread):
# Remove files that have been deleted # Remove files that have been deleted
if not self.__stopped.is_set(): if not self.__stopped.is_set():
for track in Track.select(lambda t: t.root_folder == folder): with db_session:
if not self.__is_valid_path(track.path): for track in Track.select(lambda t: t.root_folder == folder):
self.remove_file(track.path) if not self.__is_valid_path(track.path):
self.remove_file(track.path)
# Remove deleted/moved folders and update cover art info # Remove deleted/moved folders and update cover art info
folders = [ folder ] folders = [ folder ]
@ -150,26 +151,29 @@ class Scanner(Thread):
f = folders.pop() f = folders.pop()
if not f.root and not os.path.isdir(f.path): if not f.root and not os.path.isdir(f.path):
f.delete() # Pony will cascade with db_session:
f.delete() # Pony will cascade
continue continue
self.find_cover(f.path) self.find_cover(f.path)
folders += f.children with db_session:
folders += Folder[f.id].children # f has been fetched from another session, refetch or Pony will complain
if not self.__stopped.is_set(): if not self.__stopped.is_set():
folder.last_scan = int(time.time()) with db_session:
Folder[folder.id].last_scan = int(time.time())
if self.__on_folder_end is not None: if self.__on_folder_end is not None:
self.__on_folder_end(folder) self.__on_folder_end(folder)
@db_session
def prune(self): def prune(self):
if self.__stopped.is_set(): if self.__stopped.is_set():
return return
self.__stats.deleted.albums = Album.prune() with db_session:
self.__stats.deleted.artists = Artist.prune() self.__stats.deleted.albums = Album.prune()
Folder.prune() self.__stats.deleted.artists = Artist.prune()
Folder.prune()
def __is_valid_path(self, path): def __is_valid_path(self, path):
if not os.path.exists(path): if not os.path.exists(path):