upnp: factor out code that build a CFileItem from a PLT_MediaObject
authorJoakim Plate <elupus@ecce.se>
Tue, 6 Nov 2012 21:00:55 +0000 (22:00 +0100)
committerJoakim Plate <elupus@ecce.se>
Sun, 20 Jan 2013 17:31:22 +0000 (18:31 +0100)
xbmc/filesystem/UPnPDirectory.cpp
xbmc/network/upnp/UPnPInternal.cpp
xbmc/network/upnp/UPnPInternal.h

index 14e245e..2a3c893 100644 (file)
@@ -36,23 +36,6 @@ using namespace UPNP;
 
 namespace XFILE
 {
-/*----------------------------------------------------------------------
-|   CResourceFinder
-+---------------------------------------------------------------------*/
-class CResourceFinder {
-public:
-    CResourceFinder(const char* protocol, const char* content = NULL) : m_Protocol(protocol), m_Content(content) {}
-    bool operator()(const PLT_MediaItemResource& resource) const {
-        if (m_Content.IsEmpty())
-            return (resource.m_ProtocolInfo.GetProtocol().Compare(m_Protocol, true) == 0);
-        else
-            return ((resource.m_ProtocolInfo.GetProtocol().Compare(m_Protocol, true) == 0)
-                  && resource.m_ProtocolInfo.GetContentType().StartsWith(m_Content, true));
-    }
-private:
-    NPT_String m_Protocol;
-    NPT_String m_Content;
-};
 
 static CStdString GetContentMapping(NPT_String& objectClass)
 {
@@ -188,78 +171,7 @@ bool CUPnPDirectory::GetResource(const CURL& path, CFileItem &item)
     if (entry == 0)
         return false;
 
-    PLT_MediaItemResource resource;
-
-    // look for a resource with "xbmc-get" protocol
-    // if we can't find one, try to find a valid resource
-    if(NPT_FAILED(NPT_ContainerFind((*entry)->m_Resources,
-                      CResourceFinder("xbmc-get"), resource))) {
-        const char* content = NULL;
-        if ((*entry)->m_ObjectClass.type.StartsWith("object.item.audioItem"))
-             content = "audio";
-        else if ((*entry)->m_ObjectClass.type.StartsWith("object.item.imageItem"))
-             content = "image";
-        else if ((*entry)->m_ObjectClass.type.StartsWith("object.item.videoItem"))
-             content = "video";
-
-        if(NPT_FAILED(NPT_ContainerFind((*entry)->m_Resources,
-                          CResourceFinder("http-get", content), resource))) {
-            if((*entry)->m_Resources.GetItemCount()) {
-                // last attempt to find something suitable
-                resource = (*entry)->m_Resources[0];
-            }
-            else {
-                CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - no resources returned for object %s", object.c_str());
-                return false;
-            }
-        }
-    }
-
-    // store original path so we remember it
-    item.SetProperty("original_listitem_url",  item.GetPath());
-    item.SetProperty("original_listitem_mime", item.GetMimeType(false));
-
-    // if it's an item, path is the first url to the item
-    // we hope the server made the first one reachable for us
-    // (it could be a format we dont know how to play however)
-    item.SetPath((const char*) resource.m_Uri);
-
-    // look for content type in protocol info
-    if (resource.m_ProtocolInfo.IsValid()) {
-        CLog::Log(LOGDEBUG, "CUPnPDirectory::GetResource - resource protocol info '%s'",
-            (const char*)(resource.m_ProtocolInfo.ToString()));
-
-        if (resource.m_ProtocolInfo.GetContentType().Compare("application/octet-stream") != 0) {
-            item.SetMimeType((const char*)resource.m_ProtocolInfo.GetContentType());
-        }
-    } else {
-        CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - invalid protocol info '%s'",
-            (const char*)(resource.m_ProtocolInfo.ToString()));
-    }
-
-    // look for subtitles
-    unsigned subs = 0;
-    for(unsigned r = 0; r < (*entry)->m_Resources.GetItemCount(); r++)
-    {
-        PLT_MediaItemResource& res  = (*entry)->m_Resources[r];
-        PLT_ProtocolInfo&      info = res.m_ProtocolInfo;
-        static const char* allowed[] = { "text/srt"
-                                       , "text/ssa"
-                                       , "text/sub"
-                                       , "text/idx" };
-        for(unsigned type = 0; type < sizeof(allowed)/sizeof(allowed[0]); type++)
-        {
-            if(info.Match(PLT_ProtocolInfo("*", "*", allowed[type], "*")))
-            {
-                CStdString prop;
-                prop.Format("upnp:subtitle:%d", ++subs);
-                item.SetProperty(prop, (const char*)res.m_Uri);
-                break;
-            }
-        }
-    }
-
-    return true;
+  return UPNP::GetResource(*entry, item);
 }
 
 
