33 #include <nsAppDirectoryServiceDefs.h>
34 #include <nsArrayUtils.h>
35 #include <nsAutoPtr.h>
36 #include <nsCOMArray.h>
37 #include <nsComponentManagerUtils.h>
38 #include <nsDirectoryServiceUtils.h>
39 #include <nsXPCOMCIDInternal.h>
41 #include <nsIBufferedStreams.h>
43 #include <nsIFileURL.h>
44 #include <nsIInputStream.h>
45 #include <nsIIOService.h>
46 #include <nsILineInputStream.h>
47 #include <nsILocalFile.h>
48 #include <nsIProperties.h>
49 #include <nsISimpleEnumerator.h>
51 #include <nsIXULRuntime.h>
53 #include <nsNetUtil.h>
54 #include <nsThreadUtils.h>
60 #include <sbIAlbumArtFetcherSet.h>
61 #include <sbIAlbumArtListener.h>
62 #include <sbFileUtils.h>
63 #include <sbILibrary.h>
64 #include <sbILocalDatabaseLibrary.h>
65 #include <sbIMediaList.h>
66 #include <sbIPropertyArray.h>
68 #include <sbIMediacoreTypeSniffer.h>
73 #ifdef SB_ENABLE_TEST_HARNESS
74 #include <sbITimingService.h>
85 static PRLogModuleInfo* giTunesImporter = nsnull;
88 if (!giTunesImporter) \
89 giTunesImporter = PR_NewLogModule("sbiTunesImporter"); \
90 PR_LOG(giTunesImporter, PR_LOG_DEBUG, args); \
94 if (!giTunesImporter) \
95 giTunesImporter = PR_NewLogModule("sbiTunesImporter"); \
96 PR_LOG(giTunesImporter, PR_LOG_WARN, args); \
123 if (aRating.IsEmpty()) {
126 PRInt32
rating = aRating.ToInteger(&rv, 10);
128 if (NS_SUCCEEDED(rv)) {
129 result.AppendInt((rating + 10) / 20, 10);
145 if (aDuration.IsEmpty()) {
148 PRInt32
const duration = aDuration.ToInteger(&rv, 10);
150 if (NS_SUCCEEDED(rv)) {
151 result.AppendInt(duration * 1000);
167 if (aDateTime.IsEmpty()) {
175 nsCAutoString dateTime = ::NS_LossyConvertUTF16toASCII(aDateTime);
176 nsTArray<nsCString> splitString;
178 NS_ENSURE_TRUE(splitString.Length() > 0, nsString());
179 dateTime = splitString[0];
183 NS_ENSURE_TRUE(splitString.Length() > 1, nsString());
184 nsCAutoString dateString = splitString[0];
185 nsCAutoString timeString = splitString[1];
189 NS_ENSURE_TRUE(splitString.Length() > 2, nsString());
190 nsCAutoString yearString = splitString[0];
191 nsCAutoString monthString = splitString[1];
192 nsCAutoString dayString = splitString[2];
197 PR_snprintf(cDateTime,
207 PRStatus status = PR_ParseTimeString(cDateTime, PR_TRUE, &prTime);
210 if (status == PR_FAILURE) {
211 NS_WARNING(
"Failed to parse time in sbiTunesImporter ConvertDateTime");
216 prTime /= PR_USEC_PER_MSEC;
259 mDataFormatVersion(DATA_FORMAT_VERSION),
260 mFoundChanges(PR_FALSE),
261 mImportPlaylists(PR_TRUE),
262 mMissingMediaCount(0),
263 mOSType(UNINITIALIZED),
265 mUnsupportedMediaCount(0)
268 mTrackBatch.reserve(BATCH_SIZE);
271 sbiTunesImporter::~sbiTunesImporter()
278 sbiTunesImporter::Cancel() {
280 mStatus->SetStatusText(msg);
288 sbiTunesImporter::GetLibraryType(nsAString & aLibraryType)
290 aLibraryType = NS_LITERAL_STRING(
"iTunes");
296 sbiTunesImporter::GetLibraryReadableType(nsAString & aLibraryReadableType)
298 aLibraryReadableType = NS_LITERAL_STRING(
"iTunes");
304 sbiTunesImporter::GetLibraryDefaultFileName(nsAString & aLibraryDefaultFileName)
306 aLibraryDefaultFileName = NS_LITERAL_STRING(
"iTunes Music Library.xml");
312 sbiTunesImporter::GetLibraryDefaultFilePath(nsAString & aLibraryDefaultFilePath)
315 nsCOMPtr<nsIProperties> directoryService =
316 do_CreateInstance(
"@mozilla.org/file/directory_service;1", &rv);
317 NS_ENSURE_SUCCESS(rv, rv);
319 nsCOMPtr<nsIFile> libraryFile;
321 nsString defaultLibraryName;
322 rv = GetLibraryDefaultFileName(defaultLibraryName);
323 NS_ENSURE_SUCCESS(rv, rv);
329 rv = directoryService->Get(
"Music",
331 getter_AddRefs(libraryFile));
332 NS_ENSURE_SUCCESS(rv, rv);
334 rv = libraryFile->Append(NS_LITERAL_STRING(
"iTunes"));
335 NS_ENSURE_SUCCESS(rv, rv);
339 rv = directoryService->Get(
"Music",
341 getter_AddRefs(libraryFile));
344 rv = directoryService->Get(
"Pers",
346 getter_AddRefs(libraryFile));
347 NS_ENSURE_SUCCESS(rv, rv);
349 rv = libraryFile->Append(NS_LITERAL_STRING(
"My Music"));
350 NS_ENSURE_SUCCESS(rv, rv);
353 rv = libraryFile->Append(NS_LITERAL_STRING(
"iTunes"));
354 NS_ENSURE_SUCCESS(rv, rv);
362 rv = directoryService->Get(
"Home",
364 getter_AddRefs(libraryFile));
365 NS_ENSURE_SUCCESS(rv, rv);
370 rv = libraryFile->Append(defaultLibraryName);
371 NS_ENSURE_SUCCESS(rv, rv);
374 PRBool exists = PR_FALSE;
375 rv = libraryFile->Exists(&exists);
376 NS_ENSURE_SUCCESS(rv, rv);
380 rv = libraryFile->GetPath(path);
381 NS_ENSURE_SUCCESS(rv, rv);
383 aLibraryDefaultFilePath =
path;
392 sbiTunesImporter::GetLibraryFileExtensionList(
393 nsAString & aLibraryFileExtensionList)
395 aLibraryFileExtensionList = NS_LITERAL_STRING(
"xml");
401 sbiTunesImporter::GetLibraryPreviouslyImported(
402 PRBool *aLibraryPreviouslyImported)
406 NS_ENSURE_SUCCESS(rv, rv);
408 nsCString
const & temp =
prefs.GetCharPref(
"lib_prev_mod_time", nsCString());
409 *aLibraryPreviouslyImported = temp.IsEmpty() ? PR_FALSE : PR_TRUE;
415 sbiTunesImporter::GetLibraryPreviousImportPath(
416 nsAString & aLibraryPreviousImportPath)
420 NS_ENSURE_SUCCESS(rv, rv);
422 aLibraryPreviousImportPath =
423 ::NS_ConvertUTF8toUTF16(
prefs.GetCharPref(
"lib_prev_path",
430 sbiTunesImporter::Initialize()
433 NS_ENSURE_SUCCESS(rv, rv);
436 do_CreateInstance(
"@mozilla.org/network/io-service;1", &rv);
437 NS_ENSURE_SUCCESS(rv, rv);
440 do_CreateInstance(
"@songbirdnest.com/Songbird/album-art-fetcher-set;1", &rv);
441 NS_ENSURE_SUCCESS(rv, rv);
444 mBatchEnded = PR_FALSE;
445 mFoundChanges = PR_FALSE;
446 mUnsupportedMediaCount = 0;
447 mMissingMediaCount = 0;
450 NS_ENSURE_SUCCESS(rv, rv);
452 mLDBLibrary = do_QueryInterface(mLibrary, &rv);
453 NS_ENSURE_SUCCESS(rv, rv);
455 #ifdef SB_ENABLE_TEST_HARNESS
457 mTimingService = do_GetService(
"@songbirdnest.com/Songbird/TimingService;1", &rv);
461 NS_ENSURE_SUCCESS(rv, rv);
465 nsCOMPtr<nsIFile> resultsFile;
466 rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
467 getter_AddRefs(resultsFile));
468 NS_ENSURE_SUCCESS(rv, rv);
469 rv = resultsFile->Append(NS_LITERAL_STRING(
"itunesexportresults.txt"));
470 NS_ENSURE_SUCCESS(rv, rv);
473 rv = resultsFile->Exists(&success);
474 NS_ENSURE_SUCCESS(rv, rv);
481 nsCOMPtr<nsIInputStream> inputStream;
482 rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), resultsFile);
483 NS_ENSURE_SUCCESS(rv, rv);
484 nsCOMPtr<nsILineInputStream> lineStream = do_QueryInterface(inputStream, &rv);
485 NS_ENSURE_SUCCESS(rv, rv);
489 rv = lineStream->ReadLine(line, &success);
490 NS_ENSURE_SUCCESS(rv, rv);
492 if (StringBeginsWith(line, NS_LITERAL_CSTRING(
"["))) {
500 const int LEN_GUID = 36;
501 const int LEN_PID = 16;
503 if (line.Length() < LEN_GUID + LEN_PID + 2) {
506 if (line[LEN_GUID] !=
'=' ||
507 line[LEN_GUID + 1 + LEN_PID] !=
',')
513 NS_ConvertASCIItoUTF16 sbid(Substring(line, 0, LEN_GUID)),
514 libid(Substring(line, LEN_GUID + 1, LEN_PID)),
515 id(Substring(line, LEN_GUID + 2 + LEN_PID));
516 miTunesDBServices.
MapID(libid,
id, sbid);
518 inputStream->Close();
519 resultsFile->Remove(PR_FALSE);
529 sbiTunesImporter::Finalize()
532 mBatchEnded = PR_TRUE;
534 mLDBLibrary->ForceEndUpdateBatch();
539 mLDBLibrary = nsnull;
546 nsresult sbiTunesImporter::DBModified(
sbPrefBranch & aPrefs,
547 nsAString
const & aLibPath,
548 PRBool * aModified) {
549 *aModified = PR_TRUE;
554 rv = GetLibraryPreviousImportPath(prevPath);
555 if (NS_FAILED(rv) || !aLibPath.Equals(prevPath)) {
561 rv = file->InitWithPath(aLibPath);
566 PRInt64 lastModified;
567 rv = file->GetLastModifiedTime(&lastModified);
571 nsCString
const & temp = aPrefs.
GetCharPref(
"lib_prev_mod_time", nsCString());
572 if (temp.IsEmpty()) {
575 PRInt64 prevLastModified =
577 if (NS_SUCCEEDED(rv)) {
578 *aModified = lastModified != prevLastModified;
586 sbiTunesImporter::Import(
const nsAString & aLibFilePath,
587 const nsAString & aGUID,
588 PRBool aCheckForChanges,
591 NS_ENSURE_ARG_POINTER(aJobProgress);
592 TRACE((
"sbiTunesImporter::Import(%s, %s, %s)",
593 NS_LossyConvertUTF16toASCII(aLibFilePath).
get(),
594 NS_LossyConvertUTF16toASCII(aGUID).
get(),
595 (aCheckForChanges ?
"true" :
"false")));
597 NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_FAILURE);
602 mFoundChanges = PR_FALSE;
603 mMissingMediaCount = 0;
605 mUnsupportedMediaCount = 0;
607 mLibraryPath = aLibFilePath;
608 mImport = aCheckForChanges ? PR_FALSE : PR_TRUE;
610 NS_ENSURE_SUCCESS(rv, rv);
615 NS_ENSURE_TRUE(mStatus.get(), NS_ERROR_FAILURE);
617 mStatus->Initialize();
619 mDataFormatVersion =
prefs.GetIntPref(
"version", DATA_FORMAT_VERSION);
622 if (!mImport && NS_SUCCEEDED(DBModified(
prefs,
624 &modified)) && !modified) {
626 rv = mStatus->Reset();
627 NS_ENSURE_SUCCESS(rv, rv);
634 mImportPlaylists = PR_FALSE;
635 mBatchEnded = PR_FALSE;
639 NS_ENSURE_SUCCESS(rv, rv);
641 mImportPlaylists = userPrefs.GetBoolPref(
"import_playlists", PR_FALSE);
644 mTypeSniffer = do_CreateInstance(
"@songbirdnest.com/Songbird/Mediacore/TypeSniffer;1", &rv);
645 NS_ENSURE_SUCCESS(rv, rv);
647 #ifdef SB_ENABLE_TEST_HARNESS
648 if (mTimingService) {
649 mTimingIdentifier = NS_LITERAL_STRING(
"ITunesImport-");
650 mTimingIdentifer.AppendInt(time(0));
651 mTimingService->StartPerfTimer(mTimingIdentifier);
656 NS_ENSURE_SUCCESS(rv, rv);
658 nsCOMPtr<nsILocalFile> file = do_CreateInstance(
"@mozilla.org/file/local;1",
660 NS_ENSURE_SUCCESS(rv, rv);
662 rv = file->InitWithPath(mLibraryPath);
663 if (NS_SUCCEEDED(rv)) {
665 rv = file->GetFileSize(&size);
666 if (NS_SUCCEEDED(rv)) {
667 mStatus->SetProgressMax(size);
672 nsAString
const & msg =
674 SBLocalizedString(
"import_library.itunes.updating");
676 mStatus->SetStatusText(msg);
681 mLDBLibrary->ForceBeginUpdateBatch();
686 rv = mParser->Parse(mStream,
this);
687 NS_ENSURE_SUCCESS(rv, rv);
690 *aJobProgress = jobProgress;
691 NS_IF_ADDREF(*aJobProgress);
699 NS_WARN_IF_FALSE(mListener == nsnull && aListener,
"Listener was previously set");
701 mListener = aListener;
710 nsCOMPtr<nsIXULRuntime> appInfo =
711 do_CreateInstance(XULRUNTIME_SERVICE_CONTRACTID, &rv);
715 rv = appInfo->GetOS(osName);
721 if (osName.Find(
"darwin") != -1) {
724 else if (osName.Find(
"linux") != -1) {
727 else if (osName.Find(
"win") != -1) {
740 NS_IMETHODIMP sbiTunesImporter::OnTopLevelProperties(
sbIStringMap *aProperties) {
741 NS_ENSURE_ARG_POINTER(aProperties);
743 nsresult rv = aProperties->Get(NS_LITERAL_STRING(
"Library Persistent ID"),
745 NS_ENSURE_SUCCESS(rv, rv);
747 nsString
id(NS_LITERAL_STRING(
"Library Persistent ID"));
748 id.Append(miTunesLibID);
749 rv = miTunesLibSig.
Update(
id);
750 NS_ENSURE_SUCCESS(rv, rv);
757 NS_ENSURE_ARG_POINTER(aProperties);
759 if (mStatus->CancelRequested()) {
763 nsresult rv = UpdateProgress();
765 nsAutoPtr<iTunesTrack> track(
new iTunesTrack);
766 NS_ENSURE_TRUE(track, NS_ERROR_OUT_OF_MEMORY);
768 rv = track->Initialize(aProperties);
769 NS_ENSURE_SUCCESS(rv, rv);
773 if (track->mProperties.Get(NS_LITERAL_STRING(
"Location"), &uri16)) {
774 LOG((
"Importing Track %s\n", NS_ConvertUTF16toUTF8(uri16).
get()));
778 nsString persistentID;
783 mTrackBatch.push_back(track.forget());
784 if (mTrackBatch.size() == BATCH_SIZE) {
791 sbiTunesImporter::OnTracksComplete() {
792 if (!mStatus->CancelRequested() && mTrackBatch.size() > 0) {
799 sbiTunesImporter::ShouldImportPlaylist(
sbIStringMap * aProperties) {
801 nsString playlistName;
802 nsresult rv = aProperties->Get(NS_LITERAL_STRING(
"Name"), playlistName);
803 NS_ENSURE_SUCCESS(rv, PR_FALSE);
808 if (!mSongbirdFolderID.IsEmpty()) {
810 rv = aProperties->Get(NS_LITERAL_STRING(
"Parent Persistent ID"), parentID);
811 if (NS_FAILED(rv) || parentID.Equals(mSongbirdFolderID)) {
817 aProperties->Get(NS_LITERAL_STRING(
"Master"), master);
820 aProperties->Get(NS_LITERAL_STRING(
"Smart Info"), smartInfo);
823 aProperties->Get(NS_LITERAL_STRING(
"Folder"), isFolder);
825 nsString delimitedName;
826 delimitedName.AppendLiteral(
":");
827 delimitedName.Append(playlistName);
828 delimitedName.AppendLiteral(
":");
831 return !master.EqualsLiteral(
"true") &&
832 smartInfo.IsEmpty() &&
833 !isFolder.EqualsLiteral(
"true") &&
834 mPlaylistBlacklist.Find(delimitedName) == -1;
843 nsString playlistName;
844 nsresult rv = aProperties->Get(NS_LITERAL_STRING(
"Name"), playlistName);
845 NS_ENSURE_SUCCESS(rv, PR_FALSE);
848 aProperties->Get(NS_LITERAL_STRING(
"Smart Info"), smartInfo);
851 aProperties->Get(NS_LITERAL_STRING(
"Folder"), isFolder);
853 return smartInfo.IsEmpty() &&
854 isFolder.EqualsLiteral(
"true") &&
855 playlistName.EqualsLiteral(
"Songbird");
860 nsAString
const & aPlaylistName,
862 NS_ENSURE_ARG_POINTER(aMediaList);
864 nsCOMArray<sbIMediaItem> mediaItems;
870 if (NS_SUCCEEDED(rv) && mediaItems.Count() > 0) {
871 NS_WARN_IF_FALSE(mediaItems.Count() > 1,
"We got multiple playlists for "
872 "the same name in iTunesImport");
876 rv = mediaItem->QueryInterface(NS_GET_IID(
sbIMediaList),
877 reinterpret_cast<void**>(aMediaList));
878 NS_ENSURE_SUCCESS(rv, rv);
883 *aMediaList = nsnull;
888 sbiTunesImporter::UpdateProgress() {
889 mStatus->SetProgress(mBytesRead);
896 PRUint32 aTrackIdsCount)
898 NS_ENSURE_ARG_POINTER(aProperties);
899 NS_ENSURE_ARG_POINTER(aTrackIds);
901 if (mStatus->CancelRequested()) {
905 nsresult rv = UpdateProgress();
909 aProperties->Get(NS_LITERAL_STRING(
"Playlist Persistent ID"),
912 else if (ShouldImportPlaylist(aProperties)) {
914 rv = aProperties->Get(NS_LITERAL_STRING(
"Playlist Persistent ID"),
916 NS_ENSURE_SUCCESS(rv, rv);
918 NS_NAMED_LITERAL_STRING(
name,
"Name");
919 nsString playlistName;
920 rv = aProperties->Get(
name, playlistName);
921 NS_ENSURE_SUCCESS(rv, rv);
923 LOG((
"Importing playlist %s\n", NS_ConvertUTF16toUTF8(playlistName).
get()));
925 text.Append(playlistName);
927 rv = miTunesLibSig.
Update(text);
928 NS_ENSURE_SUCCESS(rv, rv);
930 if (mImportPlaylists) {
931 nsString playlistSBGUID;
934 nsCOMPtr<sbIMediaList> mediaList;
935 if ((NS_FAILED(rv) || playlistSBGUID.IsEmpty())
936 && mDataFormatVersion < 2) {
939 getter_AddRefs(mediaList));
940 NS_ENSURE_SUCCESS(rv, rv);
942 else if (!playlistSBGUID.IsEmpty()) {
943 nsCOMPtr<sbIMediaItem> mediaListAsItem;
946 rv = mLibrary->GetItemByGuid(playlistSBGUID, getter_AddRefs(mediaListAsItem));
947 if (NS_SUCCEEDED(rv)) {
949 mediaList = do_QueryInterface(mediaListAsItem);
952 ImportPlaylist(aProperties,
965 nsresult rv = aMediaList->GetLength(&length);
966 NS_ENSURE_SUCCESS(rv, rv);
969 nsCOMPtr<sbIMediaItem> mediaItem;
970 for (PRUint32 index = 0; index < length; ++index) {
971 rv = aMediaList->GetItemByIndex(index, getter_AddRefs(mediaItem));
972 NS_ENSURE_SUCCESS(rv, rv);
974 rv = mediaItem->GetGuid(guid);
975 NS_ENSURE_SUCCESS(rv, rv);
987 NS_ENSURE_SUCCESS(rv, rv);
990 NS_ENSURE_SUCCESS(rv, rv);
992 nsString computedSignature;
994 NS_ENSURE_SUCCESS(rv, rv);
996 nsString playlistGuid;
997 rv = aMediaList->GetGuid(playlistGuid);
998 NS_ENSURE_SUCCESS(rv, rv);
1000 nsString storedSignature;
1002 NS_ENSURE_SUCCESS(rv, rv);
1004 aIsDirty = !computedSignature.Equals(storedSignature);
1010 sbiTunesImporter::GetDirtyPlaylistAction(nsAString
const & aPlaylistName,
1011 nsAString & aAction) {
1012 aAction = NS_LITERAL_STRING(
"replace");
1014 if (mPlaylistAction.IsEmpty()) {
1017 nsresult rv = mListener->OnDirtyPlaylist(aPlaylistName,
1020 NS_ENSURE_SUCCESS(rv, rv);
1022 mPlaylistAction = aAction;
1026 aAction = mPlaylistAction;
1033 nsIMutableArray * aItems) {
1034 nsCOMPtr<nsISimpleEnumerator> enumerator;
1035 nsresult rv = aItems->Enumerate(getter_AddRefs(enumerator));
1036 NS_ENSURE_SUCCESS(rv, rv);
1038 rv = aMediaList->AddSome(enumerator);
1039 NS_ENSURE_SUCCESS(rv, rv);
1045 sbiTunesImporter::ProcessPlaylistItems(
sbIMediaList * aMediaList,
1046 PRInt32 * aTrackIds,
1047 PRUint32 aTrackIdsCount) {
1048 NS_ENSURE_ARG_POINTER(aMediaList);
1049 NS_ENSURE_ARG_POINTER(aTrackIds);
1052 nsCOMPtr<nsIMutableArray> tracks =
1053 do_CreateInstance(
"@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
1054 NS_ENSURE_SUCCESS(rv, rv);
1056 nsCOMPtr<sbIMediaItem> mediaItem;
1057 for (PRUint32 index = 0; index < aTrackIdsCount; ++index) {
1059 if (((index + 1) % BATCH_SIZE) == 0) {
1061 NS_ENSURE_SUCCESS(rv, rv);
1063 rv = tracks->Clear();
1064 NS_ENSURE_SUCCESS(rv, rv);
1067 trackID.AppendInt(aTrackIds[index], 10);
1071 text.AppendLiteral(
"Persistent ID");
1072 text.Append(miTunesLibID);
1073 text.Append(trackID);
1074 rv = miTunesLibSig.
Update(text);
1075 NS_ENSURE_SUCCESS(rv, rv);
1077 TrackIDMap::const_iterator iter = mTrackIDMap.find(trackID);
1078 if (iter != mTrackIDMap.end()) {
1079 rv = mLibrary->GetItemByGuid(iter->second, getter_AddRefs(mediaItem));
1080 NS_ENSURE_SUCCESS(rv, rv);
1082 rv = tracks->AppendElement(mediaItem, PR_FALSE);
1083 NS_ENSURE_SUCCESS(rv, rv);
1087 NS_ENSURE_SUCCESS(rv, rv);
1097 NS_ENSURE_SUCCESS(rv, rv);
1100 NS_ENSURE_SUCCESS(rv, rv);
1102 nsString theSignature;
1104 NS_ENSURE_SUCCESS(rv, rv);
1107 rv = aMediaList->GetGuid(guid);
1108 NS_ENSURE_SUCCESS(rv, rv);
1111 NS_ENSURE_SUCCESS(rv, rv);
1117 sbiTunesImporter::ImportPlaylist(
sbIStringMap *aProperties,
1119 PRUint32 aTrackIdsCount,
1121 NS_ENSURE_ARG_POINTER(aProperties);
1122 NS_ENSURE_ARG_POINTER(aTrackIds);
1126 nsCOMPtr<sbIMediaList> mediaList(aMediaList);
1127 PRBool isDirty = PR_TRUE;
1130 NS_ENSURE_SUCCESS(rv, rv);
1133 nsString playlistiTunesID;
1134 rv = aProperties->Get(NS_LITERAL_STRING(
"Playlist Persistent ID"),
1136 NS_ENSURE_SUCCESS(rv, rv);
1138 nsString playlistName;
1139 rv = aProperties->Get(NS_LITERAL_STRING(
"Name"), playlistName);
1140 NS_ENSURE_SUCCESS(rv, rv);
1142 nsCString action(
"replace");
1143 if (!mImportPlaylists) {
1146 else if (mediaList && isDirty) {
1147 nsString userAction;
1148 rv = GetDirtyPlaylistAction(playlistName, userAction);
1149 NS_ENSURE_SUCCESS(rv, rv);
1150 action = NS_LossyConvertUTF16toASCII(userAction);
1153 if (action.Equals(
"replace")) {
1154 mFoundChanges = PR_TRUE;
1156 if (aTrackIdsCount > 0) {
1162 rv = mediaList->Clear();
1163 NS_ENSURE_SUCCESS(rv, rv);
1166 rv = mediaList->SetName(playlistName);
1167 NS_ENSURE_SUCCESS(rv, rv);
1172 nsCOMPtr<sbIMutablePropertyArray> properties =
1174 NS_ENSURE_SUCCESS(rv, rv);
1178 NS_ENSURE_SUCCESS(rv, rv);
1182 NS_ENSURE_SUCCESS(rv, rv);
1184 rv = mLibrary->CreateMediaList(NS_LITERAL_STRING(
"simple"),
1186 getter_AddRefs(mediaList));
1187 NS_ENSURE_SUCCESS(rv, rv);
1189 rv = mediaList->GetGuid(guid);
1190 NS_ENSURE_SUCCESS(rv, rv);
1193 rv = miTunesDBServices.
MapID(miTunesLibID, playlistiTunesID, guid);
1194 NS_ENSURE_SUCCESS(rv, rv);
1197 rv = ProcessPlaylistItems(mediaList,
1200 NS_ENSURE_SUCCESS(rv, rv);
1209 sbiTunesImporter::OnPlaylistsComplete() {
1212 char const * completionMsg;
1214 completionMsg =
"import_library.itunes.complete";
1217 if (mFoundChanges) {
1218 completionMsg =
"import_library.itunes.updating.has_changes";
1221 completionMsg =
"import_library.itunes.updating.no_changes";
1226 mLDBLibrary->ForceEndUpdateBatch();
1227 mBatchEnded = PR_TRUE;
1230 mStatus->SetStatusText(SBLocalizedString(completionMsg));
1235 #ifdef SB_ENABLE_TEST_HARNESS
1236 if (mTimingService) {
1237 mTimingService->StopPerfTimer(mTimingIdentifier);
1243 if (!mImport && mFoundChanges) {
1244 mListener->OnLibraryChanged(mLibraryPath, miTunesLibID);
1250 NS_ENSURE_SUCCESS(rv, rv);
1253 prefs.SetCharPref(
"lib_prev_path", NS_ConvertUTF16toUTF8(mLibraryPath));
1256 nsCOMPtr<nsILocalFile> file =
1257 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
1258 NS_ENSURE_SUCCESS(rv, rv);
1260 rv = file->InitWithPath(mLibraryPath);
1261 NS_ENSURE_SUCCESS(rv, rv);
1263 PRInt64 lastModified;
1264 file->GetLastModifiedTime(&lastModified);
1265 sbAutoString lastModifiedStr(static_cast<PRUint64>(lastModified));
1266 prefs.SetCharPref(
"lib_prev_mod_time",
1267 NS_ConvertUTF16toUTF8(lastModifiedStr));
1268 if (mMissingMediaCount > 0) {
1269 mListener->OnNonExistentMedia(mMissingMediaCount,
1274 if (mUnsupportedMediaCount > 0) {
1275 mListener->OnUnsupportedMedia();
1282 sbiTunesImporter::OnError(
const nsAString & aErrorMessage, PRBool *_retval)
1284 LOG((
"XML Parsing error: %s\n",
1285 ::NS_LossyConvertUTF16toASCII(aErrorMessage).
get()));
1286 if (mStatus.get() && !mStatus->CancelRequested()) {
1287 mListener->OnImportError();
1305 mChangedProperties = do_CreateInstance(
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1", rv);
1312 PRUint32 length = 0;
1327 static PLDHashOperator
1331 NS_ENSURE_TRUE(aUserArg, PL_DHASH_STOP);
1335 nsString currentValue;
1336 data->
mProperties->GetPropertyValue(aKey, currentValue);
1337 if (!aValue.Equals(currentValue)) {
1340 return PL_DHASH_NEXT;
1343 nsresult sbiTunesImporter::ProcessUpdates() {
1345 TrackBatch::iterator
const end = mTrackBatch.end();
1346 for (TrackBatch::iterator iter = mTrackBatch.begin();
1352 nsCOMPtr<nsIURI>
uri;
1353 iTunesTrack *
const track = *iter;
1355 rv = miTunesDBServices.
GetSBIDFromITID(miTunesLibID, track->mTrackID, guid);
1356 if (NS_SUCCEEDED(rv) && !guid.IsEmpty()) {
1360 mTrackIDMap.insert(TrackIDMap::value_type(track->mTrackID, guid));
1361 track->mSBGuid = guid;
1362 nsCOMPtr<sbIMediaItem> mediaItem;
1363 rv = mLibrary->GetMediaItem(guid, getter_AddRefs(mediaItem));
1364 if (NS_SUCCEEDED(rv)) {
1365 mFoundChanges = PR_TRUE;
1368 nsCOMPtr<sbIPropertyArray> properties;
1369 rv = mediaItem->GetProperties(nsnull, getter_AddRefs(properties));
1370 if (NS_SUCCEEDED(rv)) {
1372 NS_ENSURE_SUCCESS(rv, rv);
1376 nsString contentURL;
1378 rv = properties->GetPropertyValue(CONTENT_URL,
1380 if (NS_SUCCEEDED(rv)) {
1383 track->GetTrackURI(GetOSType(),
1386 getter_AddRefs(uri));
1387 nsCOMPtr<nsIURI> fixedUri;
1389 NS_ENSURE_SUCCESS(rv, rv);
1390 nsCString trackCURI;
1391 rv = fixedUri->GetSpec(trackCURI);
1392 if (NS_SUCCEEDED(rv)) {
1393 nsString
const & trackURI = NS_ConvertUTF8toUTF16(trackCURI);
1394 if (!trackURI.Equals(contentURL)) {
1395 data.mChangedProperties->AppendProperty(CONTENT_URL,
1403 if (
data.NeedsUpdating()) {
1404 rv = mediaItem->SetProperties(
data.mChangedProperties);
1405 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
1406 "Failed to set a property on iTunes import");
1416 sbiTunesImporter::ProcessNewItems(
1417 TracksByID & aTrackMap,
1418 nsIArray ** aNewItems) {
1419 NS_ENSURE_ARG_POINTER(aNewItems);
1423 nsCOMPtr<nsIMutableArray> uriArray =
1424 do_CreateInstance(
"@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
1425 NS_ENSURE_SUCCESS(rv, rv);
1427 nsCOMPtr<nsIMutableArray> propertyArrays =
1428 do_CreateInstance(
"@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
1429 NS_ENSURE_SUCCESS(rv, rv);
1431 nsCOMPtr<nsIURI>
uri;
1433 TrackBatch::iterator
const begin = mTrackBatch.begin();
1434 TrackBatch::iterator
const end = mTrackBatch.end();
1435 for (TrackBatch::iterator iter = begin; iter != end; ++iter) {
1442 nsString persistentID;
1446 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
1448 aTrackMap.insert(TracksByID::value_type(persistentID, iter - begin));
1450 nsCOMPtr<nsIFile>
file;
1452 rv = (*iter)->GetTrackURI(GetOSType(),
1455 getter_AddRefs(uri));
1456 if (NS_SUCCEEDED(rv)) {
1457 nsCOMPtr<nsIFileURL> trackFile = do_QueryInterface(uri, &rv);
1458 PRBool trackExists = PR_FALSE;
1459 if (NS_SUCCEEDED(rv)) {
1460 rv = trackFile->GetFile(getter_AddRefs(file));
1461 if (NS_SUCCEEDED(rv)) {
1462 file->Exists(&trackExists);
1467 LOG((
"processTrack: File protocol error %d\n", rv));
1468 LOG((
"%s\n", spec.BeginReading()));
1471 ++mMissingMediaCount;
1477 PRBool supported = PR_FALSE;
1479 mTypeSniffer->IsValidMediaURL(uri, &supported);
1482 ++mUnsupportedMediaCount;
1484 nsString sig(NS_LITERAL_STRING(
"supported"));
1486 sig.AppendLiteral(
"true");
1489 sig.AppendLiteral(
"false");
1491 rv = miTunesLibSig.
Update(sig);
1493 mFoundChanges = PR_TRUE;
1496 PRInt64 fileSize = 0;
1497 file->GetFileSize(&fileSize);
1500 NS_ENSURE_SUCCESS(rv, rv);
1503 rv = uriArray->AppendElement(uri, PR_FALSE);
1504 NS_ENSURE_SUCCESS(rv, rv);
1507 nsCOMPtr<sbIPropertyArray> propertyArray;
1508 rv = (*iter)->GetPropertyArray(getter_AddRefs(propertyArray));
1509 NS_ENSURE_SUCCESS(rv, rv);
1511 rv = propertyArrays->AppendElement(propertyArray, PR_FALSE);
1512 NS_ENSURE_SUCCESS(rv, rv);
1518 rv = propertyArrays->GetLength(&length);
1519 NS_ENSURE_SUCCESS(rv, rv);
1524 rv = mLibrary->BatchCreateMediaItems(uriArray,
1530 *aNewItems = nsnull;
1536 sbiTunesImporter::ProcessCreatedItems(
1537 nsIArray * aCreatedItems,
1538 TracksByID
const & aTrackMap) {
1539 NS_ENSURE_ARG_POINTER(aCreatedItems);
1542 nsresult rv = aCreatedItems->GetLength(&length);
1543 NS_ENSURE_SUCCESS(rv, rv);
1545 TracksByID::const_iterator trackMapEnd = aTrackMap.end();
1546 nsCOMPtr<sbIMediaItem> mediaItem;
1547 nsCOMPtr<sbIAlbumArtListener> albumArtListener =
1549 for (PRUint32 index = 0; index < length; ++index) {
1551 mediaItem = do_QueryElementAt(aCreatedItems,
1554 NS_ENSURE_SUCCESS(rv, rv);
1557 rv = mediaItem->GetGuid(guid);
1558 NS_ENSURE_SUCCESS(rv, rv);
1560 nsString iTunesGUID;
1563 TracksByID::const_iterator iter = aTrackMap.find(iTunesGUID);
1564 if (iter != trackMapEnd) {
1565 mTrackBatch[iter->second]->mSBGuid = guid;
1566 mTrackIDMap.insert(TrackIDMap::value_type(
1567 mTrackBatch[iter->second]->mTrackID,
1571 mAlbumArtFetcher->FetchAlbumArtForTrack(mediaItem,
1578 nsCOMPtr<nsIURI>
uri;
1579 nsCOMPtr<sbIPropertyArray> propertyArray;
1580 TrackBatch::iterator
const end = mTrackBatch.end();
1581 for (TrackBatch::iterator iter = mTrackBatch.begin();
1587 iTunesTrack *
const track = *iter;
1589 if (track->mSBGuid.IsEmpty()) {
1590 rv = track->GetTrackURI(GetOSType(),
1593 getter_AddRefs(uri));
1595 if (rv == NS_ERROR_NOT_AVAILABLE) {
1598 NS_ENSURE_SUCCESS(rv, rv);
1600 rv = track->GetPropertyArray(getter_AddRefs(propertyArray));
1601 NS_ENSURE_SUCCESS(rv, rv);
1603 rv = mLibrary->CreateMediaItem(uri,
1606 getter_AddRefs(mediaItem));
1607 NS_ENSURE_SUCCESS(rv, rv);
1609 rv = mediaItem->GetGuid(track->mSBGuid);
1610 NS_ENSURE_SUCCESS(rv, rv);
1611 mTrackIDMap.insert(TrackIDMap::value_type(track->mTrackID,
1614 if (!track->mSBGuid.IsEmpty()) {
1615 rv = miTunesDBServices.
MapID(miTunesLibID,
1618 NS_ENSURE_SUCCESS(rv, rv);
1625 void sbiTunesImporter::DestructiTunesTrack(iTunesTrack * aTrack) {
1629 nsresult sbiTunesImporter::ProcessTrackBatch() {
1632 rv = ProcessUpdates();
1633 NS_ENSURE_SUCCESS(rv, rv);
1635 nsCOMPtr<nsIArray> newItems;
1636 TracksByID trackMap;
1637 rv = ProcessNewItems(trackMap,
1638 getter_AddRefs(newItems));
1639 NS_ENSURE_SUCCESS(rv, rv);
1643 rv = ProcessCreatedItems(newItems, trackMap);
1644 NS_ENSURE_SUCCESS(rv, rv);
1646 std::for_each(mTrackBatch.begin(), mTrackBatch.end(), DestructiTunesTrack);
1649 mTrackBatch.clear();
1653 sbiTunesImporter::iTunesTrack::iTunesTrack() {
1654 MOZ_COUNT_CTOR(iTunesTrack);
1656 sbiTunesImporter::iTunesTrack::~iTunesTrack() {
1657 MOZ_COUNT_DTOR(iTunesTrack);
1661 sbiTunesImporter::iTunesTrack::Initialize(
sbIStringMap * aProperties) {
1662 NS_ENSURE_ARG_POINTER(aProperties);
1664 nsresult rv = aProperties->Get(NS_LITERAL_STRING(
"Track ID"), mTrackID);
1665 NS_ENSURE_SUCCESS(rv, rv);
1668 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
1670 NS_NAMED_LITERAL_STRING(location,
"Location");
1673 rv = aProperties->Get(location, URI);
1674 NS_ENSURE_SUCCESS(rv, rv);
1677 NS_ENSURE_SUCCESS(rv, rv);
1679 for (
unsigned int index = 0; index < NS_ARRAY_LENGTH(gPropertyMap); ++index) {
1680 PropertyMap const & propertyMapEntry = gPropertyMap[index];
1682 rv = aProperties->Get(NS_ConvertASCIItoUTF16(propertyMapEntry.
ITProperty),
1684 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"sbIStringMap::Get failed");
1685 if (!value.IsVoid()) {
1695 GetContentType(aProperties));
1701 sbiTunesImporter::iTunesTrack::GetContentType(
sbIStringMap * aProperties)
1706 nsString podcastValue;
1707 rv = aProperties->Get(NS_LITERAL_STRING(
"Podcast"), podcastValue);
1708 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"sbIStringMap::Get failed");
1710 if (NS_SUCCEEDED(rv) && podcastValue.EqualsLiteral(
"true")) {
1711 result = NS_LITERAL_STRING(
"podcast");
1715 rv = aProperties->Get(NS_LITERAL_STRING(
"Has Video"), hasVideo);
1716 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"sbIStringMap::Get failed");
1718 if (NS_SUCCEEDED(rv) && hasVideo.EqualsLiteral(
"true")) {
1719 result = NS_LITERAL_STRING(
"video");
1722 result = NS_LITERAL_STRING(
"audio");
1729 static PLDHashOperator
1733 NS_ENSURE_TRUE(aUserArg, PL_DHASH_STOP);
1737 nsresult rv = array->AppendProperty(aKey, aValue);
1738 NS_ENSURE_SUCCESS(rv, ::PL_DHASH_STOP);
1739 return PL_DHASH_NEXT;
1743 sbiTunesImporter::iTunesTrack::GetPropertyArray(
1745 NS_ENSURE_ARG_POINTER(aPropertyArray);
1748 nsCOMPtr<sbIMutablePropertyArray>
array =
1749 do_CreateInstance(
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1",
1751 NS_ENSURE_SUCCESS(rv, rv);
1754 nsCOMPtr<sbIPropertyArray> propertyArray = do_QueryInterface(array);
1755 propertyArray.forget(aPropertyArray);
1761 sbiTunesImporter::iTunesTrack::GetTrackURI(
1763 nsIIOService * aIOService,
1765 nsIURI ** aTrackURI) {
1766 NS_ENSURE_ARG_POINTER(aIOService);
1767 NS_ENSURE_ARG_POINTER(aTrackURI);
1770 *aTrackURI = mURI.get();
1771 NS_ADDREF(*aTrackURI);
1775 if (!
mProperties.Get(NS_LITERAL_STRING(
"Location"), &uri16)) {
1776 return NS_ERROR_NOT_AVAILABLE;
1779 if (uri16.IsEmpty()) {
1780 return NS_ERROR_NOT_AVAILABLE;
1783 nsCString uri = NS_ConvertUTF16toUTF8(uri16);
1785 nsCString adjustedURI;
1787 if (uri[uri.Length() - 1] ==
'/') {
1788 uri.Cut(uri.Length() -1, 1);
1791 if (uri.Find(
"file://localhost//", CaseInsensitiveCompare) == 0) {
1792 adjustedURI.AssignLiteral(
"file://///");
1795 else if (uri.Find(
"file://localhost/", CaseInsensitiveCompare) == 0) {
1796 adjustedURI.AssignLiteral(
"file:///");
1800 char const c = uri[0];
1801 if (uri.Length() > 3 &&
1802 ((c >=
'A' && c <= 'Z') || (c >=
'a' && c <=
'z')) &&
1805 adjustedURI =
"file:///";
1809 adjustedURI =
"file:////";
1813 adjustedURI.Append(uri);
1816 if (aOSType == WINDOWS_OS) {
1817 ToLowerCase(adjustedURI);
1820 nsString locationSig;
1821 locationSig.AssignLiteral(
"Location");
1822 locationSig.AppendLiteral(adjustedURI.BeginReading());
1824 nsresult rv = aSignature.
Update(locationSig);
1825 NS_ENSURE_SUCCESS(rv, rv);
1828 rv = aIOService->NewURI(adjustedURI, nsnull, nsnull, getter_AddRefs(mURI));
1829 NS_ENSURE_SUCCESS(rv, rv);
1831 *aTrackURI = mURI.get();
1832 NS_ADDREF(*aTrackURI);
1839 sbiTunesImporter::OnProgress(PRInt64 aBytesResad)
1841 mBytesRead = aBytesResad;
static nsresult GetItemsByProperty(sbIMediaList *aMediaList, nsAString const &aPropertyName, nsAString const &aValue, nsCOMArray< sbIMediaItem > &aMediaItems)
#define SB_PROPERTY_TOTALDISCS
Interface for importing external libraries.
nsString ConvertDuration(nsAString const &aDuration)
#define SB_PROPERTY_MEDIALISTNAME
#define SB_PROPERTY_PLAYCOUNT
nsCString GetCharPref(const char *aKey, const nsCString &aDefault)
nsresult sbOpenInputStream(nsAString const &aPath, nsIInputStream **aStream)
#define SB_PROPERTY_SAMPLERATE
nsCOMPtr< nsIArray > mProperties
dataSBHighestRatedArtists SBProperties rating
nsCOMPtr< sbIMutablePropertyArray > mChangedProperties
nsCOMPtr< sbIPropertyArray > mProperties
#define SB_PROPERTY_ALBUMARTISTNAME
Generic interface for exposing long running jobs to the UI.
#define SB_PROPERTY_RATING
static PRBool IsSongbirdFolder(sbIStringMap *aProperties)
ValueConversion mConversion
nsresult StoreSignature(nsAString const &aID, nsAString const &aSignature)
nsresult Update(nsAString const &aStringData)
#define NS_LOCALFILE_CONTRACTID
static nsresult GetContentURI(nsIURI *aURI, nsIURI **_retval, nsIIOService *aIOService=nsnull)
Return a library content URI for the URI specified by aURI. A library content URI is a specially form...
#define SB_PROPERTY_LASTPLAYTIME
#define SB_PROPERTY_TOTALTRACKS
nsresult GetSBIDFromITID(nsAString const &aiTunesLibID, nsAString const &aiiTunesID, nsAString &aSongbirdID)
nsresult RetrieveSignature(nsAString const &aID, nsAString &aSignature)
#define SB_PROPERTY_BITRATE
static nsresult FindPlaylistByName(sbILibrary *aLibrary, nsAString const &aPlaylistName, sbIMediaList **aMediaList)
#define SB_PROPERTY_CONTENTLENGTH
static nsresult StorePlaylistSignature(sbIMediaList *aMediaList)
An interface to carry around arrays of nsIProperty instances Note that implementations of the interfa...
const unsigned long TYPE_LOCAL
static PLDHashOperator EnumReadFunc(nsAString const &aKey, nsString aValue, void *aUserArg)
#define SB_PROPERTY_GENRE
#define SB_PROPERTY_CONTENTTYPE
NS_IMPL_ISUPPORTS2(sbiTunesImporter, sbILibraryImporter, sbIiTunesXMLParserListener) sbiTunesImporter
static PLDHashOperator ConvertToPropertyArray(nsAString const &aKey, nsString aValue, void *aUserArg)
#define SB_PROPERTY_DURATION
NS_DECL_ISUPPORTS NS_DECL_SBIJOBPROGRESS static NS_DECL_SBIJOBCANCELABLE sbiTunesImporterJob * New()
#define SB_PROPERTY_DISCNUMBER
NS_DECL_ISUPPORTS static NS_DECL_SBIALBUMARTLISTENER sbiTunesImporterAlbumArtListener * New()
static sbiTunesImporterStatus * New(sbiTunesImporterJob *aJobProgress)
nsresult GetSignature(nsAString &aSignature)
NS_DECL_ISUPPORTS NS_DECL_SBIITUNESXMLPARSER NS_DECL_NSISAXCONTENTHANDLER static NS_DECL_NSISAXERRORHANDLER sbiTunesXMLParser * New()
void nsCString_Split(const nsACString &aString, const nsACString &aDelimiter, nsTArray< nsCString > &aSubStringArray)
nsString ConvertRating(nsAString const &aRating)
sbiTunesImporterEnumeratePropertiesData(sbIPropertyArray *aProperties, nsresult *rv)
Media library abstraction.
#define SB_PROPERTY_ARTISTNAME
nsString ConvertDateTime(nsAString const &aDateTime)
static nsresult ComputePlaylistSignature(sbiTunesSignature &aSignature, sbIMediaList *aMediaList)
Interface for listening to library importer events.
#define SB_PROPERTY_ALBUMNAME
#define SB_PROPERTY_COMPOSERNAME
PRInt64 nsString_ToInt64(const nsAString &str, nsresult *rv)
static nsresult AddItemsToPlaylist(sbIMediaList *aMediaList, nsIMutableArray *aItems)
char const SB_ITUNES_LIBRARY_IMPORTER_PREF_PREFIX[]
#define SB_PROPERTY_LASTSKIPTIME
nsresult GetMainLibrary(sbILibrary **aMainLibrary)
#define SB_PROPERTY_TRACKNAME
#define SB_PROPERTY_COMMENT
static nsresult IsPlaylistDirty(sbIMediaList *aMediaList, PRBool &aIsDirty)
bool NeedsUpdating() const
nsString(* ValueConversion)(nsAString const &aValue)
#define SB_PROPERTY_CONTENTURL
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
#define SB_PROPERTY_ITUNES_GUID
#define SB_PROPERTY_SKIPCOUNT
nsresult MapID(nsAString const &aiTunesLibID, nsAString const &aiTunesID, nsAString const &aSongbirdID)
PropertyMap gPropertyMap[]
char const SB_ITUNES_LIBRARY_IMPORT_PREF_PREFIX[]
#define SB_PROPERTY_TRACKNUMBER