MythTV  master
upnpcdsobjects.cpp
Go to the documentation of this file.
1 // Program Name: upnpcdsobjects.cpp
3 // Created : Oct. 24, 2005
4 //
5 // Purpose : uPnp Content Directory Service Object Definitions
6 //
7 // Copyright (c) 2005 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see COPYING for details
10 //
12 
13 #include <QTextStream>
14 #include <QTextCodec>
15 #include <QUrl>
16 
17 #include "upnpcds.h"
18 #include "mythlogging.h"
19 
20 inline QString GetBool( bool bVal ) { return( (bVal) ? "1" : "0" ); }
21 
24 //
25 //
26 //
29 
30 CDSObject::CDSObject( const QString &sId,
31  const QString &sTitle,
32  const QString &sParentId )
33  : ReferenceCounter("CDSObject", false),
34  m_sId(HTTPRequest::Encode(sId)),
35  m_sParentId(HTTPRequest::Encode(sParentId)),
36  m_sTitle(HTTPRequest::Encode(sTitle))
37 {
38 }
39 
41 //
43 
45 {
46  while (!m_resources.empty())
47  {
48  delete m_resources.takeLast();
49  }
50 
51  while (!m_children.empty())
52  {
53  m_children.takeLast()->DecrRef();
54  }
55 
56  // NOLINTNEXTLINE(modernize-loop-convert)
57  for (auto it = m_properties.begin(); it != m_properties.end(); ++it)
58  {
59  delete *it;
60  *it = nullptr;
61  }
62  m_properties.clear();
63 }
64 
66 //
68 
70 {
71  if (pProp)
72  {
73  // If this property is allowed multiple times in an object
74  // e.g. Different sizes of artwork, then just insert it
75  // Otherwise remove all existing instances of this property first
76  // NOTE: This requires ALL instances of a property which can exist
77  // more than once to have m_bAllowMulti set to true.
78  if (pProp->m_bMultiValue)
79  m_properties.insertMulti(pProp->m_sName, pProp);
80  else
81  {
82  Properties::iterator it = m_properties.find(pProp->m_sName);
83  while (it != m_properties.end() && it.key() == pProp->m_sName)
84  {
85  delete *it;
86  it = m_properties.erase(it);
87  }
88  m_properties[pProp->m_sName] = pProp;
89  }
90  }
91 
92  return pProp;
93 }
94 
96 //
98 
99 QList<Property*> CDSObject::GetProperties( const QString &sName )
100 {
101  QList<Property*> props;
102  Properties::iterator it = m_properties.find(sName);
103  while (it != m_properties.end() && it.key() == sName)
104  {
105  if (*it)
106  props.append(*it);
107  ++it;
108  }
109 
110  return props;
111 }
112 
114 //
116 
117 void CDSObject::SetPropValue( const QString &sName, const QString &sValue,
118  const QString &sType )
119 {
120  Properties::iterator it = m_properties.find(sName);
121  if (it != m_properties.end() && *it)
122  {
123  if ((*it)->m_bMultiValue)
124  {
125  LOG(VB_UPNP, LOG_WARNING,
126  QString("SetPropValue(%1) called on property with bAllowMulti. "
127  "Only the last inserted property will be updated.").arg(sName));
128  }
129  (*it)->SetValue(sValue);
130 
131  if (!sType.isEmpty())
132  (*it)->AddAttribute( "type", sType );
133  }
134  else
135  LOG(VB_UPNP, LOG_WARNING,
136  QString("SetPropValue(%1) called with non-existent property.").arg(sName));
137 }
138 
140 //
142 
143 QString CDSObject::GetPropValue(const QString &sName) const
144 {
145  Properties::const_iterator it = m_properties.find(sName);
146 
147  if (it != m_properties.end() && *it)
148  {
149  if ((*it)->m_bMultiValue)
150  {
151  LOG(VB_UPNP, LOG_WARNING,
152  QString("GetPropValue(%1) called on property with bAllowMulti. "
153  "Only the last inserted property will be return."));
154  }
155  return (*it)->GetValue().toUtf8();
156  }
157 
158  return "";
159 }
160 
162 //
164 
166 {
167  if (pChild && !m_children.contains(pChild))
168  {
169  pChild->IncrRef();
170  m_nChildCount++;
171  if (pChild->m_eType == OT_Container)
173  pChild->m_sParentId = m_sId;
174  m_children.append( pChild );
175  }
176 
177  return( pChild );
178 }
179 
181 //
183 
184 CDSObject *CDSObject::GetChild( const QString &sID )
185 {
186  CDSObject *pChild = nullptr;
187  CDSObjects::iterator it;
188  for (it = m_children.begin(); it != m_children.end(); ++it)
189  {
190  pChild = *it;
191  if (!pChild)
192  continue;
193 
194  if (pChild->m_sId == sID)
195  return pChild;
196  }
197 
198  return nullptr;
199 }
200 
202 //
204 
205 Resource *CDSObject::AddResource( const QString& sProtocol, const QString& sURI )
206 {
207  auto *pRes = new Resource( sProtocol, sURI );
208 
209  m_resources.append( pRes );
210 
211  return( pRes );
212 }
213 
214 
219 uint32_t CDSObject::GetChildCount(void) const
220 {
221  uint32_t nCount = m_children.count();
222  if (nCount == 0)
223  return( m_nChildCount );
224 
225  return( nCount );
226 }
227 
232 void CDSObject::SetChildCount( uint32_t nCount )
233 {
234  m_nChildCount = nCount;
235 }
236 
246 {
247  return m_nChildContainerCount;
248 }
249 
255 void CDSObject::SetChildContainerCount( uint32_t nCount )
256 {
257  m_nChildContainerCount = nCount;
258 }
259 
261 //
263 
264 QString CDSObject::toXml( FilterMap &filter,
265  bool ignoreChildren ) const
266 {
267  QString sXML;
268  QTextStream os( &sXML, QIODevice::WriteOnly );
269  os.setCodec(QTextCodec::codecForName("UTF-8"));
270  toXml(os, filter, ignoreChildren);
271  os << flush;
272  return( sXML );
273 }
274 
276 //
278 
279 void CDSObject::toXml( QTextStream &os, FilterMap &filter,
280  bool ignoreChildren ) const
281 {
282  QString sEndTag = "";
283 
308  bool bFilter = true;
309 
310  if (filter.contains("*"))
311  bFilter = false;
312 
313  switch( m_eType )
314  {
315  case OT_Container:
316  {
317  if (bFilter && filter.contains("container#"))
318  bFilter = false;
319 
320  os << "<container id=\"" << m_sId
321  << "\" parentID=\"" << m_sParentId
322  << "\" restricted=\"" << GetBool( m_bRestricted );
323 
324  if (!bFilter || filter.contains("@searchable"))
325  os << "\" searchable=\"" << GetBool( m_bSearchable );
326 
327  if (!bFilter || filter.contains("@childCount"))
328  os << "\" childCount=\"" << GetChildCount();
329 
330  if (!bFilter || filter.contains("@childContainerCount"))
331  os << "\" childContainerCount=\"" << GetChildContainerCount();
332 
333  os << "\" >" << endl;
334 
335  sEndTag = "</container>";
336 
337  break;
338  }
339  case OT_Item:
340  {
341  if (bFilter && filter.contains("item#"))
342  bFilter = false;
343 
344  os << "<item id=\"" << m_sId
345  << "\" parentID=\"" << m_sParentId
346  << "\" restricted=\"" << GetBool( m_bRestricted )
347  << "\" >" << endl;
348 
349  sEndTag = "</item>";
350 
351  break;
352  }
353  default: break;
354  }
355 
356  os << "<dc:title>" << m_sTitle << "</dc:title>" << endl;
357  os << "<upnp:class>" << m_sClass << "</upnp:class>" << endl;
358 
359  // ----------------------------------------------------------------------
360  // Output all Properties
361  // ----------------------------------------------------------------------
362 
363  foreach (auto pProp, m_properties)
364  {
365  if (pProp->m_bRequired || (!pProp->GetValue().isEmpty()))
366  {
367  QString sName;
368 
369  if (!pProp->m_sNameSpace.isEmpty())
370  sName = pProp->m_sNameSpace + ':' + pProp->m_sName;
371  else
372  sName = pProp->m_sName;
373 
374  if (pProp->m_bRequired ||
375  (!bFilter) ||
376  FilterContains(filter, sName))
377  {
378  bool filterAttributes = true;
379  if (!bFilter || filter.contains(QString("%1#").arg(sName)))
380  filterAttributes = false;
381 
382  os << "<" << sName;
383 
384  for (const auto & attr : pProp->m_lstAttributes)
385  {
386  QString filterName = QString("%1@%2").arg(sName)
387  .arg(attr.m_sName);
388  if (attr.m_bRequired || !filterAttributes ||
389  filter.contains(filterName))
390  os << " " << attr.m_sName << "=\"" << attr.m_sValue << "\"";
391  }
392 
393  os << ">";
394  os << pProp->GetEncodedValue();
395  os << "</" << sName << ">" << endl;
396  }
397  }
398  }
399 
400  // ----------------------------------------------------------------------
401  // Output any Res Elements
402  // ----------------------------------------------------------------------
403 
404  if (!bFilter || filter.contains("res"))
405  {
406  bool filterAttributes = true;
407  if (!bFilter || filter.contains("res#"))
408  filterAttributes = false;
409  foreach (auto resource, m_resources)
410  {
411  os << "<res protocolInfo=\"" << resource->m_sProtocolInfo << "\" ";
412 
413  QString filterName;
414  for (const auto & attr : resource->m_lstAttributes)
415  {
416  filterName = QString("res@%1").arg(attr.m_sName);
417  if (attr.m_bRequired || !filterAttributes ||
418  filter.contains(filterName))
419  os << attr.m_sName << "=\"" << attr.m_sValue << "\" ";
420  }
421 
422  os << ">" << resource->m_sURI;
423  os << "</res>" << endl;
424  }
425  }
426 
427  // ----------------------------------------------------------------------
428  // Output any children
429  // ----------------------------------------------------------------------
430 
431  if (!ignoreChildren)
432  {
433  for (auto *cit : m_children)
434  cit->toXml(os, filter);
435  }
436 
437  // ----------------------------------------------------------------------
438  // Close Element Tag
439  // ----------------------------------------------------------------------
440 
441  os << sEndTag << endl;
442  os << flush;
443 }
444 
445 
447 //
449 
450 CDSObject *CDSObject::CreateItem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
451 {
452  if (pObject == nullptr)
453  {
454  pObject = new CDSObject( sId, sTitle, sParentId );
455  pObject->m_sClass = "object.item";
456  }
457 
458  pObject->m_eType = OT_Item;
459  pObject->m_bSearchable = false; // UPnP - CDS B.1.5 @searchable
460 
461  pObject->AddProperty( new Property( "refID" ) );
462 
463  return( pObject );
464 }
465 
467 
468 CDSObject *CDSObject::CreateContainer( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
469 {
470  if (pObject == nullptr)
471  {
472  pObject = new CDSObject( sId, sTitle, sParentId );
473  pObject->m_sClass = "object.container";
474  }
475 
476  pObject->m_eType = OT_Container;
477  pObject->m_bSearchable = true; // DLNA requirement - 7.4.3.5.9
478 
479  pObject->AddProperty( new Property( "childCount" ));
480  pObject->AddProperty( new Property( "createClass" ));
481  pObject->AddProperty( new Property( "searchClass" ));
482  pObject->AddProperty( new Property( "searchable" ));
483 
484  pObject->AddProperty( new Property( "creator", "dc" ));
485  pObject->AddProperty( new Property( "date" , "dc" ));
486 
487  pObject->AddProperty( new Property( "longDescription", "upnp" ));
488  pObject->AddProperty( new Property( "description" , "dc" ));
489 
490  return( pObject );
491 }
492 
494 
495 CDSObject *CDSObject::CreateAudioItem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
496 {
497  if (pObject == nullptr)
498  {
499  pObject = new CDSObject( sId, sTitle, sParentId );
500  pObject->m_sClass = "object.item.audioItem";
501  }
502 
503  CreateItem( sId, sTitle, sParentId, pObject );
504 
505  pObject->AddProperty( new Property( "genre" , "upnp" ));
506  pObject->AddProperty( new Property( "description" , "dc" ));
507  pObject->AddProperty( new Property( "longDescription" , "upnp" ));
508  pObject->AddProperty( new Property( "publisher" , "dc" ));
509  pObject->AddProperty( new Property( "language" , "dc" ));
510  pObject->AddProperty( new Property( "relation" , "dc" ));
511  pObject->AddProperty( new Property( "rights" , "dc" ));
512 
513  pObject->AddProperty( new Property( "creator" , "dc" ));
514  pObject->AddProperty( new Property( "date" , "dc" ));
515 
516  return( pObject );
517 }
518 
520 
521 CDSObject *CDSObject::CreateMusicTrack( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
522 {
523  if (pObject == nullptr)
524  {
525  pObject = new CDSObject( sId, sTitle, sParentId );
526  pObject->m_sClass = "object.item.audioItem.musicTrack";
527  }
528 
529  CreateAudioItem( sId, sTitle, sParentId, pObject );
530 
531  pObject->AddProperty( new Property( "artist" , "upnp" ));
532  pObject->AddProperty( new Property( "album" , "upnp" ));
533  pObject->AddProperty( new Property( "originalTrackNumber" , "upnp" ));
534  pObject->AddProperty( new Property( "playlist" , "upnp" ));
535  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
536  pObject->AddProperty( new Property( "contributor" , "dc" ));
537 
538  pObject->AddProperty( new Property( "playbackCount" , "upnp" ));
539  pObject->AddProperty( new Property( "lastPlaybackTime" , "upnp" ));
540 
541  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // TN
542  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // SM
543  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // MED
544  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // LRG
545 
546 #if 0
547  pObject->AddProperty( new Property( "publisher" , "dc" ));
548  pObject->AddProperty( new Property( "language" , "dc" ));
549  pObject->AddProperty( new Property( "relation" , "dc" ));
550  pObject->AddProperty( new Property( "rights" , "dc" ));
551 
552 
553  pObject->AddProperty( new Property( "playlist" , "upnp" ));
554  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
555  pObject->AddProperty( new Property( "contributor" , "dc" ));
556 #endif
557 
558  return( pObject );
559 }
560 
562 
563 CDSObject *CDSObject::CreateAudioBroadcast( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
564 {
565  if (pObject == nullptr)
566  {
567  pObject = new CDSObject( sId, sTitle, sParentId );
568  pObject->m_sClass = "object.item.audioItem.audioBroadcast";
569  }
570 
571  CreateAudioItem( sId, sTitle, sParentId, pObject );
572 
573  pObject->AddProperty( new Property( "region" , "upnp" ));
574  pObject->AddProperty( new Property( "radioCallSign" , "upnp" ));
575  pObject->AddProperty( new Property( "radioStationID" , "upnp" ));
576  pObject->AddProperty( new Property( "radioBand" , "upnp" ));
577  pObject->AddProperty( new Property( "channelNr" , "upnp" ));
578 
579  return( pObject );
580 }
581 
583 
584 CDSObject *CDSObject::CreateAudioBook( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
585 {
586  if (pObject == nullptr)
587  {
588  pObject = new CDSObject( sId, sTitle, sParentId );
589  pObject->m_sClass = "object.item.audioItem.audioBook";
590  }
591 
592  CreateAudioItem( sId, sTitle, sParentId, pObject );
593 
594  pObject->AddProperty( new Property( "storageMedium", "upnp" ));
595  pObject->AddProperty( new Property( "producer" , "upnp" ));
596  pObject->AddProperty( new Property( "contributor" , "dc" ));
597 
598  return( pObject );
599 }
600 
602 
603 CDSObject *CDSObject::CreateVideoItem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
604 {
605  if (pObject == nullptr)
606  {
607  pObject = new CDSObject( sId, sTitle, sParentId );
608  pObject->m_sClass = "object.item.videoItem";
609  }
610 
611  CreateItem( sId, sTitle, sParentId, pObject );
612 
613  pObject->AddProperty( new Property( "genre" , "upnp" ));
614  pObject->AddProperty( new Property( "longDescription", "upnp" ));
615  pObject->AddProperty( new Property( "producer" , "upnp" ));
616  pObject->AddProperty( new Property( "rating" , "upnp" ));
617  pObject->AddProperty( new Property( "actor" , "upnp" ));
618  pObject->AddProperty( new Property( "director" , "upnp" ));
619  pObject->AddProperty( new Property( "episodeNumber" , "upnp" ));
620  pObject->AddProperty( new Property( "episodeCount" , "upnp" ));
621  pObject->AddProperty( new Property( "seriesTitle" , "upnp" ));
622  pObject->AddProperty( new Property( "programTitle" , "upnp" ));
623  pObject->AddProperty( new Property( "description" , "dc" ));
624  pObject->AddProperty( new Property( "publisher" , "dc" ));
625  pObject->AddProperty( new Property( "language" , "dc" ));
626  pObject->AddProperty( new Property( "relation" , "dc" ));
627 
628  pObject->AddProperty( new Property( "creator" , "dc" ));
629  pObject->AddProperty( new Property( "date" , "dc" ));
630 
631  pObject->AddProperty( new Property( "channelID" , "upnp" ));
632  pObject->AddProperty( new Property( "callSign" , "upnp" ));
633  pObject->AddProperty( new Property( "channelNr" , "upnp" ));
634  pObject->AddProperty( new Property( "channelName" , "upnp" ));
635 
636  pObject->AddProperty( new Property( "scheduledStartTime", "upnp" ));
637  pObject->AddProperty( new Property( "scheduledEndTime" , "upnp" ));
638  pObject->AddProperty( new Property( "scheduledDuration" , "upnp" ));
639  pObject->AddProperty( new Property( "srsRecordScheduleID" , "upnp" ));
640  pObject->AddProperty( new Property( "recordedStartDateTime" , "upnp" ));
641  pObject->AddProperty( new Property( "recordedDuration" , "upnp" ));
642  pObject->AddProperty( new Property( "recordedDayOfWeek" , "upnp" ));
643 
644  pObject->AddProperty( new Property( "programID" , "upnp" ));
645  pObject->AddProperty( new Property( "seriesID" , "upnp" ));
646 
647  // Added for Microsoft Media Player Compatibility
648  pObject->AddProperty( new Property( "artist" , "upnp" ));
649  pObject->AddProperty( new Property( "album" , "upnp" ));
650  //
651 
652  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true )); // TN
653  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true )); // SM
654  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true )); // MED
655  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true )); // LRG
656  return( pObject );
657 }
658 
660 
661 CDSObject *CDSObject::CreateMovie( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
662 {
663  if (pObject == nullptr)
664  {
665  pObject = new CDSObject( sId, sTitle, sParentId );
666  pObject->m_sClass = "object.item.videoItem.movie";
667  }
668 
669  CreateVideoItem( sId, sTitle, sParentId, pObject );
670 
671  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
672  pObject->AddProperty( new Property( "DVDRegionCode" , "upnp" ));
673 
674  return( pObject );
675 }
676 
678 
679 CDSObject *CDSObject::CreateVideoBroadcast( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
680 {
681  if (pObject == nullptr)
682  {
683  pObject = new CDSObject( sId, sTitle, sParentId );
684  pObject->m_sClass = "object.item.videoItem.videoBroadcast";
685  }
686 
687  CreateVideoItem( sId, sTitle, sParentId, pObject );
688 
689  pObject->AddProperty( new Property( "icon" , "upnp" ));
690  pObject->AddProperty( new Property( "region" , "upnp" ));
691 
692  return( pObject );
693 }
694 
696 
697 CDSObject *CDSObject::CreateMusicVideoClip( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
698 {
699  if (pObject == nullptr)
700  {
701  pObject = new CDSObject( sId, sTitle, sParentId );
702  pObject->m_sClass = "object.item.videoItem.musicVideoClip";
703  }
704 
705  CreateVideoItem( sId, sTitle, sParentId, pObject );
706 
707  pObject->AddProperty( new Property( "artist" , "upnp" ));
708  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
709  pObject->AddProperty( new Property( "album" , "upnp" ));
710  pObject->AddProperty( new Property( "contributor" , "dc" ));
711 
712  return( pObject );
713 }
714 
716 
717 CDSObject *CDSObject::CreateImageItem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
718 {
719  if (pObject == nullptr)
720  {
721  pObject = new CDSObject( sId, sTitle, sParentId );
722  pObject->m_sClass = "object.item.imageItem";
723  }
724 
725  CreateItem( sId, sTitle, sParentId, pObject );
726 
727  pObject->AddProperty( new Property( "longDescription", "upnp" ));
728  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
729  pObject->AddProperty( new Property( "rating" , "upnp" ));
730  pObject->AddProperty( new Property( "description" , "dc" ));
731  pObject->AddProperty( new Property( "publisher" , "dc" ));
732  pObject->AddProperty( new Property( "rights" , "dc" ));
733 
734  pObject->AddProperty( new Property( "creator" , "dc" ));
735  pObject->AddProperty( new Property( "date" , "dc" ));
736 
737  return( pObject );
738 }
739 
741 
742 CDSObject *CDSObject::CreatePhoto( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
743 {
744  if (pObject == nullptr)
745  {
746  pObject = new CDSObject( sId, sTitle, sParentId );
747  pObject->m_sClass = "object.item.imageItem.photo";
748  }
749 
750  CreateImageItem( sId, sTitle, sParentId, pObject );
751 
752  pObject->AddProperty( new Property( "album", "upnp" ));
753 
754  return( pObject );
755 }
756 
758 
759 CDSObject *CDSObject::CreatePlaylistItem ( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
760 {
761  if (pObject == nullptr)
762  {
763  pObject = new CDSObject( sId, sTitle, sParentId );
764  pObject->m_sClass = "object.item.playlistItem";
765  }
766 
767  CreateItem( sId, sTitle, sParentId, pObject );
768 
769  pObject->AddProperty( new Property( "artist" , "upnp" ));
770  pObject->AddProperty( new Property( "genre" , "upnp" ));
771  pObject->AddProperty( new Property( "longDescription", "upnp" ));
772  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
773  pObject->AddProperty( new Property( "description" , "dc" ));
774  pObject->AddProperty( new Property( "language" , "dc" ));
775 
776  return( pObject );
777 }
778 
780 
781 CDSObject *CDSObject::CreateTextItem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
782 {
783  if (pObject == nullptr)
784  {
785  pObject = new CDSObject( sId, sTitle, sParentId );
786  pObject->m_sClass = "object.item.textItem";
787  }
788 
789  CreateItem( sId, sTitle, sParentId, pObject );
790 
791  pObject->AddProperty( new Property( "author" , "upnp" ));
792  pObject->AddProperty( new Property( "protection" , "upnp" ));
793  pObject->AddProperty( new Property( "longDescription", "upnp" ));
794  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
795  pObject->AddProperty( new Property( "rating" , "upnp" ));
796  pObject->AddProperty( new Property( "description" , "dc" ));
797  pObject->AddProperty( new Property( "publisher" , "dc" ));
798  pObject->AddProperty( new Property( "contributor" , "dc" ));
799  pObject->AddProperty( new Property( "relation" , "dc" ));
800  pObject->AddProperty( new Property( "language" , "dc" ));
801  pObject->AddProperty( new Property( "rights" , "dc" ));
802 
803  return( pObject );
804 }
805 
807 
808 CDSObject *CDSObject::CreateAlbum( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
809 {
810  if (pObject == nullptr)
811  {
812  pObject = new CDSObject( sId, sTitle, sParentId );
813  pObject->m_sClass = "object.container.album";
814  }
815 
816  CreateContainer( sId, sTitle, sParentId, pObject );
817 
818  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
819  pObject->AddProperty( new Property( "publisher" , "dc" ));
820  pObject->AddProperty( new Property( "contributor" , "dc" ));
821  pObject->AddProperty( new Property( "relation" , "dc" ));
822  pObject->AddProperty( new Property( "rights" , "dc" ));
823 
824  // Artwork
825  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // TN
826  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // SM
827  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // MED
828  pObject->AddProperty( new Property( "albumArtURI", "upnp", false, "", true)); // LRG
829 
830  return( pObject );
831 }
832 
834 
835 CDSObject *CDSObject::CreateMusicAlbum( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
836 {
837  if (pObject == nullptr)
838  {
839  pObject = new CDSObject( sId, sTitle, sParentId );
840  pObject->m_sClass = "object.container.album.musicAlbum";
841  }
842 
843  CreateAlbum( sId, sTitle, sParentId, pObject );
844 
845  pObject->AddProperty( new Property( "artist" , "upnp" ));
846  pObject->AddProperty( new Property( "genre" , "upnp" ));
847  pObject->AddProperty( new Property( "producer" , "upnp" ));
848  pObject->AddProperty( new Property( "toc" , "upnp" ));
849 
850  return( pObject );
851 }
852 
854 
855 CDSObject *CDSObject::CreatePhotoAlbum( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
856 {
857  if (pObject == nullptr)
858  {
859  pObject = new CDSObject( sId, sTitle, sParentId );
860  pObject->m_sClass = "object.container.album.photoAlbum";
861  }
862 
863  CreateAlbum( sId, sTitle, sParentId, pObject );
864 
865  return( pObject );
866 }
867 
869 
870 CDSObject *CDSObject::CreateGenre( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
871 {
872  if (pObject == nullptr)
873  {
874  pObject = new CDSObject( sId, sTitle, sParentId );
875  pObject->m_sClass = "object.container.genre";
876  }
877 
878  CreateContainer( sId, sTitle, sParentId, pObject );
879 
880  return( pObject );
881 }
882 
884 
885 CDSObject *CDSObject::CreateMusicGenre( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
886 {
887  if (pObject == nullptr)
888  {
889  pObject = new CDSObject( sId, sTitle, sParentId );
890  pObject->m_sClass = "object.container.genre.musicGenre";
891  }
892 
893  CreateGenre( sId, sTitle, sParentId, pObject );
894 
895  return( pObject );
896 }
897 
899 
900 CDSObject *CDSObject::CreateMovieGenre( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
901 {
902  if (pObject == nullptr)
903  {
904  pObject = new CDSObject( sId, sTitle, sParentId );
905  pObject->m_sClass = "object.container.genre.movieGenre";
906  }
907 
908  CreateGenre( sId, sTitle, sParentId, pObject );
909 
910  return( pObject );
911 }
912 
914 
915 CDSObject *CDSObject::CreatePlaylistContainer( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
916 {
917  if (pObject == nullptr)
918  {
919  pObject = new CDSObject( sId, sTitle, sParentId );
920  pObject->m_sClass = "object.container.playlistContainer";
921  }
922 
923  CreateContainer( sId, sTitle, sParentId, pObject );
924 
925  pObject->AddProperty( new Property( "artist" , "upnp" ));
926  pObject->AddProperty( new Property( "genre" , "upnp" ));
927  pObject->AddProperty( new Property( "producer" , "upnp" ));
928  pObject->AddProperty( new Property( "storageMedium" , "upnp" ));
929  pObject->AddProperty( new Property( "contributor" , "dc" ));
930  pObject->AddProperty( new Property( "language" , "dc" ));
931  pObject->AddProperty( new Property( "rights" , "dc" ));
932 
933  return( pObject );
934 }
935 
937 
938 CDSObject *CDSObject::CreatePerson( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
939 {
940  if (pObject == nullptr)
941  {
942  pObject = new CDSObject( sId, sTitle, sParentId );
943  pObject->m_sClass = "object.container.person";
944  }
945 
946  CreateContainer( sId, sTitle, sParentId, pObject );
947 
948  pObject->AddProperty( new Property( "language", "dc" ));
949 
950  return( pObject );
951 }
952 
954 
955 CDSObject *CDSObject::CreateMusicArtist( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
956 {
957  if (pObject == nullptr)
958  {
959  pObject = new CDSObject( sId, sTitle, sParentId );
960  pObject->m_sClass = "object.container.person.musicArtist";
961  }
962 
963  CreatePerson( sId, sTitle, sParentId, pObject );
964 
965  pObject->AddProperty( new Property( "genre" , "upnp" ));
966  pObject->AddProperty( new Property( "artistDiscographyURI", "upnp" ));
967 
968  return( pObject );
969 }
970 
972 
973 CDSObject *CDSObject::CreateStorageSystem( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
974 {
975  if (pObject == nullptr)
976  {
977  pObject = new CDSObject( sId, sTitle, sParentId );
978  pObject->m_sClass = "object.container.storageSystem";
979  }
980 
981  CreateContainer( sId, sTitle, sParentId, pObject );
982 
983  pObject->AddProperty( new Property( "storageTotal" , "upnp", true, "-1" ));
984  pObject->AddProperty( new Property( "storageUsed" , "upnp", true, "-1" ));
985  pObject->AddProperty( new Property( "storageFree" , "upnp", true, "-1" ));
986  pObject->AddProperty( new Property( "storageMaxPartition", "upnp", true, "-1" ));
987  pObject->AddProperty( new Property( "storageMedium" , "upnp", true, "HDD" ));
988 
989  return( pObject );
990 }
991 
993 
994 CDSObject *CDSObject::CreateStorageVolume( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
995 {
996  if (pObject == nullptr)
997  {
998  pObject = new CDSObject( sId, sTitle, sParentId );
999  pObject->m_sClass = "object.container.storageVolume";
1000  }
1001 
1002  CreateContainer( sId, sTitle, sParentId, pObject );
1003 
1004  pObject->AddProperty( new Property( "storageTotal" , "upnp", true, "-1" ));
1005  pObject->AddProperty( new Property( "storageUsed" , "upnp", true, "-1" ));
1006  pObject->AddProperty( new Property( "storageFree" , "upnp", true, "-1" ));
1007  pObject->AddProperty( new Property( "storageMedium", "upnp", true, "HDD" ));
1008 
1009  return( pObject );
1010 }
1011 
1013 
1014 CDSObject *CDSObject::CreateStorageFolder( const QString& sId, const QString& sTitle, const QString& sParentId, CDSObject *pObject )
1015 {
1016  if (pObject == nullptr)
1017  {
1018  pObject = new CDSObject( sId, sTitle, sParentId );
1019  pObject->m_sClass = "object.container.storageFolder";
1020  }
1021 
1022  CreateContainer( sId, sTitle, sParentId, pObject );
1023 
1024  pObject->AddProperty( new Property( "storageUsed", "upnp", true, "-1" ));
1025 
1026  return( pObject );
1027 }
1028 
1029 bool CDSObject::FilterContains(const FilterMap &filter, const QString& name)
1030 {
1031  // ContentDirectory Service, 2013 UPnP Forum
1032  // 2.3.18 A_ARG_TYPE_Filter
1033 
1034  // Exact match
1035  if (filter.contains(name, Qt::CaseInsensitive))
1036  return true;
1037 
1038  // # signfies that this property and all it's children must be returned
1039  // This is presently implemented higher up to save time
1040 
1041  // If an attribute is required then it's parent must also be returned
1042  QString dependentAttribute = QString("%1@").arg(name);
1043  QStringList matches = filter.filter(name, Qt::CaseInsensitive);
1044  QStringList::iterator it;
1045  for (it = matches.begin(); it != matches.end(); ++it)
1046  {
1047  if ((*it).startsWith(dependentAttribute))
1048  return true;
1049  }
1050 
1051  return false;
1052 }
1053 
static CDSObject * CreatePlaylistContainer(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreatePlaylistItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
Resource * AddResource(const QString &sProtocol, const QString &sURI)
uint32_t GetChildContainerCount(void) const
Return the number of child containers in this container.
static CDSObject * CreateAudioBook(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateMusicVideoClip(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
bool m_bRestricted
static CDSObject * CreateMusicArtist(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateContainer(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
Properties m_properties
static CDSObject * CreateAudioItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateStorageSystem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
QString m_sName
CDSObject * AddChild(CDSObject *pChild)
static CDSObject * CreatePhotoAlbum(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
General purpose reference counter.
QString m_sId
static CDSObject * CreateMovieGenre(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
bool m_bSearchable
QString GetBool(bool bVal)
void SetChildCount(uint32_t nCount)
Allows the caller to set childCount without having to load children.
static CDSObject * CreatePhoto(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
QMap< uint, int > FilterMap
static CDSObject * CreateMusicGenre(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
Property * AddProperty(Property *pProp)
static CDSObject * CreateImageItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
CDSObjects m_children
static CDSObject * CreateMusicTrack(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
void SetChildContainerCount(uint32_t nCount)
Allows the caller to set childContainerCount without having to load children.
ObjectTypes m_eType
CDSObject(const QString &sId="-1", const QString &sTitle="", const QString &sParentId="-1")
virtual int IncrRef(void)
Increments reference count.
QString m_sParentId
static CDSObject * CreateItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
~CDSObject() override
static CDSObject * CreatePerson(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateVideoItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
uint32_t m_nChildCount
static bool FilterContains(const FilterMap &filter, const QString &name)
QList< Property * > GetProperties(const QString &sName)
QString toXml(FilterMap &filter, bool ignoreChildren=false) const
uint32_t GetChildCount(void) const
Return the number of children in this container.
CDSObject * GetChild(const QString &sID)
QString GetPropValue(const QString &sName) const
static CDSObject * CreateMovie(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static CDSObject * CreateAlbum(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
void SetPropValue(const QString &sName, const QString &sValue, const QString &type="")
static CDSObject * CreateStorageFolder(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
Resources m_resources
static CDSObject * CreateStorageVolume(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateTextItem(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
QString m_sTitle
static CDSObject * CreateGenre(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
QString m_sClass
bool m_bMultiValue
static CDSObject * CreateAudioBroadcast(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateVideoBroadcast(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
static CDSObject * CreateMusicAlbum(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
uint32_t m_nChildContainerCount