sbFileAlbumArtFetcher.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2010 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
27 //------------------------------------------------------------------------------
28 //------------------------------------------------------------------------------
29 //
30 // Songbird local file album art fetcher.
31 //
32 //------------------------------------------------------------------------------
33 //------------------------------------------------------------------------------
34 
40 //------------------------------------------------------------------------------
41 //
42 // Songbird local file album art fetcher imported services.
43 //
44 //------------------------------------------------------------------------------
45 
46 // Self imports.
47 #include "sbFileAlbumArtFetcher.h"
48 
49 // Songbird imports.
50 #include <sbIAlbumArtListener.h>
51 #include <sbIMediaItem.h>
53 #include <sbStandardProperties.h>
54 #include <sbStringBundle.h>
55 #include <sbStringUtils.h>
56 
57 // Mozilla imports.
58 #include <nsIFile.h>
59 #include <nsIFileURL.h>
60 #include <nsIIOService.h>
61 #include <nsMemory.h>
62 #include <nsServiceManagerUtils.h>
63 #include <nsUnicharUtils.h>
64 #include <nsIMutableArray.h>
65 
66 //------------------------------------------------------------------------------
67 //
68 // nsISupports implementation.
69 //
70 //------------------------------------------------------------------------------
71 
73 
74 
75 //------------------------------------------------------------------------------
76 //
77 // sbIAlbumArtFetcher implementation.
78 //
79 //------------------------------------------------------------------------------
80 
81 /* \brief try to fetch album art for the given list of media items
82  * \param aMediaItems the media item that we're looking for album art for
83  * \param aListener the listener to inform of success or failure
84  */
85 
86 NS_IMETHODIMP
87 sbFileAlbumArtFetcher::FetchAlbumArtForAlbum(nsIArray* aMediaItems,
88  sbIAlbumArtListener* aListener)
89 {
90  // Validate arguments.
91  NS_ENSURE_ARG_POINTER(aMediaItems);
92 
93  // Function variables.
94  nsresult rv;
95  nsCOMPtr<nsIFile> albumArtFile;
96  nsCOMPtr<nsIURI> albumArtURI;
97 
98  // Get the first item to search for artwork
99  // We assume that all the items for this album are in the same folder and have
100  // a cover image file.
101  nsCOMPtr<sbIMediaItem> firstMediaItem;
102  rv = aMediaItems->QueryElementAt(0,
103  NS_GET_IID(sbIMediaItem),
104  getter_AddRefs(firstMediaItem));
105  NS_ENSURE_SUCCESS(rv, rv);
106 
107  // Search the media item content source directory entries for an
108  // album art file.
109  rv = FindAlbumArtFile(firstMediaItem,
110  getter_AddRefs(albumArtFile));
111  NS_ENSURE_SUCCESS(rv, rv);
112 
113  // Indicate if an album art file was found or not.
114  if (albumArtFile) {
115  // Create an album art file URI.
116  rv = mIOService->NewFileURI(albumArtFile, getter_AddRefs(albumArtURI));
117  NS_ENSURE_SUCCESS(rv, rv);
118  }
119 
120  if (aListener) {
121  aListener->OnAlbumResult(albumArtURI, aMediaItems);
122  aListener->OnSearchComplete(aMediaItems);
123  }
124 
125  return NS_OK;
126 }
127 
128 NS_IMETHODIMP
129 sbFileAlbumArtFetcher::FetchAlbumArtForTrack(sbIMediaItem* aMediaItem,
130  sbIAlbumArtListener* aListener)
131 {
132  // Validate arguments.
133  NS_ENSURE_ARG_POINTER(aMediaItem);
134 
135  // Function variables.
136  nsresult rv;
137  nsCOMPtr<nsIFile> albumArtFile;
138  nsCOMPtr<nsIURI> albumArtURI;
139 
140  // Search the media item content source directory entries for an
141  // album art file.
142  rv = FindAlbumArtFile(aMediaItem,
143  getter_AddRefs(albumArtFile));
144  NS_ENSURE_SUCCESS(rv, rv);
145 
146  // Indicate if an album art file was found or not.
147  if (albumArtFile) {
148  // Create an album art file URI.
149  rv = mIOService->NewFileURI(albumArtFile, getter_AddRefs(albumArtURI));
150  NS_ENSURE_SUCCESS(rv, rv);
151  }
152 
153  if (aListener) {
154  aListener->OnTrackResult(albumArtURI, aMediaItem);
155  // We need to wrap this item in an array since the OnSearchComplete
156  // expects it.
157  nsCOMPtr<nsIMutableArray> items =
158  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
159  NS_ENSURE_SUCCESS(rv, rv);
160  rv = items->AppendElement(NS_ISUPPORTS_CAST(sbIMediaItem*, aMediaItem),
161  PR_FALSE);
162  NS_ENSURE_SUCCESS(rv, rv);
163  aListener->OnSearchComplete(items);
164  }
165 
166  return NS_OK;
167 }
168 
169 /* \brief shut down the fetcher
170  */
171 
172 NS_IMETHODIMP
173 sbFileAlbumArtFetcher::Shutdown()
174 {
175  return NS_OK;
176 }
177 
178 
179 //
180 // Getters/setters.
181 //
182 
187 NS_IMETHODIMP
188 sbFileAlbumArtFetcher::GetShortName(nsAString& aShortName)
189 {
190  aShortName.AssignLiteral("file");
191  return NS_OK;
192 }
193 
194 
201 NS_IMETHODIMP
202 sbFileAlbumArtFetcher::GetName(nsAString& aName)
203 {
204  sbStringBundle stringBundle;
205  aName.Assign(stringBundle.Get("songbird.albumart.file.name"));
206  return NS_OK;
207 }
208 
209 
215 NS_IMETHODIMP
216 sbFileAlbumArtFetcher::GetDescription(nsAString& aDescription)
217 {
218  sbStringBundle stringBundle;
219  aDescription.Assign(stringBundle.Get("songbird.albumart.file.description"));
220  return NS_OK;
221 }
222 
223 
228 NS_IMETHODIMP
229 sbFileAlbumArtFetcher::GetIsLocal(PRBool* aIsLocal)
230 {
231  NS_ENSURE_ARG_POINTER(aIsLocal);
232  *aIsLocal = PR_TRUE;
233  return NS_OK;
234 }
235 
240 NS_IMETHODIMP
241 sbFileAlbumArtFetcher::GetIsEnabled(PRBool* aIsEnabled)
242 {
243  NS_ENSURE_ARG_POINTER(aIsEnabled);
244  NS_ENSURE_STATE(mPrefService);
245 
246  nsresult rv = mPrefService->GetBoolPref("songbird.albumart.file.enabled",
247  aIsEnabled);
248  if (NS_FAILED(rv)) {
249  *aIsEnabled = PR_FALSE;
250  }
251 
252  return NS_OK;
253 }
254 
255 NS_IMETHODIMP
256 sbFileAlbumArtFetcher::SetIsEnabled(PRBool aIsEnabled)
257 {
258  NS_ENSURE_STATE(mPrefService);
259  return mPrefService->SetBoolPref("songbird.albumart.file.enabled",
260  aIsEnabled);
261 }
262 
267 NS_IMETHODIMP
268 sbFileAlbumArtFetcher::GetPriority(PRInt32* aPriority)
269 {
270  NS_ENSURE_ARG_POINTER(aPriority);
271  NS_ENSURE_STATE(mPrefService);
272 
273  nsresult rv = mPrefService->GetIntPref("songbird.albumart.file.priority",
274  aPriority);
275  if (NS_FAILED(rv)) {
276  // Default to appending
277  *aPriority = -1;
278  }
279 
280  return NS_OK;
281 }
282 
283 NS_IMETHODIMP
284 sbFileAlbumArtFetcher::SetPriority(PRInt32 aPriority)
285 {
286  NS_ENSURE_STATE(mPrefService);
287  return mPrefService->SetIntPref("songbird.albumart.file.priority",
288  aPriority);
289 }
290 
295 NS_IMETHODIMP
296 sbFileAlbumArtFetcher::GetAlbumArtSourceList(nsIArray** aAlbumArtSourceList)
297 {
298  NS_ENSURE_ARG_POINTER(aAlbumArtSourceList);
299  NS_ADDREF(*aAlbumArtSourceList = mAlbumArtSourceList);
300  return NS_OK;
301 }
302 
303 NS_IMETHODIMP
304 sbFileAlbumArtFetcher::SetAlbumArtSourceList(nsIArray* aAlbumArtSourceList)
305 {
306  mAlbumArtSourceList = aAlbumArtSourceList;
307  return NS_OK;
308 }
309 
314 NS_IMETHODIMP
315 sbFileAlbumArtFetcher::GetIsFetching(PRBool* aIsFetching)
316 {
317  NS_ENSURE_ARG_POINTER(aIsFetching);
318  // This fetcher operates synchronously, so indicate that it's not fetching.
319  *aIsFetching = PR_FALSE;
320  return NS_OK;
321 }
322 
323 
324 //------------------------------------------------------------------------------
325 //
326 // Public services.
327 //
328 //------------------------------------------------------------------------------
329 
335 {
336 }
337 
338 
344 {
345 }
346 
347 
352 nsresult
354 {
355  nsresult rv;
356 
357  // Get the I/O service
358  mIOService = do_GetService("@mozilla.org/network/io-service;1", &rv);
359  NS_ENSURE_SUCCESS(rv, rv);
360 
361  // Get the preference branch.
362  mPrefService = do_GetService("@mozilla.org/preferences-service;1", &rv);
363  NS_ENSURE_SUCCESS(rv, rv);
364 
365  // Read the album art file extension list.
366  nsCString fileExtensions;
367  rv = mPrefService->GetCharPref("songbird.albumart.file.extensions",
368  getter_Copies(fileExtensions));
369  NS_ENSURE_SUCCESS(rv, rv);
370  nsString_Split(NS_ConvertUTF8toUTF16(fileExtensions),
371  NS_LITERAL_STRING(","),
372  mFileExtensionList);
373 
374  // Read the album art file base name list.
375  nsCString fileBaseNames;
376  rv = mPrefService->GetCharPref("songbird.albumart.file.base_names",
377  getter_Copies(fileBaseNames));
378  NS_ENSURE_SUCCESS(rv, rv);
379  nsString_Split(NS_ConvertUTF8toUTF16(fileBaseNames),
380  NS_LITERAL_STRING(","),
381  mFileBaseNameList);
382 
383  // Get the album art service.
384  mAlbumArtService = do_GetService(SB_ALBUMARTSERVICE_CONTRACTID, &rv);
385  NS_ENSURE_SUCCESS(rv, rv);
386 
387  return NS_OK;
388 }
389 
390 
391 //------------------------------------------------------------------------------
392 //
393 // Internal services.
394 //
395 //------------------------------------------------------------------------------
396 
410 nsresult
411 sbFileAlbumArtFetcher::GetURLDirEntries
412  (nsIURL* aURL,
413  PRBool* aIsLocalFile,
414  nsISimpleEnumerator** contentSrcDirEntries)
415 {
416  // Validate arguments.
417  NS_ENSURE_ARG_POINTER(aURL);
418  NS_ENSURE_ARG_POINTER(aIsLocalFile);
419  NS_ENSURE_ARG_POINTER(contentSrcDirEntries);
420 
421  // Function variables.
422  nsresult rv;
423 
424  // Get the media item content source local file URL. Do nothing more if not a
425  // local file.
426  nsCOMPtr<nsIFileURL> contentSrcFileURL = do_QueryInterface(aURL,
427  &rv);
428  if (NS_FAILED(rv)) {
429  *aIsLocalFile = PR_FALSE;
430  return NS_OK;
431  }
432 
433  // Get the media item content source directory.
434  nsCOMPtr<nsIFile> contentSrcFile;
435  rv = contentSrcFileURL->GetFile(getter_AddRefs(contentSrcFile));
436  NS_ENSURE_SUCCESS(rv, rv);
437  nsCOMPtr<nsIFile> contentSrcDir;
438  rv = contentSrcFile->GetParent(getter_AddRefs(contentSrcDir));
439  NS_ENSURE_SUCCESS(rv, rv);
440 
441  // Get the media item content source directory entries.
442  rv = contentSrcDir->GetDirectoryEntries(contentSrcDirEntries);
443  NS_ENSURE_SUCCESS(rv, rv);
444 
445  // Return results.
446  *aIsLocalFile = PR_TRUE;
447 
448  return NS_OK;
449 }
450 
451 
459 nsresult
460 sbFileAlbumArtFetcher::FindAlbumArtFile(sbIMediaItem* aMediaItem,
461  nsIFile** aAlbumArtFile)
462 {
463  // Validate arguments.
464  NS_ENSURE_ARG_POINTER(aMediaItem);
465  NS_ENSURE_ARG_POINTER(aAlbumArtFile);
466 
467  // Function variables.
468  nsresult rv;
469  nsCOMPtr<nsISimpleEnumerator> contentSrcDirEntries;
470  nsCOMPtr<nsIMutableArray> entriesToBeCached = nsnull;
471 
472  // Set default result.
473  *aAlbumArtFile = nsnull;
474 
475  // Get the max file size preference
476  PRInt32 maxFileSize;
477  rv = mPrefService->GetIntPref("songbird.albumart.maxsize", &maxFileSize);
478  NS_ENSURE_SUCCESS(rv, rv);
479 
480  // Figure out what album we're looking for
481  nsString artistName;
482  nsString albumName;
483  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ARTISTNAME),
484  artistName);
485  NS_ENSURE_SUCCESS(rv, rv);
486  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
487  albumName);
488  NS_ENSURE_SUCCESS(rv, rv);
489  nsString artistAlbum(artistName);
490  artistAlbum.AppendLiteral(" - ");
491  artistAlbum.Append(albumName);
492 
493  // Before doing anything else, check to see if we've
494  // recently cached a value for the given artist/album
495  nsString cacheKeyFile = NS_LITERAL_STRING("File:");
496  cacheKeyFile.Append(artistAlbum);
497  nsCOMPtr<nsISupports> cacheData = nsnull;
498  rv = mAlbumArtService->RetrieveTemporaryData(cacheKeyFile,
499  getter_AddRefs(cacheData));
500 
501  // Try to get the file from the cache data
502  if (NS_SUCCEEDED(rv)) {
503  nsCOMPtr<nsIFile> file = do_QueryInterface(cacheData, &rv);
504  if (NS_SUCCEEDED(rv)) {
505  // Ensure the size of the file is less than the max file size preference
506  PRInt64 fileSize;
507  rv = file->GetFileSize(&fileSize);
508  NS_ENSURE_SUCCESS(rv, rv);
509 
510  if (fileSize <= maxFileSize) {
511  // We got a cached file for this so return the result
512  file.forget(aAlbumArtFile);
513  return NS_OK;
514  }
515  }
516  }
517 
518  // Get the media item content source
519  nsCOMPtr<nsIURI> contentSrcURI;
520  rv = aMediaItem->GetContentSrc(getter_AddRefs(contentSrcURI));
521  NS_ENSURE_SUCCESS(rv, rv);
522  nsCOMPtr<nsIURL> contentSrcURL = do_QueryInterface(contentSrcURI, &rv);
523  NS_ENSURE_SUCCESS(rv, rv);
524 
525  // First check to see if we have a cached list of all the images
526  // in this directory (useful in the edge case of 10000 tracks
527  // from different albums, all in the same directory)
528  nsCString directory;
529  contentSrcURL->GetDirectory(directory);
530  nsString cacheKeyDir = NS_LITERAL_STRING("Directory:");
531  cacheKeyDir.Append(NS_ConvertUTF8toUTF16(directory));
532  rv = mAlbumArtService->RetrieveTemporaryData(cacheKeyDir,
533  getter_AddRefs(cacheData));
534 
535  // Try to get the entries from the cache data
536  if (NS_SUCCEEDED(rv)) {
537  nsCOMPtr<nsIArray> cachedEntries = do_QueryInterface(cacheData, &rv);
538  NS_ENSURE_SUCCESS(rv, rv);
539  rv = cachedEntries->Enumerate(getter_AddRefs(contentSrcDirEntries));
540  NS_ENSURE_SUCCESS(rv, rv);
541 
542  } else {
543 
544  // Get the media item content source directory entries.
545  PRBool isLocalFile = PR_FALSE;
546  rv = GetURLDirEntries(contentSrcURL,
547  &isLocalFile,
548  getter_AddRefs(contentSrcDirEntries));
549  NS_ENSURE_SUCCESS(rv, rv);
550  if (!isLocalFile) {
551  return NS_OK;
552  }
553 
554  // Create an array to cache the image entries we find
555  entriesToBeCached =
556  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
557  NS_ENSURE_SUCCESS(rv, rv);
558  }
559 
560  // Search the media item content source directory entries for an album art
561  // file.
562  while (!(*aAlbumArtFile) && entriesToBeCached) {
563  // Get the next directory entry.
564  PRBool hasMoreElements;
565  rv = contentSrcDirEntries->HasMoreElements(&hasMoreElements);
566  NS_ENSURE_SUCCESS(rv, rv);
567  if (!hasMoreElements)
568  break;
569  nsCOMPtr<nsIFile> file;
570  rv = contentSrcDirEntries->GetNext(getter_AddRefs(file));
571  NS_ENSURE_SUCCESS(rv, rv);
572 
573  // Skip file if it's not a regular file (e.g., a directory).
574  PRBool isFile;
575  rv = file->IsFile(&isFile);
576  NS_ENSURE_SUCCESS(rv, rv);
577  if (!isFile)
578  continue;
579 
580  // Get the file leaf name in lower case.
581  nsString leafName;
582  rv = file->GetLeafName(leafName);
583  NS_ENSURE_SUCCESS(rv, rv);
584  ToLowerCase(leafName);
585 
586  // Get the file extension. Skip file if it has no extension.
587  PRInt32 fileExtensionIndex = leafName.RFind(NS_LITERAL_STRING("."));
588  if (fileExtensionIndex < 0)
589  continue;
590 
591  // Check if file extension matches any album art file extension. Skip file
592  // if it doesn't.
593  nsDependentSubstring fileExtension(leafName, fileExtensionIndex + 1);
594  PRBool fileExtensionMatched = PR_FALSE;
595  for (PRUint32 i = 0; i < mFileExtensionList.Length(); i++) {
596  if (fileExtension.Equals(mFileExtensionList[i])) {
597  fileExtensionMatched = PR_TRUE;
598  break;
599  }
600  }
601  if (!fileExtensionMatched)
602  continue;
603 
604  // Ensure the size of the file is less than the max file size preference
605  PRInt64 fileSize;
606  rv = file->GetFileSize(&fileSize);
607  NS_ENSURE_SUCCESS(rv, rv);
608  if (fileSize > maxFileSize)
609  continue;
610 
611  // This is an image file. If we are building
612  // a new cache list, add it now
613  if (entriesToBeCached) {
614  entriesToBeCached->AppendElement(file, PR_FALSE);
615  }
616 
617  // Check if file name matches any album art file name. File is an
618  // album art file if it does.
619  nsDependentSubstring fileBaseName(leafName, 0, fileExtensionIndex);
620  // Loop backwards, since album specific images should
621  // take precedence over "cover.jpg" etc.
622  for (PRInt32 i = (mFileBaseNameList.Length() - 1); i >= 0; i--) {
623  if (fileBaseName.Equals(mFileBaseNameList[i])) {
624  if (!(*aAlbumArtFile)) {
625  file.forget(aAlbumArtFile);
626  }
627  }
628  }
629  }
630 
631  // If needed, cache the list of images in this folder
632  if (entriesToBeCached) {
633  rv = mAlbumArtService->CacheTemporaryData(cacheKeyDir, entriesToBeCached);
634  NS_ENSURE_SUCCESS(rv, rv);
635  }
636 
637  // Now save the file in the cache if we found one.
638  if (*aAlbumArtFile) {
639  rv = mAlbumArtService->CacheTemporaryData(cacheKeyFile, *aAlbumArtFile);
640  }
641 
642  return NS_OK;
643 }
return NS_OK
#define SB_ALBUMARTSERVICE_CONTRACTID
nsString Get(const nsAString &aKey, const nsAString &aDefault=SBVoidString())
NS_DECL_ISUPPORTS NS_DECL_SBIALBUMARTFETCHER sbFileAlbumArtFetcher()
NS_IMPL_THREADSAFE_ISUPPORTS1(sbDeviceCapsCompatibility, sbIDeviceCapsCompatibility) sbDeviceCapsCompatibility
A component which is interested in the result of an album art fetch request.
void nsString_Split(const nsAString &aString, const nsAString &aDelimiter, nsTArray< nsString > &aSubStringArray)
#define SB_PROPERTY_ARTISTNAME
Songbird String Bundle Definitions.
SimpleArrayEnumerator prototype hasMoreElements
_updateCookies aName
#define SB_PROPERTY_ALBUMNAME
Interface that defines a single item of media in the system.
Interface for an album art fetcher. Instantiate as a component instance.
_getSelectedPageStyle s i
Songbird Local File Album Art Fetcher Definitions.
var file