Switch to side-by-side view

--- a/upqo/ohplaylist_qo.h
+++ b/upqo/ohplaylist_qo.h
@@ -29,6 +29,8 @@
 #include "libupnpp/control/cdircontent.hxx"
 #include "libupnpp/soaphelp.hxx"
 
+#include "ohpool.h"
+
 class OHPLMetadata {
 public:
     virtual std::string getDidl() const = 0;
@@ -92,13 +94,21 @@
     }
 
 public slots:
-    virtual void sync() {
-        //qDebug() << "OHPL::sync";
+
+    /// Read state from the remote. Used when starting up, to avoid
+    /// having to wait for events.
+    virtual void fetchState() {
         std::vector<int> ids;
-        int tp;
-        if (idArray(&ids, &tp)) {
+        int tok;
+        if (idArray(&ids, &tok))
             onIdArrayChanged(ids);
-        }
+        if (m_srv->id(&tok) == 0) {
+            m_curid = tok;
+            emit currentTrackId(tok);
+        }
+        UPnPClient::OHPlaylist::TPState tpst;
+        if (m_srv->transportState(&tpst) == 0)
+            emit tpStateChanged(tpst);
     }
 
     // Ping renderer to check it's still there.
@@ -188,20 +198,6 @@
         return ret == 0;
     }
 
-    /// Read state from the remote. Used when starting up, to avoid
-    /// having to wait for events.
-    virtual void fetchState() {
-        std::vector<int> ids;
-        int tok;
-        m_srv->idArray(&ids, &tok);
-        onIdArrayChanged(ids);
-        if (m_srv->id(&tok) == 0)
-            emit currentTrackId(tok);
-        UPnPClient::OHPlaylist::TPState tpst;
-        if (m_srv->transportState(&tpst) == 0)
-            emit tpStateChanged(tpst);
-    }
-    
 signals:
     void currentTrackId(int);
     void trackArrayChanged();
@@ -216,91 +212,16 @@
 private slots:
 
     void onIdArrayChanged(std::vector<int> nids) {
-        //qDebug() << "OHPL::onIdArrayChanged: " << vtos(nids).c_str();
-
-        // We used to do nothing if the id array was unchanged, but
-        // this gained very little, and going through lets us
-        // re-read the current title metadata further on. This could
-        // have changed without an id change, for example if the renderer
-        // is upmpdcli and mpd is playing an internet radio (no qvers
-        // update when the title changes).
-#if 0
-        if (!m_forceUpdate && nids == m_idsv) {
-            //qDebug() << "OHPL::onIdArrayChanged: unchanged";
+        m_forceUpdate = false;
+        m_idsv = nids;
+
+        if (!ohupdmetapool(nids, m_curid, m_metapool, m_srv))
             return;
-        }
-#endif
-        m_forceUpdate = false;
-
-        // Clean up metapool entries not in ids. We build a set with
-        // the new ids list first. For small lists it does not matter,
-        // for big ones, this will prevent what would otherwise be a
-        // linear search the repeated search to make this
-        // quadratic. We're sort of O(n * log(n)) instead.
-        if (!m_metapool.empty() && !nids.empty()){
-            STD_UNORDERED_SET<int> tmpset(nids.begin(), nids.end());
-            for (STD_UNORDERED_MAP<int, UPnPClient::UPnPDirObject>::iterator it
-                     = m_metapool.begin(); it != m_metapool.end(); ) {
-                if (tmpset.find(it->first) == tmpset.end()) {
-                    it = m_metapool.erase(it);
-                } else {
-                    it++;
-                }
-            }
-        }
-
-        // Find ids for which we have no metadata. Always re-read current title
-        std::vector<int> unids; // unknown
-        for (std::vector<int>::iterator it = nids.begin(); 
-             it != nids.end(); it++) {
-            if (m_metapool.find(*it) == m_metapool.end() || m_curid == *it)
-                unids.push_back(*it);
-        }
-        if (!unids.empty()) {
-            //qDebug() << "OHPL::onIdArrayChanged: need metadata for: " 
-            //       << vtos(unids).c_str();
-        }
-        // Fetch needed metadata, 10 entries at a time
-        const unsigned int batchsize(10);
-        for (unsigned int i = 0; i < unids.size();) {
-            unsigned int j = 0;
-            std::vector<int> metaslice;
-            for (; j < batchsize && (i+j) < unids.size(); j++) {
-                metaslice.push_back(unids[i+j]);
-            }
-
-            //qDebug() << "OHPL::onIdArrayChanged: Requesting metadata for " 
-            //<< vtos(metaslice).c_str();
-            std::vector<UPnPClient::OHPlaylist::TrackListEntry> entries;
-            int ret;
-            if ((ret = m_srv->readList(metaslice, &entries))) {
-                qDebug() << "OHPL: readList failed: " << ret;
-                goto out;
-            }
-            for (std::vector<UPnPClient::OHPlaylist::TrackListEntry>::iterator
-                     it = entries.begin(); it != entries.end(); it++) {
-                //qDebug() << "OHPL: data for " << it->id << " " << 
-                //    it->dirent.m_title.c_str();
-                // Kazoo for example does not set a resource (uri)
-                // inside the dirent.  Set it from the uri field in
-                // this case.
-                if (it->dirent.m_resources.empty()) {
-                    UPnPClient::UPnPResource res;
-                    res.m_uri = it->url;
-                    it->dirent.m_resources.push_back(res);
-                }
-                m_metapool[it->id] = it->dirent;
-            }
-            i += j;
-        }
-
-        m_idsv = nids;
+
         qDebug() << "OHPL::onIdArrayChanged: emit trackArrayChanged(). " <<
             "idsv size" << m_idsv.size() << " pool size " << m_metapool.size();
         emit trackArrayChanged();
         emit currentTrackId(m_curid);
-    out:
-        return;
     }
 
 protected:
@@ -310,15 +231,6 @@
     bool m_forceUpdate;
     bool m_discardArrayEvents;
 
-    std::string vtos(std::vector<int> nids) {
-        std::string sids;
-        for (std::vector<int>::iterator it = nids.begin(); 
-             it != nids.end(); it++)
-            sids += UPnPP::SoapHelp::i2s(*it) + " ";
-        return sids;
-    }
-
-
 private:
     virtual bool idArray(std::vector<int> *ids, int *tokp) {
         return m_srv->idArray(ids, tokp) == 0;