/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // We accept upnp://devuuid/[item_id/] NPT_String path = strPath.c_str(); if (!path.StartsWith("upnp://", true)) { return false; } if (path.Compare("upnp://", true) == 0) { upnp->StartClient(); // root -> get list of devices const NPT_Lock<PLT_DeviceDataReferenceList>& devices = upnp->m_MediaBrowser->GetMediaServers(); NPT_List<PLT_DeviceDataReference>::Iterator device = devices.GetFirstItem(); while (device) { NPT_String name = (*device)->GetFriendlyName(); NPT_String uuid = (*device)->GetUUID(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/")); pItem->m_bIsFolder = true; pItem->SetArt("thumb", (const char*)(*device)->GetIconUrl("image/png")); items.Add(pItem); ++device; } } else { if (!path.EndsWith("/")) path += "/"; // look for nextslash int next_slash = path.Find('/', 7); NPT_String uuid = (next_slash==-1)?path.SubString(7):path.SubString(7, next_slash-7); NPT_String object_id = (next_slash==-1)?"":path.SubString(next_slash+1); object_id.TrimRight("/"); if (object_id.GetLength()) { CStdString tmp = (char*) object_id; CURL::Decode(tmp); object_id = tmp; } // try to find the device with wait on startup PLT_DeviceDataReference device; if (!FindDeviceWait(upnp, uuid, device)) goto failure; // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // remember a count of object classes std::map<NPT_String, int> classes; // just a guess as to what types of files we want bool video = true; bool audio = true; bool image = true; m_strFileMask.TrimLeft("/"); if (!m_strFileMask.IsEmpty()) { video = m_strFileMask.Find(".wmv") >= 0; audio = m_strFileMask.Find(".wma") >= 0; image = m_strFileMask.Find(".jpg") >= 0; } // special case for Windows Media Connect and WMP11 when looking for root // We can target which root subfolder we want based on directory mask if (object_id == "0" && ((device->GetFriendlyName().Find("Windows Media Connect", 0, true) >= 0) || (device->m_ModelName == "Windows Media Player Sharing"))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "1"; } else if (!audio && video && !image) { // video object_id = "2"; } else if (!audio && !video && image) { // pictures object_id = "3"; } } #ifdef DISABLE_SPECIALCASE // same thing but special case for XBMC if (object_id == "0" && ((device->m_ModelName.Find("XBMC", 0, true) >= 0) || (device->m_ModelName.Find("Xbox Media Center", 0, true) >= 0))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "virtualpath://upnpmusic"; } else if (!audio && video && !image) { // video object_id = "virtualpath://upnpvideo"; } else if (!audio && !video && image) { // pictures object_id = "virtualpath://upnppictures"; } } #endif // if error, return now, the device could have gone away // this will make us go back to the sources list PLT_MediaObjectListReference list; NPT_Result res = upnp->m_MediaBrowser->BrowseSync(device, object_id, list); if (NPT_FAILED(res)) goto failure; // empty list is ok if (list.IsNull()) goto cleanup; PLT_MediaObjectList::Iterator entry = list->GetFirstItem(); while (entry) { // disregard items with wrong class/type if( (!video && (*entry)->m_ObjectClass.type.CompareN("object.item.videoitem", 21,true) == 0) || (!audio && (*entry)->m_ObjectClass.type.CompareN("object.item.audioitem", 21,true) == 0) || (!image && (*entry)->m_ObjectClass.type.CompareN("object.item.imageitem", 21,true) == 0) ) { ++entry; continue; } // never show empty containers in media views if((*entry)->IsContainer()) { if( (audio || video || image) && ((PLT_MediaContainer*)(*entry))->m_ChildrenCount == 0) { ++entry; continue; } } // keep count of classes classes[(*entry)->m_ObjectClass.type]++; CFileItemPtr pItem = BuildObject(*entry); if(!pItem) { ++entry; continue; } CStdString id = (char*) (*entry)->m_ObjectID; CURL::Encode(id); URIUtils::AddSlashAtEnd(id); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str())); items.Add(pItem); ++entry; } NPT_String max_string = ""; int max_count = 0; for(std::map<NPT_String, int>::iterator it = classes.begin(); it != classes.end(); it++) { if(it->second > max_count) { max_string = it->first; max_count = it->second; } } std::string content = GetContentMapping(max_string); items.SetContent(content); if (content == "unknown") { items.AddSortMethod(SORT_METHOD_UNSORTED, 571, LABEL_MASKS("%L", "%I", "%L", "")); items.AddSortMethod(SORT_METHOD_LABEL_IGNORE_FOLDERS, 551, LABEL_MASKS("%L", "%I", "%L", "")); items.AddSortMethod(SORT_METHOD_SIZE, 553, LABEL_MASKS("%L", "%I", "%L", "%I")); items.AddSortMethod(SORT_METHOD_DATE, 552, LABEL_MASKS("%L", "%J", "%L", "%J")); } } cleanup: return true; failure: return false; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // We accept upnp://devuuid/[item_id/] NPT_String path = strPath.c_str(); if (!path.StartsWith("upnp://", true)) { return false; } if (path.Compare("upnp://", true) == 0) { upnp->StartClient(); // root -> get list of devices const NPT_Lock<PLT_DeviceDataReferenceList>& devices = upnp->m_MediaBrowser->GetMediaServers(); NPT_List<PLT_DeviceDataReference>::Iterator device = devices.GetFirstItem(); while (device) { NPT_String name = (*device)->GetFriendlyName(); NPT_String uuid = (*device)->GetUUID(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/")); pItem->m_bIsFolder = true; pItem->SetThumbnailImage((const char*)(*device)->GetIconUrl("image/jpeg")); items.Add(pItem); ++device; } } else { if (!path.EndsWith("/")) path += "/"; // look for nextslash int next_slash = path.Find('/', 7); NPT_String uuid = (next_slash==-1)?path.SubString(7):path.SubString(7, next_slash-7); NPT_String object_id = (next_slash==-1)?"":path.SubString(next_slash+1); object_id.TrimRight("/"); if (object_id.GetLength()) { CStdString tmp = (char*) object_id; CURL::Decode(tmp); object_id = tmp; } // try to find the device with wait on startup PLT_DeviceDataReference device; if (!FindDeviceWait(upnp, uuid, device)) goto failure; // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // remember a count of object classes std::map<NPT_String, int> classes; // just a guess as to what types of files we want bool video = true; bool audio = true; bool image = true; m_strFileMask.TrimLeft("/"); if (!m_strFileMask.IsEmpty()) { video = m_strFileMask.Find(".wmv") >= 0; audio = m_strFileMask.Find(".wma") >= 0; image = m_strFileMask.Find(".jpg") >= 0; } // special case for Windows Media Connect and WMP11 when looking for root // We can target which root subfolder we want based on directory mask if (object_id == "0" && ((device->GetFriendlyName().Find("Windows Media Connect", 0, true) >= 0) || (device->m_ModelName == "Windows Media Player Sharing"))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "1"; } else if (!audio && video && !image) { // video object_id = "2"; } else if (!audio && !video && image) { // pictures object_id = "3"; } } #ifdef DISABLE_SPECIALCASE // same thing but special case for XBMC if (object_id == "0" && ((device->m_ModelName.Find("XBMC", 0, true) >= 0) || (device->m_ModelName.Find("Xbox Media Center", 0, true) >= 0))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "virtualpath://upnpmusic"; } else if (!audio && video && !image) { // video object_id = "virtualpath://upnpvideo"; } else if (!audio && !video && image) { // pictures object_id = "virtualpath://upnppictures"; } } #endif // if error, return now, the device could have gone away // this will make us go back to the sources list PLT_MediaObjectListReference list; NPT_Result res = upnp->m_MediaBrowser->BrowseSync(device, object_id, list); if (NPT_FAILED(res)) goto failure; // empty list is ok if (list.IsNull()) goto cleanup; PLT_MediaObjectList::Iterator entry = list->GetFirstItem(); while (entry) { // disregard items with wrong class/type if( (!video && (*entry)->m_ObjectClass.type.CompareN("object.item.videoitem", 21,true) == 0) || (!audio && (*entry)->m_ObjectClass.type.CompareN("object.item.audioitem", 21,true) == 0) || (!image && (*entry)->m_ObjectClass.type.CompareN("object.item.imageitem", 21,true) == 0) ) { ++entry; continue; } // never show empty containers in media views if((*entry)->IsContainer()) { if( (audio || video || image) && ((PLT_MediaContainer*)(*entry))->m_ChildrenCount == 0) { ++entry; continue; } } 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(); 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); CUPnP::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); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), NULL); } } else { // set a general content type if (ObjectClass.StartsWith("object.item.videoitem")) pItem->SetMimeType("video/octet-stream"); else if(ObjectClass.StartsWith("object.item.audioitem")) pItem->SetMimeType("audio/octet-stream"); else if(ObjectClass.StartsWith("object.item.imageitem")) pItem->SetMimeType("image/octet-stream"); if ((*entry)->m_Resources.GetItemCount()) { PLT_MediaItemResource& resource = (*entry)->m_Resources[0]; // set metadata if (resource.m_Size != (NPT_LargeSize)-1) { pItem->m_dwSize = resource.m_Size; } // look for metadata if( ObjectClass.StartsWith("object.item.videoitem") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), &resource); } else if( ObjectClass.StartsWith("object.item.audioitem") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), &resource); } else if( ObjectClass.StartsWith("object.item.imageitem") ) { //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_art_uri.GetLength()) pItem->SetThumbnailImage((const char*) (*entry)->m_ExtraInfo.album_art_uri); else if((*entry)->m_Description.icon_uri.GetLength()) pItem->SetThumbnailImage((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->SetProperty("fanart_image", (const char*)res.m_Uri); break; } } items.Add(pItem); ++entry; } NPT_String max_string = ""; int max_count = 0; for(std::map<NPT_String, int>::iterator it = classes.begin(); it != classes.end(); it++) { if(it->second > max_count) { max_string = it->first; max_count = it->second; } } items.SetContent(GetContentMapping(max_string)); } cleanup: return true; failure: return false; }