Merge pull request #4406 from jmarshallnz/thumb_fixes
[vuplus_xbmc] / xbmc / music / MusicThumbLoader.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "MusicThumbLoader.h"
22 #include "FileItem.h"
23 #include "TextureDatabase.h"
24 #include "music/tags/MusicInfoTag.h"
25 #include "music/tags/MusicInfoTagLoaderFactory.h"
26 #include "music/infoscanner/MusicInfoScanner.h"
27 #include "music/Artist.h"
28 #include "video/VideoThumbLoader.h"
29
30 using namespace std;
31 using namespace MUSIC_INFO;
32
33 CMusicThumbLoader::CMusicThumbLoader() : CThumbLoader()
34 {
35   m_musicDatabase = new CMusicDatabase;
36 }
37
38 CMusicThumbLoader::~CMusicThumbLoader()
39 {
40   delete m_musicDatabase;
41 }
42
43 void CMusicThumbLoader::OnLoaderStart()
44 {
45   m_musicDatabase->Open();
46   m_albumArt.clear();
47   CThumbLoader::OnLoaderStart();
48 }
49
50 void CMusicThumbLoader::OnLoaderFinish()
51 {
52   m_musicDatabase->Close();
53   m_albumArt.clear();
54   CThumbLoader::OnLoaderFinish();
55 }
56
57 bool CMusicThumbLoader::LoadItem(CFileItem* pItem)
58 {
59   bool result  = LoadItemCached(pItem);
60        result |= LoadItemLookup(pItem);
61
62   return result;
63 }
64
65 bool CMusicThumbLoader::LoadItemCached(CFileItem* pItem)
66 {
67   if (pItem->m_bIsShareOrDrive)
68     return false;
69
70   if (pItem->HasMusicInfoTag() && pItem->GetArt().empty())
71   {
72     if (FillLibraryArt(*pItem))
73       return true;
74       
75     if (pItem->GetMusicInfoTag()->GetType() == "artist")
76       return false; // No fallback
77   }
78
79   if (pItem->HasVideoInfoTag() && pItem->GetArt().empty())
80   { // music video
81     CVideoThumbLoader loader;
82     if (loader.LoadItemCached(pItem))
83       return true;
84   }
85
86   if (!pItem->HasArt("thumb"))
87   {
88     std::string art = GetCachedImage(*pItem, "thumb");
89     if (!art.empty())
90       pItem->SetArt("thumb", art);
91   }
92
93   if (!pItem->HasArt("fanart"))
94   {
95     std::string art = GetCachedImage(*pItem, "fanart");
96     if (!art.empty())
97     {
98       pItem->SetArt("fanart", art);
99     }
100     else if (pItem->HasMusicInfoTag() && !pItem->GetMusicInfoTag()->GetArtist().empty())
101     {
102       std::string artist = pItem->GetMusicInfoTag()->GetArtist()[0];
103       m_musicDatabase->Open();
104       int idArtist = m_musicDatabase->GetArtistByName(artist);
105       if (idArtist >= 0)
106       {
107         string fanart = m_musicDatabase->GetArtForItem(idArtist, "artist", "fanart");
108         if (!fanart.empty())
109         {
110           pItem->SetArt("artist.fanart", fanart);
111           pItem->SetArtFallback("fanart", "artist.fanart");
112         }
113         else if (!pItem->GetMusicInfoTag()->GetAlbumArtist().empty() &&
114                  pItem->GetMusicInfoTag()->GetAlbumArtist()[0] != artist)
115         {
116           // If no artist fanart and the album artist is different to the artist,
117           // try to get fanart from the album artist
118           artist = pItem->GetMusicInfoTag()->GetAlbumArtist()[0];
119           idArtist = m_musicDatabase->GetArtistByName(artist);
120           if (idArtist >= 0)
121           {
122             fanart = m_musicDatabase->GetArtForItem(idArtist, "artist", "fanart");
123             if (!fanart.empty())
124             {
125               pItem->SetArt("albumartist.fanart", fanart);
126               pItem->SetArtFallback("fanart", "albumartist.fanart");
127             }
128           }
129         }
130       }
131       m_musicDatabase->Close();
132     }
133   }
134
135   return false;
136 }
137
138 bool CMusicThumbLoader::LoadItemLookup(CFileItem* pItem)
139 {
140   if (pItem->m_bIsShareOrDrive)
141     return false;
142
143   if (pItem->HasMusicInfoTag() && pItem->GetMusicInfoTag()->GetType() == "artist") // No fallback for artist
144     return false;
145
146   if (pItem->HasVideoInfoTag())
147   { // music video
148     CVideoThumbLoader loader;
149     if (loader.LoadItemLookup(pItem))
150       return true;
151   }
152
153   if (!pItem->HasArt("thumb"))
154   {
155     // Look for embedded art
156     if (pItem->HasMusicInfoTag() && !pItem->GetMusicInfoTag()->GetCoverArtInfo().empty())
157     {
158       // The item has got embedded art but user thumbs overrule, so check for those first
159       if (!FillThumb(*pItem, false)) // Check for user thumbs but ignore folder thumbs
160       {
161         // No user thumb, use embedded art
162         CStdString thumb = CTextureUtils::GetWrappedImageURL(pItem->GetPath(), "music");
163         pItem->SetArt("thumb", thumb);
164       }
165     }
166     else
167     {
168       // Check for user thumbs
169       FillThumb(*pItem, true);
170     }
171   }
172
173   return true;
174 }
175
176 bool CMusicThumbLoader::FillThumb(CFileItem &item, bool folderThumbs /* = true */)
177 {
178   if (item.HasArt("thumb"))
179     return true;
180   CStdString thumb = GetCachedImage(item, "thumb");
181   if (thumb.empty())
182   {
183     thumb = item.GetUserMusicThumb(false, folderThumbs);
184     if (!thumb.empty())
185       SetCachedImage(item, "thumb", thumb);
186   }
187   if (!thumb.empty())
188     item.SetArt("thumb", thumb);
189   return !thumb.empty();
190 }
191
192 bool CMusicThumbLoader::FillLibraryArt(CFileItem &item)
193 {
194   CMusicInfoTag &tag = *item.GetMusicInfoTag();
195   if (tag.GetDatabaseId() > -1 && !tag.GetType().empty())
196   {
197     m_musicDatabase->Open();
198     map<string, string> artwork;
199     if (m_musicDatabase->GetArtForItem(tag.GetDatabaseId(), tag.GetType(), artwork))
200       item.SetArt(artwork);
201     else if (tag.GetType() == "song")
202     { // no art for the song, try the album
203       ArtCache::const_iterator i = m_albumArt.find(tag.GetAlbumId());
204       if (i == m_albumArt.end())
205       {
206         m_musicDatabase->GetArtForItem(tag.GetAlbumId(), "album", artwork);
207         i = m_albumArt.insert(make_pair(tag.GetAlbumId(), artwork)).first;
208       }
209       if (i != m_albumArt.end())
210       {
211         item.AppendArt(i->second, "album");
212         for (map<string, string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j)
213           item.SetArtFallback(j->first, "album." + j->first);
214       }
215     }
216     if (tag.GetType() == "song" || tag.GetType() == "album")
217     { // fanart from the artist
218       string fanart = m_musicDatabase->GetArtistArtForItem(tag.GetDatabaseId(), tag.GetType(), "fanart");
219       if (!fanart.empty())
220       {
221         item.SetArt("artist.fanart", fanart);
222         item.SetArtFallback("fanart", "artist.fanart");
223       }
224       else if (tag.GetType() == "song")
225       {
226         // If no artist fanart, try for album artist fanart
227         fanart = m_musicDatabase->GetArtistArtForItem(tag.GetAlbumId(), "album", "fanart");
228         if (!fanart.empty())
229         {
230           item.SetArt("albumartist.fanart", fanart);
231           item.SetArtFallback("fanart", "albumartist.fanart");
232         }
233       }
234     }
235     m_musicDatabase->Close();
236   }
237   return !item.GetArt().empty();
238 }
239
240 bool CMusicThumbLoader::GetEmbeddedThumb(const std::string &path, EmbeddedArt &art)
241 {
242   auto_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(path));
243   CMusicInfoTag tag;
244   if (NULL != pLoader.get())
245     pLoader->Load(path, tag, &art);
246
247   return !art.empty();
248 }