# -*- coding: utf-8 -*-
-# Copyright (c) 2009, 2010, 2011, 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2009-2015, 2019-2021 kaliko <kaliko@azylum.org>
+# Copyright (c) 2019 sacha <sachahony@gmail.com>
#
# This file is part of sima
#
# You should have received a copy of the GNU General Public License
# along with sima. If not, see <http://www.gnu.org/licenses/>.
#
-#
"""
Deal with configuration and data files.
import sys
from configparser import Error
-from os import (access, makedirs, environ, stat, chmod, W_OK, R_OK)
+from os import (access, makedirs, getenv, stat, chmod, W_OK)
from os.path import (join, isdir, isfile, dirname, exists)
from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
'sima': {
'internal': "Crop, Lastfm, Random",
'contrib': "",
- 'user_db': "false",
+ 'user_db': False,
'history_duration': 8,
'queue_length': 2,
'var_dir': 'empty',
- 'musicbrainzid': "true",
+ 'musicbrainzid': True,
+ 'repeat_disable_queue': True,
+ 'single_disable_queue': True,
+ 'mopidy_compat': False,
},
- 'daemon':{
+ 'daemon': {
'daemon': False,
'pidfile': "",
},
'consume': 10,
'priority': 0,
},
- 'echonest': {
- 'queue_mode': "track", #TODO control values
- 'max_art': 15,
- 'single_album': "false",
- 'track_to_add': 1,
- 'album_to_add': 1,
- 'depth': 1,
- 'priority': 100,
- },
'lastfm': {
- 'queue_mode': "track", #TODO control values
+ 'queue_mode': "track", # TODO control values
'max_art': 10,
- 'single_album': "false",
+ 'single_album': False,
'track_to_add': 1,
'album_to_add': 1,
+ 'shuffle_album': False,
+ 'track_to_add_from_album': 0, # <=0 means keep all
'depth': 1,
'cache': True,
'priority': 100,
},
'random': {
- 'flavour': "sensible", # in pure, sensible
+ 'flavour': "sensible", # in pure, sensible
'track_to_add': 1,
'priority': 50,
},
+ 'tags': {
+ 'comment': "",
+ 'date': "",
+ 'genre': "",
+ 'label': "",
+ 'originaldate': "",
+ 'filter': "",
+ 'queue_mode': "track",
+ 'single_album': False,
+ 'track_to_add': 1,
+ 'album_to_add': 1,
+ 'priority': 80,
+ },
+ 'genre': {
+ 'queue_mode': "track",
+ 'single_album': False,
+ 'track_to_add': 1,
+ 'album_to_add': 1,
+ 'priority': 80,
+ },
}
#
-class ConfMan(object): # CONFIG MANAGER CLASS
+class ConfMan: # CONFIG MANAGER CLASS
"""
Configuration manager.
Default configuration is stored in DEFAULT_CONF dictionnary.
self.use_envar()
self.startopt = options
- ## INIT CALLS
+ # INIT CALLS
self.init_config()
self.supersedes_config_with_cmd_line_options()
+ # set dbfile
+ self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
# Controls files access
self.control_facc()
- # generate dbfile
- self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
+
+ # Create directories
+ data_dir = self.config['sima']['var_dir']
+ if not isdir(data_dir):
+ self.log.trace('Creating "%s"', data_dir)
+ makedirs(data_dir)
+ chmod(data_dir, 0o700)
def control_facc(self):
"""Controls file access.
This is relevant only for file provided through the configuration file
since files provided on the command line are already checked with
- argparse.
+ argparse. Also add config['sima']['db_file'] contructed here in init
"""
ok = True
- for op, ftochk in [('logfile', self.config.get('log','logfile')),
- ('pidfile', self.config.get('daemon', 'pidfile')),]:
+ for op, ftochk in [('logfile', self.config.get('log', 'logfile')),
+ ('pidfile', self.config.get('daemon', 'pidfile')),
+ ('db file', self.config.get('sima', 'db_file'))]:
if not ftochk:
continue
if isdir(ftochk):
- self.log.critical('Need a file not a directory: "{}"'.format(ftochk))
+ self.log.critical('Need a file not a directory: "%s"', ftochk)
ok = False
if not exists(ftochk):
# Is parent directory writable then
filedir = dirname(ftochk)
if not access(filedir, W_OK):
- self.log.critical('no write access to "{0}" ({1})'.format(filedir, op))
+ self.log.critical('no write access to "%s" (%s)', filedir, op)
ok = False
else:
if not access(ftochk, W_OK):
- self.log.critical('no write access to "{0}" ({1})'.format(ftochk, op))
+ self.log.critical('no write access to "%s" (%s)', ftochk, op)
ok = False
if not ok:
- if exists(self.conf_file):
- self.log.warning('Try to check the configuration file: {}'.format(self.conf_file))
sys.exit(2)
def control_mod(self):
Controls conf file permissions.
"""
mode = S_IMODE(stat(self.conf_file)[ST_MODE])
- self.log.debug('file permission is: %o' % mode)
+ self.log.debug('file permission is: %o', mode)
if mode & S_IRWXO or mode & S_IRWXG:
self.log.warning('File is readable by "other" and/or' +
- ' "group" (actual permission %o octal).' %
- mode)
- self.log.warning('Consider setting permissions' +
- ' to 600 octal.')
+ ' "group" (actual permission %o octal).', mode)
+ self.log.warning('Consider setting permissions to 600 octal.')
def supersedes_config_with_cmd_line_options(self):
"""Updates defaults settings with command line options"""
for opt in self.config.options(sec):
if opt in list(self.startopt.keys()):
self.config.set(sec, opt, str(self.startopt.get(opt)))
+ # honor MPD_HOST format as in mpc(1) for command line option --host
+ if self.startopt.get('host'):
+ if '@' in self.startopt.get('host'):
+ host, passwd = utils.parse_mpd_host(self.startopt.get('host'))
+ if passwd:
+ self.config.set('MPD', 'password', passwd)
+ if host:
+ self.config.set('MPD', 'host', host)
def use_envar(self):
"""Use MPD en.var. to set defaults"""
mpd_host, mpd_port, passwd = utils.get_mpd_environ()
if mpd_host:
- self.log.info('Env. variable MPD_HOST set to "%s"' % mpd_host)
+ self.log.info('Env. variable MPD_HOST set to "%s"', mpd_host)
self.config['MPD'].update(host=mpd_host)
if passwd:
self.log.info('Env. variable MPD_HOST contains password.')
self.config['MPD'].update(password=passwd)
if mpd_port:
- self.log.info('Env. variable MPD_PORT set to "%s".' % mpd_port)
+ self.log.info('Env. variable MPD_PORT set to "%s".', mpd_port)
self.config['MPD'].update(port=mpd_port)
def init_config(self):
http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
"""
- homedir = environ.get('HOME')
+ homedir = getenv('HOME')
- if environ.get('XDG_DATA_HOME'):
- data_dir = join(environ.get('XDG_DATA_HOME'), DIRNAME)
+ if getenv('XDG_DATA_HOME'):
+ data_dir = join(getenv('XDG_DATA_HOME'), DIRNAME)
elif homedir and isdir(homedir) and homedir not in ['/']:
data_dir = join(homedir, '.local', 'share', DIRNAME)
else:
- self.log.error('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
- self.log.error('Please use "--var_dir" to set a proper location')
+ self.log.critical('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
+ self.log.critical('Please use "--var-dir" to set a proper location')
sys.exit(1)
- if not isdir(data_dir):
- makedirs(data_dir)
- chmod(data_dir, 0o700)
-
if self.startopt.get('conf_file'):
# No need to handle conf file location
pass
- elif environ.get('XDG_CONFIG_HOME'):
- conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
+ elif getenv('XDG_CONFIG_HOME'):
+ conf_dir = join(getenv('XDG_CONFIG_HOME'), DIRNAME)
+ self.conf_file = join(conf_dir, CONF_FILE)
elif homedir and isdir(homedir) and homedir not in ['/']:
conf_dir = join(homedir, '.config', DIRNAME)
- # Create conf_dir if necessary
- if not isdir(conf_dir):
- makedirs(conf_dir)
- chmod(conf_dir, 0o700)
self.conf_file = join(conf_dir, CONF_FILE)
else:
self.log.critical('Can\'t find a suitable location for config folder (XDG_CONFIG_HOME)')
self.log.critical('Please use "--config" to locate the conf file')
sys.exit(1)
- ## Sima sqlite DB
+ # Sima sqlite DB
self.config['sima']['var_dir'] = join(data_dir)
# If no conf file present, uses defaults
if not isfile(self.conf_file):
return
- self.log.info('Loading configuration from: %s' % self.conf_file)
+ self.log.info('Loading configuration from: %s', self.conf_file)
self.control_mod()
try: