Switch to unified view

a/src/contentdirectory.cxx b/src/contentdirectory.cxx
...
...
21
21
22
#include <functional>
22
#include <functional>
23
#include <iostream>
23
#include <iostream>
24
#include <map>
24
#include <map>
25
#include <utility>
25
#include <utility>
26
#include <unordered_map>
26
27
27
#include "libupnpp/log.hxx"
28
#include "libupnpp/log.hxx"
28
#include "libupnpp/soaphelp.hxx"
29
#include "libupnpp/soaphelp.hxx"
29
#include "libupnpp/device/device.hxx"
30
#include "libupnpp/device/device.hxx"
30
31
32
#include "pathut.h"
33
#include "smallut.h"
34
#include "upmpdutils.hxx"
35
#include "cdplugins/cdplugin.hxx"
36
#include "cdplugins/tidal.hxx"
37
31
using namespace std;
38
using namespace std;
32
using namespace std::placeholders;
39
using namespace std::placeholders;
40
41
extern string g_datadir;
42
43
class ContentDirectory::Internal {
44
public:
45
    ~Internal() {
46
  for (auto& it : plugins) {
47
      delete it.second;
48
  }
49
    }
50
    CDPlugin *pluginFactory(const string& appname) {
51
  LOGDEB("ContentDirectory::pluginFactory: for " << appname << endl);
52
  if (!appname.compare("tidal")) {
53
      string pthcdplugs = path_cat(g_datadir, "cdplugins");
54
      return new Tidal({pthcdplugs, path_cat(pthcdplugs, appname)});
55
  } else {
56
      return nullptr;
57
  }
58
    }
59
    CDPlugin *pluginForApp(const string& appname) {
60
  auto it = plugins.find(appname);
61
  if (it != plugins.end()) {
62
      return it->second;
63
  } else {
64
      CDPlugin *plug = pluginFactory(appname);
65
      if (plug) {
66
      plugins[appname] = plug;
67
      }
68
      return plug;
69
  }
70
    }
71
    unordered_map<string, CDPlugin *> plugins;
72
};
33
73
34
static const string
74
static const string
35
sTpContentDirectory("urn:schemas-upnp-org:service:ContentDirectory:1");
75
sTpContentDirectory("urn:schemas-upnp-org:service:ContentDirectory:1");
36
static const string
76
static const string
37
sIdContentDirectory("urn:upnp-org:serviceId:ContentDirectory");
77
sIdContentDirectory("urn:upnp-org:serviceId:ContentDirectory");
38
78
39
ContentDirectory::ContentDirectory(UPnPProvider::UpnpDevice *dev)
79
ContentDirectory::ContentDirectory(UPnPProvider::UpnpDevice *dev)
40
    : UpnpService(sTpContentDirectory, sIdContentDirectory, dev)
80
    : UpnpService(sTpContentDirectory, sIdContentDirectory, dev),
81
      m(new Internal)
