1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-09-19 10:51:04 +00:00

Improve config.py to read file only in check

This commit is contained in:
Óscar García Amor 2017-08-08 10:37:22 +02:00
parent 09ce5ae455
commit a1619dd96a
10 changed files with 153 additions and 93 deletions

70
.gitignore vendored
View File

@ -1,6 +1,68 @@
*.pyc # ---> Python
.*.sw[a-z] # Byte-compiled / optimized / DLL files
*~ __pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/ build/
develop-eggs/
dist/ dist/
MANIFEST downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# ---> Vim
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~

View File

@ -20,7 +20,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys, cmd, argparse, getpass, time import sys, cmd, argparse, getpass, time
from supysonic.config import Config from supysonic import config
from supysonic.db import get_store, Folder, User from supysonic.db import get_store, Folder, User
from supysonic.managers.folder import FolderManager from supysonic.managers.folder import FolderManager
@ -225,10 +225,10 @@ class CLI(cmd.Cmd):
print "Successfully changed '{}' password".format(name) print "Successfully changed '{}' password".format(name)
if __name__ == "__main__": if __name__ == "__main__":
if not Config().check(): if not config.check():
sys.exit(1) sys.exit(1)
cli = CLI(get_store(Config().get('base', 'database_uri'))) cli = CLI(get_store(config.get('base', 'database_uri')))
if len(sys.argv) > 1: if len(sys.argv) > 1:
cli.onecmd(' '.join(sys.argv[1:])) cli.onecmd(' '.join(sys.argv[1:]))
else: else:

View File

@ -27,7 +27,7 @@ import codecs
from xml.etree import ElementTree from xml.etree import ElementTree
from supysonic import scanner from supysonic import scanner
from supysonic.config import Config from supysonic import config
from supysonic.web import app, store from supysonic.web import app, store
from supysonic.db import Track, Album, Artist, Folder, User, ClientPrefs, now from supysonic.db import Track, Album, Artist, Folder, User, ClientPrefs, now
from . import get_entity from . import get_entity
@ -71,14 +71,14 @@ def stream_media():
if format and format != 'raw' and format != src_suffix: if format and format != 'raw' and format != src_suffix:
dst_suffix = format dst_suffix = format
dst_mimetype = Config().get_mime(dst_suffix) dst_mimetype = config.get_mime(dst_suffix)
if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate): if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate):
transcoder = Config().get('transcoding', 'transcoder_{}_{}'.format(src_suffix, dst_suffix)) transcoder = config.get('transcoding', 'transcoder_{}_{}'.format(src_suffix, dst_suffix))
decoder = Config().get('transcoding', 'decoder_' + src_suffix) or Config().get('transcoding', 'decoder') decoder = config.get('transcoding', 'decoder_' + src_suffix) or config.get('transcoding', 'decoder')
encoder = Config().get('transcoding', 'encoder_' + dst_suffix) or Config().get('transcoding', 'encoder') encoder = config.get('transcoding', 'encoder_' + dst_suffix) or config.get('transcoding', 'encoder')
if not transcoder and (not decoder or not encoder): if not transcoder and (not decoder or not encoder):
transcoder = Config().get('transcoding', 'transcoder') transcoder = config.get('transcoding', 'transcoder')
if not transcoder: if not transcoder:
message = 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix) message = 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix)
app.logger.info(message) app.logger.info(message)
@ -154,7 +154,7 @@ def cover_art():
if size > im.size[0] and size > im.size[1]: if size > im.size[0] and size > im.size[1]:
return send_file(os.path.join(res.path, 'cover.jpg')) return send_file(os.path.join(res.path, 'cover.jpg'))
size_path = os.path.join(Config().get('webapp', 'cache_dir'), str(size)) size_path = os.path.join(config.get('webapp', 'cache_dir'), str(size))
path = os.path.join(size_path, str(res.id)) path = os.path.join(size_path, str(res.id))
if os.path.exists(path): if os.path.exists(path):
return send_file(path) return send_file(path)

View File

