mirror of
https://github.com/spl0k/supysonic.git
synced 2024-11-09 19:52:16 +00:00
Web UI now scans in background
This commit is contained in:
parent
7bbbdac41c
commit
e210f25bb3
@ -3,16 +3,18 @@
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
||||
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||
# 2017 Óscar García Amor
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
from flask import redirect, request, session, url_for
|
||||
from flask import current_app, redirect, request, session, url_for
|
||||
from flask import Blueprint
|
||||
from functools import wraps
|
||||
from pony.orm import ObjectNotFound
|
||||
|
||||
from ..daemon.client import DaemonClient
|
||||
from ..daemon.exceptions import DaemonUnavailableError
|
||||
from ..db import Artist, Album, Track
|
||||
from ..managers.user import UserManager
|
||||
|
||||
@ -34,6 +36,18 @@ def login_check():
|
||||
flash('Please login')
|
||||
return redirect(url_for('frontend.login', returnUrl = request.script_root + request.url[len(request.url_root)-1:]))
|
||||
|
||||
@frontend.before_request
|
||||
def scan_status():
|
||||
if not request.user or not request.user.admin:
|
||||
return
|
||||
|
||||
try:
|
||||
scanned = DaemonClient(current_app.config['DAEMON']['socket']).get_scanning_progress()
|
||||
if scanned is not None:
|
||||
flash('Scanning in progress, {} files scanned.'.format(scanned))
|
||||
except DaemonUnavailableError:
|
||||
pass
|
||||
|
||||
@frontend.route('/')
|
||||
def index():
|
||||
stats = {
|
||||
|
@ -3,7 +3,7 @@
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
||||
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
@ -13,6 +13,8 @@ import uuid
|
||||
from flask import current_app, flash, redirect, render_template, request, url_for
|
||||
from pony.orm import ObjectNotFound
|
||||
|
||||
from ..daemon.client import DaemonClient
|
||||
from ..daemon.exceptions import DaemonUnavailableError
|
||||
from ..db import Folder
|
||||
from ..managers.folder import FolderManager
|
||||
from ..scanner import Scanner
|
||||
@ -22,7 +24,13 @@ from . import admin_only, frontend
|
||||
@frontend.route('/folder')
|
||||
@admin_only
|
||||
def folder_index():
|
||||
return render_template('folders.html', folders = Folder.select(lambda f: f.root))
|
||||
try:
|
||||
DaemonClient(current_app.config['DAEMON']['socket']).get_scanning_progress()
|
||||
allow_scan = True
|
||||
except DaemonUnavailableError:
|
||||
allow_scan = False
|
||||
flash("The daemon is unavailable, can't scan from the web interface, use the CLI to do so.", 'warning')
|
||||
return render_template('folders.html', folders = Folder.select(lambda f: f.root), allow_scan = allow_scan)
|
||||
|
||||
@frontend.route('/folder/add')
|
||||
@admin_only
|
||||
@ -69,35 +77,18 @@ def del_folder(id):
|
||||
@frontend.route('/folder/scan/<id>')
|
||||
@admin_only
|
||||
def scan_folder(id = None):
|
||||
extensions = current_app.config['BASE']['scanner_extensions']
|
||||
if extensions:
|
||||
extensions = extensions.split(' ')
|
||||
try:
|
||||
if id is not None:
|
||||
folders = [ FolderManager.get(id).name ]
|
||||
else:
|
||||
folders = []
|
||||
DaemonClient(current_app.config['DAEMON']['socket']).scan(folders)
|
||||
flash('Scanning started')
|
||||
except ValueError as e:
|
||||
flash(str(e), 'error')
|
||||
except ObjectNotFound:
|
||||
flash('No such folder', 'error')
|
||||
except DaemonUnavailableError:
|
||||
flash("Can't start scan", 'error')
|
||||
|
||||
scanner = Scanner(extensions = extensions)
|
||||
|
||||
if id is None:
|
||||
for folder in Folder.select(lambda f: f.root):
|
||||
scanner.scan(folder)
|
||||
else:
|
||||
try:
|
||||
folder = FolderManager.get(id)
|
||||
except ValueError as e:
|
||||
flash(str(e), 'error')
|
||||
return redirect(url_for('frontend.folder_index'))
|
||||
except ObjectNotFound:
|
||||
flash('No such folder', 'error')
|
||||
return redirect(url_for('frontend.folder_index'))
|
||||
|
||||
scanner.scan(folder)
|
||||
|
||||
scanner.finish()
|
||||
stats = scanner.stats()
|
||||
|
||||
flash('Added: {0.artists} artists, {0.albums} albums, {0.tracks} tracks'.format(stats.added))
|
||||
flash('Deleted: {0.artists} artists, {0.albums} albums, {0.tracks} tracks'.format(stats.deleted))
|
||||
if stats.errors:
|
||||
flash('Errors in:')
|
||||
for err in stats.errors:
|
||||
flash('- ' + err)
|
||||
return redirect(url_for('frontend.folder_index'))
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
This file is part of Supysonic.
|
||||
Supysonic is a Python implementation of the Subsonic server API.
|
||||
|
||||
Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
||||
Copyright (C) 2013-2019 Alban 'spl0k' Féron
|
||||
2017 Óscar García Amor
|
||||
|
||||
Distributed under terms of the GNU AGPLv3 license.
|
||||
@ -18,7 +18,7 @@
|
||||
</div>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr><th>Name</th><th>Path</th><th></th><th></th></tr>
|
||||
<tr><th>Name</th><th>Path</th><th></th>{% if allow_scan %}<th></th>{% endif %}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for folder in folders %}
|
||||
@ -26,15 +26,15 @@
|
||||
<td>{{ folder.name }}</td><td>{{ folder.path }}</td><td>
|
||||
<button class="btn btn-danger btn-xs" data-href="{{ url_for('frontend.del_folder', id = folder.id) }}" data-toggle="modal" data-target="#confirm-delete" aria-label="Delete folder">
|
||||
<span class="glyphicon glyphicon-remove-circle" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="Delete folder"></span></button></td>
|
||||
<td><a class="btn btn-default btn-xs" href="{{ url_for('frontend.scan_folder', id = folder.id) }}" aria-label="Scan folder">
|
||||
<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="Scan folder"></span></a></td>
|
||||
{%if allow_scan %}<td><a class="btn btn-default btn-xs" href="{{ url_for('frontend.scan_folder', id = folder.id) }}" aria-label="Scan folder">
|
||||
<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="Scan folder"></span></a></td>{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<a href="{{ url_for('frontend.add_folder_form') }}" class="btn btn-default">Add</a>
|
||||
<a href="{{ url_for('frontend.scan_folder') }}" class="btn btn-default">Scan all</a>
|
||||
{% if allow_scan %}<a href="{{ url_for('frontend.scan_folder') }}" class="btn btn-default">Scan all</a>{% endif %}
|
||||
</div>
|
||||
<div class="modal fade" id="confirm-delete" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
|
@ -4,7 +4,7 @@
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2017-2018 Alban 'spl0k' Féron
|
||||
# Copyright (C) 2017-2019 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
@ -94,12 +94,9 @@ class FolderTestCase(FrontendTestBase):
|
||||
rv = self.client.get('/folder/scan/' + str(uuid.uuid4()), follow_redirects = True)
|
||||
self.assertIn('No such folder', rv.data)
|
||||
rv = self.client.get('/folder/scan/' + str(folder.id), follow_redirects = True)
|
||||
self.assertIn('Added', rv.data)
|
||||
self.assertIn('Deleted', rv.data)
|
||||
self.assertIn('start', rv.data)
|
||||
rv = self.client.get('/folder/scan', follow_redirects = True)
|
||||
self.assertIn('Added', rv.data)
|
||||
self.assertIn('Deleted', rv.data)
|
||||
self.assertIn('start', rv.data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user