@@ -402,125 +314,23 @@ CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
                 }
             }
 
-            NPT_String ObjectClass = (*entry)->m_ObjectClass.type.ToLowercase();
 
             // keep count of classes
             classes[(*entry)->m_ObjectClass.type]++;
-
-            CFileItemPtr pItem(new CFileItem((const char*)(*entry)->m_Title));
-            pItem->SetLabelPreformated(true);
-            pItem->m_strTitle = (const char*)(*entry)->m_Title;
-            pItem->m_bIsFolder = (*entry)->IsContainer();
+            CFileItemPtr pItem = BuildObject(*entry);
+            if(!pItem) {
+                ++entry;
+                continue;
+            }
 
             CStdString id = (char*) (*entry)->m_ObjectID;
             CURL::Encode(id);
-            pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str()));
-
-            // if it's a container, format a string as upnp://uuid/object_id
-            if (pItem->m_bIsFolder) {
-                pItem->SetPath(pItem->GetPath() + "/");
-
-                // look for metadata
-                if( ObjectClass.StartsWith("object.container.album.videoalbum") ) {
-                    pItem->SetLabelPreformated(false);
-                    UPNP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), NULL);
-
-                } else if( ObjectClass.StartsWith("object.container.album.photoalbum")) {
-                  //CPictureInfoTag* tag = pItem->GetPictureInfoTag();
-
-                } else if( ObjectClass.StartsWith("object.container.album") ) {
-                    pItem->SetLabelPreformated(false);
-                    UPNP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), NULL);
-                }
-
+            if(pItem->m_bIsFolder) {
+                pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str()));
             } else {
-
-                // set a general content type
-                audio = image = video = false;
-                const char* content = NULL;
-                if (ObjectClass.StartsWith("object.item.videoitem")) {
-                    pItem->SetMimeType("video/octet-stream");
-                    content = "video";
-                    video = true;
-                }
-                else if(ObjectClass.StartsWith("object.item.audioitem")) {
-                    pItem->SetMimeType("audio/octet-stream");
-                    content = "audio";
-                    audio = true;
-                }
-                else if(ObjectClass.StartsWith("object.item.imageitem")) {
-                    pItem->SetMimeType("image/octet-stream");
-                    content = "image";
-                    image = true;
-                }
-
-                // attempt to find a valid resource (may be multiple)
-                PLT_MediaItemResource resource;
-                if(NPT_SUCCEEDED(NPT_ContainerFind((*entry)->m_Resources,
-                                  CResourceFinder("http-get", content), resource))) {
-
-                    // set metadata
-                    if (resource.m_Size != (NPT_LargeSize)-1) {
-                        pItem->m_dwSize  = resource.m_Size;
-                    }
-
-                    // look for metadata
-                    if(video) {
-                        pItem->SetLabelPreformated(false);
-                        UPNP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), &resource);
-
-                    } else if(audio) {
-                        pItem->SetLabelPreformated(false);
-                        UPNP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), &resource);
-
-                    } else if(image) {
-                      //CPictureInfoTag* tag = pItem->GetPictureInfoTag();
-
-                    }
-                }
+                pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str() + "/"));
             }
 