@ -15,59 +15,57 @@ import mimetypes
import os import os
import tempfile import tempfile
class Config(object): # Seek for standard locations
config_file = [
'supysonic.conf',
os.path.expanduser('~/.config/supysonic/supysonic.conf'),
os.path.expanduser('~/.supysonic'),
'/etc/supysonic'
]
config = ConfigParser({ 'cache_dir': os.path.join(tempfile.gettempdir(), 'supysonic') })
def check():
""" """
Config object to work with config file Checks the config file and mandatory fields
""" """
def __init__(self): try:
# Seek for standard locations config.read(config_file)
config_file = [ except Exception as e:
'supysonic.conf', err = 'Config file is corrupted.\n{0}'.format(e)
os.path.expanduser('~/.config/supysonic/supysonic.conf'), raise SystemExit(err)
os.path.expanduser('~/.supysonic'),
'/etc/supysonic'
]
self.config = ConfigParser({ 'cache_dir': os.path.join(tempfile.gettempdir(), 'supysonic') })
# Try read config file or raise error
try:
self.config.read(config_file)
except Exception as e:
err = 'Config file is corrupted.\n{0}'.format(e)
raise SystemExit(err)
def check(self): try:
""" config.get('base', 'database_uri')
Checks the config for mandatory fields except (NoSectionError, NoOptionError):
""" raise SystemExit('No database URI set')
try:
self.config.get('base', 'database_uri')
except (NoSectionError, NoOptionError):
raise SystemExit('No database URI set')
return True
def get(self, section, option): return True
"""
Returns a config option value from config file
:param section: section where the option is stored def get(section, option):
:param option: option name """
:return: a config option value Returns a config option value from config file
:rtype: string
"""
try:
return self.config.get(section, option)
except (NoSectionError, NoOptionError):
return None
def get_mime(self, extension): :param section: section where the option is stored
""" :param option: option name
Returns mimetype of an extension based on config file :return: a config option value
:rtype: string
"""
try:
return config.get(section, option)
except (NoSectionError, NoOptionError):
return None
:param extension: extension string def get_mime(extension):
:return: mimetype """
:rtype: string Returns mimetype of an extension based on config file
"""
guessed_mime = mimetypes.guess_type('dummy.' + extension, False)[0] :param extension: extension string
config_mime = self.get('mimetypes', extension) :return: mimetype
default_mime = 'application/octet-stream' :rtype: string
return guessed_mime or config_mime or default_mime """
guessed_mime = mimetypes.guess_type('dummy.' + extension, False)[0]
config_mime = get('mimetypes', extension)
default_mime = 'application/octet-stream'
return guessed_mime or config_mime or default_mime

View File

@ -27,7 +27,7 @@ from storm.variables import Variable
import uuid, datetime, time import uuid, datetime, time
import os.path import os.path
from supysonic.config import Config from supysonic import config
def now(): def now():
return datetime.datetime.now().replace(microsecond = 0) return datetime.datetime.now().replace(microsecond = 0)
@ -213,7 +213,7 @@ class Track(object):
if prefs and prefs.format and prefs.format != self.suffix(): if prefs and prefs.format and prefs.format != self.suffix():
info['transcodedSuffix'] = prefs.format info['transcodedSuffix'] = prefs.format
info['transcodedContentType'] = Config().get_mime(prefs.format) info['transcodedContentType'] = config.get_mime(prefs.format)
return info return info

View File

@ -24,7 +24,7 @@ from supysonic.web import app, store
from supysonic.managers.user import UserManager from supysonic.managers.user import UserManager
from supysonic.db import User, ClientPrefs from supysonic.db import User, ClientPrefs
import uuid, csv import uuid, csv
from supysonic.config import Config from supysonic import config
from supysonic.lastfm import LastFm from supysonic.lastfm import LastFm
@app.before_request @app.before_request
@ -43,12 +43,12 @@ def user_index():
def user_profile(uid): def user_profile(uid):
if uid == 'me': if uid == 'me':
prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid'))) prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid')))
return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = Config().get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin)
else: else:
if not UserManager.get(store, session.get('userid'))[1].admin or not UserManager.get(store, uid)[0] is UserManager.SUCCESS: if not UserManager.get(store, session.get('userid'))[1].admin or not UserManager.get(store, uid)[0] is UserManager.SUCCESS:
return redirect(url_for('index')) return redirect(url_for('index'))
prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(uid)) prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(uid))
return render_template('profile.html', user = UserManager.get(store, uid)[1], api_key = Config().get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin) return render_template('profile.html', user = UserManager.get(store, uid)[1], api_key = config.get('lastfm', 'api_key'), clients = prefs, admin = UserManager.get(store, session.get('userid'))[1].admin)
@app.route('/user/<uid>', methods = [ 'POST' ]) @app.route('/user/<uid>', methods = [ 'POST' ])
def update_clients(uid): def update_clients(uid):

