]> kaliko git repositories - mpd-sima.git/blobdiff - sima/utils/config.py
Add abstract unix socket support for MPD connection
[mpd-sima.git] / sima / utils / config.py
index 346bbe77c1103b3141746549e4b2fa8b7a95d773..a46c0c66493e3519ab1af41cefe7d88e8087ddbf 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,7 @@
 #  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/>.
 #
-#
+# pylint: disable=bad-continuation
 
 """
 Deal with configuration and data files.
 
 """
 Deal with configuration and data files.
@@ -29,7 +30,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, environ, 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 +49,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 +70,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
+            'queue_mode': "track",  # TODO control values
             'max_art': 10,
             'max_art': 10,
-            'single_album': "false",
+            '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 +139,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 +158,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,7 +187,7 @@ 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' +
                              ' "group" (actual permission %o octal).' %
         if mode & S_IRWXO or mode & S_IRWXG:
             self.log.warning('File is readable by "other" and/or' +
                              ' "group" (actual permission %o octal).' %
@@ -185,18 +201,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):
@@ -214,7 +238,7 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
             data_dir = join(homedir, '.local', 'share', DIRNAME)
         else:
             self.log.critical('Can\'t find a suitable location for data folder (XDG_DATA_HOME)')
             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'):
             sys.exit(1)
 
         if self.startopt.get('conf_file'):
@@ -222,6 +246,7 @@ class ConfMan(object):  # CONFIG MANAGER CLASS
             pass
         elif environ.get('XDG_CONFIG_HOME'):
             conf_dir = join(environ.get('XDG_CONFIG_HOME'), DIRNAME)
             pass
         elif environ.get('XDG_CONFIG_HOME'):
             conf_dir = join(environ.get('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 +255,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: