static void ParseItemVoddler(CFileItem* item, SResources& resources, TiXmlElement* element, const std::string& name, const std::string& xmlns, const std::string& path) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); std::string text = GetValue(element); if(name == "trailer") { vtag->m_strTrailer = text; SResource res; res.tag = "voddler:trailer"; res.mime = XMLUtils::GetAttribute(element, "type"); res.path = text; resources.push_back(res); } else if(name == "year") vtag->SetYear(atoi(text.c_str())); else if(name == "rating") vtag->SetRating((float)atof(text.c_str())); else if(name == "tagline") vtag->m_strTagLine = text; else if(name == "posterwall") { const char* url = element->Attribute("url"); if(url) item->SetArt("fanart", url); else if(IsPathToThumbnail(text)) item->SetArt("fanart", text); } }
int CGUIWindowVideoNav::GetFirstUnwatchedItemIndex(bool includeAllSeasons, bool includeSpecials) { int iIndex = 0; int iUnwatchedSeason = INT_MAX; // Run through the list of items and find the season number of the first season with unwatched episodes for (int i = 0; i < m_vecItems->Size(); ++i) { CFileItemPtr pItem = m_vecItems->Get(i); if (pItem->IsParentFolder() || !pItem->HasVideoInfoTag()) continue; CVideoInfoTag *pTag = pItem->GetVideoInfoTag(); if ((!includeAllSeasons && pTag->m_iSeason < 0) || (!includeSpecials && pTag->m_iSeason == 0)) continue; // Is the season unwatched, and is its season number lower than the currently identified // first unwatched season if (pTag->GetPlayCount() == 0 && pTag->m_iSeason < iUnwatchedSeason) { iUnwatchedSeason = pTag->m_iSeason; iIndex = i; } } NODE_TYPE nodeType = CVideoDatabaseDirectory::GetDirectoryChildType(m_vecItems->GetPath()); if (nodeType == NODE_TYPE::NODE_TYPE_EPISODES) { iIndex = 0; int iUnwatchedEpisode = INT_MAX; // Now run through the list of items and check episodes from the season identified above // to find the first (lowest episode number) unwatched episode. for (int i = 0; i < m_vecItems->Size(); ++i) { CFileItemPtr pItem = m_vecItems->Get(i); if (pItem->IsParentFolder() || !pItem->HasVideoInfoTag()) continue; CVideoInfoTag *pTag = pItem->GetVideoInfoTag(); // Does the episode belong to the unwatched season and Is the episode unwatched, and is its episode number // lower than the currently identified first unwatched episode if (pTag->m_iSeason == iUnwatchedSeason && pTag->GetPlayCount() == 0 && pTag->m_iEpisode < iUnwatchedEpisode) { iUnwatchedEpisode = pTag->m_iEpisode; iIndex = i; } } } return iIndex; }
JSONRPC_STATUS CVideoLibrary::SetEpisodeDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result) { int id = (int)parameterObject["episodeid"].asInteger(); CVideoDatabase videodatabase; if (!videodatabase.Open()) return InternalError; CVideoInfoTag infos; videodatabase.GetEpisodeInfo("", infos, id); if (infos.m_iDbId <= 0) { videodatabase.Close(); return InvalidParams; } int tvshowid = videodatabase.GetTvShowForEpisode(id); if (tvshowid <= 0) { videodatabase.Close(); return InvalidParams; } // get artwork std::map<std::string, std::string> artwork; videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork); int playcount = infos.GetPlayCount(); CDateTime lastPlayed = infos.m_lastPlayed; std::set<std::string> removedArtwork; std::set<std::string> updatedDetails; UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails); if (videodatabase.SetDetailsForEpisode(infos.m_strFileNameAndPath, infos, artwork, tvshowid, id) <= 0) return InternalError; if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeEpisode, removedArtwork)) return InternalError; if (playcount != infos.GetPlayCount() || lastPlayed != infos.m_lastPlayed) { // restore original playcount or the new one won't be announced int newPlaycount = infos.GetPlayCount(); infos.SetPlayCount(playcount); videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed); } UpdateResumePoint(parameterObject, infos, videodatabase); CJSONRPCUtils::NotifyItemUpdated(); return ACK; }
JSONRPC_STATUS CVideoLibrary::SetMusicVideoDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result) { int id = (int)parameterObject["musicvideoid"].asInteger(); CVideoDatabase videodatabase; if (!videodatabase.Open()) return InternalError; CVideoInfoTag infos; videodatabase.GetMusicVideoInfo("", infos, id); if (infos.m_iDbId <= 0) { videodatabase.Close(); return InvalidParams; } // get artwork std::map<std::string, std::string> artwork; videodatabase.GetArtForItem(infos.m_iDbId, infos.m_type, artwork); int playcount = infos.GetPlayCount(); CDateTime lastPlayed = infos.m_lastPlayed; std::set<std::string> removedArtwork; std::set<std::string> updatedDetails; UpdateVideoTag(parameterObject, infos, artwork, removedArtwork, updatedDetails); // we need to manually remove tags/taglinks for now because they aren't replaced // due to scrapers not supporting them videodatabase.RemoveTagsFromItem(id, MediaTypeMusicVideo); if (videodatabase.SetDetailsForMusicVideo(infos.m_strFileNameAndPath, infos, artwork, id) <= 0) return InternalError; if (!videodatabase.RemoveArtForItem(infos.m_iDbId, MediaTypeMusicVideo, removedArtwork)) return InternalError; if (playcount != infos.GetPlayCount()|| lastPlayed != infos.m_lastPlayed) { // restore original playcount or the new one won't be announced int newPlaycount = infos.GetPlayCount(); infos.SetPlayCount(playcount); videodatabase.SetPlayCount(CFileItem(infos), newPlaycount, infos.m_lastPlayed); } UpdateResumePoint(parameterObject, infos, videodatabase); CJSONRPCUtils::NotifyItemUpdated(); return ACK; }
bool CIMDB::GetDetails(const CScraperUrl &url, CVideoInfoTag &movieDetails, CGUIDialogProgress *pProgress /* = NULL */) { //CLog::Log(LOGDEBUG,"CIMDB::GetDetails(%s)", url.m_strURL.c_str()); m_url = url; m_movieDetails = movieDetails; // load our scraper xml if (!m_parser.Load("special://xbmc/system/scrapers/video/"+m_info.strPath)) return false; // fill in the defaults movieDetails.Reset(); if (pProgress) { // threaded version m_state = GET_DETAILS; m_found = 0; if (ThreadHandle()) StopThread(); Create(); while (!m_found) { pProgress->Progress(); if (pProgress->IsCanceled()) { CloseThread(); return false; } Sleep(1); } movieDetails = m_movieDetails; CloseThread(); return true; } else // unthreaded return InternalGetDetails(url, movieDetails); }
bool CIMDB::GetEpisodeDetails(const CScraperUrl &url, CVideoInfoTag &movieDetails, CGUIDialogProgress *pProgress /* = NULL */) { //CLog::Log(LOGDEBUG,"CIMDB::GetDetails(%s)", url.m_strURL.c_str()); m_url = url; m_movieDetails = movieDetails; // fill in the defaults movieDetails.Reset(); if (pProgress) { // threaded version m_state = GET_EPISODE_DETAILS; m_found = 0; if (ThreadHandle()) StopThread(); Create(); while (!m_found) { pProgress->Progress(); if (pProgress->IsCanceled()) { CloseThread(); return false; } Sleep(1); } movieDetails = m_movieDetails; CloseThread(); return true; } else // unthreaded return InternalGetDetails(url, movieDetails, "GetEpisodeDetails"); }
bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url, CVideoInfoTag &movieDetails, CGUIDialogProgress *pProgress /* = NULL */) { //CLog::Log(LOGDEBUG,"CVideoInfoDownloader::GetDetails(%s)", url.m_strURL.c_str()); m_url = url; m_movieDetails = movieDetails; // fill in the defaults movieDetails.Reset(); if (pProgress) { // threaded version m_state = GET_EPISODE_DETAILS; m_found = 0; if (IsRunning()) StopThread(); Create(); while (!m_found) { pProgress->Progress(); if (pProgress->IsCanceled()) { CloseThread(); return false; } Sleep(1); } movieDetails = m_movieDetails; CloseThread(); return true; } else // unthreaded return m_info->GetVideoDetails(*m_http, url, false/*fMovie*/, movieDetails); }
static void ParseItemZink(CFileItem* item, SResources& resources, TiXmlElement* element, const std::string& name, const std::string& xmlns, const std::string& path) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); std::string text = GetValue(element); if (name == "episode") vtag->m_iEpisode = atoi(text.c_str()); else if(name == "season") vtag->m_iSeason = atoi(text.c_str()); else if(name == "views") vtag->m_playCount = atoi(text.c_str()); else if(name == "airdate") vtag->m_firstAired.SetFromDateString(text); else if(name == "userrating") vtag->SetRating((float)atof(text.c_str())); else if(name == "duration") vtag->m_duration = atoi(text.c_str()); else if(name == "durationstr") vtag->m_duration = StringUtils::TimeStringToSeconds(text); }
bool CIMDB::LoadXML(const CStdString& strXMLFile, CVideoInfoTag &movieDetails, bool bDownload /* = true */) { TiXmlDocument doc; movieDetails.Reset(); if (doc.LoadFile(strXMLFile) && ParseDetails(doc, movieDetails)) { // excellent! return true; } if (!bDownload) return true; return false; }
static void ParseItemItunes(CFileItem* item, SResources& resources, TiXmlElement* item_child, const std::string& name, const std::string& xmlns, const std::string& path) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); std::string text = GetValue(item_child); if(name == "image") { const char * url = item_child->Attribute("href"); if(url) item->SetArt("thumb", url); else item->SetArt("thumb", text); } else if(name == "summary") vtag->m_strPlot = text; else if(name == "subtitle") vtag->m_strPlotOutline = text; else if(name == "author") vtag->m_writingCredits.push_back(text); else if(name == "duration") vtag->SetDuration(StringUtils::TimeStringToSeconds(text)); else if(name == "keywords") item->SetProperty("keywords", text); }
static void ParseItemBoxee(CFileItem* item, SResources& resources, TiXmlElement* element, const std::string& name, const std::string& xmlns, const std::string& path) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); std::string text = GetValue(element); if (name == "image") item->SetArt("thumb", text); else if(name == "user_agent") item->SetProperty("boxee:user_agent", text); else if(name == "content_type") item->SetMimeType(text); else if(name == "runtime") vtag->SetDuration(StringUtils::TimeStringToSeconds(text)); else if(name == "episode") vtag->m_iEpisode = atoi(text.c_str()); else if(name == "season") vtag->m_iSeason = atoi(text.c_str()); else if(name == "view-count") vtag->SetPlayCount(atoi(text.c_str())); else if(name == "tv-show-title") vtag->m_strShowTitle = text; else if(name == "release-date") item->SetProperty("boxee:releasedate", text); }
bool CVideoLibrary::FillFileItemList(const CVariant ¶meterObject, CFileItemList &list) { CVideoDatabase videodatabase; if (videodatabase.Open()) { CStdString file = parameterObject["file"].asString(); int movieID = (int)parameterObject["movieid"].asInteger(-1); int episodeID = (int)parameterObject["episodeid"].asInteger(-1); int musicVideoID = (int)parameterObject["musicvideoid"].asInteger(-1); bool success = false; CFileItem fileItem; if (FillFileItem(file, fileItem)) { success = true; list.Add(CFileItemPtr(new CFileItem(fileItem))); } if (movieID > 0) { CVideoInfoTag details; videodatabase.GetMovieInfo("", details, movieID); if (!details.IsEmpty()) { list.Add(CFileItemPtr(new CFileItem(details))); success = true; } } if (episodeID > 0) { CVideoInfoTag details; if (videodatabase.GetEpisodeInfo("", details, episodeID) && !details.IsEmpty()) { list.Add(CFileItemPtr(new CFileItem(details))); success = true; } } if (musicVideoID > 0) { CVideoInfoTag details; videodatabase.GetMusicVideoInfo("", details, musicVideoID); if (!details.IsEmpty()) { list.Add(CFileItemPtr(new CFileItem(details))); success = true; } } videodatabase.Close(); return success; } return false; }
bool CIMDB::ParseDetails(TiXmlDocument &doc, CVideoInfoTag &movieDetails) { TiXmlHandle docHandle( &doc ); TiXmlElement *details = docHandle.FirstChild( "details" ).Element(); if (!details) { CLog::Log(LOGERROR, "%s: Invalid xml file",__FUNCTION__); return false; } // set chaining to true here as this is called by our scrapers movieDetails.Load(details, true); CHTMLUtil::RemoveTags(movieDetails.m_strPlot); return true; }
bool CVideoLibrary::FillFileItemList(const Value ¶meterObject, CFileItemList &list) { CVideoDatabase videodatabase; if ((parameterObject["movieid"].isInt() || parameterObject["episodeid"].isInt() || parameterObject["musicvideoid"].isInt()) && videodatabase.Open()) { int movieID = ParameterAsInt(parameterObject, -1, "movieid"); int episodeID = ParameterAsInt(parameterObject, -1, "episodeid"); int musicVideoID = ParameterAsInt(parameterObject, -1, "musicvideoid"); bool success = true; if (movieID > 0) { CVideoInfoTag details; videodatabase.GetMovieInfo("", details, movieID); if (!details.IsEmpty()) { CFileItemPtr item = CFileItemPtr(new CFileItem(details)); list.Add(item); success &= true; } success = false; } if (episodeID > 0) { CVideoInfoTag details; if (videodatabase.GetEpisodeInfo("", details, episodeID) && !details.IsEmpty()) { CFileItemPtr item = CFileItemPtr(new CFileItem(details)); list.Add(item); success &= true; } success = false; } if (musicVideoID > 0) { CVideoInfoTag details; videodatabase.GetMusicVideoInfo("", details, musicVideoID); if (!details.IsEmpty()) { CFileItemPtr item = CFileItemPtr(new CFileItem(details)); list.Add(item); success &= true; } success = false; } videodatabase.Close(); return success; } return false; }
static void ParseItem(CFileItem* item, TiXmlElement* root, const std::string& path) { SResources resources; ParseItem(item, resources, root, path); const char* prio[] = { "media:content", "voddler:trailer", "rss:enclosure", "svtplay:broadcasts", "svtplay:xmllink", "rss:link", "rss:guid", NULL }; std::string mime; if (FindMime(resources, "video/")) mime = "video/"; else if(FindMime(resources, "audio/")) mime = "audio/"; else if(FindMime(resources, "application/rss")) mime = "application/rss"; else if(FindMime(resources, "image/")) mime = "image/"; int maxrate = CSettings::Get().GetInt(CSettings::SETTING_NETWORK_BANDWIDTH); if(maxrate == 0) maxrate = INT_MAX; SResources::iterator best = resources.end(); for(const char** type = prio; *type && best == resources.end(); type++) { for(SResources::iterator it = resources.begin(); it != resources.end(); it++) { if(!StringUtils::StartsWith(it->mime, mime)) continue; if(it->tag == *type) { if(best == resources.end()) { best = it; continue; } if(it->bitrate == best->bitrate) { if(it->width*it->height > best->width*best->height) best = it; continue; } if(it->bitrate > maxrate) { if(it->bitrate < best->bitrate) best = it; continue; } if(it->bitrate > best->bitrate) { best = it; continue; } } } } if(best != resources.end()) { item->SetMimeType(best->mime); item->SetPath(best->path); item->m_dwSize = best->size; if(best->duration) item->SetProperty("duration", StringUtils::SecondsToTimeString(best->duration)); /* handling of mimetypes fo directories are sub optimal at best */ if(best->mime == "application/rss+xml" && StringUtils::StartsWithNoCase(item->GetPath(), "http://")) item->SetPath("rss://" + item->GetPath().substr(7)); if(StringUtils::StartsWithNoCase(item->GetPath(), "rss://")) item->m_bIsFolder = true; else item->m_bIsFolder = false; } if(!item->m_strTitle.empty()) item->SetLabel(item->m_strTitle); if(item->HasVideoInfoTag()) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); if(item->HasProperty("duration") && !vtag->GetDuration()) vtag->m_duration = StringUtils::TimeStringToSeconds(item->GetProperty("duration").asString()); if(item->HasProperty("description") && vtag->m_strPlot.empty()) vtag->m_strPlot = item->GetProperty("description").asString(); if(vtag->m_strPlotOutline.empty() && !vtag->m_strPlot.empty()) { size_t pos = vtag->m_strPlot.find('\n'); if(pos != std::string::npos) vtag->m_strPlotOutline = vtag->m_strPlot.substr(0, pos); else vtag->m_strPlotOutline = vtag->m_strPlot; } if(!vtag->GetDuration()) item->SetLabel2(StringUtils::SecondsToTimeString(vtag->GetDuration())); } }
CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const ScraperPtr& info, int episode, const CStdString& strPath2) { m_info = info; // assume we can use these settings m_type = ScraperTypeFromContent(info->Content()); if (FAILED(Load(strPath))) return NO_NFO; CFileItemList items; bool bNfo=false; AddonPtr addon; ScraperPtr defaultScraper; if (!CAddonMgr::Get().GetDefault(m_type, addon)) return NO_NFO; else defaultScraper = boost::dynamic_pointer_cast<CScraper>(addon); if (m_type == ADDON_SCRAPER_ALBUMS) { CAlbum album; bNfo = GetDetails(album); } else if (m_type == ADDON_SCRAPER_ARTISTS) { CArtist artist; bNfo = GetDetails(artist); } else if (m_type == ADDON_SCRAPER_TVSHOWS || m_type == ADDON_SCRAPER_MOVIES || m_type == ADDON_SCRAPER_MUSICVIDEOS) { // first check if it's an XML file with the info we need CVideoInfoTag details; bNfo = GetDetails(details); if (episode > -1 && bNfo && m_type == ADDON_SCRAPER_TVSHOWS) { int infos=0; while (m_headofdoc && details.m_iEpisode != episode) { m_headofdoc = strstr(m_headofdoc+1,"<episodedetails>"); bNfo = GetDetails(details); infos++; } if (details.m_iEpisode != episode) { bNfo = false; details.Reset(); m_headofdoc = m_doc; if (infos == 1) // still allow differing nfo/file numbers for single ep nfo's bNfo = GetDetails(details); } } } vector<ScraperPtr> vecScrapers; // add selected scraper if (m_info) vecScrapers.push_back(m_info); VECADDONS addons; CAddonMgr::Get().GetAddons(m_type,addons); // first pass - add language based scrapers if (m_info && g_guiSettings.GetBool("scrapers.langfallback")) AddScrapers(addons,vecScrapers); // add default scraper if ((m_info && m_info->ID() != defaultScraper->ID()) || !m_info) vecScrapers.push_back(defaultScraper); // search .. int res = -1; for (unsigned int i=0;i<vecScrapers.size();++i) if ((res = Scrape(vecScrapers[i])) == 0 || res == 2) break; if (res == 2) return ERROR_NFO; if (bNfo) return (m_strImDbUrl.size() > 0) ? COMBINED_NFO:FULL_NFO; return (m_strImDbUrl.size() > 0) ? URL_NFO : NO_NFO; }
static void ParseItem(CFileItem* item, TiXmlElement* root, const CStdString& path) { SResources resources; ParseItem(item, resources, root, path); const char* prio[] = { "media:content", "voddler:trailer", "rss:enclosure", "svtplay:broadcasts", "svtplay:xmllink", "rss:link", "rss:guid", NULL }; CStdString mime; if (FindMime(resources, "video/")) mime = "video/"; else if(FindMime(resources, "audio/")) mime = "audio/"; else if(FindMime(resources, "application/rss")) mime = "application/rss"; else if(FindMime(resources, "image/")) mime = "image/"; int maxrate = g_guiSettings.GetInt("network.bandwidth"); if(maxrate == 0) maxrate = INT_MAX; SResources::iterator best = resources.end(); for(const char** type = prio; *type && best == resources.end(); type++) { for(SResources::iterator it = resources.begin(); it != resources.end(); it++) { if(it->mime.Left(mime.length()) != mime) continue; if(it->tag == *type) { if(best == resources.end()) { best = it; continue; } if(it->bitrate == best->bitrate) { if(it->width*it->height > best->width*best->height) best = it; continue; } if(it->bitrate > maxrate) { if(it->bitrate < best->bitrate) best = it; continue; } if(it->bitrate > best->bitrate) { best = it; continue; } } } } if(best != resources.end()) { item->SetMimeType(best->mime); item->SetPath(best->path); item->m_dwSize = best->size; if(best->duration) item->SetProperty("duration", StringUtils::SecondsToTimeString(best->duration)); /* handling of mimetypes fo directories are sub optimal at best */ if(best->mime == "application/rss+xml" && item->GetPath().Left(7).Equals("http://")) item->SetPath("rss://" + item->GetPath().Mid(7)); if(item->GetPath().Left(6).Equals("rss://")) item->m_bIsFolder = true; else item->m_bIsFolder = false; } if(!item->m_strTitle.IsEmpty()) item->SetLabel(item->m_strTitle); if(item->HasVideoInfoTag()) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); if(item->HasProperty("duration") && !vtag->GetDuration()) vtag->m_duration = StringUtils::TimeStringToSeconds(item->GetProperty("duration").asString()); if(item->HasProperty("description") && vtag->m_strPlot.IsEmpty()) vtag->m_strPlot = item->GetProperty("description").asString(); if(vtag->m_strPlotOutline.IsEmpty() && !vtag->m_strPlot.IsEmpty()) { int pos = vtag->m_strPlot.Find('\n'); if(pos >= 0) vtag->m_strPlotOutline = vtag->m_strPlot.Left(pos); else vtag->m_strPlotOutline = vtag->m_strPlot; } if(!vtag->GetDuration()) item->SetLabel2(StringUtils::SecondsToTimeString(vtag->GetDuration())); } }
CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const ScraperPtr& info, int episode, const CStdString& strPath2) { m_info = info; // assume we can use these settings m_type = ScraperTypeFromContent(info->Content()); if (FAILED(Load(strPath))) return NO_NFO; CFileItemList items; bool bNfo=false; AddonPtr addon; ScraperPtr defaultScraper; if (CAddonMgr::Get().GetDefault(m_type, addon)) defaultScraper = boost::dynamic_pointer_cast<CScraper>(addon); if (m_type == ADDON_SCRAPER_ALBUMS) { CAlbum album; bNfo = GetDetails(album); } else if (m_type == ADDON_SCRAPER_ARTISTS) { CArtist artist; bNfo = GetDetails(artist); } else if (m_type == ADDON_SCRAPER_TVSHOWS || m_type == ADDON_SCRAPER_MOVIES || m_type == ADDON_SCRAPER_MUSICVIDEOS) { // first check if it's an XML file with the info we need CVideoInfoTag details; bNfo = GetDetails(details); if (episode > -1 && bNfo && m_type == ADDON_SCRAPER_TVSHOWS) { int infos=0; while (m_headofdoc && details.m_iEpisode != episode) { m_headofdoc = strstr(m_headofdoc+1,"<episodedetails"); bNfo = GetDetails(details); infos++; } if (details.m_iEpisode != episode) { bNfo = false; details.Reset(); m_headofdoc = m_doc; if (infos == 1) // still allow differing nfo/file numbers for single ep nfo's bNfo = GetDetails(details); } } } vector<ScraperPtr> vecScrapers; // add selected scraper - first proirity if (m_info) vecScrapers.push_back(m_info); // Add all scrapers except selected and default VECADDONS addons; CAddonMgr::Get().GetAddons(m_type,addons); for (unsigned i = 0; i < addons.size(); ++i) { ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(addons[i]); // skip if scraper requires settings and there's nothing set yet if (scraper->RequiresSettings() && !scraper->HasUserSettings()) continue; if( (!m_info || m_info->ID() != scraper->ID()) && (!defaultScraper || defaultScraper->ID() != scraper->ID()) ) vecScrapers.push_back(scraper); } // add default scraper - not user selectable so it's last priority if( defaultScraper && (!m_info || m_info->ID() != defaultScraper->ID()) && ( !defaultScraper->RequiresSettings() || defaultScraper->HasUserSettings() ) ) vecScrapers.push_back(defaultScraper); // search .. int res = -1; for (unsigned int i=0;i<vecScrapers.size();++i) if ((res = Scrape(vecScrapers[i])) == 0 || res == 2) break; if (res == 2) return ERROR_NFO; if (bNfo) return m_scurl.m_url.empty() ? FULL_NFO : COMBINED_NFO; return m_scurl.m_url.empty() ? NO_NFO : URL_NFO; }
bool CThumbExtractor::DoWork() { if (m_item.IsLiveTV() // Due to a pvr addon api design flaw (no support for multiple concurrent streams // per addon instance), pvr recording thumbnail extraction does not work (reliably). || URIUtils::IsPVRRecording(m_item.GetDynPath()) || URIUtils::IsUPnP(m_item.GetPath()) || URIUtils::IsBluray(m_item.GetPath()) || m_item.IsBDFile() || m_item.IsDVD() || m_item.IsDiscImage() || m_item.IsDVDFile(false, true) || m_item.IsInternetStream() || m_item.IsDiscStub() || m_item.IsPlayList()) return false; // For HTTP/FTP we only allow extraction when on a LAN if (URIUtils::IsRemote(m_item.GetPath()) && !URIUtils::IsOnLAN(m_item.GetPath()) && (URIUtils::IsFTP(m_item.GetPath()) || URIUtils::IsHTTP(m_item.GetPath()))) return false; bool result=false; if (m_thumb) { CLog::Log(LOGDEBUG,"%s - trying to extract thumb from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str()); // construct the thumb cache file CTextureDetails details; details.file = CTextureCache::GetCacheFile(m_target) + ".jpg"; result = CDVDFileInfo::ExtractThumb(m_item, details, m_fillStreamDetails ? &m_item.GetVideoInfoTag()->m_streamDetails : nullptr, m_pos); if(result) { CTextureCache::GetInstance().AddCachedTexture(m_target, details); m_item.SetProperty("HasAutoThumb", true); m_item.SetProperty("AutoThumbImage", m_target); m_item.SetArt("thumb", m_target); CVideoInfoTag* info = m_item.GetVideoInfoTag(); if (info->m_iDbId > 0 && !info->m_type.empty()) { CVideoDatabase db; if (db.Open()) { db.SetArtForItem(info->m_iDbId, info->m_type, "thumb", m_item.GetArt("thumb")); db.Close(); } } } } else if (!m_item.IsPlugin() && (!m_item.HasVideoInfoTag() || !m_item.GetVideoInfoTag()->HasStreamDetails())) { // No tag or no details set, so extract them CLog::Log(LOGDEBUG,"%s - trying to extract filestream details from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str()); result = CDVDFileInfo::GetFileStreamDetails(&m_item); } if (result) { CVideoInfoTag* info = m_item.GetVideoInfoTag(); CVideoDatabase db; if (db.Open()) { if (URIUtils::IsStack(m_listpath)) { // Don't know the total time of the stack, so set duration to zero to avoid confusion info->m_streamDetails.SetVideoDuration(0, 0); // Restore original stack path m_item.SetPath(m_listpath); } if (info->m_iFileId < 0) db.SetStreamDetailsForFile(info->m_streamDetails, !info->m_strFileNameAndPath.empty() ? info->m_strFileNameAndPath : m_item.GetPath()); else db.SetStreamDetailsForFileId(info->m_streamDetails, info->m_iFileId); // overwrite the runtime value if the one from streamdetails is available if (info->m_iDbId > 0 && info->GetStaticDuration() != info->GetDuration()) { info->SetDuration(info->GetDuration()); // store the updated information in the database db.SetDetailsForItem(info->m_iDbId, info->m_type, *info, m_item.GetArt()); } db.Close(); } return true; } return false; }
static void ParseItemMRSS(CFileItem* item, SResources& resources, TiXmlElement* item_child, const std::string& name, const std::string& xmlns, const std::string& path) { CVideoInfoTag* vtag = item->GetVideoInfoTag(); std::string text = GetValue(item_child); if(name == "content") { SResource res; res.tag = "media:content"; res.mime = XMLUtils::GetAttribute(item_child, "type"); res.path = XMLUtils::GetAttribute(item_child, "url"); item_child->Attribute("width", &res.width); item_child->Attribute("height", &res.height); item_child->Attribute("bitrate", &res.bitrate); item_child->Attribute("duration", &res.duration); if(item_child->Attribute("fileSize")) res.size = _atoi64(item_child->Attribute("fileSize")); resources.push_back(res); ParseItem(item, resources, item_child, path); } else if(name == "group") { ParseItem(item, resources, item_child, path); } else if(name == "thumbnail") { if(!item_child->NoChildren() && IsPathToThumbnail(item_child->FirstChild()->ValueStr())) item->SetArt("thumb", item_child->FirstChild()->ValueStr()); else { const char * url = item_child->Attribute("url"); if(url && IsPathToThumbnail(url)) item->SetArt("thumb", url); } } else if (name == "title") { if(text.empty()) return; if(text.length() > item->m_strTitle.length()) item->m_strTitle = text; } else if(name == "description") { if(text.empty()) return; std::string description = text; if(XMLUtils::GetAttribute(item_child, "type") == "html") HTML::CHTMLUtil::RemoveTags(description); item->SetProperty("description", description); } else if(name == "category") { if(text.empty()) return; std::string scheme = XMLUtils::GetAttribute(item_child, "scheme"); /* okey this is silly, boxee what did you think?? */ if (scheme == "urn:boxee:genre") vtag->m_genre.push_back(text); else if(scheme == "urn:boxee:title-type") { if (text == "tv") item->SetProperty("boxee:istvshow", true); else if(text == "movie") item->SetProperty("boxee:ismovie", true); } else if(scheme == "urn:boxee:episode") vtag->m_iEpisode = atoi(text.c_str()); else if(scheme == "urn:boxee:season") vtag->m_iSeason = atoi(text.c_str()); else if(scheme == "urn:boxee:show-title") vtag->m_strShowTitle = text.c_str(); else if(scheme == "urn:boxee:view-count") vtag->m_playCount = atoi(text.c_str()); else if(scheme == "urn:boxee:source") item->SetProperty("boxee:provider_source", text); else vtag->m_genre = StringUtils::Split(text, g_advancedSettings.m_videoItemSeparator); } else if(name == "rating") { std::string scheme = XMLUtils::GetAttribute(item_child, "scheme"); if(scheme == "urn:user") vtag->SetRating((float)atof(text.c_str())); else vtag->m_strMPAARating = text; } else if(name == "credit") { std::string role = XMLUtils::GetAttribute(item_child, "role"); if (role == "director") vtag->m_director.push_back(text); else if(role == "author" || role == "writer") vtag->m_writingCredits.push_back(text); else if(role == "actor") { SActorInfo actor; actor.strName = text; vtag->m_cast.push_back(actor); } } else if(name == "copyright") vtag->m_studio = StringUtils::Split(text, g_advancedSettings.m_videoItemSeparator); else if(name == "keywords") item->SetProperty("keywords", text); }
void CVideoLibrary::UpdateVideoTag(const CVariant ¶meterObject, CVideoInfoTag& details, std::map<std::string, std::string> &artwork, std::set<std::string> &removedArtwork, std::set<std::string> &updatedDetails) { if (ParameterNotNull(parameterObject, "title")) details.SetTitle(parameterObject["title"].asString()); if (ParameterNotNull(parameterObject, "playcount")) details.m_playCount = (int)parameterObject["playcount"].asInteger(); if (ParameterNotNull(parameterObject, "runtime")) details.m_duration = (int)parameterObject["runtime"].asInteger(); std::vector<std::string> director(details.m_director); UpdateVideoTagField(parameterObject, "director", director, updatedDetails); details.SetDirector(director); std::vector<std::string> studio(details.m_studio); UpdateVideoTagField(parameterObject, "studio", studio, updatedDetails); details.SetStudio(studio); if (ParameterNotNull(parameterObject, "year")) details.m_iYear = (int)parameterObject["year"].asInteger(); if (ParameterNotNull(parameterObject, "plot")) details.SetPlot(parameterObject["plot"].asString()); if (ParameterNotNull(parameterObject, "album")) details.SetAlbum(parameterObject["album"].asString()); std::vector<std::string> artist(details.m_artist); UpdateVideoTagField(parameterObject, "artist", artist, updatedDetails); details.SetArtist(artist); std::vector<std::string> genre(details.m_genre); UpdateVideoTagField(parameterObject, "genre", genre, updatedDetails); details.SetGenre(genre); if (ParameterNotNull(parameterObject, "track")) details.m_iTrack = (int)parameterObject["track"].asInteger(); if (ParameterNotNull(parameterObject, "rating")) { details.SetRating(parameterObject["rating"].asFloat()); updatedDetails.insert("ratings"); } if (ParameterNotNull(parameterObject, "votes")) { details.SetVotes(StringUtils::ReturnDigits(parameterObject["votes"].asString())); updatedDetails.insert("ratings"); //Votes and ratings both need updates now, this will trigger those } if (ParameterNotNull(parameterObject, "ratings")) { CVariant ratings = parameterObject["ratings"]; for (CVariant::const_iterator_map rIt = ratings.begin_map(); rIt != ratings.end_map(); rIt++) { if (rIt->second.isArray() && ParameterNotNull(rIt->second, "name") && ParameterNotNull(rIt->second, "rating")) { details.SetRating(rIt->second["rating"].asFloat(), rIt->second["name"].asString()); if (ParameterNotNull(rIt->second, "votes")) details.SetVotes(StringUtils::ReturnDigits(parameterObject["votes"].asString()), rIt->second["name"].asString()); } } updatedDetails.insert("ratings"); } if (ParameterNotNull(parameterObject, "userrating")) details.m_iUserRating = parameterObject["userrating"].asInteger(); if (ParameterNotNull(parameterObject, "mpaa")) details.SetMPAARating(parameterObject["mpaa"].asString()); if (ParameterNotNull(parameterObject, "imdbnumber")) details.SetIMDBNumber(parameterObject["imdbnumber"].asString()); if (ParameterNotNull(parameterObject, "premiered")) SetFromDBDate(parameterObject["premiered"], details.m_premiered); if (ParameterNotNull(parameterObject, "lastplayed")) SetFromDBDateTime(parameterObject["lastplayed"], details.m_lastPlayed); if (ParameterNotNull(parameterObject, "firstaired")) SetFromDBDate(parameterObject["firstaired"], details.m_firstAired); if (ParameterNotNull(parameterObject, "productioncode")) details.SetProductionCode(parameterObject["productioncode"].asString()); if (ParameterNotNull(parameterObject, "season")) details.m_iSeason = (int)parameterObject["season"].asInteger(); if (ParameterNotNull(parameterObject, "episode")) details.m_iEpisode = (int)parameterObject["episode"].asInteger(); if (ParameterNotNull(parameterObject, "originaltitle")) details.SetOriginalTitle(parameterObject["originaltitle"].asString()); if (ParameterNotNull(parameterObject, "trailer")) details.SetTrailer(parameterObject["trailer"].asString()); if (ParameterNotNull(parameterObject, "tagline")) details.SetTagLine(parameterObject["tagline"].asString()); if (ParameterNotNull(parameterObject, "plotoutline")) details.SetPlotOutline(parameterObject["plotoutline"].asString()); std::vector<std::string> credits(details.m_writingCredits); UpdateVideoTagField(parameterObject, "writer", credits, updatedDetails); details.SetWritingCredits(credits); std::vector<std::string> country(details.m_country); UpdateVideoTagField(parameterObject, "country", country, updatedDetails); details.SetCountry(country); if (ParameterNotNull(parameterObject, "top250")) details.m_iTop250 = (int)parameterObject["top250"].asInteger(); if (ParameterNotNull(parameterObject, "sorttitle")) details.SetSortTitle(parameterObject["sorttitle"].asString()); if (ParameterNotNull(parameterObject, "episodeguide")) details.SetEpisodeGuide(parameterObject["episodeguide"].asString()); if (ParameterNotNull(parameterObject, "set")) { details.SetSet(parameterObject["set"].asString()); updatedDetails.insert("set"); } std::vector<std::string> showLink(details.m_showLink); UpdateVideoTagField(parameterObject, "showlink", showLink, updatedDetails); details.SetShowLink(showLink); std::vector<std::string> tags(details.m_tags); UpdateVideoTagField(parameterObject, "tag", tags, updatedDetails); details.SetTags(tags); if (ParameterNotNull(parameterObject, "thumbnail")) { std::string value = parameterObject["thumbnail"].asString(); artwork["thumb"] = StringUtils::Trim(value); updatedDetails.insert("art.altered"); } if (ParameterNotNull(parameterObject, "fanart")) { std::string value = parameterObject["fanart"].asString(); artwork["fanart"] = StringUtils::Trim(value); updatedDetails.insert("art.altered"); } if (ParameterNotNull(parameterObject, "art")) { CVariant art = parameterObject["art"]; for (CVariant::const_iterator_map artIt = art.begin_map(); artIt != art.end_map(); artIt++) { if (artIt->second.isString() && !artIt->second.asString().empty()) { artwork[artIt->first] = CTextureUtils::UnwrapImageURL(artIt->second.asString()); updatedDetails.insert("art.altered"); } else if (artIt->second.isNull()) { artwork.erase(artIt->first); removedArtwork.insert(artIt->first); } } } }
bool CThumbExtractor::DoWork() { if (m_item.IsLiveTV() || URIUtils::IsUPnP(m_item.GetPath()) || m_item.IsDAAP() || m_item.IsDVD() || m_item.IsDiscImage() || m_item.IsDVDFile(false, true) || m_item.IsInternetStream() || m_item.IsDiscStub() || m_item.IsPlayList()) return false; if (URIUtils::IsRemote(m_item.GetPath()) && !URIUtils::IsOnLAN(m_item.GetPath())) { // A quasi internet filesystem like webdav is generally fast enough for extracting stuff if (!URIUtils::IsDAV(m_item.GetPath())) return false; } bool result=false; if (m_thumb) { CLog::Log(LOGDEBUG,"%s - trying to extract thumb from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str()); // construct the thumb cache file CTextureDetails details; details.file = CTextureCache::GetCacheFile(m_target) + ".jpg"; result = CDVDFileInfo::ExtractThumb(m_item.GetPath(), details, &m_item.GetVideoInfoTag()->m_streamDetails); if(result) { CTextureCache::Get().AddCachedTexture(m_target, details); m_item.SetProperty("HasAutoThumb", true); m_item.SetProperty("AutoThumbImage", m_target); m_item.SetArt("thumb", m_target); CVideoInfoTag* info = m_item.GetVideoInfoTag(); if (info->m_iDbId > 0 && !info->m_type.empty()) { CVideoDatabase db; if (db.Open()) { db.SetArtForItem(info->m_iDbId, info->m_type, "thumb", m_item.GetArt("thumb")); db.Close(); } } } } else if (!m_item.HasVideoInfoTag() || !m_item.GetVideoInfoTag()->HasStreamDetails()) { // No tag or no details set, so extract them CLog::Log(LOGDEBUG,"%s - trying to extract filestream details from video file %s", __FUNCTION__, CURL::GetRedacted(m_item.GetPath()).c_str()); result = CDVDFileInfo::GetFileStreamDetails(&m_item); } if (result) { CVideoInfoTag* info = m_item.GetVideoInfoTag(); CVideoDatabase db; if (db.Open()) { if (URIUtils::IsStack(m_listpath)) { // Don't know the total time of the stack, so set duration to zero to avoid confusion info->m_streamDetails.SetVideoDuration(0, 0); // Restore original stack path m_item.SetPath(m_listpath); } if (info->m_iFileId < 0) db.SetStreamDetailsForFile(info->m_streamDetails, !info->m_strFileNameAndPath.empty() ? info->m_strFileNameAndPath : static_cast<const std::string&>(m_item.GetPath())); else db.SetStreamDetailsForFileId(info->m_streamDetails, info->m_iFileId); // overwrite the runtime value if the one from streamdetails is available if (info->m_iDbId > 0 && info->m_duration != info->GetDuration()) { info->m_duration = info->GetDuration(); // store the updated information in the database db.SetDetailsForItem(info->m_iDbId, info->m_type, *info, m_item.GetArt()); } db.Close(); } return true; } return false; }