View File

@ -19,13 +19,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import requests, hashlib import requests, hashlib
from supysonic.config import Config from supysonic import config
class LastFm: class LastFm:
def __init__(self, user, logger): def __init__(self, user, logger):
self.__user = user self.__user = user
self.__api_key = Config().get('lastfm', 'api_key') self.__api_key = config.get('lastfm', 'api_key')
self.__api_secret = Config().get('lastfm', 'secret') self.__api_secret = config.get('lastfm', 'secret')
self.__enabled = self.__api_key is not None and self.__api_secret is not None self.__enabled = self.__api_key is not None and self.__api_secret is not None
self.__logger = logger self.__logger = logger

View File

@ -25,7 +25,7 @@ import mutagen
from storm.expr import ComparableExpr, compile, Like from storm.expr import ComparableExpr, compile, Like
from storm.exceptions import NotSupportedError from storm.exceptions import NotSupportedError
from supysonic.config import Config from supysonic import config
from supysonic.db import Folder, Artist, Album, Track, User, PlaylistTrack from supysonic.db import Folder, Artist, Album, Track, User, PlaylistTrack
from supysonic.db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack from supysonic.db import StarredFolder, StarredArtist, StarredAlbum, StarredTrack
from supysonic.db import RatingFolder, RatingTrack from supysonic.db import RatingFolder, RatingTrack
@ -63,7 +63,7 @@ class Scanner:
self.__deleted_albums = 0 self.__deleted_albums = 0
self.__deleted_tracks = 0 self.__deleted_tracks = 0
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.__folders_to_check = set()
@ -166,7 +166,7 @@ class Scanner:
tr.duration = int(tag.info.length) tr.duration = int(tag.info.length)
tr.bitrate = (tag.info.bitrate if hasattr(tag.info, 'bitrate') else int(os.path.getsize(path) * 8 / tag.info.length)) / 1000 tr.bitrate = (tag.info.bitrate if hasattr(tag.info, 'bitrate') else int(os.path.getsize(path) * 8 / tag.info.length)) / 1000
tr.content_type = Config().get_mime(os.path.splitext(path)[1][1:]) tr.content_type = config.get_mime(os.path.splitext(path)[1][1:])
tr.last_modification = os.path.getmtime(path) tr.last_modification = os.path.getmtime(path)
tralbum = self.__find_album(albumartist, album) tralbum = self.__find_album(albumartist, album)

View File

@ -27,7 +27,7 @@ from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler from watchdog.events import PatternMatchingEventHandler
from supysonic import db from supysonic import db
from supysonic.config import Config from supysonic import config
from supysonic.scanner import Scanner from supysonic.scanner import Scanner
OP_SCAN = 1 OP_SCAN = 1
@ -36,7 +36,7 @@ OP_MOVE = 4
class SupysonicWatcherEventHandler(PatternMatchingEventHandler): class SupysonicWatcherEventHandler(PatternMatchingEventHandler):
def __init__(self, queue, logger): def __init__(self, queue, logger):
extensions = Config().get('base', 'scanner_extensions') extensions = config.get('base', 'scanner_extensions')
patterns = map(lambda e: "*." + e.lower(), extensions.split()) if extensions else None patterns = map(lambda e: "*." + e.lower(), extensions.split()) if extensions else None
super(SupysonicWatcherEventHandler, self).__init__(patterns = patterns, ignore_directories = True) super(SupysonicWatcherEventHandler, self).__init__(patterns = patterns, ignore_directories = True)
@ -133,7 +133,7 @@ class ScannerProcessingQueue(Thread):
continue continue
self.__logger.debug("Instantiating scanner") self.__logger.debug("Instantiating scanner")
store = db.get_store(Config().get('base', 'database_uri')) store = db.get_store(config.get('base', 'database_uri'))
scanner = Scanner(store) scanner = Scanner(store)
item = self.__next_item() item = self.__next_item()
@ -201,17 +201,17 @@ class ScannerProcessingQueue(Thread):
class SupysonicWatcher(object): class SupysonicWatcher(object):
def run(self): def run(self):
if not Config().check(): if not config.check():
return return
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
if Config().get('daemon', 'log_file'): if config.get('daemon', 'log_file'):
log_handler = TimedRotatingFileHandler(Config().get('daemon', 'log_file'), when = 'midnight') log_handler = TimedRotatingFileHandler(config.get('daemon', 'log_file'), when = 'midnight')
else: else:
log_handler = logging.NullHandler() log_handler = logging.NullHandler()
log_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")) log_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
logger.addHandler(log_handler) logger.addHandler(log_handler)
if Config().get('daemon', 'log_level'): if config.get('daemon', 'log_level'):
mapping = { mapping = {
'DEBUG': logging.DEBUG, 'DEBUG': logging.DEBUG,
'INFO': logging.INFO, 'INFO': logging.INFO,
@ -219,9 +219,9 @@ class SupysonicWatcher(object):
'ERROR': logging.ERROR, 'ERROR': logging.ERROR,
'CRTICAL': logging.CRITICAL 'CRTICAL': logging.CRITICAL
} }
logger.setLevel(mapping.get(Config().get('daemon', 'log_level').upper(), logging.NOTSET)) logger.setLevel(mapping.get(config.get('daemon', 'log_level').upper(), logging.NOTSET))
store = db.get_store(Config().get('base', 'database_uri')) store = db.get_store(config.get('base', 'database_uri'))
folders = store.find(db.Folder, db.Folder.root == True) folders = store.find(db.Folder, db.Folder.root == True)
if not folders.count(): if not folders.count():

