Go to the documentation of this file.
19 #include "libmythbase/mythversion.h"
25 static constexpr
const char*
DIDL_LITE_BEGIN { R
"(<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">)" };
47 for (
auto *
const object : qAsConst(objects))
63 for (
auto *item : qAsConst(
m_List))
64 sXML += item->toXml(filter, ignoreChildren);
74 :
Eventing(
"UPnpCDS",
"CDS_Event", sSharePath )
89 SetValue< uint16_t >(
"SystemUpdateID", 0 );
94 SetValue< QString >(
"ServiceResetToken",
112 "urn:schemas-upnp-org:av:avs" ));
114 "http://www.w3.org/2001/XMLSchema-instance" ));
116 "urn:schemas-upnp-org:av:avs "
117 "http://www.upnp.org/schemas/av/avs.xsd" ));
144 if (sURI ==
"X_GetFeatureList" ||
174 CDSShortCutList::iterator it;
175 for (it = shortcuts.begin(); it != shortcuts.end(); ++it)
200 const QString& objectID)
237 LOG(VB_UPNP, LOG_DEBUG,
238 QString(
"UPnpCDS::ProcessRequest - BaseUrl (%1) not ours...")
285 "Windows-Media-Player/" },
289 "Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x" },
301 R
"(cn="Sony Corporation"; mn="Blu-ray Disc Player")" },
314 int idx = sHeaderValue.indexOf(except.sHeaderValue);
318 pCDSRequest->
m_eClient = except.nClientType;
320 idx += except.sHeaderValue.length();
324 if ( sHeaderValue[idx] ==
'/')
330 QString
version = sHeaderValue.mid(idx).trimmed();
334 idx =
version.indexOf(
'.', idx + 1 );
348 LOG(VB_UPNP, LOG_INFO,
349 QString(
"DetermineClient %1:%2 Identified as %3 version %4")
350 .arg(except.sHeaderKey, sHeaderValue)
376 pRequest->
m_mapParams[
"requestedcount"].toUShort();
382 LOG(VB_UPNP, LOG_DEBUG, QString(
"UPnpCDS::ProcessRequest \n"
386 ": BrowseFlag = %4 \n"
388 ": StartingIndex = %6 \n"
389 ": RequestedCount = %7 \n"
390 ": SortCriteria = %8 " )
401 QString sErrorDesc =
"";
408 LOG(VB_UPNP, LOG_INFO,
409 QString(
"UPnpCDS::HandleBrowse ObjectID=%1")
455 for (
uint i = nStart;
457 (nNumberReturned < nCount);
462 sResultXML += pExtensionRoot->
toXml(filter,
true);
477 UPnpCDSExtensionList::iterator it =
m_extensions.begin();
480 LOG(VB_UPNP, LOG_INFO,
481 QString(
"UPNP Browse : Searching for : %1 / ObjectID : %2")
484 pResult = (*it)->Browse(&request);
487 if (pResult !=
nullptr)
496 pResult->
m_List.takeLast()->DecrRef();
499 nNumberReturned = pResult->
m_List.count();
522 sResults += sResultXML;
525 list.push_back(
NameValue(
"Result", sResults));
526 list.push_back(
NameValue(
"NumberReturned", nNumberReturned));
527 list.push_back(
NameValue(
"TotalMatches", nTotalMatches));
528 list.push_back(
NameValue(
"UpdateID", nUpdateID));
547 QString sErrorDesc =
"";
564 LOG(VB_UPNP, LOG_INFO,
565 QString(
"UPnpCDS::HandleSearch ObjectID=%1, ContainerId=%2")
573 static const QRegularExpression re {
"\\b(or|and)\\b", QRegularExpression::CaseInsensitiveOption};
575 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
577 re, QString::SkipEmptyParts);
580 re, Qt::SkipEmptyParts);
589 for ( QStringList::Iterator it = request.
m_sSearchList.begin();
593 if ((*it).contains(
"upnp:class derivedfrom", Qt::CaseInsensitive))
595 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
596 QStringList sParts = (*it).split(
' ', QString::SkipEmptyParts);
598 QStringList sParts = (*it).split(
' ', Qt::SkipEmptyParts);
601 if (sParts.count() > 2)
614 LOG(VB_UPNP, LOG_INFO, QString(
"UPnpCDS::ProcessRequest \n"
618 ": SearchCriteria = %4 \n"
620 ": StartingIndex = %6 \n"
621 ": RequestedCount = %7 \n"
622 ": SortCriteria = %8 \n"
623 ": SearchClass = %9" )
635 bool bSearchDone =
false;
638 UPnpCDSExtensionList::iterator it =
m_extensions.begin();
640 pResult = (*it)->Search(&request);
642 if (pResult !=
nullptr)
650 nNumberReturned = pResult->
m_List.count();
665 LOG(VB_UPNP, LOG_DEBUG, sResultXML);
672 sResults += sResultXML;
675 list.push_back(
NameValue(
"Result", sResults));
676 list.push_back(
NameValue(
"NumberReturned", nNumberReturned));
677 list.push_back(
NameValue(
"TotalMatches", nTotalMatches));
678 list.push_back(
NameValue(
"UpdateID", nUpdateID));
696 LOG(VB_UPNP, LOG_INFO,
697 QString(
"UPnpCDS::ProcessRequest : %1 : %2")
722 LOG(VB_UPNP, LOG_INFO,
723 QString(
"UPnpCDS::ProcessRequest : %1 : %2")
746 LOG(VB_UPNP, LOG_INFO,
747 QString(
"UPnpCDS::ProcessRequest : %1 : %2")
750 auto nId = GetValue<uint16_t>(
"SystemUpdateID");
764 LOG(VB_UPNP, LOG_INFO,
765 QString(
"UPnpCDS::ProcessRequest : %1 : %2")
770 list.push_back(
NameValue(
"FeatureList", sResults));
779 LOG(VB_UPNP, LOG_INFO,
780 QString(
"UPnpCDS::ProcessRequest : %1 : %2")
783 auto sToken = GetValue<QString>(
"ServiceResetToken");
785 list.push_back(
NameValue(
"ResetToken", sToken));
816 LOG(VB_UPNP, LOG_INFO, QString(
"%1: Browse request is for us.").arg(
m_sExtensionId));
841 LOG(VB_UPNP, LOG_DEBUG, QString(
"Browse (%1): Current Token '%2'")
850 if (pResults !=
nullptr)
865 LOG(VB_UPNP, LOG_DEBUG, QString(
"UPnpCDS::Browse: BrowseMetadata (%1)").arg(pRequest->
m_sObjectId));
866 if (
LoadMetadata(pRequest, pResults, tokens, currentToken))
875 LOG(VB_UPNP, LOG_DEBUG, QString(
"UPnpCDS::Browse: BrowseDirectChildren (%1)").arg(pRequest->
m_sObjectId));
876 if (
LoadChildren(pRequest, pResults, tokens, currentToken))
885 pResults->m_sErrorDesc =
"";
912 LOG(VB_UPNP, LOG_INFO,
913 QString(
"UPnpCDSExtension::Search : m_sClass = %1 : "
914 "m_sSearchClass = %2")
919 LOG(VB_UPNP, LOG_INFO,
920 QString(
"UPnpCDSExtension::Search - Not For Us : "
921 "m_sClass = %1 : m_sSearchClass = %2")
938 const QString &sStr,
int num )
940 QString sResult(
"" );
943 for (
int nIdx=0; nIdx < num; nIdx++)
945 if ((nPos = sStr.lastIndexOf( sToken, nPos )) == -1)
950 sResult = sStr.left( nPos );
1016 QStringList tokens = Id.split(
'/');
1018 QStringList::iterator it;
1019 for (it = tokens.begin() + 1; it < tokens.end(); ++it)
1022 QString key = (*it).section(
'=', 0, 0).toLower();
1023 QString value = (*it).section(
'=', 1, 1);
1025 tokenMap.insert(key, value);
1026 LOG(VB_UPNP, LOG_DEBUG, QString(
"Token Key: %1 Value: %2").arg(key,
1050 QStringList tokens = Id.split(
'/');
1051 QString
current = tokens.last();
1052 QString key =
current.section(
'=', 0, 0).toLower();
1053 QString value =
current.section(
'=', 1, 1);
1055 return {key, value};
1059 const QString &name,
1066 const QString &name,
1067 const QString &value)
1070 QString currentName = currentToken.first;
1071 QString currentValue = currentToken.second;
1075 if (currentName == name.toLower() && !currentValue.isEmpty() &&
1076 currentValue == value.toLower())
1078 if (currentName == name.toLower() && currentValue.isEmpty())
1079 return QString(
"%1=%2").arg(requestId, value);
1080 return QString(
"%1/%2=%3").arg(requestId, name, value);
1085 LOG(VB_GENERAL, LOG_CRIT,
"UPnpCDSExtension::CreateRoot() called on base class");
1107 xml =
"<shortcutlist>\r\n";
1109 QMap<ShortCutType, QString>::iterator it;
1113 QString objectID = *it;
1114 xml +=
"<shortcut>\r\n";
1117 xml +=
"</shortcut>\r\n";
1120 xml +=
"</shortcutlist>\r\n";
1126 const QString &objectID)
1132 LOG(VB_GENERAL, LOG_ERR, QString(
"UPnPCDSShortcuts::AddShortCut(): "
1133 "Attempted to register duplicate "
1150 str =
"MUSIC_ALBUMS";
1153 str =
"MUSIC_ARTISTS";
1156 str =
"MUSIC_GENRES";
1159 str =
"MUSIC_PLAYLISTS";
1162 str =
"MUSIC_RECENTLY_ADDED";
1165 str =
"MUSIC_LAST_PLAYED";
1168 str =
"MUSIC_AUDIOBOOKS";
1171 str =
"MUSIC_STATIONS";
1177 str =
"MUSIC_FOLDER_STRUCTURE";
1184 str =
"IMAGES_YEARS";
1187 str =
"IMAGES_YEARS_MONTH";
1190 str =
"IMAGES_ALBUM";
1193 str =
"IMAGES_SLIDESHOWS";
1196 str =
"IMAGES_RECENTLY_ADDED";
1199 str =
"IMAGES_LAST_WATCHED";
1205 str =
"IMAGES_FOLDER_STRUCTURE";
1212 str =
"VIDEOS_GENRES";
1215 str =
"VIDEOS_YEARS";
1218 str =
"VIDEOS_YEARS_MONTH";
1221 str =
"VIDEOS_ALBUM";
1224 str =
"VIDEOS_RECENTLY_ADDED";
1227 str =
"VIDEOS_LAST_PLAYED";
1230 str =
"VIDEOS_RECORDINGS";
1237 str =
"VIDEOS_FOLDER_STRUCTURE";
QString GetResultXML(FilterMap &filter, bool ignoreChildren=false)
QString GetRequestHeader(const QString &sKey, const QString &sDefault)
uint16_t m_nRequestedCount
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
UPnPFeatureList m_features
QStringList GetBasePaths() override
virtual void CreateRoot()
QMap< UPnPShortcutFeature::ShortCutType, QString > CDSShortCutList
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual ~UPnpCDSExtension()
QStringList GetBasePaths() override
static void HandleGetSortCapabilities(HTTPRequest *pRequest)
Return the list of supported sorting fields.
Standard UPnP Shortcut feature.
void HandleSearch(HTTPRequest *pRequest)
void HandleGetSystemUpdateID(HTTPRequest *pRequest)
static QString CreateIDString(const QString &RequestId, const QString &Name, int Value)
uint16_t m_nStartingIndex
UPnpCDSExtensionList m_extensions
virtual bool IsSearchRequestForUs(UPnpCDSRequest *pRequest)
void AddFeature(UPnPFeature *feature)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool ProcessRequest(HTTPRequest *pRequest) override
static IDTokenMap TokenizeIDString(const QString &Id)
Split the 'Id' String up into tokens for handling by each extension.
void SetChildContainerCount(uint32_t nCount)
Allows the caller to set childContainerCount without having to load children.
UPnpCDSBrowseFlag m_eBrowseFlag
static QString Encode(const QString &sIn)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static void FormatErrorResponse(HTTPRequest *pRequest, UPnPResultCode eCode, const QString &sMsg="")
virtual UPnpCDSExtensionResults * Browse(UPnpCDSRequest *pRequest)
@ CDS_BrowseDirectChildren
void FormatActionResponse(Serializer *ser)
void RegisterService(UPnpDevice *device)
Creates a UPnpService and adds it to the UPnpDevice's list of services.
UPnpCDS(UPnpDevice *pDevice, const QString &sSharePath)
QMap< uint, int > FilterMap
static void DetermineClient(HTTPRequest *pRequest, UPnpCDSRequest *pCDSRequest)
QString m_sSearchCriteria
static const std::array< featureStruct, 7 > feature
static const std::array< const UPnpCDSClientException, 5 > clientExceptions
void HandleGetServiceResetToken(HTTPRequest *pRequest)
void UnregisterExtension(UPnpCDSExtension *pExtension)
QString m_sServiceDescFileName
virtual UPnpCDSExtensionResults * Search(UPnpCDSRequest *pRequest)
void Add(CDSObject *pObject)
static constexpr const char * DIDL_LITE_END
QMap< ShortCutType, QString > m_shortcuts
@ CDSM_GetSearchCapabilities
void AddAttribute(const NameValue &attribute)
void RegisterFeature(UPnPFeature *feature)
UPnPResultCode m_eErrorCode
QList< CDSObject * > CDSObjects
bool AddShortCut(ShortCutType type, const QString &objectID)
@ IMAGES_FOLDER_STRUCTURE
void SetChildCount(uint32_t nCount)
Allows the caller to set childCount without having to load children.
void HandleBrowse(HTTPRequest *pRequest)
@ CDSM_GetServiceDescription
static constexpr const char * DIDL_LITE_BEGIN
bool ProcessRequest(HTTPRequest *pRequest) override
static UPnpCDSBrowseFlag GetBrowseFlag(const QString &sFlag)
virtual bool LoadMetadata(const UPnpCDSRequest *pRequest, UPnpCDSExtensionResults *pResults, const IDTokenMap &tokens, const QString ¤tToken)
Fetch just the metadata for the item identified in the request.
ShortCutType
Allowed values for the Container Shortcut feature.
@ UPnPResult_InvalidAction
virtual bool LoadChildren(const UPnpCDSRequest *pRequest, UPnpCDSExtensionResults *pResults, const IDTokenMap &tokens, const QString ¤tToken)
Fetch the children of the container identified in the request.
static UPnpCDSMethod GetMethod(const QString &sURI)
QStringList m_sSearchList
QString GetValue(const QString &setting)
virtual CDSObject * GetRoot()
void FormatFileResponse(const QString &sFileName)
QMap< QString, QString > IDTokenMap
static QString RemoveToken(const QString &sToken, const QString &sStr, int num)
@ UPnPResult_CDS_NoSuchObject
static CDSObject * CreateContainer(const QString &sId, const QString &sTitle, const QString &sParentId, CDSObject *pObject=nullptr)
@ CDSM_GetSortCapabilities
static void HandleGetSearchCapabilities(HTTPRequest *pRequest)
Return the list of supported search fields.
void AddVariable(StateVariableBase *pBase)
QString toXml(FilterMap &filter, bool ignoreChildren=false) const
QPair< QString, QString > IDToken
@ VIDEOS_FOLDER_STRUCTURE
QString CreateXML() override
void RegisterExtension(UPnpCDSExtension *pExtension)
virtual int IncrRef(void)
Increments reference count.
static QString TypeToName(ShortCutType type)
static IDToken GetCurrentToken(const QString &Id)
Split the 'Id' String up into tokens and return the last (current) token.
virtual CDSShortCutList GetShortCuts()
@ CDSM_GetServiceResetToken
UPnPShortcutFeature * m_pShortCuts
void HandleGetFeatureList(HTTPRequest *pRequest)
void RegisterShortCut(UPnPShortcutFeature::ShortCutType type, const QString &objectID)
virtual bool IsBrowseRequestForUs(UPnpCDSRequest *pRequest)