-            // look for date?
-            if((*entry)->m_Description.date.GetLength()) {
-                SYSTEMTIME time = {};
-                sscanf((*entry)->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu",
-                       &time.wYear, &time.wMonth, &time.wDay, &time.wHour, &time.wMinute, &time.wSecond);
-                pItem->m_dateTime = time;
-            }
-
-            // if there is a thumbnail available set it here
-            if((*entry)->m_ExtraInfo.album_arts.GetItem(0))
-                // only considers first album art
-                pItem->SetArt("thumb", (const char*) (*entry)->m_ExtraInfo.album_arts.GetItem(0)->uri);
-            else if((*entry)->m_Description.icon_uri.GetLength())
-                pItem->SetArt("thumb", (const char*) (*entry)->m_Description.icon_uri);
-
-            PLT_ProtocolInfo fanart_mask("xbmc.org", "*", "fanart", "*");
-            for(unsigned i = 0; i < (*entry)->m_Resources.GetItemCount(); ++i) {
-                PLT_MediaItemResource& res = (*entry)->m_Resources[i];
-                if(res.m_ProtocolInfo.Match(fanart_mask)) {
-                    pItem->SetArt("fanart", (const char*)res.m_Uri);
-                    break;
-                }
-            }
-            // set the watched overlay, as this will not be set later due to
-            // content set on file item list
-            if (pItem->HasVideoInfoTag()) {
-                int episodes = pItem->GetVideoInfoTag()->m_iEpisode;
-                int played   = pItem->GetVideoInfoTag()->m_playCount;
-                const std::string& type = pItem->GetVideoInfoTag()->m_type;
-                bool watched(false);
-                if (type == "tvshow" || type == "season") {
-                    pItem->SetProperty("totalepisodes", episodes);
-                    pItem->SetProperty("numepisodes", episodes);
-                    pItem->SetProperty("watchedepisodes", played);
-                    pItem->SetProperty("unwatchedepisodes", episodes - played);
-                    watched = (episodes && played == episodes);
-                }
-                else if (type == "episode" || type == "movie")
-                    watched = (played > 0);
-                pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, watched);
-            }
             items.Add(pItem);
 
             ++entry;
index 77a0a3d..efdecdd 100644 (file)
@@ -175,6 +175,23 @@ GetProtocolInfo(const CFileItem&              item,
     return proto;
 }
 
+  /*----------------------------------------------------------------------
+   |   CResourceFinder
+   +---------------------------------------------------------------------*/
+CResourceFinder::CResourceFinder(const char* protocol, const char* content)
+  : m_Protocol(protocol)
+  , m_Content(content)
+{
+}
+
+bool CResourceFinder::operator()(const PLT_MediaItemResource& resource) const {
+    if (m_Content.IsEmpty())
+        return (resource.m_ProtocolInfo.GetProtocol().Compare(m_Protocol, true) == 0);
+    else
+        return ((resource.m_ProtocolInfo.GetProtocol().Compare(m_Protocol, true) == 0)
+              && resource.m_ProtocolInfo.GetContentType().StartsWith(m_Content, true));
+}
+
 /*----------------------------------------------------------------------
 |   PopulateObjectFromTag
 +---------------------------------------------------------------------*/
@@ -676,5 +693,220 @@ PopulateTagFromObject(CVideoInfoTag&         tag,
     return NPT_SUCCESS;
 }
 
