2 * Copyright (C) 2012-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "EdenVideoArtUpdater.h"
22 #include "video/VideoDatabase.h"
23 #include "video/VideoInfoScanner.h"
25 #include "utils/log.h"
26 #include "utils/Crc32.h"
27 #include "utils/URIUtils.h"
28 #include "utils/ScraperUrl.h"
29 #include "utils/StringUtils.h"
30 #include "TextureCache.h"
31 #include "TextureCacheJob.h"
32 #include "pictures/Picture.h"
33 #include "profiles/ProfilesManager.h"
34 #include "settings/AdvancedSettings.h"
35 #include "settings/Settings.h"
36 #include "guilib/Texture.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "guilib/LocalizeStrings.h"
39 #include "filesystem/File.h"
40 #include "filesystem/StackDirectory.h"
41 #include "dialogs/GUIDialogExtendedProgressBar.h"
42 #include "interfaces/AnnouncementManager.h"
45 using namespace VIDEO;
46 using namespace XFILE;
48 CEdenVideoArtUpdater::CEdenVideoArtUpdater() : CThread("VideoArtUpdater")
53 CEdenVideoArtUpdater::~CEdenVideoArtUpdater()
58 void CEdenVideoArtUpdater::Start()
60 CEdenVideoArtUpdater *updater = new CEdenVideoArtUpdater();
61 updater->Create(true); // autodelete
64 void CEdenVideoArtUpdater::Process()
73 CGUIDialogExtendedProgressBar* dialog =
74 (CGUIDialogExtendedProgressBar*)g_windowManager.GetWindow(WINDOW_DIALOG_EXT_PROGRESS);
76 CGUIDialogProgressBarHandle *handle = dialog->GetHandle(g_localizeStrings.Get(314));
77 handle->SetTitle(g_localizeStrings.Get(12349));
80 db.GetMoviesByWhere("videodb://movies/titles/", CDatabase::Filter(), items);
81 for (int i = 0; i < items.Size(); i++)
83 CFileItemPtr item = items[i];
84 handle->SetProgress(i, items.Size());
85 handle->SetText(StringUtils::Format(g_localizeStrings.Get(12350).c_str(), item->GetLabel().c_str()));
86 string cachedThumb = GetCachedVideoThumb(*item);
87 string cachedFanart = GetCachedFanart(*item);
89 item->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
90 item->GetVideoInfoTag()->m_fanart.Unpack();
91 item->GetVideoInfoTag()->m_strPictureURL.Parse();
93 map<string, string> artwork;
94 if (!db.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork)
95 || (artwork.size() == 1 && artwork.find("thumb") != artwork.end()))
97 CStdString art = CVideoInfoScanner::GetImage(item.get(), true, item->GetVideoInfoTag()->m_basePath != item->GetPath(), "thumb");
99 if (CacheTexture(art, cachedThumb, item->GetLabel(), type))
100 artwork.insert(make_pair(type, art));
102 art = CVideoInfoScanner::GetFanart(item.get(), true);
103 if (CacheTexture(art, cachedFanart, item->GetLabel()))
104 artwork.insert(make_pair("fanart", art));
107 artwork.insert(make_pair("thumb", ""));
108 db.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork);
114 db.GetMusicVideosNav("videodb://musicvideos/titles/", items, false);
115 for (int i = 0; i < items.Size(); i++)
117 CFileItemPtr item = items[i];
118 handle->SetProgress(i, items.Size());
119 handle->SetText(StringUtils::Format(g_localizeStrings.Get(12350).c_str(), item->GetLabel().c_str()));
120 string cachedThumb = GetCachedVideoThumb(*item);
121 string cachedFanart = GetCachedFanart(*item);
123 item->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
124 item->GetVideoInfoTag()->m_fanart.Unpack();
125 item->GetVideoInfoTag()->m_strPictureURL.Parse();
127 map<string, string> artwork;
128 if (!db.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork)
129 || (artwork.size() == 1 && artwork.find("thumb") != artwork.end()))
131 CStdString art = CVideoInfoScanner::GetImage(item.get(), true, item->GetVideoInfoTag()->m_basePath != item->GetPath(), "thumb");
133 if (CacheTexture(art, cachedThumb, item->GetLabel(), type))
134 artwork.insert(make_pair(type, art));
136 art = CVideoInfoScanner::GetFanart(item.get(), true);
137 if (CacheTexture(art, cachedFanart, item->GetLabel()))
138 artwork.insert(make_pair("fanart", art));
141 artwork.insert(make_pair("thumb", ""));
142 db.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork);
148 // count the number of episodes
149 db.GetTvShowsNav("videodb://tvshows/titles/", items);
150 for (int i = 0; i < items.Size(); i++)
152 CFileItemPtr item = items[i];
153 handle->SetText(StringUtils::Format(g_localizeStrings.Get(12350).c_str(), item->GetLabel().c_str()));
154 string cachedThumb = GetCachedVideoThumb(*item);
155 string cachedFanart = GetCachedFanart(*item);
157 item->SetPath(item->GetVideoInfoTag()->m_strPath);
158 item->GetVideoInfoTag()->m_fanart.Unpack();
159 item->GetVideoInfoTag()->m_strPictureURL.Parse();
161 map<string, string> artwork;
162 if (!db.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork)
163 || (artwork.size() == 1 && artwork.find("thumb") != artwork.end()))
165 CStdString art = CVideoInfoScanner::GetImage(item.get(), true, false, "thumb");
167 if (CacheTexture(art, cachedThumb, item->GetLabel(), type))
168 artwork.insert(make_pair(type, art));
170 art = CVideoInfoScanner::GetFanart(item.get(), true);
171 if (CacheTexture(art, cachedFanart, item->GetLabel()))
172 artwork.insert(make_pair("fanart", art));
175 artwork.insert(make_pair("thumb", ""));
176 db.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork);
180 map<int, map<string, string> > seasons;
181 vector<string> artTypes; artTypes.push_back("thumb");
182 CVideoInfoScanner::GetSeasonThumbs(*item->GetVideoInfoTag(), seasons, artTypes, true);
183 for (map<int, map<string, string> >::const_iterator j = seasons.begin(); j != seasons.end(); ++j)
185 if (j->second.empty())
187 int idSeason = db.AddSeason(item->GetVideoInfoTag()->m_iDbId, j->first);
188 map<string, string> seasonArt;
189 if (idSeason > -1 && !db.GetArtForItem(idSeason, "season", seasonArt))
191 std::string cachedSeason = GetCachedSeasonThumb(j->first, item->GetVideoInfoTag()->m_strPath);
193 std::string originalUrl = j->second.begin()->second;
194 if (CacheTexture(originalUrl, cachedSeason, "", type))
195 db.SetArtForItem(idSeason, "season", type, originalUrl);
200 CFileItemList items2;
201 db.GetEpisodesByWhere("videodb://tvshows/titles/-1/-1/", db.PrepareSQL("episodeview.idShow=%d", item->GetVideoInfoTag()->m_iDbId), items2);
202 for (int j = 0; j < items2.Size(); j++)
204 handle->SetProgress(j, items2.Size());
205 CFileItemPtr episode = items2[j];
206 string cachedThumb = GetCachedEpisodeThumb(*episode);
207 if (!CFile::Exists(cachedThumb))
208 cachedThumb = GetCachedVideoThumb(*episode);
209 episode->SetPath(episode->GetVideoInfoTag()->m_strFileNameAndPath);
210 episode->GetVideoInfoTag()->m_strPictureURL.Parse();
212 map<string, string> artwork;
213 if (!db.GetArtForItem(episode->GetVideoInfoTag()->m_iDbId, episode->GetVideoInfoTag()->m_type, artwork)
214 || (artwork.size() == 1 && artwork.find("thumb") != artwork.end()))
216 CStdString art = CVideoInfoScanner::GetImage(episode.get(), true, episode->GetVideoInfoTag()->m_basePath != episode->GetPath(), "thumb");
217 if (CacheTexture(art, cachedThumb, episode->GetLabel()))
218 artwork.insert(make_pair("thumb", art));
220 artwork.insert(make_pair("thumb", ""));
221 db.SetArtForItem(episode->GetVideoInfoTag()->m_iDbId, episode->GetVideoInfoTag()->m_type, artwork);
228 db.GetSetsNav("videodb://movies/sets/", items, VIDEODB_CONTENT_MOVIES);
229 for (int i = 0; i < items.Size(); i++)
231 CFileItemPtr item = items[i];
232 handle->SetProgress(i, items.Size());
233 handle->SetText(StringUtils::Format(g_localizeStrings.Get(12350).c_str(), item->GetLabel().c_str()));
234 map<string, string> artwork;
235 if (!db.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork))
236 { // grab the first movie from this set
237 CFileItemList items2;
238 db.GetMoviesNav("videodb://movies/titles/", items2, -1, -1, -1, -1, -1, -1, item->GetVideoInfoTag()->m_iDbId);
239 if (items2.Size() > 1)
241 if (db.GetArtForItem(items2[0]->GetVideoInfoTag()->m_iDbId, items2[0]->GetVideoInfoTag()->m_type, artwork))
242 db.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork);
249 if (CSettings::Get().GetBool("videolibrary.actorthumbs"))
251 db.GetActorsNav("videodb://movies/titles/", items, VIDEODB_CONTENT_MOVIES);
252 db.GetActorsNav("videodb://tvshows/titles/", items, VIDEODB_CONTENT_TVSHOWS);
253 db.GetActorsNav("videodb://tvshows/titles/", items, VIDEODB_CONTENT_EPISODES);
254 db.GetActorsNav("videodb://musicvideos/titles/", items, VIDEODB_CONTENT_MUSICVIDEOS);
255 for (int i = 0; i < items.Size(); i++)
257 CFileItemPtr item = items[i];
258 handle->SetProgress(i, items.Size());
259 handle->SetText(StringUtils::Format(g_localizeStrings.Get(12350).c_str(), item->GetLabel().c_str()));
260 map<string, string> artwork;
261 if (!db.GetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork))
263 item->GetVideoInfoTag()->m_strPictureURL.Parse();
264 string cachedThumb = GetCachedActorThumb(*item);
266 string art = CScraperUrl::GetThumbURL(item->GetVideoInfoTag()->m_strPictureURL.GetFirstThumb());
267 if (CacheTexture(art, cachedThumb, item->GetLabel()))
268 artwork.insert(make_pair("thumb", art));
270 artwork.insert(make_pair("thumb", ""));
271 db.SetArtForItem(item->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_type, artwork);
275 handle->MarkFinished();
277 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnScanFinished");
282 bool CEdenVideoArtUpdater::CacheTexture(std::string &originalUrl, const std::string &cachedFile, const std::string &label)
285 return CacheTexture(originalUrl, cachedFile, label, type);
288 bool CEdenVideoArtUpdater::CacheTexture(std::string &originalUrl, const std::string &cachedFile, const std::string &label, std::string &type)
290 if (!CFile::Exists(cachedFile))
292 CLog::Log(LOGERROR, "%s No cached art for item %s (should be %s)", __FUNCTION__, label.c_str(), cachedFile.c_str());
295 if (originalUrl.empty())
297 originalUrl = GetThumb(cachedFile, "http://unknown/video/", true);
298 CLog::Log(LOGERROR, "%s No original url for item %s, but cached art exists, using %s", __FUNCTION__, label.c_str(), originalUrl.c_str());
301 CTextureDetails details;
302 details.updateable = false;
303 details.hash = "NOHASH";
304 type = "thumb"; // unknown art type
306 CBaseTexture *texture = CTextureCacheJob::LoadImage(cachedFile, 0, 0, "");
309 if (texture->HasAlpha())
310 details.file = CTextureCache::GetCacheFile(originalUrl) + ".png";
312 details.file = CTextureCache::GetCacheFile(originalUrl) + ".jpg";
314 CLog::Log(LOGDEBUG, "Caching image '%s' ('%s') to '%s' for item '%s'", originalUrl.c_str(), cachedFile.c_str(), details.file.c_str(), label.c_str());
316 uint32_t width = 0, height = 0;
317 if (CPicture::CacheTexture(texture, width, height, CTextureCache::GetCachedPath(details.file)))
319 details.width = width;
320 details.height = height;
321 type = CVideoInfoScanner::GetArtTypeFromSize(details.width, details.height);
323 m_textureDB.AddCachedTexture(originalUrl, details);
327 CLog::Log(LOGERROR, "Can't cache image '%s' ('%s') for item '%s'", originalUrl.c_str(), cachedFile.c_str(), label.c_str());
331 CStdString CEdenVideoArtUpdater::GetCachedActorThumb(const CFileItem &item)
333 return GetThumb("actor" + item.GetLabel(), CProfilesManager::Get().GetVideoThumbFolder(), true);
336 CStdString CEdenVideoArtUpdater::GetCachedSeasonThumb(int season, const CStdString &path)
340 label = g_localizeStrings.Get(20366);
341 else if (season == 0)
342 label = g_localizeStrings.Get(20381);
344 label.Format(g_localizeStrings.Get(20358), season);
345 return GetThumb("season" + path + label, CProfilesManager::Get().GetVideoThumbFolder(), true);
348 CStdString CEdenVideoArtUpdater::GetCachedEpisodeThumb(const CFileItem &item)
350 // get the locally cached thumb
352 strCRC.Format("%sepisode%i", item.GetVideoInfoTag()->m_strFileNameAndPath.c_str(), item.GetVideoInfoTag()->m_iEpisode);
353 return GetThumb(strCRC, CProfilesManager::Get().GetVideoThumbFolder(), true);
356 CStdString CEdenVideoArtUpdater::GetCachedVideoThumb(const CFileItem &item)
358 if (item.m_bIsFolder && !item.GetVideoInfoTag()->m_strPath.IsEmpty())
359 return GetThumb(item.GetVideoInfoTag()->m_strPath, CProfilesManager::Get().GetVideoThumbFolder(), true);
360 else if (!item.GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
362 CStdString path = item.GetVideoInfoTag()->m_strFileNameAndPath;
363 if (URIUtils::IsStack(path))
364 path = CStackDirectory::GetFirstStackedFile(path);
365 return GetThumb(path, CProfilesManager::Get().GetVideoThumbFolder(), true);
367 return GetThumb(item.GetPath(), CProfilesManager::Get().GetVideoThumbFolder(), true);
370 CStdString CEdenVideoArtUpdater::GetCachedFanart(const CFileItem &item)
372 if (!item.GetVideoInfoTag()->m_artist.empty())
373 return GetThumb(StringUtils::Join(item.GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator), URIUtils::AddFileToFolder(CProfilesManager::Get().GetThumbnailsFolder(), "Music/Fanart/"), false);
374 CStdString path = item.GetVideoInfoTag()->GetPath();
377 return GetThumb(path, URIUtils::AddFileToFolder(CProfilesManager::Get().GetVideoThumbFolder(), "Fanart/"), false);
380 CStdString CEdenVideoArtUpdater::GetThumb(const CStdString &path, const CStdString &path2, bool split)
382 // get the locally cached thumb
384 crc.ComputeFromLowerCase(path);
390 hex.Format("%08x", (__int32)crc);
391 thumb.Format("%c\\%08x.tbn", hex[0], (unsigned __int32)crc);
394 thumb.Format("%08x.tbn", (unsigned __int32)crc);
396 return URIUtils::AddFileToFolder(path2, thumb);