Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / itunes_data_provider.cc
blobc5ed53bc273d07a8a2e9335deb1c2446181b26ac
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/format_macros.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/platform_file.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
20 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
21 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
22 #include "chrome/common/media_galleries/itunes_library.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "third_party/icu/source/common/unicode/locid.h"
25 #include "webkit/browser/fileapi/native_file_util.h"
27 namespace itunes {
29 namespace {
31 // Colon and slash are not allowed in filenames, replace them with underscore.
32 std::string EscapeBadCharacters(const std::string& input) {
33 std::string result;
34 base::ReplaceChars(input, ":/", "_", &result);
35 return result;
38 ITunesDataProvider::Album MakeUniqueTrackNames(const parser::Album& album) {
39 // TODO(vandebo): It would be nice to ensure that names returned from here
40 // are stable, but aside from persisting every name returned, it's not
41 // obvious how to do that (without including the track id in every name).
42 typedef std::set<const parser::Track*> TrackRefs;
43 typedef std::map<ITunesDataProvider::TrackName, TrackRefs> AlbumInfo;
45 ITunesDataProvider::Album result;
46 AlbumInfo duped_tracks;
48 parser::Album::const_iterator album_it;
49 for (album_it = album.begin(); album_it != album.end(); ++album_it) {
50 const parser::Track& track = *album_it;
51 std::string name =
52 EscapeBadCharacters(track.location.BaseName().AsUTF8Unsafe());
53 duped_tracks[name].insert(&track);
56 for (AlbumInfo::const_iterator name_it = duped_tracks.begin();
57 name_it != duped_tracks.end();
58 ++name_it) {
59 const TrackRefs& track_refs = name_it->second;
60 if (track_refs.size() == 1) {
61 result[name_it->first] = (*track_refs.begin())->location;
62 } else {
63 for (TrackRefs::const_iterator track_it = track_refs.begin();
64 track_it != track_refs.end();
65 ++track_it) {
66 base::FilePath track_file_name = (*track_it)->location.BaseName();
67 std::string id =
68 base::StringPrintf(" (%" PRId64 ")", (*track_it)->id);
69 std::string uniquified_track_name =
70 track_file_name.InsertBeforeExtensionASCII(id).AsUTF8Unsafe();
71 std::string escaped_track_name =
72 EscapeBadCharacters(uniquified_track_name);
73 result[escaped_track_name] = (*track_it)->location;
78 return result;
81 // |result_path| is set if |locale_string| maps to a localized directory name
82 // and it exists in the filesystem.
83 bool CheckLocaleStringAutoAddPath(
84 const base::FilePath& media_path,
85 const std::map<std::string, std::string>& localized_dir_names,
86 const std::string& locale_string,
87 base::FilePath* result_path) {
88 DCHECK(!media_path.empty());
89 DCHECK(!localized_dir_names.empty());
90 DCHECK(!locale_string.empty());
91 DCHECK(result_path);
93 std::map<std::string, std::string>::const_iterator it =
94 localized_dir_names.find(locale_string);
95 if (it == localized_dir_names.end())
96 return false;
98 base::FilePath localized_auto_add_path =
99 media_path.Append(base::FilePath::FromUTF8Unsafe(it->second));
100 if (!fileapi::NativeFileUtil::DirectoryExists(localized_auto_add_path))
101 return false;
103 *result_path = localized_auto_add_path;
104 return true;
107 // This method is complex because Apple localizes the directory name in versions
108 // of iTunes before 10.6.
109 base::FilePath GetAutoAddPath(const base::FilePath& library_path) {
110 const char kiTunesMediaDir[] = "iTunes Media";
111 base::FilePath media_path =
112 library_path.DirName().AppendASCII(kiTunesMediaDir);
114 // Test 'universal' path first.
115 base::FilePath universal_auto_add_path =
116 media_path.AppendASCII("Automatically Add to iTunes.localized");
117 if (fileapi::NativeFileUtil::DirectoryExists(universal_auto_add_path))
118 return universal_auto_add_path;
120 // Test user locale. Localized directory names encoded in UTF-8.
121 std::map<std::string, std::string> localized_dir_names;
122 localized_dir_names["nl"] = "Voeg automatisch toe aan iTunes";
123 localized_dir_names["en"] = "Automatically Add to iTunes";
124 localized_dir_names["fr"] = "Ajouter automatiquement \xC3\xA0 iTunes";
125 localized_dir_names["de"] = "Automatisch zu iTunes hinzuf\xC3\xBCgen";
126 localized_dir_names["it"] = "Aggiungi automaticamente a iTunes";
127 localized_dir_names["ja"] = "iTunes \xE3\x81\xAB\xE8\x87\xAA\xE5\x8B\x95\xE7"
128 "\x9A\x84\xE3\x81\xAB\xE8\xBF\xBD\xE5\x8A\xA0";
129 localized_dir_names["es"] = "A\xC3\xB1""adir autom\xC3\xA1ticamente a iTunes";
130 localized_dir_names["da"] = "F\xC3\xB8j automatisk til iTunes";
131 localized_dir_names["en-GB"] = "Automatically Add to iTunes";
132 localized_dir_names["fi"] = "Lis\xC3\xA4\xC3\xA4 automaattisesti iTunesiin";
133 localized_dir_names["ko"] = "iTunes\xEC\x97\x90 \xEC\x9E\x90\xEB\x8F\x99\xEC"
134 "\x9C\xBC\xEB\xA1\x9C \xEC\xB6\x94\xEA\xB0\x80";
135 localized_dir_names["no"] = "Legg til automatisk i iTunes";
136 localized_dir_names["pl"] = "Automatycznie dodaj do iTunes";
137 localized_dir_names["pt"] = "Adicionar Automaticamente ao iTunes";
138 localized_dir_names["pt-PT"] = "Adicionar ao iTunes automaticamente";
139 localized_dir_names["ru"] = "\xD0\x90\xD0\xB2\xD1\x82\xD0\xBE\xD0\xBC\xD0\xB0"
140 "\xD1\x82\xD0\xB8\xD1\x87\xD0\xB5\xD1\x81\xD0\xBA"
141 "\xD0\xB8 \xD0\xB4\xD0\xBE\xD0\xB1\xD0\xB0\xD0"
142 "\xB2\xD0\xBB\xD1\x8F\xD1\x82\xD1\x8C \xD0\xB2"
143 "iTunes";
144 localized_dir_names["sv"] = "L\xC3\xA4gg automatiskt till i iTunes";
145 localized_dir_names["zh-CN"] = "\xE8\x87\xAA\xE5\x8A\xA8\xE6\xB7\xBB\xE5\x8A"
146 "\xA0\xE5\x88\xB0 iTunes";
147 localized_dir_names["zh-TW"] = "\xE8\x87\xAA\xE5\x8B\x95\xE5\x8A\xA0\xE5\x85"
148 "\xA5 iTunes";
150 const icu::Locale locale = icu::Locale::getDefault();
151 const char* language = locale.getLanguage();
152 const char* country = locale.getCountry();
154 base::FilePath result_path;
155 if (language != NULL && *language != '\0') {
156 if (country != NULL && *country != '\0' &&
157 CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
158 std::string(language) + "-" + country,
159 &result_path)) {
160 return result_path;
163 if (CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
164 language, &result_path)) {
165 return result_path;
169 // Fallback to trying English.
170 if (CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
171 "en", &result_path)) {
172 return result_path;
175 return base::FilePath();
178 } // namespace
180 ITunesDataProvider::ITunesDataProvider(const base::FilePath& library_path)
181 : iapps::IAppsDataProvider(library_path),
182 auto_add_path_(GetAutoAddPath(library_path)),
183 weak_factory_(this) {}
185 ITunesDataProvider::~ITunesDataProvider() {}
187 void ITunesDataProvider::DoParseLibrary(
188 const base::FilePath& library_path,
189 const ReadyCallback& ready_callback) {
190 xml_parser_ = new iapps::SafeIAppsLibraryParser;
191 xml_parser_->ParseITunesLibrary(
192 library_path,
193 base::Bind(&ITunesDataProvider::OnLibraryParsed,
194 weak_factory_.GetWeakPtr(),
195 ready_callback));
198 const base::FilePath& ITunesDataProvider::auto_add_path() const {
199 return auto_add_path_;
202 bool ITunesDataProvider::KnownArtist(const ArtistName& artist) const {
203 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
204 DCHECK(valid());
205 return ContainsKey(library_, artist);
208 bool ITunesDataProvider::KnownAlbum(const ArtistName& artist,
209 const AlbumName& album) const {
210 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
211 DCHECK(valid());
212 Library::const_iterator library_it = library_.find(artist);
213 if (library_it == library_.end())
214 return false;
215 return ContainsKey(library_it->second, album);
218 base::FilePath ITunesDataProvider::GetTrackLocation(
219 const ArtistName& artist, const AlbumName& album,
220 const TrackName& track) const {
221 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
222 DCHECK(valid());
223 Library::const_iterator library_it = library_.find(artist);
224 if (library_it == library_.end())
225 return base::FilePath();
227 Artist::const_iterator artist_it = library_it->second.find(album);
228 if (artist_it == library_it->second.end())
229 return base::FilePath();
231 Album::const_iterator album_it = artist_it->second.find(track);
232 if (album_it == artist_it->second.end())
233 return base::FilePath();
234 return album_it->second;
237 std::set<ITunesDataProvider::ArtistName>
238 ITunesDataProvider::GetArtistNames() const {
239 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
240 DCHECK(valid());
241 std::set<ArtistName> result;
242 Library::const_iterator it;
243 for (it = library_.begin(); it != library_.end(); ++it) {
244 result.insert(it->first);
246 return result;
249 std::set<ITunesDataProvider::AlbumName> ITunesDataProvider::GetAlbumNames(
250 const ArtistName& artist) const {
251 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
252 DCHECK(valid());
253 std::set<AlbumName> result;
254 Library::const_iterator artist_lookup = library_.find(artist);
255 if (artist_lookup == library_.end())
256 return result;
258 const Artist& artist_entry = artist_lookup->second;
259 Artist::const_iterator it;
260 for (it = artist_entry.begin(); it != artist_entry.end(); ++it) {
261 result.insert(it->first);
263 return result;
266 ITunesDataProvider::Album ITunesDataProvider::GetAlbum(
267 const ArtistName& artist, const AlbumName& album) const {
268 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
269 DCHECK(valid());
270 Album result;
271 Library::const_iterator artist_lookup = library_.find(artist);
272 if (artist_lookup != library_.end()) {
273 Artist::const_iterator album_lookup = artist_lookup->second.find(album);
274 if (album_lookup != artist_lookup->second.end())
275 result = album_lookup->second;
277 return result;
280 void ITunesDataProvider::OnLibraryParsed(const ReadyCallback& ready_callback,
281 bool result,
282 const parser::Library& library) {
283 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
284 set_valid(result);
285 if (valid()) {
286 library_.clear();
287 for (parser::Library::const_iterator artist_it = library.begin();
288 artist_it != library.end();
289 ++artist_it) {
290 std::string artist_name = EscapeBadCharacters(artist_it->first);
291 for (parser::Albums::const_iterator album_it = artist_it->second.begin();
292 album_it != artist_it->second.end();
293 ++album_it) {
294 std::string album_name = EscapeBadCharacters(album_it->first);
295 library_[artist_name][album_name] =
296 MakeUniqueTrackNames(album_it->second);
300 ready_callback.Run(valid());
303 } // namespace itunes