--- a
+++ b/src/mediaserver/cdplugins/spotify/spotiproxy.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2017-2018 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
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _SPOTIPROXY_H_INCLUDED_
+#define _SPOTIPROXY_H_INCLUDED_
+
+#include <string>
+#include <memory>
+#include <functional>
+
+#include "bufxchange.h"
+#include "abuffer.h"
+#include "netfetch.h"
+
+   
+/** 
+ * Represent a Spotify session, and possibly a single active play transaction
+ */
+class SpotiProxy {
+public:
+
+    /** 
+     * Create/get reference to the SpotiProxy singleton. Call with
+     * actual user/pass the first time. Later calls can either use the
+     * same pair or empty values. cachedir and settingsdir can't change either.
+     */
+    static SpotiProxy *getSpotiProxy(
+        const std::string& user = "", const std::string& pass = "",
+        const std::string& cachedir="", const std::string& settingsdir=""
+        );
+
+    /** Alternatively, the login parameters can be set by a separate call prior
+     *  to the above, and independantly from login. All calls to
+     *  getSpotiProxy() can then be param-less */
+    static void setParams(
+        const std::string& user, const std::string& pass,
+        const std::string& cachedir, const std::string& settingsdir);
+
+    ~SpotiProxy();
+
+    const std::string& getReason();
+
+    bool loginOk();
+
+    typedef std::function<int (
+        const void *frames, int num_frames, int channels, int rate)> AudioSink;
+
+    bool playTrack(const std::string& trackid, AudioSink sink,
+                     int seekmsecs = 0);
+
+    bool startPlay(const std::string& trackid, AudioSink sink,
+                     int seekmsecs = 0);
+    bool waitForEndOfPlay();
+
+    bool isPlaying();
+    int durationMs();
+    
+    void stop();
+    
+    class Internal;
+private:
+    SpotiProxy(const std::string&, const std::string&, const std::string&,
+               const std::string&);
+    std::unique_ptr<Internal> m;
+};
+
+
+//
+// NetFetch adapter for libspotify audio streams
+class SpotiFetch : public NetFetch {
+public:
+    SpotiFetch(const std::string& url);
+    ~SpotiFetch();
+
+    /// Start the transfer to the output queue.
+    bool start(BufXChange<ABuffer*> *queue, uint64_t offset = 0) override;
+
+    // Wait for HTTP headers. This allows, e.g. doing stuff depending
+    // on content-type before proceeding with the actual data transfer
+    bool waitForHeaders(int maxSecs = 0) override;
+    // Retrieve header value (after a successful waitForHeaders).
+    bool headerValue(const std::string& nm, std::string& val) override;
+
+    // Check if the fetch operation is done and retrieve the results
+    // if it is. This does not wait, it returns false if the transfer
+    // is still running.
+    bool fetchDone(FetchStatus *code, int *http_code) override;
+
+    /// Reset after transfer done, for retrying for exemple.
+    bool reset() override;
+
+    class Internal;
+private:
+    std::unique_ptr<Internal> m;
+};
+
+#endif /* _SPOTIPROXY_H_INCLUDED_ */