Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package upmpdcli for openSUSE:Factory 
checked in at 2022-08-13 22:37:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/upmpdcli (Old)
 and      /work/SRC/openSUSE:Factory/.upmpdcli.new.1521 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "upmpdcli"

Sat Aug 13 22:37:13 2022 rev:10 rq:994889 version:1.5.19

Changes:
--------
--- /work/SRC/openSUSE:Factory/upmpdcli/upmpdcli.changes        2022-06-02 
21:54:16.492373587 +0200
+++ /work/SRC/openSUSE:Factory/.upmpdcli.new.1521/upmpdcli.changes      
2022-08-13 22:37:14.446731814 +0200
@@ -0,0 +1,12 @@
+-------------------------------------------------------------------
+Sat Aug 13 10:59:31 UTC 2022 - Michael Pujos <pujos.mich...@gmail.com>
+
+- update to 1.5.19:
+  * Fix uprcl web control interface (asking for update did not work)
+  * Fix upradios stations list order
+- update to 1.5.18:
+  * Create an upmpdcli group during installation and change the group
+    to upmpdcli when started as root (in addition to the setuid())
+  * uprcl: try to show more information when the initialisation fails
+
+-------------------------------------------------------------------

Old:
----
  upmpdcli-1.5.17.tar.gz
  upmpdcli-1.5.17.tar.gz.asc

New:
----
  upmpdcli-1.5.19.tar.gz
  upmpdcli-1.5.19.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ upmpdcli.spec ++++++
--- /var/tmp/diff_new_pack.c2XXIG/_old  2022-08-13 22:37:14.978733160 +0200
+++ /var/tmp/diff_new_pack.c2XXIG/_new  2022-08-13 22:37:14.982733170 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           upmpdcli
-Version:        1.5.17
+Version:        1.5.19
 Release:        0
 Summary:        UPnP Media Renderer front-end to MPD, the Music Player Daemon
 License:        GPL-2.0-or-later

++++++ upmpdcli-1.5.17.tar.gz -> upmpdcli-1.5.19.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/upmpdcli-1.5.17/Makefile.in 
new/upmpdcli-1.5.19/Makefile.in
--- old/upmpdcli-1.5.17/Makefile.in     2022-05-21 16:11:59.000000000 +0200
+++ new/upmpdcli-1.5.19/Makefile.in     2022-06-28 09:15:54.000000000 +0200
@@ -1749,8 +1749,8 @@
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-@MAKECONFGUI_FALSE@clean-local:
 @MAKECONFGUI_FALSE@install-exec-local:
+@MAKECONFGUI_FALSE@clean-local:
 clean: clean-am
 
 clean-am: clean-binPROGRAMS clean-generic clean-local mostlyclean-am
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/upmpdcli-1.5.17/cfgui/picoxml.h 
new/upmpdcli-1.5.19/cfgui/picoxml.h
--- old/upmpdcli-1.5.17/cfgui/picoxml.h 2021-12-14 11:41:23.000000000 +0100
+++ new/upmpdcli-1.5.19/cfgui/picoxml.h 2022-06-16 09:00:07.000000000 +0200
@@ -71,7 +71,7 @@
     PicoXMLParser(const std::string& input)
         : m_in(input), m_pos(0) {}
 
-    virtual ~PicoXMLParser() {}
+    virtual ~PicoXMLParser() = default;
     PicoXMLParser(const PicoXMLParser&) = delete;
     PicoXMLParser& operator=(const PicoXMLParser&) = delete;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/upmpdcli-1.5.17/configure 
new/upmpdcli-1.5.19/configure
--- old/upmpdcli-1.5.17/configure       2022-05-21 16:11:59.000000000 +0200
+++ new/upmpdcli-1.5.19/configure       2022-06-28 09:15:54.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for upmpdcli 1.5.17.
+# Generated by GNU Autoconf 2.69 for upmpdcli 1.5.19.
 #
 # Report bugs to <j...@lesbonscomptes.com>.
 #