View File

@ -13,13 +13,13 @@ from flask import Flask, g
from os import makedirs, path from os import makedirs, path
from werkzeug.local import LocalProxy from werkzeug.local import LocalProxy
from supysonic.config import Config from supysonic import config
from supysonic.db import get_store from supysonic.db import get_store
# Supysonic database open # Supysonic database open
def get_db(): def get_db():
if not hasattr(g, 'database'): if not hasattr(g, 'database'):
g.database = get_store(Config().get('base', 'database_uri')) g.database = get_store(config.get('base', 'database_uri'))
return g.database return g.database
# Supysonic database close # Supysonic database close
@ -33,17 +33,17 @@ def create_application():
global app global app
# Check config for mandatory fields # Check config for mandatory fields
Config().check() config.check()
# Test for the cache directory # Test for the cache directory
if not path.exists(Config().get('webapp', 'cache_dir')): if not path.exists(config.get('webapp', 'cache_dir')):
os.makedirs(Config().get('webapp', 'cache_dir')) os.makedirs(config.get('webapp', 'cache_dir'))
# Flask! # Flask!
app = Flask(__name__) app = Flask(__name__)
# Set a secret key for sessions # Set a secret key for sessions
secret_key = Config().get('base', 'secret_key') secret_key = config.get('base', 'secret_key')
# If secret key is not defined in config, set develop key # If secret key is not defined in config, set develop key
if secret_key is None: if secret_key is None:
app.secret_key = 'd3v3l0p' app.secret_key = 'd3v3l0p'
@ -54,11 +54,11 @@ def create_application():
app.teardown_appcontext(close_db) app.teardown_appcontext(close_db)
# Set loglevel # Set loglevel
if Config().get('webapp', 'log_file'): if config.get('webapp', 'log_file'):
import logging import logging
from logging.handlers import TimedRotatingFileHandler from logging.handlers import TimedRotatingFileHandler
handler = TimedRotatingFileHandler(Config().get('webapp', 'log_file'), when = 'midnight') handler = TimedRotatingFileHandler(config.get('webapp', 'log_file'), when = 'midnight')
if Config().get('webapp', 'log_level'): if config.get('webapp', 'log_level'):
mapping = { mapping = {
'DEBUG': logging.DEBUG, 'DEBUG': logging.DEBUG,
'INFO': logging.INFO, 'INFO': logging.INFO,
@ -66,7 +66,7 @@ def create_application():
'ERROR': logging.ERROR, 'ERROR': logging.ERROR,
'CRTICAL': logging.CRITICAL 'CRTICAL': logging.CRITICAL
} }
handler.setLevel(mapping.get(Config().get('webapp', 'log_level').upper(), logging.NOTSET)) handler.setLevel(mapping.get(config.get('webapp', 'log_level').upper(), logging.NOTSET))
app.logger.addHandler(handler) app.logger.addHandler(handler)
# Import app sections # Import app sections