36 #include <nsAutoLock.h>
39 #include <nsArrayUtils.h>
40 #include <nsUnicharUtils.h>
41 #include <nsComponentManagerUtils.h>
42 #include <nsServiceManagerUtils.h>
43 #include <nsCRTGlue.h>
45 #include <nsIFileURL.h>
46 #include <nsAutoPtr.h>
47 #include <nsThreadUtils.h>
49 #include <nsNetUtil.h>
50 #include <nsIClassInfoImpl.h>
51 #include <nsIProgrammingLanguage.h>
53 #include <nsIIOService.h>
54 #include <nsIPrefService.h>
55 #include <nsIPrefBranch2.h>
56 #include <nsIStringBundle.h>
58 #include <sbIFileMetadataService.h>
59 #include <sbILibrary.h>
60 #include <sbILibraryManager.h>
61 #include <sbILibraryResource.h>
62 #include <sbILibraryUtils.h>
63 #include <sbILocalDatabaseLibrary.h>
65 #include <sbILocalDatabaseMediaItem.h>
66 #include <sbIPropertyArray.h>
67 #include <sbIPropertyInfo.h>
68 #include <sbIPropertyManager.h>
69 #include <sbIMediaItem.h>
70 #include <sbIMediaList.h>
73 #include <sbIAlbumArtFetcherSet.h>
74 #include <sbIWatchFolderService.h>
80 #include "sbIMetadataManager.h"
81 #include "sbIMetadataHandler.h"
99 extern PRLogModuleInfo* gMetadataLog;
100 #define TRACE(args) PR_LOG(gMetadataLog, PR_LOG_DEBUG, args)
101 #define LOG(args) PR_LOG(gMetadataLog, PR_LOG_WARN, args)
103 #define __FUNCTION__ __PRETTY_FUNCTION__
132 mCompletedItemCount(0),
136 mRequiredProperties(nsnull),
137 mNextMainThreadIndex(0),
138 mNextBackgroundThreadIndex(0),
139 mBackgroundItemsLock(nsnull),
140 mProcessedBackgroundThreadItems(nsnull),
141 mProcessedBackgroundItemsLock(nsnull),
142 mInLibraryBatch(PR_FALSE),
143 mStringBundle(nsnull)
145 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
151 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
157 if (mBackgroundItemsLock) {
158 nsAutoLock::DestroyLock(mBackgroundItemsLock);
160 if (mProcessedBackgroundItemsLock) {
161 nsAutoLock::DestroyLock(mProcessedBackgroundItemsLock);
170 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
171 NS_ENSURE_ARG_POINTER(aMediaItemsArray);
172 NS_ASSERTION(NS_IsMainThread(), \
173 "sbMetadataJob::Init: MUST NOT INIT OFF OF MAIN THREAD!");
176 NS_ENSURE_FALSE(mBackgroundItemsLock, NS_ERROR_ALREADY_INITIALIZED);
177 mBackgroundItemsLock = nsAutoLock::NewLock(
178 "sbMetadataJob background item lock");
179 NS_ENSURE_TRUE(mBackgroundItemsLock, NS_ERROR_OUT_OF_MEMORY);
181 NS_ENSURE_FALSE(mProcessedBackgroundItemsLock, NS_ERROR_ALREADY_INITIALIZED);
182 mProcessedBackgroundItemsLock = nsAutoLock::NewLock(
183 "sbMetadataJob processed background items lock");
184 NS_ENSURE_TRUE(mProcessedBackgroundItemsLock, NS_ERROR_OUT_OF_MEMORY);
188 rv = aMediaItemsArray->GetLength(&length);
189 NS_ENSURE_SUCCESS(rv, rv);
190 NS_ENSURE_TRUE(length > 0, NS_ERROR_INVALID_ARG);
192 nsCOMPtr<sbIMediaItem> mediaItem =
193 do_QueryElementAt(aMediaItemsArray, 0, &rv);
194 NS_ENSURE_SUCCESS(rv, rv);
196 rv = mediaItem->GetLibrary(getter_AddRefs(mLibrary));
197 NS_ENSURE_SUCCESS(rv, rv);
203 NS_ENSURE_ARG_POINTER(aRequiredProperties);
207 rv = aRequiredProperties->HasMore(&hasMore);
208 NS_ENSURE_SUCCESS(rv, rv);
212 rv = aRequiredProperties->GetNext(propertyId);
213 NS_ENSURE_SUCCESS(rv, rv);
215 mRequiredProperties.AppendString(propertyId);
217 rv = aRequiredProperties->HasMore(&hasMore);
218 NS_ENSURE_SUCCESS(rv, rv);
222 PRBool enableRatingWrite = PR_FALSE;
223 PRBool enableArtworkWrite = PR_FALSE;
224 nsCOMPtr<nsIPrefBranch> prefService =
225 do_GetService(
"@mozilla.org/preferences-service;1", &rv);
226 NS_ENSURE_SUCCESS( rv, rv);
227 prefService->GetBoolPref(
"songbird.metadata.ratings.enableWriting",
229 prefService->GetBoolPref(
"songbird.metadata.artwork.enableWriting",
230 &enableArtworkWrite);
232 if (!enableRatingWrite) {
236 if (!enableArtworkWrite) {
243 NS_ENSURE_SUCCESS(rv, rv);
245 if (mBackgroundThreadJobItems.Length() > 0) {
255 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
256 NS_ENSURE_ARG_POINTER(aMediaItemsArray);
257 NS_ENSURE_STATE(mLibrary);
258 NS_ASSERTION(NS_IsMainThread(), \
259 "sbMetadataJob::AppendMediaItems is main thread only!");
263 return NS_ERROR_UNEXPECTED;
266 rv = aMediaItemsArray->GetLength(&length);
267 NS_ENSURE_SUCCESS(rv, rv);
268 NS_ENSURE_TRUE(length > 0, NS_ERROR_INVALID_ARG);
270 nsCOMPtr<sbIMediaItem> mediaItem;
276 for (PRUint32
i=0;
i < length;
i++) {
277 mediaItem = do_QueryElementAt(aMediaItemsArray,
i, &rv);
278 NS_ENSURE_SUCCESS(rv, rv);
280 nsCOMPtr<sbILibrary> library;
281 rv = mediaItem->GetLibrary(getter_AddRefs(library));
282 NS_ENSURE_SUCCESS(rv, rv);
285 rv = library->Equals(mLibrary, &equals);
286 NS_ENSURE_SUCCESS(rv, rv);
289 NS_ERROR(
"Not all items from the same library");
290 return NS_ERROR_INVALID_ARG;
297 PRBool shouldIgnorePaths = PR_FALSE;
298 nsCOMPtr<sbIWatchFolderService> wfService;
300 wfService = do_GetService(
"@songbirdnest.com/watch-folder-service;1", &rv);
301 if (NS_SUCCEEDED(rv) && wfService) {
302 rv = wfService->GetIsRunning(&shouldIgnorePaths);
303 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
304 "Could not determine if watchfolders is running!");
311 mTotalItemCount += length;
319 PRBool resizedMainThreadItems = PR_FALSE;
320 PRBool resizedBackgroundThreadItems = PR_FALSE;
322 for (PRUint32
i=0;
i < length;
i++) {
323 mediaItem = do_QueryElementAt(aMediaItemsArray,
i, &rv);
324 NS_ENSURE_SUCCESS(rv, rv);
329 if (shouldIgnorePaths) {
330 nsString mediaItemPath;
333 if (NS_SUCCEEDED(rv)) {
334 rv = wfService->AddIgnorePath(mediaItemPath);
335 if (NS_SUCCEEDED(rv)) {
336 mIgnoredContentPaths.insert(mediaItemPath);
339 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
340 "Could not add a watch folder ignore path!");
345 nsRefPtr<sbMetadataJobItem> jobItem =
347 NS_ENSURE_TRUE(jobItem, NS_ERROR_OUT_OF_MEMORY);
352 rv = SetUpHandlerForJobItem(jobItem);
356 HandleFailedItem(jobItem);
357 mCompletedItemCount++;
361 PRBool requiresMainThread = PR_TRUE;
362 nsCOMPtr<sbIMetadataHandler>
handler;
363 rv = jobItem->GetHandler(getter_AddRefs(handler));
364 NS_ENSURE_SUCCESS(rv, rv);
365 rv = handler->GetRequiresMainThread(&requiresMainThread);
366 NS_ASSERTION(NS_SUCCEEDED(rv), \
367 "sbMetadataJob::AppendMediaItems GetRequiresMainThread failed");
370 if (requiresMainThread) {
374 if (!resizedMainThreadItems) {
375 resizedMainThreadItems =
376 mMainThreadJobItems.SetCapacity(mTotalItemCount);
377 NS_ENSURE_TRUE(resizedMainThreadItems, NS_ERROR_OUT_OF_MEMORY);
380 mMainThreadJobItems.AppendElement(jobItem);
382 nsAutoLock lock(mBackgroundItemsLock);
386 if (!resizedBackgroundThreadItems) {
387 resizedBackgroundThreadItems =
388 mBackgroundThreadJobItems.SetCapacity(mTotalItemCount);
389 NS_ENSURE_TRUE(resizedBackgroundThreadItems, NS_ERROR_OUT_OF_MEMORY);
392 mBackgroundThreadJobItems.AppendElement(jobItem);
403 NS_ENSURE_ARG_POINTER(aJobItem);
407 PRBool resizedMainThreadItems = PR_FALSE;
408 PRBool resizedBackgroundThreadItems = PR_FALSE;
411 PRBool requiresMainThread = PR_TRUE;
412 nsCOMPtr<sbIMetadataHandler>
handler;
413 nsresult rv = aJobItem->
GetHandler(getter_AddRefs(handler));
414 NS_ENSURE_SUCCESS(rv, rv);
415 rv = handler->GetRequiresMainThread(&requiresMainThread);
416 NS_ASSERTION(NS_SUCCEEDED(rv), \
417 "sbMetadataJob::AppendJobItems GetRequiresMainThread failed");
420 if (requiresMainThread) {
423 if (!resizedMainThreadItems) {
424 resizedMainThreadItems =
425 mMainThreadJobItems.SetCapacity(mTotalItemCount);
426 NS_ENSURE_TRUE(resizedMainThreadItems, NS_ERROR_OUT_OF_MEMORY);
429 mMainThreadJobItems.AppendElement(aJobItem);
431 nsAutoLock lock(mBackgroundItemsLock);
435 if (!resizedBackgroundThreadItems) {
436 resizedBackgroundThreadItems =
437 mBackgroundThreadJobItems.SetCapacity(mTotalItemCount);
438 NS_ENSURE_TRUE(resizedBackgroundThreadItems, NS_ERROR_OUT_OF_MEMORY);
441 mBackgroundThreadJobItems.AppendElement(aJobItem);
452 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
453 NS_ENSURE_ARG_POINTER(aJobItem);
454 NS_ASSERTION(NS_IsMainThread(), \
455 "sbMetadataJob::SetUpHandlerForJobItem is main thread only!");
459 nsCOMPtr<sbIMediaItem> mediaItem;
461 NS_ENSURE_SUCCESS(rv, rv);
465 NS_ENSURE_SUCCESS(rv, rv);
467 rv = aJobItem->
SetURL(NS_ConvertUTF16toUTF8(stringURL));
468 NS_ENSURE_SUCCESS(rv, rv);
471 nsCOMPtr<sbIMetadataManager> metadataManager =
472 do_GetService(
"@songbirdnest.com/Songbird/MetadataManager;1", &rv);
473 NS_ENSURE_SUCCESS(rv, rv);
474 nsCOMPtr<sbIMetadataHandler>
handler;
475 rv = metadataManager->GetHandlerForMediaURL(stringURL,
476 getter_AddRefs(handler));
478 if (rv == NS_ERROR_UNEXPECTED) {
482 NS_ENSURE_SUCCESS(rv, rv);
483 if (stringURL.IsEmpty()) {
485 rv = NS_ERROR_UNEXPECTED;
490 if (StringBeginsWith(stringURL, NS_LITERAL_STRING(
"file://"))) {
492 rv = metadataManager->GetHandlerForMediaURL(stringURL,
493 getter_AddRefs(handler));
496 rv = NS_ERROR_UNEXPECTED;
502 LOG((
"Failed to find metadata handler\n"));
505 NS_ENSURE_SUCCESS(rv, rv);
509 NS_ENSURE_SUCCESS(rv, rv);
518 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
519 NS_ENSURE_ARG_POINTER(aJobItem);
524 TRACE((
"%s[%.8x]: not running", __FUNCTION__,
this));
525 return NS_ERROR_NOT_AVAILABLE;
528 nsRefPtr<sbMetadataJobItem> item = nsnull;
530 if (aMainThreadOnly) {
533 NS_ASSERTION(NS_IsMainThread(), \
534 "sbMetadataJob::GetQueuedItem: main thread item off main thread!");
536 if (mNextMainThreadIndex < mMainThreadJobItems.Length()) {
537 mMainThreadJobItems[mNextMainThreadIndex++].swap(item);
539 TRACE((
"%s[%.8x] - NOT_AVAILABLE (%i/%i)\n",
541 mNextMainThreadIndex, mMainThreadJobItems.Length()));
542 return NS_ERROR_NOT_AVAILABLE;
549 nsAutoLock lock(mBackgroundItemsLock);
551 if (mNextBackgroundThreadIndex < mBackgroundThreadJobItems.Length()) {
552 mBackgroundThreadJobItems[mNextBackgroundThreadIndex++].swap(item);
554 TRACE((
"%s[%.8x] - background NOT_AVAILABLE (%i/%i)\n",
556 mNextBackgroundThreadIndex, mBackgroundThreadJobItems.Length()));
557 return NS_ERROR_NOT_AVAILABLE;
560 NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
565 rv = PrepareWriteItem(item);
567 if (!NS_SUCCEEDED(rv)) {
568 NS_ERROR(
"sbMetadataJob::GetQueuedItem failed to prepare a "
569 "job item for writing.");
572 NS_ENSURE_SUCCESS(rv, rv);
575 TRACE((
"%s[%.8x]: got %.8x", __FUNCTION__,
this, item.get()));
576 item.forget(aJobItem);
583 NS_ENSURE_ARG_POINTER(aJobItem);
584 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
588 LOG((
"%s[%.8x] ignored. Job canceled\n", __FUNCTION__,
this));
594 if (NS_IsMainThread()) {
595 HandleProcessedItem(aJobItem);
598 DeferProcessedItemHandling(aJobItem);
606 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
607 NS_ENSURE_ARG_POINTER(aJobItem);
609 "sbMetadataJob::PrepareWriteItem called during a read job");
613 nsCOMPtr<sbIMutablePropertyArray> writeProps;
615 NS_ENSURE_SUCCESS(rv, rv);
617 nsCOMPtr<sbIMetadataHandler>
handler;
618 rv = aJobItem->
GetHandler(getter_AddRefs(handler));
619 NS_ENSURE_SUCCESS(rv, rv);
622 rv = handler->SetProps(writeProps);
623 NS_ENSURE_SUCCESS(rv, rv);
631 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
632 NS_ENSURE_ARG_POINTER(aJobItem);
633 NS_ASSERTION(NS_IsMainThread(), \
634 "sbMetadataJob::HandleProcessedItem is main thread only!");
637 mCompletedItemCount++;
642 PRBool willRetry = PR_FALSE;
643 rv = CopyPropertiesToMediaItem(aJobItem, &willRetry);
644 NS_ASSERTION(NS_SUCCEEDED(rv), \
645 "sbMetadataJob::HandleProcessedItem CopyPropertiesToMediaItem failed!");
654 PRBool processed = PR_FALSE;
657 rv = HandleFailedItem(aJobItem);
658 NS_ASSERTION(NS_SUCCEEDED(rv), \
659 "sbMetadataJob::HandleProcessedItem HandleFailedItem failed!");
662 rv = HandleWrittenItem(aJobItem);
666 nsCOMPtr<sbIMetadataHandler>
handler;
667 rv = aJobItem->
GetHandler(getter_AddRefs(handler));
668 NS_ENSURE_SUCCESS(rv, rv);
669 rv = handler->Close();
670 NS_ENSURE_SUCCESS(rv, rv);
676 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
679 nsCOMPtr<sbIMediaItem> item;
681 NS_ENSURE_SUCCESS(rv, rv);
683 nsCOMPtr<nsIURI> contentURI;
684 rv = item->GetContentSrc(getter_AddRefs(contentURI));
685 NS_ENSURE_SUCCESS(rv, rv);
688 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(contentURI, &rv);
692 nsCOMPtr<nsIFile>
file;
693 rv = fileURL->GetFile(getter_AddRefs(file));
694 NS_ENSURE_SUCCESS(rv, rv);
697 rv = file->GetFileSize(&fileSize);
698 NS_ENSURE_SUCCESS(rv, rv);
700 nsString strContentLength;
705 NS_ENSURE_SUCCESS(rv, rv);
712 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
713 NS_ENSURE_ARG_POINTER(aJobItem);
719 nsAutoLock lock(mProcessedBackgroundItemsLock);
726 LOG((
"%s[%.8x] - Job canceled\n", __FUNCTION__,
this));
731 if (!mProcessedBackgroundThreadItems) {
732 mProcessedBackgroundThreadItems =
733 new nsTArray<nsRefPtr<sbMetadataJobItem> >(
738 mProcessedBackgroundThreadItems->AppendElement(aJobItem);
747 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
748 NS_ENSURE_ARG_POINTER(aJobItem);
749 NS_ENSURE_ARG_POINTER(aWillRetry);
750 NS_ASSERTION(NS_IsMainThread(), \
751 "sbMetadataJob::CopyPropertiesToMediaItem is main thread only!");
755 nsCOMPtr<sbIMediaItem> item;
757 NS_ENSURE_SUCCESS(rv, rv);
760 nsCOMPtr<sbIMutablePropertyArray> newProps =
762 NS_ENSURE_SUCCESS(rv, rv);
766 nsAutoString oldName;
767 rv = item->GetProperty( trackNameKey, oldName );
768 nsAutoString trackName;
771 nsCOMPtr<sbIMetadataHandler>
handler;
772 rv = aJobItem->
GetHandler(getter_AddRefs(handler));
773 NS_ENSURE_SUCCESS(rv, rv);
775 nsCOMPtr<sbIMutablePropertyArray> props;
776 PRUint32 propsLength = 0;
777 rv = handler->GetProps(getter_AddRefs(props));
781 if (NS_SUCCEEDED(rv)) {
782 NS_ENSURE_TRUE(props, NS_ERROR_UNEXPECTED);
783 rv = props->GetLength(&propsLength);
784 NS_ENSURE_SUCCESS(rv, rv);
785 rv = props->GetPropertyValue( trackNameKey, trackName );
793 nsAutoString contentType;
794 rv = props->GetPropertyValue( contentTypeKey, contentType );
798 if (NS_FAILED(rv) || !contentType.EqualsLiteral(
"video")) {
799 rv = HandleFailedItem(aJobItem, PR_TRUE, aWillRetry);
800 NS_ENSURE_SUCCESS(rv, rv);
804 rv = HandleFailedItem(aJobItem, PR_TRUE, aWillRetry);
805 NS_ENSURE_SUCCESS(rv, rv);
809 if(*aWillRetry == PR_TRUE) {
814 nsCOMPtr<sbIPropertyManager> propMan =
816 NS_ENSURE_SUCCESS(rv, rv);
819 PRBool defaultTrackname = trackName.IsEmpty() && !oldName.IsEmpty();
822 if ( trackName.IsEmpty() && oldName.IsEmpty() ) {
823 rv = CreateDefaultItemName(item, trackName);
824 NS_ENSURE_SUCCESS(rv, rv);
826 if ( !trackName.IsEmpty() ) {
827 rv = AppendToPropertiesIfValid( propMan, newProps, trackNameKey, trackName );
828 NS_ENSURE_SUCCESS(rv, rv);
829 defaultTrackname = PR_TRUE;
834 for (PRUint32
i = 0;
i < propsLength && NS_SUCCEEDED(rv);
i++) {
835 nsCOMPtr<sbIProperty> prop;
836 rv = props->GetPropertyAt(
i, getter_AddRefs(prop) );
841 if (!defaultTrackname || !
id.Equals(trackNameKey)) {
842 prop->GetValue( value );
843 if (!value.IsEmpty() && !value.IsVoid() && !value.EqualsLiteral(
" ")) {
844 AppendToPropertiesIfValid( propMan, newProps,
id, value );
849 PRBool isLocalFile = PR_FALSE;
851 PRInt64 fileSize = 0;
852 rv = GetFileSize(item, &fileSize);
853 if (NS_SUCCEEDED(rv)) {
856 rv = AppendToPropertiesIfValid(propMan,
860 NS_ENSURE_SUCCESS(rv, rv);
862 isLocalFile = PR_TRUE;
865 rv = item->SetProperties(newProps);
866 NS_ENSURE_SUCCESS(rv, rv);
872 rv = ReadAlbumArtwork(aJobItem);
873 NS_ASSERTION(NS_SUCCEEDED(rv),
874 "Metadata job failed to run album art fetcher");
889 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
895 NS_IMETHODIMP sbMetadataJob::OnTrackResult(nsIURI* aImageLocation,
898 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
900 NS_ENSURE_ARG_POINTER(aMediaItem);
902 if (aImageLocation) {
904 nsCAutoString imageFileURISpec;
905 rv = aImageLocation->GetSpec(imageFileURISpec);
906 if (NS_SUCCEEDED(rv)) {
907 rv = aMediaItem->SetProperty(
909 NS_ConvertUTF8toUTF16(imageFileURISpec));
910 NS_ENSURE_SUCCESS(rv, rv);
918 NS_IMETHODIMP sbMetadataJob::OnAlbumResult(nsIURI* aImageLocation,
919 nsIArray* aMediaItems)
921 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
927 NS_IMETHODIMP sbMetadataJob::OnSearchComplete(nsIArray* aMediaItems)
929 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
937 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
938 NS_ENSURE_ARG_POINTER(aJobItem);
943 do_CreateInstance(
"@songbirdnest.com/Songbird/album-art-fetcher-set;1", &rv);
944 NS_ENSURE_SUCCESS(rv, rv);
946 NS_ENSURE_SUCCESS(rv, rv);
950 nsCOMPtr<nsIMutableArray> sources =
951 do_CreateInstance(
"@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
952 NS_ENSURE_SUCCESS(rv, rv);
953 nsCOMPtr<sbIMetadataHandler>
handler;
954 rv = aJobItem->
GetHandler(getter_AddRefs(handler));
955 NS_ENSURE_SUCCESS(rv, rv);
956 rv = sources->AppendElement(handler, PR_FALSE);
957 NS_ENSURE_SUCCESS(rv, rv);
958 rv = mArtFetcher->SetAlbumArtSourceList(sources);
959 NS_ENSURE_SUCCESS(rv, rv);
962 nsCOMPtr<sbIMediaItem> item;
964 NS_ENSURE_SUCCESS(rv, rv);
965 rv = mArtFetcher->FetchAlbumArtForTrack(item,
this);
966 NS_ENSURE_SUCCESS(rv, rv);
968 TRACE((
"%s[%.8x] - finished rv %08x\n", __FUNCTION__,
this, rv));
975 PRBool aShouldRetry ,
978 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
979 NS_ENSURE_ARG_POINTER(aJobItem);
980 NS_ASSERTION(NS_IsMainThread(), \
981 "sbMetadataJob::HandleFailedItem is main thread only!");
985 if (aShouldRetry && aWillRetry)
987 TRACE((
"%s[%.8x] - Attempting to retry job item.", __FUNCTION__,
this));
988 *aWillRetry = PR_FALSE;
991 nsCOMPtr<sbIMetadataHandler> previousHandler;
992 rv = aJobItem->
GetHandler(getter_AddRefs(previousHandler));
996 while (NS_SUCCEEDED(rv)) {
997 nsCOMPtr<sbIMetadataManager> metadataManager =
998 do_GetService(
"@songbirdnest.com/Songbird/MetadataManager;1", &rv);
1003 nsCString stringURL;
1004 rv = aJobItem->
GetURL(stringURL);
1005 if (NS_FAILED(rv)) {
1009 NS_ConvertUTF8toUTF16 unicodeURL(stringURL);
1010 nsCOMPtr<sbIMetadataHandler>
handler;
1011 rv = metadataManager->GetNextHandlerForMediaURL(previousHandler,
1013 getter_AddRefs(handler));
1014 if(NS_FAILED(rv) || !handler) {
1027 if (NS_SUCCEEDED(rv)) {
1028 *aWillRetry = PR_TRUE;
1034 nsCOMPtr<sbIFileMetadataService> fileMetadataService =
1035 do_GetService(
"@songbirdnest.com/Songbird/FileMetadataService;1", &rv);
1036 if (NS_FAILED(rv)) {
1040 rv = fileMetadataService->RestartProcessors(
1044 if (NS_FAILED(rv)) {
1048 rv = previousHandler->Close();
1049 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to clean up handler!");
1051 TRACE((
"%s[%.8x] Retrying job item %s",
1052 __FUNCTION__,
this, stringURL.BeginReading()));
1060 nsCAutoString escapedURI, unescapedURI;
1061 rv = aJobItem->
GetURL(escapedURI);
1062 NS_ENSURE_SUCCESS(rv, rv);
1065 nsCOMPtr<nsINetUtil> netUtil =
1066 do_GetService(
"@mozilla.org/network/util;1", &rv);
1067 NS_ENSURE_SUCCESS(rv, rv);
1068 rv = netUtil->UnescapeString(escapedURI,
1069 nsINetUtil::ESCAPE_ALL,
1071 NS_ENSURE_SUCCESS(rv, rv);
1072 nsString stringURL = NS_ConvertUTF8toUTF16(unescapedURI);
1078 mErrorMessages.AppendElement(stringURL);
1084 PRInt32 slash = stringURL.RFind(NS_LITERAL_STRING(
"/"));
1085 if (slash > 0 && slash < (PRInt32)(stringURL.Length() - 1)) {
1086 stringURL = nsDependentSubstring(stringURL, slash + 1,
1087 stringURL.Length() - slash - 1);
1090 nsCOMPtr<sbIMediaItem> item;
1092 NS_ENSURE_SUCCESS(rv, rv);
1095 NS_ENSURE_SUCCESS(rv, rv);
1102 nsresult sbMetadataJob::BatchCompleteItems()
1104 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1105 NS_ASSERTION(NS_IsMainThread(), \
1106 "sbMetadataJob::BatchCompleteItems is main thread only!");
1107 nsresult rv =
NS_OK;
1110 PRBool needBatchComplete = PR_FALSE;
1112 nsAutoLock processedLock(mProcessedBackgroundItemsLock);
1113 if (mProcessedBackgroundThreadItems) {
1117 if (mProcessedBackgroundThreadItems->Length() >
1120 needBatchComplete = PR_TRUE;
1127 nsAutoLock waitingLock(mBackgroundItemsLock);
1128 if (mNextBackgroundThreadIndex > (mBackgroundThreadJobItems.Length() - 1) &&
1129 mProcessedBackgroundThreadItems->Length() > 0)
1131 needBatchComplete = PR_TRUE;
1137 if (needBatchComplete) {
1139 nsCOMPtr<sbIMediaListBatchCallback> batchCallback =
1141 NS_ENSURE_TRUE(batchCallback, NS_ERROR_OUT_OF_MEMORY);
1144 if (mInLibraryBatch) {
1145 rv = BatchCompleteItemsCallback();
1148 rv = mLibrary->RunInBatchMode(batchCallback, static_cast<sbIJobProgress*>(
this));
1151 NS_ENSURE_SUCCESS(rv, rv);
1157 nsresult sbMetadataJob::RunLibraryBatch(
nsISupports* aUserData)
1159 TRACE((
"%s [static]", __FUNCTION__));
1160 NS_ENSURE_ARG_POINTER(aUserData);
1163 return thisJob->BatchCompleteItemsCallback();
1166 nsresult sbMetadataJob::BatchCompleteItemsCallback()
1168 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1169 nsresult rv =
NS_OK;
1177 nsAutoPtr<nsTArray<nsRefPtr<sbMetadataJobItem> > > items;
1180 nsAutoLock lock(mProcessedBackgroundItemsLock);
1181 NS_ENSURE_STATE(mProcessedBackgroundThreadItems);
1183 items = mProcessedBackgroundThreadItems.forget();
1186 mProcessedBackgroundThreadItems =
1187 new nsTArray<nsRefPtr<sbMetadataJobItem> >(
1192 for (PRUint32
i = 0;
i < items->Length();
i++) {
1193 HandleProcessedItem((*items)[
i]);
1199 nsresult sbMetadataJob::BeginLibraryBatch()
1201 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1202 NS_ENSURE_STATE(mLibrary);
1203 NS_ASSERTION(NS_IsMainThread(), \
1204 "sbMetadataJob::BeginLibraryBatch is main thread only!");
1205 nsresult rv =
NS_OK;
1207 if (mInLibraryBatch) {
1215 nsCOMPtr<sbILocalDatabaseLibrary> localLibrary =
1216 do_QueryInterface(mLibrary, &rv);
1217 NS_ENSURE_SUCCESS(rv,rv);
1219 localLibrary->ForceBeginUpdateBatch();
1220 mInLibraryBatch = PR_TRUE;
1225 nsresult sbMetadataJob::EndLibraryBatch()
1227 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1228 NS_ENSURE_STATE(mLibrary);
1229 NS_ASSERTION(NS_IsMainThread(), \
1230 "sbMetadataJob::EndLibraryBatch is main thread only!");
1231 nsresult rv =
NS_OK;
1233 if (!mInLibraryBatch) {
1238 nsCOMPtr<sbILocalDatabaseLibrary> localLibrary =
1239 do_QueryInterface(mLibrary, &rv);
1240 NS_ENSURE_SUCCESS(rv,rv);
1242 localLibrary->ForceEndUpdateBatch();
1243 mInLibraryBatch = PR_FALSE;
1251 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1252 NS_ASSERTION(NS_IsMainThread(), \
1253 "sbMetadataJob::OnJobProgress is main thread only!");
1254 nsresult rv =
NS_OK;
1257 BatchCompleteItems();
1260 if (mCompletedItemCount == mTotalItemCount) {
1261 mStatus = (mErrorMessages.Length() == 0) ?
1267 for (PRInt32
i = mListeners.Count() - 1;
i >= 0; --
i) {
1268 mListeners[
i]->OnJobProgress(
this);
1279 if (mIgnoredContentPaths.size() > 0) {
1280 nsCOMPtr<sbIWatchFolderService> wfService =
1281 do_GetService(
"@songbirdnest.com/watch-folder-service;1", &rv);
1282 NS_ASSERTION(NS_SUCCEEDED(rv),
1283 "Could not get the watch folder service!");
1284 if (NS_SUCCEEDED(rv) && wfService) {
1288 for (next = begin; next != end; ++
next) {
1289 rv = wfService->RemoveIgnorePath(*next);
1290 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
1291 "Could not remove a ignored watch folder path!");
1295 mIgnoredContentPaths.clear();
1300 rv = mLibrary->Flush();
1301 NS_ASSERTION(NS_SUCCEEDED(rv),
1302 "sbMetadataJob::OnJobProgress failed to flush library!");
1312 rv = mLibrary->Optimize(PR_TRUE);
1313 NS_ASSERTION(NS_SUCCEEDED(rv),
1314 "sbMetadataJob::onJobProgress failed to optimize library!");
1322 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1323 NS_ENSURE_ARG_POINTER( aJobType );
1324 *aJobType = mJobType;
1330 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1332 nsresult rv = NS_ERROR_UNEXPECTED;
1336 PRBool wasBlocked = mBlocked;
1338 mBlocked = aBlocked;
1347 if(wasBlocked && !aBlocked) {
1348 rv = BeginLibraryBatch();
1349 NS_ENSURE_SUCCESS(rv, rv);
1353 else if(!wasBlocked && aBlocked) {
1354 rv = EndLibraryBatch();
1355 NS_ENSURE_SUCCESS(rv, rv);
1368 NS_IMETHODIMP sbMetadataJob::GetStatus(PRUint16* aStatus)
1370 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1371 NS_ENSURE_ARG_POINTER( aStatus );
1377 NS_IMETHODIMP sbMetadataJob::GetBlocked(PRBool* aBlocked)
1379 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1380 NS_ENSURE_ARG_POINTER( aBlocked );
1381 *aBlocked = mBlocked;
1386 NS_IMETHODIMP sbMetadataJob::GetStatusText(nsAString& aText)
1388 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1389 NS_ASSERTION(NS_IsMainThread(), \
1390 "sbMetadataJob::GetStatusText is main thread only!");
1391 nsresult rv =
NS_OK;
1397 nsCOMPtr<sbIMediaItem> mediaItem;
1400 if (mNextMainThreadIndex < mMainThreadJobItems.Length()) {
1401 rv = mMainThreadJobItems[mNextMainThreadIndex]->GetMediaItem(
1402 getter_AddRefs(mediaItem));
1403 NS_ENSURE_SUCCESS(rv, rv);
1408 nsAutoLock lock(mBackgroundItemsLock);
1409 if (mNextBackgroundThreadIndex < mBackgroundThreadJobItems.Length()) {
1410 rv = mBackgroundThreadJobItems[mNextBackgroundThreadIndex]->
1411 GetMediaItem(getter_AddRefs(mediaItem));
1412 NS_ENSURE_SUCCESS(rv, rv);
1418 CreateDefaultItemName(mediaItem, aText);
1420 aText = mStatusText;
1430 const char* textKey;
1433 if (mTotalItemCount == 1) {
1434 textKey =
"metadatajob.writing.failed.one";
1436 }
else if (mErrorMessages.Length() == 1) {
1437 textKey =
"metadatajob.writing.failed.oneofmany";
1440 textKey =
"metadatajob.writing.failed.manyofmany";
1447 rv = LocalizeString(
1448 NS_LITERAL_STRING(
"media_scan.complete"),
1452 mStatusText = aText;
1457 NS_IMETHODIMP sbMetadataJob::GetTitleText(nsAString& aText)
1459 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1464 if (mTitleText.IsEmpty()) {
1465 TRACE((
"sbMetadataJob::GetTitleText[0x%.8x] localizing string",
this));
1467 rv = LocalizeString(NS_LITERAL_STRING(
"metadatajob.writing.title"),
1469 if (NS_FAILED(rv)) {
1470 mTitleText.AssignLiteral(
"Metadata Write Job");
1473 rv = LocalizeString(NS_LITERAL_STRING(
"metadatajob.reading.title"),
1475 if (NS_FAILED(rv)) {
1476 mTitleText.AssignLiteral(
"Metadata Read Job");
1486 NS_IMETHODIMP sbMetadataJob::GetProgress(PRUint32* aProgress)
1488 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1489 NS_ENSURE_ARG_POINTER( aProgress );
1490 NS_ASSERTION(NS_IsMainThread(), \
1491 "sbMetadataJob::GetProgress is main thread only!");
1493 *aProgress = mNextBackgroundThreadIndex + mNextMainThreadIndex;
1498 NS_IMETHODIMP sbMetadataJob::GetTotal(PRUint32* aTotal)
1500 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1501 NS_ENSURE_ARG_POINTER( aTotal );
1502 NS_ASSERTION(NS_IsMainThread(), \
1503 "sbMetadataJob::GetTotal is main thread only!");
1505 *aTotal = mTotalItemCount;
1510 NS_IMETHODIMP sbMetadataJob::GetErrorCount(PRUint32*
aCount)
1512 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1513 NS_ENSURE_ARG_POINTER( aCount );
1514 NS_ASSERTION(NS_IsMainThread(), \
1515 "sbMetadataJob::GetErrorCount is main thread only!");
1519 *aCount = mErrorMessages.Length();
1526 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1527 NS_ENSURE_ARG_POINTER(aMessages);
1528 NS_ASSERTION(NS_IsMainThread(), \
1529 "sbMetadataJob::GetProgress is main thread only!");
1531 *aMessages = nsnull;
1535 nsCOMPtr<nsIStringEnumerator> enumerator =
1537 NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
1539 enumerator.forget(aMessages);
1547 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1548 NS_ENSURE_ARG_POINTER(aListener);
1549 NS_ASSERTION(NS_IsMainThread(), \
1550 "sbMetadataJob::AddJobProgressListener is main thread only!");
1552 PRInt32 index = mListeners.IndexOf(aListener);
1555 return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
1557 PRBool
succeeded = mListeners.AppendObject(aListener);
1558 return succeeded ?
NS_OK : NS_ERROR_FAILURE;
1565 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1566 NS_ENSURE_ARG_POINTER(aListener);
1567 NS_ASSERTION(NS_IsMainThread(), \
1568 "sbMetadataJob::RemoveJobProgressListener is main thread only!");
1570 PRInt32 indexToRemove = mListeners.IndexOf(aListener);
1571 if (indexToRemove < 0) {
1573 return NS_ERROR_UNEXPECTED;
1577 PRBool succeeded = mListeners.RemoveObjectAt(indexToRemove);
1578 NS_ENSURE_TRUE(succeeded, NS_ERROR_FAILURE);
1588 NS_IMETHODIMP sbMetadataJob::GetCrop(nsAString & aCrop)
1590 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1591 aCrop.AssignLiteral(
"center");
1600 NS_IMETHODIMP sbMetadataJob::GetCanCancel(PRBool* _retval)
1602 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1608 NS_IMETHODIMP sbMetadataJob::Cancel()
1610 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1611 NS_ASSERTION(NS_IsMainThread(), \
1612 "sbMetadataJob::Cancel is main thread only!");
1621 mMainThreadJobItems.Clear();
1622 mNextMainThreadIndex = 0;
1627 nsAutoLock processedLock(mProcessedBackgroundItemsLock);
1628 nsAutoLock waitingLock(mBackgroundItemsLock);
1636 mBackgroundThreadJobItems.Clear();
1637 mNextBackgroundThreadIndex = 0;
1641 if (mProcessedBackgroundThreadItems) {
1642 mProcessedBackgroundThreadItems->Clear();
1659 nsresult sbMetadataJob::CreateDefaultItemName(
sbIMediaItem* aItem,
1662 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1663 NS_ASSERTION(NS_IsMainThread(),
1664 "sbMetadataJob::CreateDefaultItemName is main thread only!");
1665 NS_ENSURE_ARG_POINTER(aItem);
1669 nsCOMPtr<nsIURI>
uri;
1670 rv = aItem->GetContentSrc(getter_AddRefs(uri));
1671 NS_ENSURE_SUCCESS(rv, rv);
1673 nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri, &rv);
1675 if (NS_SUCCEEDED(rv) && fileUrl) {
1676 nsCOMPtr<nsIFile> sourceFile, canonicalFile;
1677 rv = fileUrl->GetFile(getter_AddRefs(sourceFile));
1678 NS_ENSURE_SUCCESS(rv, rv);
1680 nsCOMPtr<sbILibraryUtils> libraryUtils =
1681 do_GetService(
"@songbirdnest.com/Songbird/library/Manager;1", &rv);
1682 NS_ENSURE_SUCCESS(rv, rv);
1684 rv = libraryUtils->GetCanonicalPath(sourceFile,
1685 getter_AddRefs(canonicalFile));
1686 NS_ENSURE_SUCCESS(rv, rv);
1688 rv = canonicalFile->GetLeafName(filename);
1689 NS_ENSURE_SUCCESS(rv, rv);
1692 nsCOMPtr<nsIURL>
url = do_QueryInterface(uri, &rv);
1693 NS_ENSURE_SUCCESS(rv, rv);
1696 nsCAutoString escapedURI, unescapedURI;
1697 rv = url->GetFileName(escapedURI);
1698 NS_ENSURE_SUCCESS(rv, rv);
1701 nsCOMPtr<nsINetUtil> netUtil =
1702 do_GetService(
"@mozilla.org/network/util;1", &rv);
1703 NS_ENSURE_SUCCESS(rv, rv);
1704 rv = netUtil->UnescapeString(escapedURI,
1705 nsINetUtil::ESCAPE_ALL,
1707 NS_ENSURE_SUCCESS(rv, rv);
1709 filename = NS_ConvertUTF8toUTF16(unescapedURI);
1712 PRInt32 dot = filename.RFind(NS_LITERAL_STRING(
"."));
1713 if (dot > 0 && dot < (PRInt32)(filename.Length() - 1)) {
1714 retval = nsDependentSubstring(filename, 0, dot);
1727 const nsAString& aID,
1730 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1731 NS_ASSERTION(aPropertyManager,
"aPropertyManager is null");
1732 NS_ASSERTION(aProperties,
"aProperties is null");
1734 nsCOMPtr<sbIPropertyInfo> info;
1735 nsresult rv = aPropertyManager->GetPropertyInfo(aID, getter_AddRefs(info));
1736 NS_ENSURE_SUCCESS(rv, rv);
1738 PRBool isValid = PR_FALSE;
1739 rv = info->Validate(aValue, &isValid);
1740 NS_ENSURE_SUCCESS(rv, rv);
1743 rv = aProperties->AppendProperty(aID, aValue);
1744 NS_ENSURE_SUCCESS(rv, rv);
1752 sbMetadataJob::GetFileSize(
sbIMediaItem* aMediaItem, PRInt64* aFileSize)
1754 TRACE((
"%s[%.8x]", __FUNCTION__,
this));
1755 NS_ENSURE_ARG_POINTER(aMediaItem);
1756 NS_ENSURE_ARG_POINTER(aFileSize);
1757 NS_ASSERTION(NS_IsMainThread(),
"GetFileSize is main thread only!");
1760 nsCOMPtr<nsIURI>
uri;
1761 rv = aMediaItem->GetContentSrc(getter_AddRefs(uri));
1762 NS_ENSURE_SUCCESS(rv, rv);
1765 nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri, &rv);
1766 if (rv == NS_ERROR_NO_INTERFACE) {
1771 NS_ENSURE_SUCCESS(rv, rv);
1773 nsCOMPtr<nsIFile>
file;
1774 rv = fileUrl->GetFile(getter_AddRefs(file));
1775 NS_ENSURE_SUCCESS(rv, rv);
1777 return file->GetFileSize(aFileSize);;
1782 sbMetadataJob::LocalizeString(
const nsAString&
aName, nsAString& aValue)
1784 TRACE((
"%s[%.8x] (%s)", __FUNCTION__,
this,
1785 NS_LossyConvertUTF16toASCII(aName).
get()));
1786 nsresult rv =
NS_OK;
1788 if (!mStringBundle) {
1789 nsCOMPtr<nsIStringBundleService> StringBundleService =
1790 do_GetService(
"@mozilla.org/intl/stringbundle;1", &rv );
1791 NS_ENSURE_SUCCESS(rv, rv);
1793 rv = StringBundleService->CreateBundle(
1794 "chrome://songbird/locale/songbird.properties",
1795 getter_AddRefs(mStringBundle));
1796 NS_ENSURE_SUCCESS(rv, rv);
1798 nsString
name(aName);
1800 rv = mStringBundle->GetStringFromName(
name.get(),
1801 getter_Copies(value));
1802 if (NS_FAILED(rv)) {
1803 NS_ERROR(
"sbMetadataJob::LocalizeString failed to find a string");
Interface to control UI aspects of sbIJobProgress.
#define SB_PROPERTY_ORIGINURL
function succeeded(ch, cx, status, data)
Generic interface for exposing long running jobs to the UI.
nsString Get(const nsAString &aKey, const nsAString &aDefault=SBVoidString())
#define SB_PROPERTY_RATING
const unsigned short STATUS_SUCCEEDED
Constant indicating that the job has completed.
#define SB_PROPERTYMANAGER_CONTRACTID
#define SB_PROPERTY_CONTENTLENGTH
const unsigned short STATUS_RUNNING
Constant indicating that the job is active.
An interface to carry around arrays of nsIProperty instances Note that implementations of the interfa...
const unsigned long TYPE_LOCAL
A component which is interested in the result of an album art fetch request.
#define SB_PROPERTY_CONTENTTYPE
BogusChannel prototype contentLength
Songbird String Bundle Definitions.
sbStringSet::iterator sbStringSetIter
StringArrayEnumerator prototype hasMore
Implemented to receive notifications from sbIJobProgress interfaces.
#define SB_PROPERTY_TRACKNAME
restoreHistoryPrecursor aCount
Interface for an album art fetcher. Instantiate as a component instance.
#define SB_PROPERTY_CONTENTURL
const unsigned short STATUS_FAILED
Constant indicating that the job has completed with errors.
_getSelectedPageStyle s i
#define SB_PROPERTY_PRIMARYIMAGEURL
Manager for system wide metadata properties.