@@ -580,8 +580,8 @@
 # Identity of this package.
 PACKAGE_NAME='upmpdcli'
 PACKAGE_TARNAME='upmpdcli'
-PACKAGE_VERSION='1.5.17'
-PACKAGE_STRING='upmpdcli 1.5.17'
+PACKAGE_VERSION='1.5.19'
+PACKAGE_STRING='upmpdcli 1.5.19'
 PACKAGE_BUGREPORT='j...@lesbonscomptes.com'
 PACKAGE_URL='http://www.lesbonscomptes.com/upmpdcli'
 
@@ -1331,7 +1331,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures upmpdcli 1.5.17 to adapt to many kinds of systems.
+\`configure' configures upmpdcli 1.5.19 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1398,7 +1398,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of upmpdcli 1.5.17:";;
+     short | recursive ) echo "Configuration of upmpdcli 1.5.19:";;
    esac
   cat <<\_ACEOF
 
@@ -1523,7 +1523,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-upmpdcli configure 1.5.17
+upmpdcli configure 1.5.19
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1826,7 +1826,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by upmpdcli $as_me 1.5.17, which was
+It was created by upmpdcli $as_me 1.5.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2696,7 +2696,7 @@
 
 # Define the identity of the package.
  PACKAGE='upmpdcli'
- VERSION='1.5.17'
+ VERSION='1.5.19'
 
 
 # Some tools Automake needs.
@@ -6136,7 +6136,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by upmpdcli $as_me 1.5.17, which was
+This file was extended by upmpdcli $as_me 1.5.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6203,7 +6203,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-upmpdcli config.status 1.5.17
+upmpdcli config.status 1.5.19
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/upmpdcli-1.5.17/configure.ac 
new/upmpdcli-1.5.19/configure.ac
--- old/upmpdcli-1.5.17/configure.ac    2022-05-21 16:10:56.000000000 +0200
+++ new/upmpdcli-1.5.19/configure.ac    2022-06-28 09:15:41.000000000 +0200
@@ -1,4 +1,4 @@
-AC_INIT([upmpdcli], [1.5.17], [j...@lesbonscomptes.com],
+AC_INIT([upmpdcli], [1.5.19], [j...@lesbonscomptes.com],
              [upmpdcli], [http://www.lesbonscomptes.com/upmpdcli])
 AC_PREREQ([2.53])
 AC_CONFIG_MACRO_DIRS([m4])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/upmpdcli-1.5.17/src/main.cxx 
new/upmpdcli-1.5.19/src/main.cxx
--- old/upmpdcli-1.5.17/src/main.cxx    2021-04-28 15:05:37.000000000 +0200
+++ new/upmpdcli-1.5.19/src/main.cxx    2022-06-13 10:17:53.000000000 +0200
@@ -473,7 +473,7 @@
     }
     if (geteuid() == 0) {
         if (runas == 0) {
-            LOGFAT("upmpdcli won't run as root and user " << upmpdcliuser << 
+            LOGFAT("upmpdcli won't run as root and user " << upmpdcliuser <<
                    " does not exist " << endl);
             return 1;
         }
@@ -556,20 +556,23 @@
         }
         if (!opts.cachefn.empty()) {
             if (chown(opts.cachefn.c_str(), runas, -1) != 0) {
-                LOGERR("chown("<< opts.cachefn << ") : errno : " <<
-                       errno << endl);
+                LOGERR("chown("<< opts.cachefn << ") : errno : " << errno << 
endl);
             }
         }
         if (!g_configfilename.empty()) {
-            ensureconfreadable(g_configfilename.c_str(), upmpdcliuser.c_str(),
-                               runas, runasg);
+            ensureconfreadable(g_configfilename.c_str(), upmpdcliuser.c_str(), 
runas, runasg);
         }
+
         if (initgroups(upmpdcliuser.c_str(), runasg) < 0) {
             LOGERR("initgroup failed. Errno: " << errno << endl);
         }
+
+        if (setgid(runasg) < 0) {
+            LOGSYSERR("main", "setgid", runasg);
+            LOGERR("Current gid: " << getegid() << "\n");
+        }
         if (setuid(runas) < 0) {
-            LOGFAT("Can't set my uid to " << runas << " current: " << geteuid()
-                   << endl);
+            LOGFAT("Can't set my uid to " << runas << " current: " << 
geteuid() << "\n");
             return 1;
         }
 #if 0
@@ -601,8 +604,7 @@
     if (!sc2mpdpath.empty()) {
         // Check if sc2mpd is actually there
         if (access(sc2mpdpath.c_str(), X_OK|R_OK) != 0) {
-            LOGERR("Specified path for sc2mpd: " << sc2mpdpath << 
-                   " is not executable" << endl);
+            LOGERR("Specified path for sc2mpd: " << sc2mpdpath <<  " is not 
executable\n");
             sc2mpdpath.clear();
         }
     }
@@ -612,15 +614,13 @@
         // command are executable. We'll assume that mpd is ok
         if (access(senderpath.c_str(), X_OK|R_OK) != 0) {
             LOGERR("The specified path for the sender starter script: ["
-                   << senderpath <<
-                   "] is not executable, disabling the sender mode.\n");
+                   << senderpath << "] is not executable, disabling the sender 
mode.\n");
             senderpath.clear();
         } else {
             string path;
             if (!ExecCmd::which("mpd2sc", path)) {
                 LOGERR("Sender starter was specified and found but the mpd2sc "
-                       "command is not found (or executable). Disabling "
-                       "the sender mode.\n");
+                       "command is not found (or executable). Disabling the 
sender mode.\n");
                 senderpath.clear();
             }
         }
@@ -698,8 +698,7 @@
     }
     mylib = LibUPnP::getLibUPnP();
     if (!mylib || !mylib->ok()) {
-        LOGFAT("Lib init failed: " <<
-               mylib->errAsString("main", mylib->getInitError()) << endl);
+        LOGFAT("Lib init failed: " << mylib->errAsString("main", 
mylib->getInitError()) << endl);
         return 1;
     }
     hwaddr = mylib->hwaddr();
@@ -733,14 +732,12 @@
         int fd;
         if ((fd = open(opts.screceiverstatefile.c_str(),
                        O_CREAT|O_RDWR, 0644)) < 0) {
-            LOGERR("creat(" << opts.screceiverstatefile << ") : errno : "
-                   << errno << endl);
+            LOGERR("creat(" << opts.screceiverstatefile << ") : errno : " << 
errno << endl);
         } else {
             close(fd);
             if (geteuid() == 0 && chown(opts.screceiverstatefile.c_str(),
                                         runas, -1) != 0) {
-                LOGERR("chown(" << opts.screceiverstatefile << ") : errno : "
-                       << errno << endl);
+                LOGERR("chown(" << opts.screceiverstatefile << ") : errno : " 
<< errno << endl);
             }
         }
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/pycommon/upradioconf.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/pycommon/upradioconf.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/pycommon/upradioconf.py       
2021-04-13 16:15:54.000000000 +0200
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/pycommon/upradioconf.py       
2022-06-28 09:09:53.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 2021 J.F.Dockes
+# Copyright (C) 2021-2022 J.F.Dockes
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
 #   the Free Software Foundation; either version 2 of the License, or
@@ -16,6 +16,7 @@
 
 import os
 import subprocess
+import threading
 
 from upmplgutils import uplog, direntry
 import conftree
@@ -30,29 +31,61 @@
         self._readRadios(upconfig)
         #uplog("Radios: %s" % self._radios)
 
+    def _fetchStream(self, index, title, uri, artUri, mime):
+        uplog(f"upradios: Fetching {title}")
+        streamUri=""
+        try:
+            streamUri = subprocess.check_output([self.fetchstream, uri])
+            streamUri = streamUri.decode('utf-8').strip("\r\n")
+        except Exception as ex:
+            uplog("fetchStream.py failed for %s: %s" % (title, ex))
+        if streamUri:
+            self._radios[index] = (title, streamUri, uri, artUri, mime)
+        
     def _readRadiosFromConf(self, conf):
         '''Read radio definitions from a config file (either main file or 
radiolist)'''
         keys = conf.getSubKeys_unsorted()
+        threads = []
+        cntt = 0
         for k in keys:
             if k.startswith("radio"):
                 title = k[6:]
                 uri = conf.get("url", k)
                 artUri = conf.get("artUrl", k)
                 mime = conf.get("mime", k)
-                if mime:
-                    uplog("GOT MIME %s" % mime)
-                streamUri = None
-                try:
-                    streamUri = subprocess.check_output([self.fetchstream, 
uri])
-                    streamUri = streamUri.decode('utf-8').strip("\r\n")
-                except Exception as ex:
-                    uplog("fetchStream.py failed for %s: %s" % (title, ex))
-                if streamUri:
-                    self._radios.append((title, streamUri, uri, artUri, mime))
+                self._radios.append(None)
+                idx = len(self._radios) - 1
+                t = threading.Thread(target=self._fetchStream, args=(idx, 
title, uri, artUri, mime))
+                t.start()
+                threads.append(t)
+                cntt += 1
+                # Note that it's ok to join a thread multiple times, so we 
keep things simple
+                if cntt >= self._maxthreads:
+                    uplog(f"upradios: Waiting for threads")
+                    for t in threads:
+                        t.join()
+                    uplog(f"upradios: Waiting done")
+                    cntt = 0
+        uplog(f"upradios: Waiting for threads")
+        for t in threads:
+            t.join()
+        uplog(f"upradios: Waiting done")
+        # Get rid of None entries in the list, keeping the order
+        tlist = []
+        for rd in self._radios:
+            if rd:
+                tlist.append(rd)
+        self._radios = tlist
+        uplog(f"upradios: Init done")
         
     def _readRadios(self, upconfig):
         '''Read radio definitions from main config file, then possible 
radiolist'''
         self._radios = []
+        self._maxthreads = upconfig.get("upradiosmaxthreads")
+        if self._maxthreads:
+            self._maxthreads = int(self._maxthreads)
+        else:
+            self._maxthreads = 5
         self._readRadiosFromConf(upconfig)
         radiolist = upconfig.get("radiolist")
         if radiolist:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprcl-app.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprcl-app.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprcl-app.py    
2021-03-20 14:30:41.000000000 +0100
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprcl-app.py    
2022-06-13 09:44:52.000000000 +0200
@@ -35,11 +35,10 @@
 # Initialize communication with our parent process: pipe and method
 # call dispatch
 
-# Some of the modules we use write garbage to stdout, which messes the
-# communication with our parent. Why can't people understand that this
-# is verboten ? Get off my lawn ! So we dup stdout and close it, then
-# pass the right file to cmdtalk.  (hoping that none of the imports
-# above print anything, else we'll have to move this code up)
+# Some of the modules we use write garbage to stdout, which messes the 
communication with our
+# parent. Why can't people understand that this is verboten ? So we dup stdout 
and close it, then
+# pass the right file to cmdtalk.  (hoping that none of the imports above 
print anything, else we'll
+# have to move this code up)
 _outfile = os.fdopen(os.dup(1), "w")
 os.close(1)
 fd = os.open("/dev/null", os.O_WRONLY)
@@ -121,14 +120,20 @@
         raise Exception("uprcl-app: browse: can't browse meta for now")
     else:
         try:
-            if not uprclinit.ready():
+            if not uprclinit.initdone():
                 entries = [waitentry(objid + 'notready', objid, 
uprclinit.getHttphp()),]
-            elif not idpath:
-                entries = _rootentries()
             else:
-                if len(rootmap) == 0:
-                    _rootentries()
-                entries = _browsedispatch(objid, bflg, offset, count)
+                initstatus, initmessage = uprclinit.initstatus()
+                if not initstatus:
+                    entries = [waitentry(objid + 'notready', objid, 
uprclinit.getHttphp(),
+                                         initmessage),]
+                else:
+                    if not idpath:
+                        entries = _rootentries()
+                    else:
+                        if len(rootmap) == 0:
+                            _rootentries()
+                        entries = _browsedispatch(objid, bflg, offset, count)
         finally:
             uprclinit.g_dblock.release_read()
 
@@ -140,8 +145,7 @@
         entries = entries[2]
     #msgproc.log("%s" % entries)
     encoded = json.dumps(entries)
-    return {"entries" : encoded, "nocache" : nocache,
-            "offset" : str(resoffs), "total" : str(total)}
+    return {"entries" : encoded, "nocache" : nocache, "offset" : str(resoffs), 
"total" : str(total)}
 
 
 @dispatcher.record('search')
@@ -155,12 +159,18 @@
     nocache = "1"
 
     try:
-        if not uprclinit.ready():
+        if not uprclinit.initdone():
             entries = [waitentry(objid + 'notready', objid, 
uprclinit.getHttphp()),]
         else:
-            entries = uprclsearch.search(
-                uprclinit.getTree('folders'), uprclinit.getRclConfdir(), objid,
-                upnps, uprclinit.getObjPrefix(), uprclinit.getHttphp(), 
uprclinit.getPathPrefix())
+            initstatus, initmessage = uprclinit.initstatus()
+            if not initstatus:
+                entries = [waitentry(objid + 'notready', objid, 
uprclinit.getHttphp(),
+                                     initmessage),]
+            else:
+                entries = uprclsearch.search(
+                    uprclinit.getTree('folders'), uprclinit.getRclConfdir(), 
objid,
+                    upnps, uprclinit.getObjPrefix(), uprclinit.getHttphp(),
+                    uprclinit.getPathPrefix())
     finally:
         uprclinit.g_dblock.release_read()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclfolders.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclfolders.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclfolders.py 
2021-04-06 10:39:06.000000000 +0200
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclfolders.py 
2022-06-13 12:54:49.000000000 +0200
@@ -345,11 +345,16 @@
         uplog("_rcl2folders took %.2f Seconds" % (end - start))
 
 
-    # Fetch all the docs by querying Recoll with [mime:*], which is
-    # guaranteed to match every doc without overflowing the query size
-    # (because the number of mime types is limited). Something like
-    # title:* would overflow. This creates the main doc array, which is
-    # then used by all modules.
+    # Fetch all the docs by querying Recoll with [mime:*], which is guaranteed 
to match every doc
+    # without overflowing the query size (because the number of mime types is 
limited). Something
+    # like title:* would overflow. This creates the main doc array, which is 
then used by all
+    # modules.
+    #
+    # Depending on the recoll version, we use a Python list of Recoll Docs or 
the more compact but
+    # immutable QResultStore
+    #
+    # When using the resultstore, the records are not modifyable and the 
aliastags processing is
+    # performed at indexing time by rclaudio. Cf. minimtagfixer.py
     def _fetchalldocs(self, confdir):
         #uplog("_fetchalldocs: has_resultstore: %s" % _has_resultstore)
         start = timer()
@@ -387,8 +392,7 @@
                 time.sleep(0)
 
         end = timer()
-        uplog("Retrieved %d docs in %.2f Seconds" %
-              (len(self._rcldocs), end - start))
+        uplog("Retrieved %d docs in %.2f Seconds" % (len(self._rcldocs), end - 
start))
 
 
     ##############
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclhttp.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclhttp.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclhttp.py    
2021-06-02 09:46:35.000000000 +0200
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclhttp.py    
2022-06-28 07:42:00.000000000 +0200
@@ -52,9 +52,9 @@
 
     reloadsecs='1'
     if what == 'Update Index':
-        uprclinit.start_update()
+        uprclinit.start_index_update()
     elif what == 'Reset Index':
-        uprclinit.start_update(rebuild=True)
+        uprclinit.start_index_update(rebuild=True)
     elif what == 'Refresh Status':
         reloadsecs = ''
     elif not what:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclindex.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclindex.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclindex.py   
2021-03-18 17:56:29.000000000 +0100
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclindex.py   
2022-06-12 17:03:36.000000000 +0200
@@ -28,7 +28,10 @@
 import uprclinit
 
 
-def _maybeinitconfdir(confdir, topdirs):
+# We recreate the Recoll configuration files at each startup. This is fast and 
avoids having to test
+# for changed parameters. No directly user-entered data lives in there, it all 
comes from
+# upmpdcli.conf, uprclconfrecolluser or the Minim configuration.
+def _initconfdir(confdir, topdirs):
     if not os.path.isdir(confdir):
         if os.path.exists(confdir):
             raise Exception("Exists and not directory: %s" % confdir)
@@ -83,16 +86,14 @@
 _idxproc = None
 _lastidxstatus = None
 
-
 def runindexer(confdir, topdirs, rebuild=False):
     global _idxproc, _lastidxstatus
     if _idxproc is not None:
         raise Exception("uprclrunindexer: already running")
 
-    _maybeinitconfdir(confdir, topdirs)
+    _initconfdir(confdir, topdirs)
 
-    cf = conftree.ConfSimple(os.path.join(confdir, "recoll.conf"),
-                             readonly = False)
+    cf = conftree.ConfSimple(os.path.join(confdir, "recoll.conf"), readonly = 
False)
     td = cf.get("topdirs", '')
     if td != topdirs:
         cf.set("topdirs", topdirs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclinit.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclinit.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclinit.py    
2021-12-09 18:39:20.000000000 +0100
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclinit.py    
2022-06-14 04:39:19.000000000 +0200
@@ -35,17 +35,30 @@
 from upmplgutils import uplog, findmyip, getcachedir
 from conftree import stringToStrings
 
+### Configuration stuff
+_g_rclconfdir = ""
 _g_pathprefix = ""
 _g_httphp = ""
-g_dblock = ReadWriteLock()
-_g_rclconfdir = ""
 _g_friendlyname = "UpMpd-mediaserver"
-_g_trees = {}
-_g_trees_order = ['folders', 'playlists', 'tags', 'untagged']
-g_minimconfig = None
 # Prefix for object Ids. This must be consistent with what
 # contentdirectory.cxx does
 _g_myprefix = '0$uprcl$'
+g_minimconfig = None
+
+### Index update status
+# Running state: ""/"Updating"/"Rebuilding"
+g_initrunning = ""
+# Completion status: ok/notok
+g_initstatus = False
+# Possible error message if not ok
+g_initmessage = ""
+
+### Data created during initialisation
+_g_trees = {}
+_g_trees_order = ['folders', 'playlists', 'tags', 'untagged']
+
+g_dblock = ReadWriteLock()
+
 
 def getObjPrefix():
     return _g_myprefix
@@ -70,19 +83,33 @@
 
 def _reset_index():
     _update_index(True)
+
+def initdone():
+    g_dblock.acquire_read()
+    if g_initrunning:
+        return False
+    else:
+        return True
+
+def initstatus():
+    return (g_initstatus, g_initmessage)
+
+def updaterunning():
+    return g_initrunning
+
     
-# Create or update Recoll index, then read and process the data.  This
-# runs in the separate uprcl_init_worker thread, and signals
-# startup/completion by setting/unsetting the g_initrunning flag
+# Create or update Recoll index, then read and process the data. This runs in 
a separate thread, and
+# signals startup/completion by setting/unsetting the g_initrunning flag.
+#
+# While this is running, or after a failure any access to the root container 
from a Control Point
+# will display either an "Initializing" or error message.
 def _update_index(rebuild=False):
     uplog("Creating/updating index in %s for %s" % (_g_rclconfdir, 
g_rcltopdirs))
 
-    # We take the writer lock, making sure that no browse/search
-    # thread are active, then set the busy flag and release the
-    # lock. This allows future browse operations to signal the
-    # condition to the user instead of blocking (if we kept the write
-    # lock).
-    global g_initrunning, _g_trees
+    # We take the writer lock, making sure that no browse/search thread are 
active, then set the
+    # busy flag and release the lock. This allows future browse operations to 
signal the condition
+    # to the user instead of blocking (if we kept the write lock).
+    global g_initrunning, _g_trees, g_initstatus, g_initmessage
     g_dblock.acquire_write()
     g_initrunning = "Rebuilding" if rebuild else "Updating"
     g_dblock.release_write()
@@ -107,24 +134,31 @@
         newtrees['playlists'] = playlists
         newtrees['tags'] = tagged
         _g_trees = newtrees
+        g_initstatus = True
+        uplog("Init done")
+    except Exception as ex:
+        g_initstatus = False
+        g_initmessage = str(ex)
+        uplog(f"Initialisation failed with: {g_initmessage}")
     finally:
         g_dblock.acquire_write()
-        g_initrunning = False
+        g_initrunning = ""
         g_dblock.release_write()
 
 
-# Initialisation runs in a thread because of the possibly long index
-# initialization, during which the main thread can answer
-# "initializing..." to the clients.
-def _uprcl_init_worker():
+# This is called from uprcl-app when starting up, before doing anything else. 
We read configuration
+# data, then start two threads: the permanent HTTP server and the index update 
thread.
+def uprcl_init():
+
+    global _g_pathprefix, g_initstatus, g_initmessage
 
+    
     #######
     # Acquire configuration data.
     
-    global _g_pathprefix
-    # pathprefix would typically be something like "/uprcl". It's used
-    # for dispatching URLs to the right plugin for processing. We
-    # strip it whenever we need a real file path
+    # We get the path prefix from an environment variable set by our parent 
upmpdcli. It would
+    # typically be something like "/uprcl". It's used for dispatching URLs to 
the right plugin for
+    # processing. We strip it whenever we need a real file path.
     if "UPMPD_PATHPREFIX" not in os.environ:
         raise Exception("No UPMPD_PATHPREFIX in environment")
     _g_pathprefix = os.environ["UPMPD_PATHPREFIX"]
@@ -159,13 +193,26 @@
         g_rcltopdirs = g_minimconfig.getcontentdirs()
         if g_rcltopdirs:
             g_rcltopdirs = conftree.stringsToString(g_rcltopdirs)
-    if not g_rcltopdirs:
-        raise Exception("uprclmediadirs not in config")
 
+    # At this point g_rcltopdirs is a single string (possibly with quoted 
parts). Compute a list and
+    # check the elements
+    pthlist = conftree.stringToStrings(g_rcltopdirs)
+    goodpthlist = []
+    for dir in pthlist:
+        if not os.path.isdir(dir):
+            uplog(f"uprcl: [{dir}] is not accessible")
+        else:
+            goodpthlist.append(dir)
+    if not goodpthlist:
+        g_initstatus = False
+        g_initmessage = "No accessible media directories in configuration"
+        return
+    
+    g_rcltopdirs = conftree.stringsToString(goodpthlist)
+    
     pthstr = g_upconfig.get("uprclpaths")
     if pthstr is None:
         uplog("uprclpaths not in config, using topdirs: [%s]" % g_rcltopdirs)
-        pthlist = stringToStrings(g_rcltopdirs)
         pthstr = ""
         for p in pthlist:
             pthstr += p + ":" + p + ","
@@ -179,41 +226,25 @@
         
     host,port = _g_httphp.split(':')
 
-    # Start the bottle app. Its' both the control/config interface and
-    # the file streamer
+    start_index_update()
+
+    # Start the bottle app. It's both the control/config interface and the 
file streamer
     httpthread = threading.Thread(target=runbottle,
-                                 kwargs = {'host':host ,
-                                           'port':int(port),
-                                           'pthstr':pthstr,
-                                           'pathprefix':_g_pathprefix})
+                                  kwargs = {'host':host ,
+                                            'port':int(port),
+                                            'pthstr':pthstr,
+                                            'pathprefix':_g_pathprefix})
     httpthread.daemon = True 
     httpthread.start()
 
-    _update_index()
-
-    uplog("Init done")
+    uplog("Init started")
 
 
-def uprcl_init():
-    global g_initrunning
-    g_initrunning = True
-    initthread = threading.Thread(target=_uprcl_init_worker)
-    initthread.daemon = True 
-    initthread.start()
-
-def ready():
-    g_dblock.acquire_read()
-    if g_initrunning:
-        return False
-    else:
-        return True
-
-def updaterunning():
-    return g_initrunning
-
-def start_update(rebuild=False):
+# This is called from the Bottle Web UI interface for requesting an index 
update or rebuild
+def start_index_update(rebuild=False):
     try:
-        if not ready():
+        # initdone() acquires the reader lock
+        if not initdone():
             return
         targ = _reset_index if rebuild else _update_index
         idxthread = threading.Thread(target=targ)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclplaylists.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclplaylists.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclplaylists.py       
2021-04-11 14:12:02.000000000 +0200
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclplaylists.py       
2022-06-13 07:58:24.000000000 +0200
@@ -36,7 +36,10 @@
         self._idprefix = '0$uprcl$playlists'
         self._httphp = httphp
         self._pprefix = pathprefix
-        self._radios = upradioconf.UpmpdcliRadios(uprclinit.g_upconfig)
+        if not 
conftree.valToBool(uprclinit.g_upconfig.get("uprclnoradioconf")):
+            self._radios = upradioconf.UpmpdcliRadios(uprclinit.g_upconfig)
+        else:
+            self._radios = []
         self.recoll2playlists(rcldocs)
 
     # Create the untagged entries static vector by filtering the global
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprcltagscreate.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprcltagscreate.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprcltagscreate.py      
2021-03-18 17:45:14.000000000 +0100
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprcltagscreate.py      
2022-06-12 19:04:56.000000000 +0200
@@ -186,9 +186,9 @@
     uplog("prepareTags: g_indextags: %s g_tagdisplaytag %s" %
           (g_indextags, g_tagdisplaytag))
     
-    # Compute an array of (table name, recoll field)
-    # translations. Most often they are identical. This also
-    # determines what fields we create tables for.
+    # Compute an array of (table name, recoll field) translations for the tags 
we need to process,
+    # as determined by the indexTags property. Most often they are identical. 
This also determines
+    # what fields we create tables for.
     tabtorclfield = []
     for nm in g_indextags:
         tb = _alltagtotable[nm]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclutils.py 
new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclutils.py
--- old/upmpdcli-1.5.17/src/mediaserver/cdplugins/uprcl/uprclutils.py   
2021-03-20 14:28:43.000000000 +0100
+++ new/upmpdcli-1.5.19/src/mediaserver/cdplugins/uprcl/uprclutils.py   
2022-06-13 07:19:40.000000000 +0200
@@ -174,13 +174,13 @@
 
 
 # Bogus entry for the top directory while the index/db is updating
-def waitentry(id, pid, httphp):
+def waitentry(id, pid, httphp, msg="Initializing..."):
     li = {}
     li['tp'] = 'it'
     li['id'] = id
     li['pid'] = pid
     li['upnp:class'] = 'object.item.audioItem.musicTrack'
-    li['tt'] = "Initializing..."
+    li['tt'] = msg
     li['uri'] = "http://%s%s"; % (httphp, "/waiting")
     li['res.mime'] = "audio/mpeg"
     return li

Reply via email to