41
{
82
{
42
    dev->addActionMapping(
83
    dev->addActionMapping(
43
        this, "GetSearchCapabilities",
84
        this, "GetSearchCapabilities",
44
        bind(&ContentDirectory::actGetSearchCapabilities, this, _1, _2));
85
        bind(&ContentDirectory::actGetSearchCapabilities, this, _1, _2));
45
    dev->addActionMapping(
86
    dev->addActionMapping(
...
...
54
    dev->addActionMapping(
95
    dev->addActionMapping(
55
        this, "Search",
96
        this, "Search",
56
        bind(&ContentDirectory::actSearch, this, _1, _2));
97
        bind(&ContentDirectory::actSearch, this, _1, _2));
57
}
98
}
58
99
100
ContentDirectory::~ContentDirectory()
101
{
102
    delete m;
103
}
59
104
60
int ContentDirectory::actGetSearchCapabilities(const SoapIncoming& sc, SoapOutgoing& data)
105
int ContentDirectory::actGetSearchCapabilities(const SoapIncoming& sc, SoapOutgoing& data)
61
{
106
{
62
107
63
    LOGDEB("ContentDirectory::actGetSearchCapabilities: " << endl);
108
    LOGDEB("ContentDirectory::actGetSearchCapabilities: " << endl);
...
...
83
    LOGDEB("ContentDirectory::actGetSystemUpdateID: " << endl);
128
    LOGDEB("ContentDirectory::actGetSystemUpdateID: " << endl);
84
129
85
    std::string out_Id;
130
    std::string out_Id;
86
    data.addarg("Id", out_Id);
131
    data.addarg("Id", out_Id);
87
    return UPNP_E_SUCCESS;
132
    return UPNP_E_SUCCESS;
133
}
134
135
static vector<UpSong> rootdir;
136
void makerootdir()
137
{
138
    rootdir.push_back(UpSong::container("0$tidal", "0", "Tidal"));
139
}
140
141
// Returns totalmatches
142
static size_t readroot(int offs, int cnt, vector<UpSong>& out)
143
{
144
    //LOGDEB("readroot: offs " << offs << " cnt " << cnt << endl);
145
    if (rootdir.empty()) {
146
  makerootdir();
147
    }
148
    out.clear();
149
    if (offs < 0 || cnt <= 0) {
150
  return rootdir.size();
151
    }
152
  
153
    for (int i = 0; i < cnt; i++) {
154
  if (size_t(offs + i) < rootdir.size()) {
155
      out.push_back(rootdir[offs + i]);
156
  } else {
157
      break;
158
  }
159
    }
160
    //LOGDEB("readroot: returning " << out.size() << " entries\n");
161
    return rootdir.size();
88
}
162
}
89
163
90
int ContentDirectory::actBrowse(const SoapIncoming& sc, SoapOutgoing& data)
164
int ContentDirectory::actBrowse(const SoapIncoming& sc, SoapOutgoing& data)
91
{
165
{
92
    bool ok = false;
166
    bool ok = false;
...
...
125
    if (!ok) {
199
    if (!ok) {
126
        LOGERR("ContentDirectory::actBrowse: no SortCriteria in params\n");
200
        LOGERR("ContentDirectory::actBrowse: no SortCriteria in params\n");
127
        return UPNP_E_INVALID_PARAM;
201
        return UPNP_E_INVALID_PARAM;
128
    }
202
    }
129
203
130
    LOGDEB("ContentDirectory::actBrowse: " << " ObjectID " << in_ObjectID << " BrowseFlag " << in_BrowseFlag << " Filter " << in_Filter << " StartingIndex " << in_StartingIndex << " RequestedCount " << in_RequestedCount << " SortCriteria " << in_SortCriteria << endl);
204
    LOGDEB("ContentDirectory::actBrowse: " << " ObjectID " << in_ObjectID <<
205
     " BrowseFlag " << in_BrowseFlag << " Filter " << in_Filter <<
206
     " StartingIndex " << in_StartingIndex <<
207
     " RequestedCount " << in_RequestedCount <<
208
     " SortCriteria " << in_SortCriteria << endl);
131
209
210
    vector<string> sortcrits;
211
    stringToStrings(in_SortCriteria, sortcrits);
212
213
    CDPlugin::BrowseFlag bf;
214
    if (in_BrowseFlag.compare("BrowseMetadata")) {
215
  bf = CDPlugin::BFMeta;
216
    } else {
217
  bf = CDPlugin::BFChildren;
218
    }
132
    std::string out_Result;
219
    std::string out_Result;
133
    std::string out_NumberReturned;
220
    std::string out_NumberReturned;
134
    std::string out_TotalMatches;
221
    std::string out_TotalMatches;
135
    std::string out_UpdateID;
222
    std::string out_UpdateID;
136
223
224
    // Go fetch
225
    vector<UpSong> entries;
226
    size_t tot = 0;
227
    if (!in_ObjectID.compare("0")) {
228
  // Root directory: we do this ourselves
229
  tot = readroot(in_StartingIndex, in_RequestedCount, entries);
230
    } else {
231
  // Pass off request to appropriate app, defined by 1st elt in id
232
  string app;
233
  string::size_type dol0 = in_ObjectID.find_first_of("$");
234
  if (dol0 == string::npos) {
235
      LOGERR("ContentDirectory::actBrowse: bad id [" << in_ObjectID <<
236
         "]\n");
237
  } else {
238
      string::size_type dol1 = in_ObjectID.find_first_of("$", dol0 + 1);
239
      app = in_ObjectID.substr(dol0 + 1, dol1 - dol0 -1);
240
  }
241
  LOGDEB("ContentDirectory::actBrowse: app: [" << app << "]\n");
242
243
  // for now, app has better be tidal...
244
  CDPlugin *plg = m->pluginForApp(app);
245
  if (plg) {
246
      out_TotalMatches = plg->browse(in_ObjectID, in_StartingIndex,
247
                     in_RequestedCount, entries,
248
                     sortcrits, bf);
249
  } else {
250
      LOGERR("ContentDirectory::Browse: unknown app: [" << app << "]\n");
251
  }
252
    }
253
254
255
    // Process and send out result
256
    out_NumberReturned = ulltodecstr(entries.size());
257
    out_TotalMatches = ulltodecstr(tot);
258
    out_UpdateID = "1";
259
    out_Result = headDIDL();
260
    for (unsigned int i = 0; i < entries.size(); i++) {
261
  out_Result += entries[i].didl();
262
    } 
263
    out_Result += tailDIDL();
264
    
265
    data.addarg("Result", out_Result);
266
    LOGDEB("ContentDirectory::actBrowse: result [" << out_Result << "]\n");
267
    data.addarg("NumberReturned", out_NumberReturned);
268
    data.addarg("TotalMatches", out_TotalMatches);
269
    data.addarg("UpdateID", out_UpdateID);
270
    return UPNP_E_SUCCESS;
271
}
272
273
int ContentDirectory::actSearch(const SoapIncoming& sc, SoapOutgoing& data)
274
{
275
    bool ok = false;
276
    std::string in_ContainerID;
277
    ok = sc.get("ContainerID", &in_ContainerID);
278
    if (!ok) {
279
        LOGERR("ContentDirectory::actSearch: no ContainerID in params\n");
280
        return UPNP_E_INVALID_PARAM;
281
    }
282
    std::string in_SearchCriteria;
283
    ok = sc.get("SearchCriteria", &in_SearchCriteria);
284
    if (!ok) {
285
        LOGERR("ContentDirectory::actSearch: no SearchCriteria in params\n");
286
        return UPNP_E_INVALID_PARAM;
287
    }
288
    std::string in_Filter;
289
    ok = sc.get("Filter", &in_Filter);
290
    if (!ok) {
291
        LOGERR("ContentDirectory::actSearch: no Filter in params\n");
292
        return UPNP_E_INVALID_PARAM;
293
    }
294
    int in_StartingIndex;
295
    ok = sc.get("StartingIndex", &in_StartingIndex);
296
    if (!ok) {
297
        LOGERR("ContentDirectory::actSearch: no StartingIndex in params\n");
298
        return UPNP_E_INVALID_PARAM;
299
    }
300
    int in_RequestedCount;
301
    ok = sc.get("RequestedCount", &in_RequestedCount);
302
    if (!ok) {
303
        LOGERR("ContentDirectory::actSearch: no RequestedCount in params\n");
304
        return UPNP_E_INVALID_PARAM;
305
    }
306
    std::string in_SortCriteria;
307
    ok = sc.get("SortCriteria", &in_SortCriteria);
308
    if (!ok) {
309
        LOGERR("ContentDirectory::actSearch: no SortCriteria in params\n");
310
        return UPNP_E_INVALID_PARAM;
311
    }
312
313
    LOGDEB("ContentDirectory::actSearch: " << " ContainerID " << in_ContainerID << " SearchCriteria " << in_SearchCriteria << " Filter " << in_Filter << " StartingIndex " << in_StartingIndex << " RequestedCount " << in_RequestedCount << " SortCriteria " << in_SortCriteria << endl);
314
315
    std::string out_Result;
316
    std::string out_NumberReturned;
317
    std::string out_TotalMatches;
318
    std::string out_UpdateID;
319
320
    out_NumberReturned = "0";
321
    out_TotalMatches = "0";
322
137
    data.addarg("Result", out_Result);
323
    data.addarg("Result", out_Result);
138
    data.addarg("NumberReturned", out_NumberReturned);
324
    data.addarg("NumberReturned", out_NumberReturned);
139
    data.addarg("TotalMatches", out_TotalMatches);
325
    data.addarg("TotalMatches", out_TotalMatches);
140
    data.addarg("UpdateID", out_UpdateID);
326
    data.addarg("UpdateID", out_UpdateID);
141
    return UPNP_E_SUCCESS;
327
    return UPNP_E_SUCCESS;
142
}
328
}
143
329
144
int ContentDirectory::actSearch(const SoapIncoming& sc, SoapOutgoing& data)
145
{
146
    bool ok = false;
147
    std::string in_ContainerID;
148
    ok = sc.get("ContainerID", &in_ContainerID);
149
    if (!ok) {
150
        LOGERR("ContentDirectory::actSearch: no ContainerID in params\n");
151
        return UPNP_E_INVALID_PARAM;
152
    }
153
    std::string in_SearchCriteria;
154
    ok = sc.get("SearchCriteria", &in_SearchCriteria);
155
    if (!ok) {
156
        LOGERR("ContentDirectory::actSearch: no SearchCriteria in params\n");
157
        return UPNP_E_INVALID_PARAM;
158
    }
159
    std::string in_Filter;
160
    ok = sc.get("Filter", &in_Filter);
161
    if (!ok) {
162
        LOGERR("ContentDirectory::actSearch: no Filter in params\n");
163
        return UPNP_E_INVALID_PARAM;
164
    }
165
    int in_StartingIndex;
166
    ok = sc.get("StartingIndex", &in_StartingIndex);
167
    if (!ok) {
168
        LOGERR("ContentDirectory::actSearch: no StartingIndex in params\n");
169
        return UPNP_E_INVALID_PARAM;
170
    }
171
    int in_RequestedCount;
172
    ok = sc.get("RequestedCount", &in_RequestedCount);
173
    if (!ok) {
174
        LOGERR("ContentDirectory::actSearch: no RequestedCount in params\n");
175
        return UPNP_E_INVALID_PARAM;
176
    }
177
    std::string in_SortCriteria;
178
    ok = sc.get("SortCriteria", &in_SortCriteria);
179
    if (!ok) {
180
        LOGERR("ContentDirectory::actSearch: no SortCriteria in params\n");
181
        return UPNP_E_INVALID_PARAM;
182
    }
183
184
    LOGDEB("ContentDirectory::actSearch: " << " ContainerID " << in_ContainerID << " SearchCriteria " << in_SearchCriteria << " Filter " << in_Filter << " StartingIndex " << in_StartingIndex << " RequestedCount " << in_RequestedCount << " SortCriteria " << in_SortCriteria << endl);
185
186
    std::string out_Result;
187
    std::string out_NumberReturned;
188
    std::string out_TotalMatches;
189
    std::string out_UpdateID;
190
191
    out_NumberReturned = "0";
192
    out_TotalMatches = "0";
193
194
    data.addarg("Result", out_Result);
195
    data.addarg("NumberReturned", out_NumberReturned);
196
    data.addarg("TotalMatches", out_TotalMatches);
197
    data.addarg("UpdateID", out_UpdateID);
198
    return UPNP_E_SUCCESS;
199
}
200
201