|
a/upmpd/upmpdutils.cxx |
|
b/upmpd/upmpdutils.cxx |
|
... |
|
... |
178 |
|
178 |
|
179 |
pos = s.find_last_not_of(ws);
|
179 |
pos = s.find_last_not_of(ws);
|
180 |
if (pos != string::npos && pos != s.length()-1)
|
180 |
if (pos != string::npos && pos != s.length()-1)
|
181 |
s.replace(pos+1, string::npos, string());
|
181 |
s.replace(pos+1, string::npos, string());
|
182 |
}
|
182 |
}
|
|
|
183 |
void stringToTokens(const string& str, vector<string>& tokens,
|
|
|
184 |
const string& delims, bool skipinit)
|
|
|
185 |
{
|
|
|
186 |
string::size_type startPos = 0, pos;
|
|
|
187 |
|
|
|
188 |
// Skip initial delims, return empty if this eats all.
|
|
|
189 |
if (skipinit &&
|
|
|
190 |
(startPos = str.find_first_not_of(delims, 0)) == string::npos) {
|
|
|
191 |
return;
|
|
|
192 |
}
|
|
|
193 |
while (startPos < str.size()) {
|
|
|
194 |
// Find next delimiter or end of string (end of token)
|
|
|
195 |
pos = str.find_first_of(delims, startPos);
|
|
|
196 |
|
|
|
197 |
// Add token to the vector and adjust start
|
|
|
198 |
if (pos == string::npos) {
|
|
|
199 |
tokens.push_back(str.substr(startPos));
|
|
|
200 |
break;
|
|
|
201 |
} else if (pos == startPos) {
|
|
|
202 |
// Dont' push empty tokens after first
|
|
|
203 |
if (tokens.empty())
|
|
|
204 |
tokens.push_back(string());
|
|
|
205 |
startPos = ++pos;
|
|
|
206 |
} else {
|
|
|
207 |
tokens.push_back(str.substr(startPos, pos - startPos));
|
|
|
208 |
startPos = ++pos;
|
|
|
209 |
}
|
|
|
210 |
}
|
|
|
211 |
}
|
183 |
|
212 |
|
184 |
string xmlquote(const string& in)
|
213 |
string xmlquote(const string& in)
|
185 |
{
|
214 |
{
|
186 |
string out;
|
215 |
string out;
|
187 |
for (unsigned int i = 0; i < in.size(); i++) {
|
216 |
for (unsigned int i = 0; i < in.size(); i++) {
|
|
... |
|
... |
283 |
return out;
|
312 |
return out;
|
284 |
}
|
313 |
}
|
285 |
|
314 |
|
286 |
// Bogus didl fragment maker. We probably don't need a full-blown XML
|
315 |
// Bogus didl fragment maker. We probably don't need a full-blown XML
|
287 |
// helper here
|
316 |
// helper here
|
288 |
string didlmake(const MpdStatus& mpds, bool next)
|
317 |
string didlmake(const UpSong& song)
|
289 |
{
|
318 |
{
|
290 |
const unordered_map<string, string>& songmap =
|
|
|
291 |
next? mpds.nextsong : mpds.currentsong;
|
|
|
292 |
ostringstream ss;
|
319 |
ostringstream ss;
|
293 |
ss << "<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" "
|
320 |
ss << "<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" "
|
294 |
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" "
|
321 |
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" "
|
295 |
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" "
|
322 |
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" "
|
296 |
"xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">"
|
323 |
"xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">"
|
297 |
<< "<item restricted=\"1\">";
|
324 |
<< "<item restricted=\"1\">";
|
298 |
|
325 |
|
299 |
{ const string& val = mapget(songmap, "dc:title");
|
326 |
{ const string& val = song.title;
|
300 |
ss << "<dc:title>" << xmlquote(val) << "</dc:title>";
|
327 |
ss << "<dc:title>" << xmlquote(val) << "</dc:title>";
|
301 |
}
|
328 |
}
|
302 |
|
329 |
|
303 |
// TBD Playlists etc?
|
330 |
// TBD Playlists etc?
|
304 |
ss << "<upnp:class>object.item.audioItem.musicTrack</upnp:class>";
|
331 |
ss << "<upnp:class>object.item.audioItem.musicTrack</upnp:class>";
|
305 |
|
332 |
|
306 |
{ const string& val = mapget(songmap, "upnp:artist");
|
333 |
{ const string& val = song.artist;
|
307 |
if (!val.empty()) {
|
334 |
if (!val.empty()) {
|
308 |
string a = xmlquote(val);
|
335 |
string a = xmlquote(val);
|
309 |
ss << "<dc:creator>" << a << "</dc:creator>" <<
|
336 |
ss << "<dc:creator>" << a << "</dc:creator>" <<
|
310 |
"<upnp:artist>" << a << "</upnp:artist>";
|
337 |
"<upnp:artist>" << a << "</upnp:artist>";
|
311 |
}
|
338 |
}
|
312 |
}
|
339 |
}
|
313 |
|
340 |
|
314 |
{ const string& val = mapget(songmap, "upnp:album");
|
341 |
{ const string& val = song.album;
|
315 |
if (!val.empty()) {
|
342 |
if (!val.empty()) {
|
316 |
ss << "<upnp:album>" << xmlquote(val) << "</upnp:album>";
|
343 |
ss << "<upnp:album>" << xmlquote(val) << "</upnp:album>";
|
317 |
}
|
344 |
}
|
318 |
}
|
345 |
}
|
319 |
|
346 |
|
320 |
{ const string& val = mapget(songmap, "upnp:genre");
|
347 |
{ const string& val = song.genre;
|
321 |
if (!val.empty()) {
|
348 |
if (!val.empty()) {
|
322 |
ss << "<upnp:genre>" << xmlquote(val) << "</upnp:genre>";
|
349 |
ss << "<upnp:genre>" << xmlquote(val) << "</upnp:genre>";
|
323 |
}
|
350 |
}
|
324 |
}
|
351 |
}
|
325 |
|
352 |
|
326 |
{const string& val = mapget(songmap, "upnp:originalTrackNumber");
|
353 |
{const string& val = song.tracknum;
|
327 |
if (!val.empty()) {
|
354 |
if (!val.empty()) {
|
328 |
ss << "<upnp:originalTrackNumber>" << val <<
|
355 |
ss << "<upnp:originalTrackNumber>" << val <<
|
329 |
"</upnp:originalTrackNumber>";
|
356 |
"</upnp:originalTrackNumber>";
|
330 |
}
|
357 |
}
|
331 |
}
|
358 |
}
|
|
... |
|
... |
333 |
// TBD: the res element normally has size, sampleFrequency,
|
360 |
// TBD: the res element normally has size, sampleFrequency,
|
334 |
// nrAudioChannels and protocolInfo attributes, which are bogus
|
361 |
// nrAudioChannels and protocolInfo attributes, which are bogus
|
335 |
// for the moment. partly because MPD does not supply them. And
|
362 |
// for the moment. partly because MPD does not supply them. And
|
336 |
// mostly everything is bogus if next is set...
|
363 |
// mostly everything is bogus if next is set...
|
337 |
|
364 |
|
338 |
ss << "<res " << "duration=\"" << upnpduration(mpds.songlenms) << "\" "
|
365 |
ss << "<res " << "duration=\"" << upnpduration(song.duration_secs * 1000)
|
|
|
366 |
<< "\" "
|
339 |
// Bitrate keeps changing for VBRs and forces events. Keeping
|
367 |
// Bitrate keeps changing for VBRs and forces events. Keeping
|
340 |
// it out for now.
|
368 |
// it out for now.
|
341 |
// << "bitrate=\"" << mpds.kbrate << "\" "
|
369 |
// << "bitrate=\"" << mpds.kbrate << "\" "
|
342 |
<< "sampleFrequency=\"44100\" audioChannels=\"2\" "
|
370 |
<< "sampleFrequency=\"44100\" audioChannels=\"2\" "
|
343 |
<< "protocolInfo=\"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000\""
|
371 |
<< "protocolInfo=\"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000\""
|
344 |
<< ">"
|
372 |
<< ">"
|
345 |
<< xmlquote(mapget(songmap, "uri"))
|
373 |
<< xmlquote(song.uri)
|
346 |
<< "</res>"
|
374 |
<< "</res>"
|
347 |
<< "</item></DIDL-Lite>";
|
375 |
<< "</item></DIDL-Lite>";
|
348 |
return ss.str();
|
376 |
return ss.str();
|
349 |
}
|
377 |
}
|
350 |
|
378 |
|