/*---------------------------------------------------------------------- | PLT_DeviceData::NormalizeURL +---------------------------------------------------------------------*/ NPT_HttpUrl PLT_DeviceData::NormalizeURL(const NPT_String& url) { if (url.StartsWith("http://")) return NPT_HttpUrl(url); NPT_HttpUrl norm_url = m_URLBase; if (url.StartsWith("/")) { norm_url.ParsePathPlus(url); } else { norm_url.ParsePathPlus(norm_url.GetPath() + url); } return norm_url; }
static CStdString GetContentMapping(NPT_String& objectClass) { struct SClassMapping { const char* ObjectClass; const char* Content; }; static const SClassMapping mapping[] = { { "object.item.videoItem.videoBroadcast", "episodes" } , { "object.item.videoItem.musicVideoClip", "musicvideos" } , { "object.item.videoItem" , "movies" } , { "object.item.audioItem.musicTrack" , "songs" } , { "object.item.audioItem" , "songs" } , { "object.item.imageItem.photo" , "photos" } , { "object.item.imageItem" , "photos" } , { "object.container.album.videoAlbum" , "tvshows" } , { "object.container.album.musicAlbum" , "albums" } , { "object.container.album.photoAlbum" , "photos" } , { "object.container.album" , "albums" } , { "object.container.person" , "artists" } , { NULL , NULL } }; for(const SClassMapping* map = mapping; map->ObjectClass; map++) { if(objectClass.StartsWith(map->ObjectClass, true)) { return map->Content; break; } } return "unknown"; }
/*---------------------------------------------------------------------- | CUPnPVirtualPathDirectory::SplitPath +---------------------------------------------------------------------*/ bool CUPnPVirtualPathDirectory::SplitPath(const char* object_id, NPT_String& share_name, NPT_String& path) { int index = 0; NPT_String id = object_id; id.TrimRight("/"); // reset output params first share_name = ""; path = ""; if (id.StartsWith("virtualpath://upnproot")) { index = 22; } else if (id.StartsWith("virtualpath://upnpmusic")) { index = 23; } else if (id.StartsWith("virtualpath://upnpvideo")) { index = 23; } else if (id.StartsWith("virtualpath://upnppictures")) { index = 26; } else { return false; } // nothing to split if (id.GetLength() <= (NPT_Cardinal)index) { return true; } // invalid id! if (id[index] != '/') { return false; } // look for share index = id.Find('/', index+1); share_name = id.SubString(0, (index==-1)?id.GetLength():index); if (index >= 0) { path = id.SubString(index+1); } return true; }
/*---------------------------------------------------------------------- | NPT_LogManager::ParseConfigSource +---------------------------------------------------------------------*/ NPT_Result NPT_LogManager::ParseConfigSource(NPT_String& source) { if (source.StartsWith("file:")) { /* file source */ ParseConfigFile(source.GetChars()+5); } else if (source.StartsWith("plist:")) { /* property list source */ ParseConfig(source.GetChars()+6, source.GetLength()-6); } else if (source.StartsWith("http:port=")) { /* http configurator */ unsigned int port = 0; NPT_Result result = NPT_ParseInteger(source.GetChars()+10, port, true); if (NPT_FAILED(result)) return result; new NPT_HttpLoggerConfigurator(port); } else { return NPT_ERROR_INVALID_SYNTAX; } return NPT_SUCCESS; }
bool SimpleDMS::onHttpRequest(AbortableTask *task, const FrontEnd::InterfaceContext *ifctx, const NPT_String& relPath, const FrontEnd::RequestContext& reqCtx, const NPT_HttpRequest *req, NPT_HttpResponse& resp, NPT_InputStream *inputStream, HttpOutput *httpOutput) { MediaStore::FileDetail detail; bool found = false; if (relPath.StartsWith("dms/")) { found = m_store->findFileDetail(relPath.SubString(4), detail); } if (found) { if (detail.m_type == MediaStore::FileDetail::ALAsset) { serveIOSAsset(task, detail, reqCtx, req, resp, httpOutput); } else { serveFile(task, detail.m_path, detail.m_mimeType, reqCtx, req, resp, httpOutput); } } else { setStatusCode(resp, 404); httpOutput->writeResponseHeader(resp); } return true; }
/*---------------------------------------------------------------------- | 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; }
bool parseRangeHeader(const NPT_String& text, NPT_UInt64 totalLength, NPT_UInt64& offset, NPT_UInt64& length) { if (!text.StartsWith("bytes=")) { return false; } if (text.Find(',') >= 0) { // multiple ranges, currently unsupported return false; } int sep = text.Find('-', 6); if (sep < 0) { return false; } NPT_String p1 = text.SubString(6, sep - 6); NPT_String p2 = text.SubString(sep + 1); NPT_UInt64 v1, v2; if (p1.IsEmpty()) { if (p2.IsEmpty()) { return false; } else { if (NPT_FAILED(NPT_ParseInteger64(p2, v2))) { return false; } if (v2 <= totalLength) { offset = totalLength - v2; length = v2; } else { offset = 0; length = totalLength; } } } else { if (NPT_FAILED(NPT_ParseInteger64(p1, v1))) { return false; } if (v1 >= totalLength) { return false; } if (p2.IsEmpty()) { offset = v1; length = totalLength - offset; } else { if (NPT_FAILED(NPT_ParseInteger64(p2, v2))) { return false; } if (v2 >= totalLength) { return false; } if (v2 < v1) { return false; } offset = v1; length = v2 - v1 + 1; } } return true; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CGUIDialogProgress* dlgProgress = NULL; CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // start client if it hasn't been done yet bool client_started = upnp->IsClientStarted(); upnp->StartClient(); // 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) { // root -> get list of devices const NPT_Lock<PLT_DeviceMap>& devices = upnp->m_MediaBrowser->GetMediaServers(); const NPT_List<PLT_DeviceMapEntry*>& entries = devices.GetEntries(); NPT_List<PLT_DeviceMapEntry*>::Iterator entry = entries.GetFirstItem(); while (entry) { PLT_DeviceDataReference device = (*entry)->GetValue(); NPT_String name = device->GetFriendlyName(); NPT_String uuid = (*entry)->GetKey(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->m_strPath = (const char*) "upnp://" + uuid + "/"; pItem->m_bIsFolder = true; pItem->SetThumbnailImage((const char*)device->GetIconUrl("image/jpeg")); items.Add(pItem); ++entry; } } 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; CUtil::UrlDecode(tmp); object_id = tmp; } // look for device in our list // (and wait for it to respond for 5 secs if we're just starting upnp client) NPT_TimeStamp watchdog; NPT_System::GetCurrentTimeStamp(watchdog); watchdog += 5.f; PLT_DeviceDataReference* device; for (;;) { const NPT_Lock<PLT_DeviceMap>& devices = upnp->m_MediaBrowser->GetMediaServers(); if (NPT_SUCCEEDED(devices.Get(uuid, device)) && device) break; // fail right away if device not found and upnp client was already running if (client_started) goto failure; // otherwise check if we've waited long enough without success NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); if (now > watchdog) goto failure; // sleep a bit and try again NPT_System::Sleep(NPT_TimeInterval(1, 0)); } // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // 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 // bring up dialog if object is not cached if (!upnp->m_MediaBrowser->IsCached(uuid, object_id)) { dlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS); if (dlgProgress) { dlgProgress->ShowProgressBar(false); dlgProgress->SetCanCancel(false); dlgProgress->SetHeading(20334); dlgProgress->SetLine(0, 194); dlgProgress->SetLine(1, ""); dlgProgress->SetLine(2, ""); dlgProgress->StartModal(); } } // 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->Browse(*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; } } CFileItemPtr pItem(new CFileItem((const char*)(*entry)->m_Title)); pItem->SetLabelPreformated(true); pItem->m_bIsFolder = (*entry)->IsContainer(); // if it's a container, format a string as upnp://uuid/object_id if (pItem->m_bIsFolder) { CStdString id = (char*) (*entry)->m_ObjectID; CUtil::URLEncode(id); pItem->m_strPath = (const char*) "upnp://" + uuid + "/" + id.c_str() + "/"; } else { if ((*entry)->m_Resources.GetItemCount()) { PLT_MediaItemResource& resource = (*entry)->m_Resources[0]; // look for a resource with "xbmc-get" protocol // if we can't find one, keep the first resource NPT_ContainerFind((*entry)->m_Resources, CProtocolFinder("xbmc-get"), resource); CLog::Log(LOGDEBUG, "CUPnPDirectory::GetDirectory - resource protocol info '%s'", (const char*)(resource.m_ProtocolInfo)); // 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) pItem->m_strPath = (const char*) resource.m_Uri; // set metadata if (resource.m_Size > 0) { pItem->m_dwSize = resource.m_Size; } // set a general content type CStdString type = (const char*)(*entry)->m_ObjectClass.type.Left(21); if (type.Equals("object.item.videoitem")) pItem->SetContentType("video/octet-stream"); else if(type.Equals("object.item.audioitem")) pItem->SetContentType("audio/octet-stream"); else if(type.Equals("object.item.imageitem")) pItem->SetContentType("image/octet-stream"); // look for content type in protocol info if (resource.m_ProtocolInfo.GetLength()) { char proto[1024]; char dummy1[1024]; char ct[1204]; char dummy2[1024]; int fields = sscanf(resource.m_ProtocolInfo, "%[^:]:%[^:]:%[^:]:%[^:]", proto, dummy1, ct, dummy2); if (fields == 4) { if (strcmp(ct, "application/octet-stream") != 0) { pItem->SetContentType(ct); } } else { CLog::Log(LOGERROR, "CUPnPDirectory::GetDirectory - invalid protocol info '%s'", (const char*)(resource.m_ProtocolInfo)); } } // 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; } // look for metadata if( (*entry)->m_ObjectClass.type.CompareN("object.item.videoitem", 21,true) == 0 ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), &resource); } else if( (*entry)->m_ObjectClass.type.CompareN("object.item.audioitem", 21,true) == 0 ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), &resource); } else if( (*entry)->m_ObjectClass.type.CompareN("object.item.imageitem", 21,true) == 0 ) { //CPictureInfoTag* tag = pItem->GetPictureInfoTag(); } } } // 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); items.Add(pItem); ++entry; } } cleanup: if (dlgProgress) dlgProgress->Close(); return true; failure: if (dlgProgress) dlgProgress->Close(); return false; }
/*---------------------------------------------------------------------- | CUPnPVirtualPathDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPVirtualPathDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { NPT_String path = strPath.c_str(); CMediaSource share; CFileItemPtr item; vector<CStdString> paths; path.TrimRight("/"); if (path == "virtualpath://upnproot") { // music item.reset(new CFileItem("virtualpath://upnpmusic/", true)); item->SetLabel("Music Files"); item->SetLabelPreformated(true); items.Add(item); // video item.reset(new CFileItem("virtualpath://upnpvideo/", true)); item->SetLabel("Video Files"); item->SetLabelPreformated(true); items.Add(item); // pictures item.reset(new CFileItem("virtualpath://upnppictures/", true)); item->SetLabel("Picture Files"); item->SetLabelPreformated(true); items.Add(item); // music library item.reset(new CFileItem("musicdb://", true)); item->SetLabel("Music Library"); item->SetLabelPreformated(true); items.Add(item); // video library item.reset(new CFileItem("videodb://", true)); item->SetLabel("Video Library"); item->SetLabelPreformated(true); items.Add(item); return true; } else if (path == "virtualpath://upnpmusic" || path == "virtualpath://upnpvideo" || path == "virtualpath://upnppictures") { // look for all shares given a container VECSOURCES *shares = NULL; if (path == "virtualpath://upnpmusic") { shares = g_settings.GetSourcesFromType("upnpmusic"); } else if (path == "virtualpath://upnpvideo") { shares = g_settings.GetSourcesFromType("upnpvideo"); } else if (path == "virtualpath://upnppictures") { shares = g_settings.GetSourcesFromType("upnppictures"); } if (shares) { for (unsigned int i = 0; i < shares->size(); i++) { // Does this share contains any local paths? CMediaSource &share = shares->at(i); // reconstruct share name as it could have been replaced by // a path if there was just one entry NPT_String share_name = path + "/"; share_name += share.strName + "/"; if (GetMatchingSource((const char*)share_name, share, paths) && paths.size()) { item.reset(new CFileItem((const char*)share_name, true)); item->SetLabel(share.strName); item->SetLabelPreformated(true); items.Add(item); } } } return true; } else if (!GetMatchingSource((const char*)path, share, paths)) { // split to remove share name from path NPT_String share_name; NPT_String file_path; bool bret = SplitPath(path, share_name, file_path); if (!bret || share_name.GetLength() == 0 || file_path.GetLength() == 0) { return false; } // make sure the file_path is the beginning of a share paths if (!FindSourcePath(share_name, file_path, true)) return false; // use the share name to figure out what extensions to use if (share_name.StartsWith("virtualpath://upnpmusic")) { CDirectory::GetDirectory( (const char*)file_path, items, g_stSettings.m_musicExtensions); } else if (share_name.StartsWith("virtualpath://upnpvideo")) { CDirectory::GetDirectory( (const char*)file_path, items, g_stSettings.m_videoExtensions); } else if (share_name.StartsWith("virtualpath://upnppictures")) { CDirectory::GetDirectory( (const char*)file_path, items, g_stSettings.m_pictureExtensions); } // paths should be prefixed for (int i=0; i < (int) items.Size(); ++i) { items[i]->m_strPath = share_name + "/" + items[i]->m_strPath.c_str(); } } else { // use the path to figure out what extensions to use if (path.StartsWith("virtualpath://upnpmusic")) { SetMask(g_stSettings.m_musicExtensions); } else if (path.StartsWith("virtualpath://upnpvideo")) { SetMask(g_stSettings.m_videoExtensions); } else if (path.StartsWith("virtualpath://upnppictures")) { SetMask(g_stSettings.m_pictureExtensions); } // dont allow prompting, this is a background task // although I don't think it matters here SetAllowPrompting(false); // it's a virtual path, get all items CVirtualPathDirectory::GetDirectory(strPath, items); // paths should be prefixed for (int i=0; i < (int) items.Size(); ++i) { items[i]->m_strPath = strPath + "/" + items[i]->m_strPath.c_str(); } } // always return true // this will make sure that even if nothing is found in a share // it doesn't fail upnp return true; }