X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_xbmc;a=blobdiff_plain;f=xbmc%2Fvideo%2Fdialogs%2FGUIDialogVideoInfo.cpp;h=78a0515dd2fd50567e96eb7a5d19b5b75c48952f;hp=d04415efefd720b96fc2ca08ac17d22728596bb4;hb=c4ef10a6b2516f235aa9818487667f716305d5bb;hpb=225c94e8dbe3b520c9cd274dc0904ef55828c81a diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp index d04415e..78a0515 100644 --- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp @@ -76,6 +76,12 @@ using namespace XFILE; #define CONTROL_LIST 50 +// predicate used by sorting and set_difference +bool compFileItemsByDbId(const CFileItemPtr& lhs, const CFileItemPtr& rhs) +{ + return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId; +} + CGUIDialogVideoInfo::CGUIDialogVideoInfo(void) : CGUIDialog(WINDOW_DIALOG_VIDEO_INFO, "DialogVideoInfo.xml") , m_movieItem(new CFileItem) @@ -299,11 +305,14 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item) m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered; if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid()) m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear(); - m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); - m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency - m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount); - m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount); - m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0; + if (!m_movieItem->HasProperty("totalepisodes")) + { + m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); + m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency + m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount); + m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount); + m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0; + } } else if (type == VIDEODB_CONTENT_EPISODES) { @@ -948,7 +957,10 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item) int dbId = item->GetVideoInfoTag()->m_iDbId; CContextButtons buttons; - buttons.Add(CONTEXT_BUTTON_EDIT, 16105); + if (type == "movie" || type == "set" || + type == "tvshow" || type == "episode" || + type == "musicvideo") + buttons.Add(CONTEXT_BUTTON_EDIT, 16105); if (type == "movie" || type == "tvshow") buttons.Add(CONTEXT_BUTTON_EDIT_SORTTITLE, 16107); @@ -985,8 +997,27 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item) item->GetVideoInfoTag()->m_iBookmarkId > 0) buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405); - if (!item->m_bIsFolder || type == VIDEODB_CONTENT_TVSHOWS) - buttons.Add(CONTEXT_BUTTON_DELETE, 646); + // movie sets + if (item->m_bIsFolder && type == "set") + { + buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511); + buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465); + } + + // tags + if (item->m_bIsFolder && type == "tag") + { + CVideoDbUrl videoUrl; + if (videoUrl.FromString(item->GetPath())) + { + const std::string &mediaType = videoUrl.GetItemType(); + + buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, StringUtils::Format(g_localizeStrings.Get(20460), GetLocalizedVideoType(mediaType).c_str())); + buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, StringUtils::Format(g_localizeStrings.Get(20461), GetLocalizedVideoType(mediaType).c_str())); + } + } + + buttons.Add(CONTEXT_BUTTON_DELETE, 646); bool result = false; int button = CGUIDialogContextMenu::ShowAndGetChoice(buttons); @@ -1035,6 +1066,22 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item) result = DeleteVideoItem(item); break; + case CONTEXT_BUTTON_SET_MOVIESET_ART: + result = ManageVideoItemArtwork(item, "set"); + break; + + case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS: + result = ManageMovieSets(item); + break; + + case CONTEXT_BUTTON_TAGS_ADD_ITEMS: + result = AddItemsToTag(item); + break; + + case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS: + result = RemoveItemsFromTag(item); + break; + default: result = false; break; @@ -1052,7 +1099,7 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item) //Add change a title's name bool CGUIDialogVideoInfo::UpdateVideoItemTitle(const CFileItemPtr &pItem) { - if (!pItem->HasVideoInfoTag()) + if (pItem == NULL || !pItem->HasVideoInfoTag()) return false; // dont allow update while scanning @@ -1090,7 +1137,7 @@ bool CGUIDialogVideoInfo::UpdateVideoItemTitle(const CFileItemPtr &pItem) bool CGUIDialogVideoInfo::MarkWatched(const CFileItemPtr &item, bool bMark) { - if (!CProfilesManager::Get().GetCurrentProfile().canWriteDatabases()) + if (item == NULL || !CProfilesManager::Get().GetCurrentProfile().canWriteDatabases()) return false; // dont allow update while scanning @@ -1155,13 +1202,15 @@ bool CGUIDialogVideoInfo::CanDeleteVideoItem(const CFileItemPtr &item) return params.GetMovieId() != -1 || params.GetEpisodeId() != -1 || params.GetMVideoId() != -1 || + params.GetSetId() != -1 || (params.GetTvShowId() != -1 && params.GetSeason() <= -1 && !CVideoDatabaseDirectory::IsAllItem(item->GetPath())); } bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, bool unavailable /* = false */) { - if (!item->HasVideoInfoTag() || !CanDeleteVideoItem(item)) + if (item == NULL || !item->HasVideoInfoTag() || + !CanDeleteVideoItem(item)) return false; // dont allow update while scanning @@ -1191,6 +1240,9 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, case VIDEODB_CONTENT_MUSICVIDEOS: heading = 20392; break; + case VIDEODB_CONTENT_MOVIE_SETS: + heading = 646; + break; default: return false; @@ -1214,10 +1266,16 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, if (!pDialog->IsConfirmed()) return false; - CStdString path; CVideoDatabase database; database.Open(); + if (type == VIDEODB_CONTENT_MOVIE_SETS) + { + database.DeleteSet(item->GetVideoInfoTag()->m_iDbId); + return true; + } + + CStdString path; database.GetFilePathById(item->GetVideoInfoTag()->m_iDbId, path, type); if (path.empty()) return false; @@ -1251,11 +1309,13 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, bool CGUIDialogVideoInfo::DeleteVideoItem(const CFileItemPtr &item, bool unavailable /* = false */) { + if (item == NULL) + return false; + // delete the video item from the database if (!DeleteVideoItemFromDatabase(item, unavailable)) return false; - bool result = true; // check if the user is allowed to delete the actual file as well if ((CProfilesManager::Get().GetCurrentProfile().getLockMode() == LOCK_MODE_EVERYONE || !CProfilesManager::Get().GetCurrentProfile().filesLocked() || @@ -1284,17 +1344,61 @@ bool CGUIDialogVideoInfo::DeleteVideoItem(const CFileItemPtr &item, bool unavail // HACK: stacked files need to be treated as folders in order to be deleted if (item->IsStack()) item->m_bIsFolder = true; - result = CFileUtils::DeleteItem(item); + CFileUtils::DeleteItem(item); } } CUtil::DeleteVideoDatabaseDirectoryCache(); - return result; + return true; +} + +bool CGUIDialogVideoInfo::ManageMovieSets(const CFileItemPtr &item) +{ + if (item == NULL) + return false; + + CFileItemList originalItems; + CFileItemList selectedItems; + + if (!GetMoviesForSet(item.get(), originalItems, selectedItems) || + selectedItems.Size() == 0) // need at least one item selected + return false; + + VECFILEITEMS original = originalItems.GetList(); + std::sort(original.begin(), original.end(), compFileItemsByDbId); + VECFILEITEMS selected = selectedItems.GetList(); + std::sort(selected.begin(), selected.end(), compFileItemsByDbId); + + bool refreshNeeded = false; + // update the "added" items + VECFILEITEMS addedItems; + set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId); + for (VECFILEITEMS::const_iterator it = addedItems.begin(); it != addedItems.end(); ++it) + { + if (SetMovieSet(it->get(), item.get())) + refreshNeeded = true; + } + + // update the "deleted" items + CFileItemPtr clearItem(new CFileItem()); + clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set + VECFILEITEMS deletedItems; + set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId); + for (VECFILEITEMS::iterator it = deletedItems.begin(); it != deletedItems.end(); ++it) + { + if (SetMovieSet(it->get(), clearItem.get())) + refreshNeeded = true; + } + + return refreshNeeded; } bool CGUIDialogVideoInfo::GetMoviesForSet(const CFileItem *setItem, CFileItemList &originalMovies, CFileItemList &selectedMovies) { + if (setItem == NULL || !setItem->HasVideoInfoTag()) + return false; + CVideoDatabase videodb; if (!videodb.Open()) return false; @@ -1346,13 +1450,16 @@ bool CGUIDialogVideoInfo::GetMoviesForSet(const CFileItem *setItem, CFileItemLis bool CGUIDialogVideoInfo::GetSetForMovie(const CFileItem *movieItem, CFileItemPtr &selectedSet) { + if (movieItem == NULL || !movieItem->HasVideoInfoTag()) + return false; + CVideoDatabase videodb; if (!videodb.Open()) return false; CFileItemList listItems; CStdString baseDir = "videodb://movies/sets/"; - if (!CDirectory::GetDirectory(baseDir, listItems) || listItems.Size() <= 0) + if (!CDirectory::GetDirectory(baseDir, listItems)) return false; listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle); @@ -1429,6 +1536,10 @@ bool CGUIDialogVideoInfo::GetSetForMovie(const CFileItem *movieItem, CFileItemPt bool CGUIDialogVideoInfo::SetMovieSet(const CFileItem *movieItem, const CFileItem *selectedSet) { + if (movieItem == NULL || !movieItem->HasVideoInfoTag() || + selectedSet == NULL || !selectedSet->HasVideoInfoTag()) + return false; + CVideoDatabase videodb; if (!videodb.Open()) return false; @@ -1437,6 +1548,308 @@ bool CGUIDialogVideoInfo::SetMovieSet(const CFileItem *movieItem, const CFileIte return true; } +bool CGUIDialogVideoInfo::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */) +{ + CVideoDatabase videodb; + if (!videodb.Open()) + return false; + + MediaType mediaType = MediaTypeNone; + std::string baseDir = "videodb://"; + std::string idColumn; + if (type.compare("movie") == 0) + { + mediaType = MediaTypeMovie; + baseDir += "movies"; + idColumn = "idMovie"; + } + else if (type.compare("tvshow") == 0) + { + mediaType = MediaTypeTvShow; + baseDir += "tvshows"; + idColumn = "idShow"; + } + else if (type.compare("musicvideo") == 0) + { + mediaType = MediaTypeMusicVideo; + baseDir += "musicvideos"; + idColumn = "idMVideo"; + } + + baseDir += "/titles/"; + CVideoDbUrl videoUrl; + if (!videoUrl.FromString(baseDir)) + return false; + + CVideoDatabase::Filter filter; + if (idTag > 0) + { + if (!showAll) + videoUrl.AddOption("tagid", idTag); + else + filter.where = videodb.PrepareSQL("%sview.%s NOT IN (SELECT taglinks.idMedia FROM taglinks WHERE taglinks.idTag = %d AND taglinks.media_type = '%s')", type.c_str(), idColumn.c_str(), idTag, type.c_str()); + } + + CFileItemList listItems; + if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0) + return false; + + CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); + if (dialog == NULL) + return false; + + listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle); + + dialog->Reset(); + dialog->SetMultiSelection(true); + dialog->SetHeading(strHeading); + dialog->SetItems(&listItems); + dialog->EnableButton(true, 186); + dialog->DoModal(); + + items.Copy(dialog->GetSelectedItems()); + return items.Size() > 0; +} + +bool CGUIDialogVideoInfo::AddItemsToTag(const CFileItemPtr &tagItem) +{ + if (tagItem == NULL || !tagItem->HasVideoInfoTag()) + return false; + + CVideoDbUrl videoUrl; + if (!videoUrl.FromString(tagItem->GetPath())) + return false; + + CVideoDatabase videodb; + if (!videodb.Open()) + return true; + + std::string mediaType = videoUrl.GetItemType(); + mediaType = mediaType.substr(0, mediaType.length() - 1); + + CFileItemList items; + std::string localizedType = GetLocalizedVideoType(mediaType); + std::string strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str()); + if (!GetItemsForTag(strLabel, mediaType, items, tagItem->GetVideoInfoTag()->m_iDbId)) + return true; + + for (int index = 0; index < items.Size(); index++) + { + if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0) + continue; + + videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, tagItem->GetVideoInfoTag()->m_iDbId, mediaType); + } + + return true; +} + +bool CGUIDialogVideoInfo::RemoveItemsFromTag(const CFileItemPtr &tagItem) +{ + if (tagItem == NULL || !tagItem->HasVideoInfoTag()) + return false; + + CVideoDbUrl videoUrl; + if (!videoUrl.FromString(tagItem->GetPath())) + return false; + + CVideoDatabase videodb; + if (!videodb.Open()) + return true; + + std::string mediaType = videoUrl.GetItemType(); + mediaType = mediaType.substr(0, mediaType.length() - 1); + + CFileItemList items; + std::string localizedType = GetLocalizedVideoType(mediaType); + std::string strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str()); + if (!GetItemsForTag(strLabel, mediaType, items, tagItem->GetVideoInfoTag()->m_iDbId, false)) + return true; + + for (int index = 0; index < items.Size(); index++) + { + if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0) + continue; + + videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, tagItem->GetVideoInfoTag()->m_iDbId, mediaType); + } + + return true; +} + +bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const CFileItemPtr &item, const std::string &type) +{ + if (item == NULL || !item->HasVideoInfoTag() || type.empty()) + return false; + + CVideoDatabase videodb; + if (!videodb.Open()) + return true; + + // Grab the thumbnails from the web + CFileItemList items; + CFileItemPtr noneitem(new CFileItem("thumb://None", false)); + std::string currentThumb; + int idArtist = -1; + CStdString artistPath; + string artType = "thumb"; + if (type == "artist") + { + CMusicDatabase musicdb; + if (musicdb.Open()) + { + idArtist = musicdb.GetArtistByName(item->GetLabel()); + if (idArtist >= 0 && musicdb.GetArtistPath(idArtist, artistPath)) + { + currentThumb = musicdb.GetArtForItem(idArtist, "artist", "thumb"); + if (currentThumb.empty()) + currentThumb = videodb.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType); + } + } + } + else if (type == "actor") + currentThumb = videodb.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType); + else + { // SEASON, SET + map currentArt; + artType = ChooseArtType(*item, currentArt); + if (artType.empty()) + return false; + + if (artType == "fanart") + return OnGetFanart(item); + + if (currentArt.find(artType) != currentArt.end()) + currentThumb = currentArt[artType]; + else if ((artType == "poster" || artType == "banner") && currentArt.find("thumb") != currentArt.end()) + currentThumb = currentArt["thumb"]; + } + + if (!currentThumb.empty()) + { + CFileItemPtr item(new CFileItem("thumb://Current", false)); + item->SetArt("thumb", currentThumb); + item->SetLabel(g_localizeStrings.Get(13512)); + items.Add(item); + } + noneitem->SetIconImage("DefaultFolder.png"); + noneitem->SetLabel(g_localizeStrings.Get(13515)); + + bool local = false; + vector thumbs; + if (type != "artist") + { + CVideoInfoTag tag; + if (type == "season") + videodb.GetTvShowInfo("", tag, item->GetVideoInfoTag()->m_iIdShow); + else + tag = *item->GetVideoInfoTag(); + + tag.m_strPictureURL.GetThumbURLs(thumbs, artType, type == "season" ? item->GetVideoInfoTag()->m_iSeason : -1); + + for (size_t i = 0; i < thumbs.size(); i++) + { + CFileItemPtr item(new CFileItem(StringUtils::Format("thumb://Remote%i", i), false)); + item->SetArt("thumb", thumbs[i]); + item->SetIconImage("DefaultPicture.png"); + item->SetLabel(g_localizeStrings.Get(13513)); + items.Add(item); + + // TODO: Do we need to clear the cached image? + // CTextureCache::Get().ClearCachedImage(thumbs[i]); + } + + if (type == "actor") + { + CStdString picturePath; + CStdString strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg"); + if (XFILE::CFile::Exists(strThumb)) + { + CFileItemPtr pItem(new CFileItem(strThumb,false)); + pItem->SetLabel(g_localizeStrings.Get(13514)); + pItem->SetArt("thumb", strThumb); + items.Add(pItem); + local = true; + } + else + noneitem->SetIconImage("DefaultActor.png"); + } + + if (type == "set") + noneitem->SetIconImage("DefaultVideo.png"); + } + else + { + CStdString strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg"); + if (XFILE::CFile::Exists(strThumb)) + { + CFileItemPtr pItem(new CFileItem(strThumb, false)); + pItem->SetLabel(g_localizeStrings.Get(13514)); + pItem->SetArt("thumb", strThumb); + items.Add(pItem); + local = true; + } + else + noneitem->SetIconImage("DefaultArtist.png"); + } + + if (!local) + items.Add(noneitem); + + CStdString result; + VECSOURCES sources=*CMediaSourceSettings::Get().GetSources("video"); + g_mediaManager.GetLocalDrives(sources); + AddItemPathToFileBrowserSources(sources, *item); + if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result)) + return false; // user cancelled + + if (result == "thumb://Current") + result = currentThumb; // user chose the one they have + + // delete the thumbnail if that's what the user wants, else overwrite with the + // new thumbnail + if (result == "thumb://None") + result.clear(); + else if (StringUtils::StartsWith(result, "thumb://Remote")) + { + int number = atoi(StringUtils::Mid(result, 14).c_str()); + result = thumbs[number]; + } + + // write the selected artwork to the database + if (type == "set" || + type == "actor" || + type == "season" || + (type == "artist" && idArtist < 0)) + videodb.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artType, result); + else + { + CMusicDatabase musicdb; + if (musicdb.Open()) + musicdb.SetArtForItem(idArtist, "artist", artType, result); + } + + CUtil::DeleteVideoDatabaseDirectoryCache(); + CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS); + g_windowManager.SendMessage(msg); + + return true; +} + +std::string CGUIDialogVideoInfo::GetLocalizedVideoType(const std::string &strType) +{ + if (strType == "movie" || strType == "movies") + return g_localizeStrings.Get(20342); + else if (strType == "tvshow" || strType == "tvshows") + return g_localizeStrings.Get(20343); + else if (strType == "episode" || strType == "episodes") + return g_localizeStrings.Get(20359); + else if (strType == "musicvideo" || strType == "musicvideos") + return g_localizeStrings.Get(20391); + + return ""; +} + bool CGUIDialogVideoInfo::UpdateVideoItemSortTitle(const CFileItemPtr &pItem) { // dont allow update while scanning @@ -1515,7 +1928,7 @@ bool CGUIDialogVideoInfo::LinkMovieToTvShow(const CFileItemPtr &item, bool bRemo } int iSelectedLabel = 0; - if (list.Size() > 1) + if (list.Size() > 1 || (!bRemove && !list.IsEmpty())) { list.Sort(SortByLabel, SortOrderAscending, CSettings::Get().GetBool("filelists.ignorethewhensorting") ? SortAttributeIgnoreArticle : SortAttributeNone); CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); @@ -1526,8 +1939,61 @@ bool CGUIDialogVideoInfo::LinkMovieToTvShow(const CFileItemPtr &item, bool bRemo iSelectedLabel = pDialog->GetSelectedLabel(); } - if (iSelectedLabel > -1) + if (iSelectedLabel > -1 && iSelectedLabel < list.Size()) return database.LinkMovieToTvshow(dbId, list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove); return false; } + +bool CGUIDialogVideoInfo::OnGetFanart(const CFileItemPtr &videoItem) +{ + if (videoItem == NULL || !videoItem->HasVideoInfoTag()) + return false; + + // update the db + CVideoDatabase videodb; + if (!videodb.Open()) + return false; + + CVideoThumbLoader loader; + CFileItem item(*videoItem); + loader.LoadItem(&item); + + CFileItemList items; + if (item.HasArt("fanart")) + { + CFileItemPtr itemCurrent(new CFileItem("fanart://Current", false)); + itemCurrent->SetArt("thumb", item.GetArt("fanart")); + itemCurrent->SetLabel(g_localizeStrings.Get(20440)); + items.Add(itemCurrent); + } + + // add the none option + { + CFileItemPtr itemNone(new CFileItem("fanart://None", false)); + itemNone->SetIconImage("DefaultVideo.png"); + itemNone->SetLabel(g_localizeStrings.Get(20439)); + items.Add(itemNone); + } + + CStdString result; + VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video")); + g_mediaManager.GetLocalDrives(sources); + AddItemPathToFileBrowserSources(sources, item); + bool flip = false; + if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || + StringUtils::EqualsNoCase(result, "fanart://Current")) + return false; + + if (StringUtils::EqualsNoCase(result, "fanart://None") || !CFile::Exists(result)) + result.clear(); + if (!result.empty() && flip) + result = CTextureUtils::GetWrappedImageURL(result, "", "flipped"); + + videodb.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result); + + // clear view cache and reload images + CUtil::DeleteVideoDatabaseDirectoryCache(); + + return true; +}