+CFileItemPtr BuildObject(PLT_MediaObject* entry)
+{
+  NPT_String ObjectClass = entry->m_ObjectClass.type.ToLowercase();
+
+  CFileItemPtr pItem(new CFileItem((const char*)entry->m_Title));
+  pItem->SetLabelPreformated(true);
+  pItem->m_strTitle = (const char*)entry->m_Title;
+  pItem->m_bIsFolder = entry->IsContainer();
+
+  // if it's a container, format a string as upnp://uuid/object_id
+  if (pItem->m_bIsFolder) {
+
+    // look for metadata
+    if( ObjectClass.StartsWith("object.container.album.videoalbum") ) {
+      pItem->SetLabelPreformated(false);
+      UPNP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *entry, NULL);
+
+    } else if( ObjectClass.StartsWith("object.container.album.photoalbum")) {
+      //CPictureInfoTag* tag = pItem->GetPictureInfoTag();
+
+    } else if( ObjectClass.StartsWith("object.container.album") ) {
+      pItem->SetLabelPreformated(false);
+      UPNP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *entry, NULL);
+    }
+
+  } else {
+    bool audio = false
+       , image = false
+       , video = false;
+    // set a general content type
+    const char* content = NULL;
+    if (ObjectClass.StartsWith("object.item.videoitem")) {
+      pItem->SetMimeType("video/octet-stream");
+      content = "video";
+      video = true;
+    }
+    else if(ObjectClass.StartsWith("object.item.audioitem")) {
+      pItem->SetMimeType("audio/octet-stream");
+      content = "audio";
+      audio = true;
+    }
+    else if(ObjectClass.StartsWith("object.item.imageitem")) {
+      pItem->SetMimeType("image/octet-stream");
+      content = "image";
+      image = true;
+    }
+
+    // attempt to find a valid resource (may be multiple)
+    PLT_MediaItemResource resource, *res = NULL;
+    if(NPT_SUCCEEDED(NPT_ContainerFind(entry->m_Resources,
+                                       CResourceFinder("http-get", content), resource))) {
+
+      // set metadata
+      if (resource.m_Size != (NPT_LargeSize)-1) {
+        pItem->m_dwSize  = resource.m_Size;
+      }
+      res = &resource;
+    }
+    // look for metadata
+    if(video) {
+        pItem->SetLabelPreformated(false);
+        UPNP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *entry, res);
+
+    } else if(audio) {
+        pItem->SetLabelPreformated(false);
+        UPNP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *entry, res);
+
+    } else if(image) {
+        //CPictureInfoTag* tag = pItem->GetPictureInfoTag();
+
+    }
+  }
+
+  // look for date?
+  if(entry->m_Description.date.GetLength()) {
+    SYSTEMTIME time = {};
+    sscanf(entry->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu",
+           &time.wYear, &time.wMonth, &time.wDay, &time.wHour, &time.wMinute, &time.wSecond);
+    pItem->m_dateTime = time;
+  }
+
+  // if there is a thumbnail available set it here
+  if(entry->m_ExtraInfo.album_arts.GetItem(0))
+    // only considers first album art
+    pItem->SetArt("thumb", (const char*) entry->m_ExtraInfo.album_arts.GetItem(0)->uri);
+  else if(entry->m_Description.icon_uri.GetLength())
+    pItem->SetArt("thumb", (const char*) entry->m_Description.icon_uri);
+
+  PLT_ProtocolInfo fanart_mask("xbmc.org", "*", "fanart", "*");
+  for(unsigned i = 0; i < entry->m_Resources.GetItemCount(); ++i) {
+    PLT_MediaItemResource& res = entry->m_Resources[i];
+    if(res.m_ProtocolInfo.Match(fanart_mask)) {
+      pItem->SetArt("fanart", (const char*)res.m_Uri);
+      break;
+    }
+  }
+  // set the watched overlay, as this will not be set later due to
+  // content set on file item list
+  if (pItem->HasVideoInfoTag()) {
+    int episodes = pItem->GetVideoInfoTag()->m_iEpisode;
+    int played   = pItem->GetVideoInfoTag()->m_playCount;
+    const std::string& type = pItem->GetVideoInfoTag()->m_type;
+    bool watched(false);
+    if (type == "tvshow" || type == "season") {
+      pItem->SetProperty("totalepisodes", episodes);
+      pItem->SetProperty("numepisodes", episodes);
+      pItem->SetProperty("watchedepisodes", played);
+      pItem->SetProperty("unwatchedepisodes", episodes - played);
+      watched = (episodes && played == episodes);
+    }
+    else if (type == "episode" || type == "movie")
+      watched = (played > 0);
+    pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, watched);
+  }
+  return pItem;
+}
+
+bool GetResource(const PLT_MediaObject* entry, CFileItem& item)
+{
+  PLT_MediaItemResource resource;
+
+  // store original path so we remember it
+  item.SetProperty("original_listitem_url",  item.GetPath());
+  item.SetProperty("original_listitem_mime", item.GetMimeType(false));
+
+  // look for a resource with "xbmc-get" protocol
+  // if we can't find one, try to find a valid resource
+  if(NPT_FAILED(NPT_ContainerFind(entry->m_Resources,
+                                  CResourceFinder("xbmc-get"), resource))) {
+    const char* content = NULL;
+    if (entry->m_ObjectClass.type.StartsWith("object.item.audioItem"))
+      content = "audio";
+    else if (entry->m_ObjectClass.type.StartsWith("object.item.imageItem"))
+      content = "image";
+    else if (entry->m_ObjectClass.type.StartsWith("object.item.videoItem"))
+      content = "video";
+
+    if(NPT_FAILED(NPT_ContainerFind(entry->m_Resources,
+                                    CResourceFinder("http-get", content), resource))) {
+      if(entry->m_Resources.GetItemCount()) {
+        // last attempt to find something suitable
+        resource = entry->m_Resources[0];
+      }
+      else {
+        CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - no resources available for object %s", (const char*)entry->m_ObjectID);
+        return false;
+      }
+    }
+  }
+
+  // if it's an item, path is the first url to the item
+  // we hope the server made the first one reachable for us
+  // (it could be a format we dont know how to play however)
+  item.SetPath((const char*) resource.m_Uri);
+
+  // look for content type in protocol info
+  if (resource.m_ProtocolInfo.IsValid()) {
+    CLog::Log(LOGDEBUG, "CUPnPDirectory::GetResource - resource protocol info '%s'",
+              (const char*)(resource.m_ProtocolInfo.ToString()));
+
+    if (resource.m_ProtocolInfo.GetContentType().Compare("application/octet-stream") != 0) {
+      item.SetMimeType((const char*)resource.m_ProtocolInfo.GetContentType());
+    }
+  } else {
+    CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - invalid protocol info '%s'",
+              (const char*)(resource.m_ProtocolInfo.ToString()));
+  }
+
+  // look for subtitles
+  unsigned subs = 0;
+  for(unsigned r = 0; r < entry->m_Resources.GetItemCount(); r++)
+  {
+    const PLT_MediaItemResource& res  = entry->m_Resources[r];
+    const PLT_ProtocolInfo&      info = res.m_ProtocolInfo;
+    static const char* allowed[] = { "text/srt"
+      , "text/ssa"
+      , "text/sub"
+      , "text/idx" };
+    for(unsigned type = 0; type < sizeof(allowed)/sizeof(allowed[0]); type++)
+    {
+      if(info.Match(PLT_ProtocolInfo("*", "*", allowed[type], "*")))
+      {
+        CStdString prop;
+        prop.Format("upnp:subtitle:%d", ++subs);
+        item.SetProperty(prop, (const char*)res.m_Uri);
+        break;
+      }
+    }
+  }
+  return true;
+}
+
+CFileItemPtr GetFileItem(const NPT_String& uri, const NPT_String& meta)
+{
+    PLT_MediaObjectListReference list;
+    PLT_MediaObject*             object = NULL;
+    CFileItemPtr                 item;
+
+    if (NPT_SUCCEEDED(PLT_Didl::FromDidl(meta, list))) {
+        list->Get(0, object);
+    }
+
+    if (object) {
+        item = BuildObject(object);
+    }
+
+    if (item) {
+        item->SetPath((const char*)uri);
+        GetResource(object, *item);
+    } else {
+        item.reset(new CFileItem((const char*)uri, false));
+    }
+    return item;
+}
+
 } /* namespace UPNP */
 
index e861da9..fcdd7a5 100644 (file)
@@ -22,6 +22,8 @@
 #include "utils/StdString.h"
 #include "NptTypes.h"
 #include "NptReferences.h"
+#include "NptStrings.h"
+#include "FileItem.h"
 
 class CUPnPServer;
 class CFileItem;
@@ -37,6 +39,14 @@ class CVideoInfoTag;
 
 namespace UPNP
 {
+  class CResourceFinder {
+  public:
+    CResourceFinder(const char* protocol, const char* content = NULL);
+    bool operator()(const PLT_MediaItemResource& resource) const;
+  private:
+    NPT_String m_Protocol;
+    NPT_String m_Content;
+  };
 
   enum EClientQuirks
   {
@@ -87,5 +97,9 @@ namespace UPNP
                                       const PLT_HttpRequestContext* context = NULL,
                                       CUPnPServer*                  upnp_server = NULL);
 
+  CFileItemPtr     BuildObject(PLT_MediaObject* entry);
+
+  bool             GetResource(const PLT_MediaObject* entry, CFileItem& item);
+  CFileItemPtr     GetFileItem(const NPT_String& uri, const NPT_String& meta);
 }