]> kaliko git repositories - mpd-sima.git/blobdiff - sima/utils/config.py
doc: publish html target uses setuptools build
[mpd-sima.git] / sima / utils / config.py
index 346bbe77c1103b3141746549e4b2fa8b7a95d773..caaac3ed64f388f7346c7bc663ca6b73f8e84aa8 100644 (file)
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 # -*- 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
 #
 #
 #  This file is part of sima
 #
@@ -16,7 +17,6 @@
 #  You should have received a copy of the GNU General Public License
 #  along with sima.  If not, see <http://www.gnu.org/licenses/>.
 #
 #  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.
 
 """
 Deal with configuration and data files.
@@ -29,7 +29,7 @@ import logging
 import sys
 
 from configparser import Error
 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)
 
 from os.path import (join, isdir, isfile, dirname, exists)
 from stat import (S_IMODE, ST_MODE, S_IRWXO, S_IRWXG)
 
@@ -48,13 +48,16 @@ DEFAULT_CONF = {
         'sima': {
             'internal': "Crop, Lastfm, Random",
             'contrib': "",
         'sima': {
             'internal': "Crop, Lastfm, Random",
             'contrib': "",
-            'user_db': "false",
+            'user_db': False,
             'history_duration': 8,
             'queue_length': 2,
             'var_dir': 'empty',
             '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': "",
             },
             'daemon': False,
             'pidfile': "",
             },
@@ -66,35 +69,48 @@ DEFAULT_CONF = {
             'consume': 10,
             'priority': 0,
             },
             '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': {
         'lastfm': {
-            'queue_mode': "track", #TODO control values
-            'max_art': 10,
-            'single_album': "false",
+            'queue_mode': "track",  # TODO control values
+            'max_art': 20,
+            'single_album': False,
             'track_to_add': 1,
             'album_to_add': 1,
             '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': {
             'depth': 1,
             'cache': True,
             'priority': 100,
             },
         'random': {
-            'flavour': "sensible", # in pure, sensible
+            'flavour': "sensible",  # in pure, sensible
             'track_to_add': 1,
             'priority': 50,
             },
             '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.
     """
     Configuration manager.
     Default configuration is stored in DEFAULT_CONF dictionnary.
@@ -122,18 +138,18 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
         self.use_envar()
         self.startopt = options
 
         self.use_envar()
         self.startopt = options
 
-        ## INIT CALLS
+        # INIT CALLS
         self.init_config()
         self.supersedes_config_with_cmd_line_options()
         self.init_config()
         self.supersedes_config_with_cmd_line_options()
-        # Controls files access
-        self.control_facc()
         # set dbfile
         self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
         # set dbfile
         self.config['sima']['db_file'] = join(self.config['sima']['var_dir'], 'sima.db')
+        # Controls files access
+        self.control_facc()
 
         # Create directories
         data_dir = self.config['sima']['var_dir']
         if not isdir(data_dir):
 
         # Create directories
         data_dir = self.config['sima']['var_dir']
         if not isdir(data_dir):
-            self.log.trace('Creating "{}"'.format(data_dir))
+            self.log.trace('Creating "%s"', data_dir)
             makedirs(data_dir)
             chmod(data_dir, 0o700)
 
             makedirs(data_dir)
             chmod(data_dir, 0o700)
 
@@ -141,29 +157,28 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
         """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
         """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
         """
         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):
             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):
                 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):
                     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:
                     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):
             sys.exit(2)
 
     def control_mod(self):
@@ -171,13 +186,11 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
         Controls conf file permissions.
         """
         mode = S_IMODE(stat(self.conf_file)[ST_MODE])
         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' +
         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"""
 
     def supersedes_config_with_cmd_line_options(self):
         """Updates defaults settings with command line options"""
@@ -185,18 +198,26 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
             for opt in self.config.options(sec):
                 if opt in list(self.startopt.keys()):
                     self.config.set(sec, opt, str(self.startopt.get(opt)))
             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:
 
     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.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):
             self.config['MPD'].update(port=mpd_port)
 
     def init_config(self):
@@ -206,22 +227,23 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
         http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
         """
 
         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.critical('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
         elif homedir and isdir(homedir) and homedir not in ['/']:
             data_dir = join(homedir, '.local', 'share', DIRNAME)
         else:
             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')
+            self.log.critical('Please use "--var-dir" to set a proper location')
             sys.exit(1)
 
         if self.startopt.get('conf_file'):
             # No need to handle conf file location
             pass
             sys.exit(1)
 
         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)
             self.conf_file = join(conf_dir, CONF_FILE)
         elif homedir and isdir(homedir) and homedir not in ['/']:
             conf_dir = join(homedir, '.config', DIRNAME)
             self.conf_file = join(conf_dir, CONF_FILE)
@@ -230,14 +252,14 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
             self.log.critical('Please use "--config" to locate the conf file')
             sys.exit(1)
 
             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.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:
         self.control_mod()
 
         try: