1 /**
2 * \file importconfig.cpp
3 * Configuration for import dialog.
4 *
5 * \b Project: Kid3
6 * \author Urs Fleisch
7 * \date 17 Sep 2003
8 *
9 * Copyright (C) 2003-2018 Urs Fleisch
10 *
11 * This file is part of Kid3.
12 *
13 * Kid3 is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * Kid3 is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include "importconfig.h"
28 #include <QString>
29 #include "isettings.h"
30 #include "config.h"
31
32 namespace {
33
34 /**
35 * Convert tag version to import destination value in configuration.
36 * @param tagVersion tag version
37 * @return value used in configuration, kept for backwards compatibility.
38 */
tagVersionToImportDestCfg(Frame::TagVersion tagVersion)39 inline int tagVersionToImportDestCfg(Frame::TagVersion tagVersion) {
40 return static_cast<int>(tagVersion) - 1;
41 }
42
43 /**
44 * Convert import destination value in configuration to tag version.
45 * @param importDest value used in configuration, kept for backwards
46 * compatibility.
47 * @return tag version.
48 */
importDestCfgToTagVersion(int importDest)49 inline Frame::TagVersion importDestCfgToTagVersion(int importDest) {
50 return Frame::tagVersionCast(importDest + 1);
51 }
52
53 }
54
55 int ImportConfig::s_index = -1;
56
57 /**
58 * Constructor.
59 */
ImportConfig()60 ImportConfig::ImportConfig()
61 : StoredConfig<ImportConfig>(QLatin1String("Import")), m_importServer(0),
62 m_importDest(Frame::TagV1), m_importFormatIdx(0),
63 m_maxTimeDifference(3),
64 m_importVisibleColumns(0x2000000000ULL),
65 m_importTagsIdx(0),
66 m_pictureSourceIdx(0),
67 m_enableTimeDifferenceCheck(true)
68 {
69 /**
70 * Preset import format regular expressions.
71 * The following codes are used before the () expressions.
72 * %s %{title} title (song)
73 * %l %{album} album
74 * %a %{artist} artist
75 * %c %{comment} comment
76 * %y %{year} year
77 * %t %{track} track, at least two digits
78 * %T %{tracknumber} track number
79 * %g %{genre} genre
80 * %d %{duration} duration mm:ss
81 * %D %{seconds} duration in seconds
82 * %f %{file} file name
83 * %p %{filepath} absolute file path
84 * %u %{url} URL
85 * %n %{tracks} number of tracks
86 */
87 m_importFormatNames.append(QLatin1String("CSV unquoted"));
88 m_importFormatHeaders.append(QLatin1String(""));
89 m_importFormatTracks.append(QLatin1String(
90 R"(%{track}([^\r\n\t]*)\t%{title}([^\r\n\t]*)\t%{artist}([^\r\n\t]*)\t)"
91 R"(%{album}([^\r\n\t]*)\t%{year}([^\r\n\t]*)\t%{genre}([^\r\n\t]*)\t)"
92 R"(%{comment}([^\r\n\t]*)\t(?:\d+:)?%{duration}(\d+:\d+))"));
93
94 m_importFormatNames.append(QLatin1String("CSV quoted"));
95 m_importFormatHeaders.append(QLatin1String(""));
96 // Using a raw string literal here causes clang to issue
97 // "Unbalanced opening parenthesis in C++ code".
98 m_importFormatTracks.append(QLatin1String(
99 "\"?%{track}([^\\r\\n\\t\"]*)\"?\\t\"?%{title}([^\\r\\n\\t\"]*)\"?\\t\"?"
100 "%{artist}([^\\r\\n\\t\"]*)\"?\\t\"?%{album}([^\\r\\n\\t\"]*)\"?"
101 "\\t\"?%{year}([^\\r\\n\\t\"]*)\"?\\t\"?%{genre}([^\\r\\n\\t\"]*)\"?"
102 "\\t\"?%{comment}([^\\r\\n\\t\"]*)\"?\\t\"?(?:\\d+:)?%{duration}(\\d+:\\d+)"));
103
104 m_importFormatNames.append(QLatin1String("CSV more unquoted"));
105 m_importFormatHeaders.append(QLatin1String(""));
106 m_importFormatTracks.append(QLatin1String(
107 "%{track}([^\\r\\n\\t]*)\\t%{title}([^\\r\\n\\t]*)\\t%{artist}([^\\r\\n\\t]*)\\t"
108 "%{album}([^\\r\\n\\t]*)\\t%{year}([^\\r\\n\\t]*)\\t%{genre}([^\\r\\n\\t]*)\\"
109 "t%{comment}([^\\r\\n\\t]*)\\t(?:\\d+:)?%{duration}(\\d+:\\d+)(?:\\.\\d+)?\\t"
110 "%{album artist}([^\\r\\n\\t]*)\\t%{arranger}([^\\r\\n\\t]*)\\t"
111 "%{author}([^\\r\\n\\t]*)\\t%{bpm}([^\\r\\n\\t]*)\\t"
112 "%{composer}([^\\r\\n\\t]*)\\t%{conductor}([^\\r\\n\\t]*)\\t"
113 "%{copyright}([^\\r\\n\\t]*)\\t%{disc number}([^\\r\\n\\t]*)\\t"
114 "%{encoded-by}([^\\r\\n\\t]*)\\t%{grouping}([^\\r\\n\\t]*)\\t%{isrc}([^\\r\\n\\t]*)\\t"
115 "%{language}([^\\r\\n\\t]*)\\t%{lyricist}([^\\r\\n\\t]*)\\t%{lyrics}([^\\r\\n\\t]*)\\t"
116 "%{media}([^\\r\\n\\t]*)\\t%{original album}([^\\r\\n\\t]*)\\t"
117 "%{original artist}([^\\r\\n\\t]*)\\t%{original date}([^\\r\\n\\t]*)\\t"
118 "%{part}([^\\r\\n\\t]*)\\t%{performer}([^\\r\\n\\t]*)\\t"
119 "%{publisher}([^\\r\\n\\t]*)\\t%{remixer}([^\\r\\n\\t]*)\\t"
120 "%{subtitle}([^\\r\\n\\t]*)\\t%{website}([^\\r\\n\\t]*)"));
121
122 m_importFormatNames.append(QLatin1String("CSV more quoted"));
123 m_importFormatHeaders.append(QLatin1String(""));
124 m_importFormatTracks.append(QLatin1String(
125 "\"?%{track}([^\\r\\n\\t\"]*)\"?\\t\"?%{title}([^\\r\\n\\t\"]*)\"?\\t"
126 "\"?%{artist}([^\\r\\n\\t\"]*)\"?\\t\"?%{album}([^\\r\\n\\t\"]*)\"?\\t"
127 "\"?%{year}([^\\r\\n\\t\"]*)\"?\\t\"?%{genre}([^\\r\\n\\t\"]*)\"?\\t"
128 "\"?%{comment}([^\\r\\n\\t\"]*)\"?\\t"
129 "\"?(?:\\d+:)?%{duration}(\\d+:\\d+)(?:\\.\\d+)?\"?\\t"
130 "\"?%{album artist}([^\\r\\n\\t\"]*)\"?\\t\"?%{arranger}([^\\r\\n\\t\"]*)\"?\\t"
131 "\"?%{author}([^\\r\\n\\t\"]*)\"?\\t\"?%{bpm}([^\\r\\n\\t\"]*)\"?\\t"
132 "\"?%{composer}([^\\r\\n\\t\"]*)\"?\\t\"?%{conductor}([^\\r\\n\\t\"]*)\"?\\t"
133 "\"?%{copyright}([^\\r\\n\\t\"]*)\"?\\t\"?%{disc number}([^\\r\\n\\t\"]*)\"?\\t"
134 "\"?%{encoded-by}([^\\r\\n\\t\"]*)\"?\\t\"?%{grouping}([^\\r\\n\\t\"]*)\"?\\t"
135 "\"?%{isrc}([^\\r\\n\\t\"]*)\"?\\t"
136 "\"?%{language}([^\\r\\n\\t\"]*)\"?\\t\"?%{lyricist}([^\\r\\n\\t\"]*)\"?\\t"
137 "\"?%{lyrics}([^\\r\\n\\t\"]*)\"?\\t"
138 "\"?%{media}([^\\r\\n\\t\"]*)\"?\\t\"?%{original album}([^\\r\\n\\t\"]*)\"?\\t"
139 "\"?%{original artist}([^\\r\\n\\t\"]*)\"?\\t\"?%{original date}([^\\r\\n\\t\"]*)\"?\\t"
140 "\"?%{part}([^\\r\\n\\t\"]*)\"?\\t\"?%{performer}([^\\r\\n\\t\"]*)\"?\\t"
141 "\"?%{publisher}([^\\r\\n\\t\"]*)\"?\\t\"?%{remixer}([^\\r\\n\\t\"]*)\"?\\t"
142 "\"?%{subtitle}([^\\r\\n\\t\"]*)\"?\\t\"?%{website}([^\\r\\n\\t\"]*)"));
143
144 m_importFormatNames.append(QLatin1String("freedb HTML text"));
145 m_importFormatHeaders.append(QLatin1String(
146 R"(%{artist}(\S[^\r\n/]*\S)\s*/\s*%{album}(\S[^\r\n]*\S)[\r\n]+\s*)"
147 R"(tracks:\s+\d+.*year:\s*%{year}([^\r\n\t]*)?.*)"
148 R"(genre:\s*%{genre}(\S[^\r\n]*\S)?[\r\n])"));
149 m_importFormatTracks.append(QLatin1String(
150 R"([\r\n]%{track}(\d+)[\.\s]+%{duration}(\d+:\d+)\s+%{title}(\S[^\r\n]*\S))"));
151
152 m_importFormatNames.append(QLatin1String("freedb HTML source"));
153 m_importFormatHeaders.append(QLatin1String(
154 R"(<[^>]+>%{artist}([^<\s][^\r\n/]*\S)\s*/\s*)"
155 R"(%{album}(\S[^\r\n]*[^\s>])<[^>]+>[\r\n]+\s*)"
156 R"(tracks:\s+\d+.*year:\s*%{year}([^\r\n\t]*)?.*)"
157 R"(genre:\s*%{genre}(\S[^\r\n>]*\S)?<[^>]+>[\r\n])"));
158 m_importFormatTracks.append(QLatin1String(
159 R"(<td[^>]*>\s*%{track}(\d+).</td><td[^>]*>\s*%{duration}(\d+:\d+)</td>)"
160 R"(<td[^>]*>(?:<[^>]+>)?%{title}([^<\r\n]+))"));
161
162 m_importFormatNames.append(QLatin1String("Title"));
163 m_importFormatHeaders.append(QLatin1String(""));
164 m_importFormatTracks.append(QLatin1String(R"(\s*%{title}(\S[^\r\n]*\S)\s*)"));
165
166 m_importFormatNames.append(QLatin1String("Track Title"));
167 m_importFormatHeaders.append(QLatin1String(""));
168 m_importFormatTracks.append(QLatin1String(
169 R"(\s*%{track}(\d+)[\.\s]+%{title}(\S[^\r\n]*\S)\s*)"));
170
171 m_importFormatNames.append(QLatin1String("Track Title Time"));
172 m_importFormatHeaders.append(QLatin1String(""));
173 m_importFormatTracks.append(QLatin1String(
174 R"(\s*%{track}(\d+)[\.\s]+%{title}(\S[^\r\n]*\S)\s+%{duration}(\d+:\d+)\s*)"));
175
176 m_importFormatNames.append(QLatin1String("Custom Format"));
177 m_importFormatHeaders.append(QLatin1String(""));
178 m_importFormatTracks.append(QLatin1String(""));
179
180 m_importTagsNames.append(QLatin1String("Artist to Album Artist"));
181 m_importTagsSources.append(QLatin1String("%{artist}"));
182 m_importTagsExtractions.append(QLatin1String("%{albumartist}(.+)"));
183
184 m_importTagsNames.append(QLatin1String("Album Artist to Artist"));
185 m_importTagsSources.append(QLatin1String("%{albumartist}"));
186 m_importTagsExtractions.append(QLatin1String("%{artist}(.+)"));
187
188 m_importTagsNames.append(QLatin1String("Artist to Composer"));
189 m_importTagsSources.append(QLatin1String("%{artist}"));
190 m_importTagsExtractions.append(QLatin1String("%{composer}(.+)"));
191
192 m_importTagsNames.append(QLatin1String("Artist to Conductor"));
193 m_importTagsSources.append(QLatin1String("%{artist}"));
194 m_importTagsExtractions.append(QLatin1String("%{conductor}(.+)"));
195
196 m_importTagsNames.append(QLatin1String("Track Number from Title"));
197 m_importTagsSources.append(QLatin1String("%{title}"));
198 m_importTagsExtractions.append(
199 QLatin1String(R"(\s*%{track}(\d+)[\.\s]+%{title}(\S.*\S)\s*)"));
200
201 m_importTagsNames.append(QLatin1String("Track Number to Title"));
202 m_importTagsSources.append(QLatin1String("%{track} %{title}"));
203 m_importTagsExtractions.append(QLatin1String("%{title}(.+)"));
204
205 m_importTagsNames.append(QLatin1String("Subtitle from Title"));
206 m_importTagsSources.append(QLatin1String("%{title}"));
207 m_importTagsExtractions.append(QLatin1String("%{subtitle}(.+) - "));
208
209 m_importTagsNames.append(QLatin1String("Title Annotation to Comment"));
210 m_importTagsSources.append(QLatin1String("%{title}"));
211 m_importTagsExtractions.append(
212 QLatin1String("%{title}(.+) +\\(%{comment}((?:Bonus|Remix)[^)]*)\\)"));
213
214 m_importTagsNames.append(QLatin1String("Modification Date to Date"));
215 m_importTagsSources.append(QLatin1String("%{modificationdate}"));
216 m_importTagsExtractions.append(QLatin1String(R"(%{date}(\d\d\d\d-\d\d-\d\d))"));
217
218 m_importTagsNames.append(QLatin1String("Filename to Original Filename"));
219 m_importTagsSources.append(QLatin1String("%{file}"));
220 m_importTagsExtractions.append(QLatin1String("%{TOFN}(.+)"));
221
222 m_importTagsNames.append(QLatin1String("Custom Format"));
223 m_importTagsSources.append(QLatin1String(""));
224 m_importTagsExtractions.append(QLatin1String(""));
225
226 m_pictureSourceNames.append(QLatin1String("Google Images"));
227 m_pictureSourceUrls.append(QLatin1String(
228 "http://www.google.com/search?tbm=isch&q=%u{artist}%20%u{album}"));
229 m_pictureSourceNames.append(QLatin1String("Yahoo Images"));
230 m_pictureSourceUrls.append(QLatin1String(
231 "http://images.search.yahoo.com/search/images?ei=UTF-8&p=%u{artist}%20%u{album}"));
232 m_pictureSourceNames.append(QLatin1String("Amazon"));
233 m_pictureSourceUrls.append(QLatin1String(
234 "http://www.amazon.com/s?search-alias=aps&field-keywords=%u{artist}+%u{album}"));
235 m_pictureSourceNames.append(QLatin1String("Amazon.co.uk"));
236 m_pictureSourceUrls.append(QLatin1String(
237 "http://www.amazon.co.uk/s?search-alias=aps&field-keywords=%u{artist}+%u{album}"));
238 m_pictureSourceNames.append(QLatin1String("Amazon.de"));
239 m_pictureSourceUrls.append(QLatin1String(
240 "http://www.amazon.de/s?search-alias=aps&field-keywords=%u{artist}+%u{album}"));
241 m_pictureSourceNames.append(QLatin1String("Amazon.fr"));
242 m_pictureSourceUrls.append(QLatin1String(
243 "http://www.amazon.fr/s?search-alias=aps&field-keywords=%u{artist}+%u{album}"));
244 m_pictureSourceNames.append(QLatin1String("MusicBrainz"));
245 m_pictureSourceUrls.append(QLatin1String(
246 "http://musicbrainz.org/search/textsearch.html?query=%u{artist}+%u{album}&type=release"));
247 m_pictureSourceNames.append(QLatin1String("Discogs"));
248 m_pictureSourceUrls.append(QLatin1String(
249 "http://www.discogs.com/search?q=%u{artist}+%u{album}"));
250 m_pictureSourceNames.append(QLatin1String("CD Universe"));
251 m_pictureSourceUrls.append(QLatin1String(
252 "http://www.cduniverse.com/sresult.asp?HT_Search_Info=%u{artist}+%u{album}"));
253 m_pictureSourceNames.append(QLatin1String("Coveralia"));
254 m_pictureSourceUrls.append(QLatin1String(
255 "http://www.coveralia.com/mostrar.php?bus=%u{artist}%20%u{album}&bust=2"));
256 m_pictureSourceNames.append(QLatin1String("SlothRadio"));
257 m_pictureSourceUrls.append(QLatin1String(
258 "http://www.slothradio.com/covers/?artist=%u{artist}&album=%u{album}"));
259 m_pictureSourceNames.append(QLatin1String("Albumart"));
260 m_pictureSourceUrls.append(QLatin1String(
261 "http://www.albumart.org/index.php?srchkey=%u{artist}+%u{album}&searchindex=Music"));
262 m_pictureSourceNames.append(QLatin1String("Custom Source"));
263 m_pictureSourceUrls.append(QLatin1String(""));
264
265 m_matchPictureUrlMap.append({
266 {QLatin1String("https?://www.google.(?:[^/]+)/.*imgurl=([^&]+)&.*"),
267 QLatin1String("\\1")},
268 {QLatin1String("http://images.search.yahoo.com/.*&imgurl=([^&]+)&.*"),
269 QLatin1String("http%3A%2F%2F\\1")},
270 {QLatin1String(
271 "http://(?:www.)?amazon.(?:com|co.uk|de|fr).*/(?:dp|ASIN|images|product|-)/([A-Z0-9]+).*"),
272 QLatin1String("http://images.amazon.com/images/P/\\1.01._SCLZZZZZZZ_.jpg")},
273 {QLatin1String(
274 "http://musicbrainz.org/misc/redirects/.*&asin=([A-Z0-9]+).*"),
275 QLatin1String("http://images.amazon.com/images/P/\\1.01._SCLZZZZZZZ_.jpg")},
276 {QLatin1String("(http://.*4shared.com/img/.*)"),
277 QLatin1String("\\1.jpg")}
278 });
279 }
280
281 /**
282 * Persist configuration.
283 *
284 * @param config configuration
285 */
writeToConfig(ISettings * config) const286 void ImportConfig::writeToConfig(ISettings* config) const
287 {
288 config->beginGroup(m_group);
289 config->setValue(QLatin1String("ImportServer"),
290 QVariant(m_importServer));
291 config->setValue(QLatin1String("ImportDestination"),
292 QVariant(tagVersionToImportDestCfg(m_importDest)));
293 config->setValue(QLatin1String("ImportFormatNames"),
294 QVariant(m_importFormatNames));
295 config->setValue(QLatin1String("ImportFormatHeaders"),
296 QVariant(m_importFormatHeaders));
297 config->setValue(QLatin1String("ImportFormatTracks"),
298 QVariant(m_importFormatTracks));
299 config->setValue(QLatin1String("ImportFormatIdx"),
300 QVariant(m_importFormatIdx));
301 config->setValue(QLatin1String("EnableTimeDifferenceCheck"),
302 QVariant(m_enableTimeDifferenceCheck));
303 config->setValue(QLatin1String("MaxTimeDifference"),
304 QVariant(m_maxTimeDifference));
305 #ifdef Q_OS_MAC
306 // Convince Mac OS X to store a 64-bit value.
307 config->setValue(QLatin1String("ImportVisibleColumns"),
308 QVariant(m_importVisibleColumns | (Q_UINT64_C(1) << 63)));
309 #else
310 config->setValue(QLatin1String("ImportVisibleColumns"),
311 QVariant(m_importVisibleColumns));
312 #endif
313 config->setValue(QLatin1String("ImportWindowGeometry"),
314 QVariant(m_importWindowGeometry));
315
316 config->setValue(QLatin1String("ImportTagsNames"),
317 QVariant(m_importTagsNames));
318 config->setValue(QLatin1String("ImportTagsSources"),
319 QVariant(m_importTagsSources));
320 config->setValue(QLatin1String("ImportTagsExtractions"),
321 QVariant(m_importTagsExtractions));
322 config->setValue(QLatin1String("ImportTagsIdx"),
323 QVariant(m_importTagsIdx));
324
325 config->setValue(QLatin1String("PictureSourceNames"),
326 QVariant(m_pictureSourceNames));
327 config->setValue(QLatin1String("PictureSourceUrls"),
328 QVariant(m_pictureSourceUrls));
329 config->setValue(QLatin1String("PictureSourceIdx"),
330 QVariant(m_pictureSourceIdx));
331 QStringList keys, values;
332 for (auto it = m_matchPictureUrlMap.constBegin();
333 it != m_matchPictureUrlMap.constEnd();
334 ++it) {
335 keys.append(it->first);
336 values.append(it->second);
337 }
338 config->setValue(QLatin1String("MatchPictureUrlMapKeys"), QVariant(keys));
339 config->setValue(QLatin1String("MatchPictureUrlMapValues"), QVariant(values));
340 config->setValue(QLatin1String("BrowseCoverArtWindowGeometry"),
341 QVariant(m_browseCoverArtWindowGeometry));
342
343 config->setValue(QLatin1String("DisabledPlugins"),
344 QVariant(m_disabledPlugins));
345 config->endGroup();
346 }
347
348 /**
349 * Read persisted configuration.
350 *
351 * @param config configuration
352 */
readFromConfig(ISettings * config)353 void ImportConfig::readFromConfig(ISettings* config)
354 {
355 QStringList names, headers, tracks;
356 QStringList tagsNames, tagsSources, tagsExtractions;
357 QStringList picNames, picUrls;
358
359 config->beginGroup(m_group);
360 m_importServer = config->value(QLatin1String("ImportServer"),
361 m_importServer).toInt();
362 m_importDest = importDestCfgToTagVersion(
363 config->value(QLatin1String("ImportDestination"),
364 tagVersionToImportDestCfg(m_importDest)).toInt());
365 names = config->value(QLatin1String("ImportFormatNames"),
366 m_importFormatNames).toStringList();
367 headers = config->value(QLatin1String("ImportFormatHeaders"),
368 m_importFormatHeaders).toStringList();
369 tracks = config->value(QLatin1String("ImportFormatTracks"),
370 m_importFormatTracks).toStringList();
371 m_importFormatIdx = config->value(QLatin1String("ImportFormatIdx"),
372 m_importFormatIdx).toInt();
373 m_enableTimeDifferenceCheck =
374 config->value(QLatin1String("EnableTimeDifferenceCheck"),
375 m_enableTimeDifferenceCheck).toBool();
376 m_maxTimeDifference = config->value(QLatin1String("MaxTimeDifference"),
377 m_maxTimeDifference).toInt();
378 m_importVisibleColumns = config->value(QLatin1String("ImportVisibleColumns"),
379 m_importVisibleColumns).toULongLong();
380 #ifdef Q_OS_MAC
381 m_importVisibleColumns &= ~(Q_UINT64_C(1) << 63);
382 #endif
383 m_importWindowGeometry = config->value(QLatin1String("ImportWindowGeometry"),
384 m_importWindowGeometry).toByteArray();
385
386 tagsNames = config->value(QLatin1String("ImportTagsNames"),
387 m_importTagsNames).toStringList();
388 tagsSources = config->value(QLatin1String("ImportTagsSources"),
389 m_importTagsSources).toStringList();
390 tagsExtractions = config->value(QLatin1String("ImportTagsExtractions"),
391 m_importTagsExtractions).toStringList();
392 m_importTagsIdx = config->value(QLatin1String("ImportTagsIdx"),
393 m_importTagsIdx).toInt();
394
395 picNames = config->value(QLatin1String("PictureSourceNames"),
396 m_pictureSourceNames).toStringList();
397 picUrls = config->value(QLatin1String("PictureSourceUrls"),
398 m_pictureSourceUrls).toStringList();
399 m_pictureSourceIdx = config->value(
400 QLatin1String("PictureSourceIdx"), m_pictureSourceIdx).toInt();
401 QStringList keys = config->value(QLatin1String("MatchPictureUrlMapKeys"),
402 QStringList()).toStringList();
403 QStringList values = config->value(QLatin1String("MatchPictureUrlMapValues"),
404 QStringList()).toStringList();
405 if (!keys.empty() && !values.empty()) {
406 m_matchPictureUrlMap.clear();
407 for (auto itk = keys.constBegin(), itv = values.constBegin();
408 itk != keys.constEnd() && itv != values.constEnd();
409 ++itk, ++itv) {
410 m_matchPictureUrlMap.append({*itk, *itv});
411 }
412 }
413 m_browseCoverArtWindowGeometry = config->value(
414 QLatin1String("BrowseCoverArtWindowGeometry"),
415 m_browseCoverArtWindowGeometry).toByteArray();
416
417 m_disabledPlugins = config->value(QLatin1String("DisabledPlugins"),
418 m_disabledPlugins).toStringList();
419 config->endGroup();
420
421 // KConfig seems to strip empty entries from the end of the string lists,
422 // so we have to append them again.
423 const int numNames = names.size();
424 while (headers.size() < numNames) headers.append(QLatin1String(""));
425 while (tracks.size() < numNames) tracks.append(QLatin1String(""));
426 const int numPicNames = picNames.size();
427 while (picUrls.size() < numPicNames) picUrls.append(QLatin1String(""));
428
429 /* Use defaults if no configuration found */
430 for (auto namesIt = names.constBegin(), headersIt = headers.constBegin(),
431 tracksIt = tracks.constBegin();
432 namesIt != names.constEnd() && headersIt != headers.constEnd() &&
433 tracksIt != tracks.constEnd();
434 ++namesIt, ++headersIt, ++tracksIt) {
435 int idx = m_importFormatNames.indexOf(*namesIt);
436 if (idx >= 0) {
437 m_importFormatHeaders[idx] = *headersIt;
438 m_importFormatTracks[idx] = *tracksIt;
439 } else if (!(*namesIt).isEmpty()) {
440 m_importFormatNames.append(*namesIt);
441 m_importFormatHeaders.append(*headersIt);
442 m_importFormatTracks.append(*tracksIt);
443 }
444 }
445
446 for (auto tagsNamesIt = tagsNames.constBegin(), sourcesIt = tagsSources.constBegin(),
447 extractionsIt = tagsExtractions.constBegin();
448 tagsNamesIt != tagsNames.constEnd() && sourcesIt != tagsSources.constEnd() &&
449 extractionsIt != tagsExtractions.constEnd();
450 ++tagsNamesIt, ++sourcesIt, ++extractionsIt) {
451 int idx = m_importTagsNames.indexOf(*tagsNamesIt);
452 if (idx >= 0) {
453 m_importTagsSources[idx] = *sourcesIt;
454 m_importTagsExtractions[idx] = *extractionsIt;
455 } else if (!(*tagsNamesIt).isEmpty()) {
456 m_importTagsNames.append(*tagsNamesIt);
457 m_importTagsSources.append(*sourcesIt);
458 m_importTagsExtractions.append(*extractionsIt);
459 }
460 }
461
462 for (auto picNamesIt = picNames.constBegin(), picUrlsIt = picUrls.constBegin();
463 picNamesIt != picNames.constEnd() && picUrlsIt != picUrls.constEnd();
464 ++picNamesIt, ++picUrlsIt) {
465 int idx = m_pictureSourceNames.indexOf(*picNamesIt);
466 if (idx >= 0) {
467 m_pictureSourceUrls[idx] = *picUrlsIt;
468 } else if (!(*picNamesIt).isEmpty()) {
469 m_pictureSourceNames.append(*picNamesIt);
470 m_pictureSourceUrls.append(*picUrlsIt);
471 }
472 }
473
474 if (m_importFormatIdx >= static_cast<int>(m_importFormatNames.size()))
475 m_importFormatIdx = 0;
476 if (m_importTagsIdx >= static_cast<int>(m_importTagsNames.size()))
477 m_importTagsIdx = 0;
478 if (m_pictureSourceIdx >= static_cast<int>(m_pictureSourceNames.size()))
479 m_pictureSourceIdx = 0;
480
481 // Replace mappings which do no longer work.
482 if (m_pictureSourceUrls.removeOne(QLatin1String(
483 "http://cdbaby.com/found?artist=%u{artist}&album=%u{album}"))) {
484 m_pictureSourceNames.removeOne(QLatin1String("CD Baby"));
485 }
486 if (m_pictureSourceUrls.removeOne(QLatin1String(
487 "http://www.jamendo.com/en/search/all/%u{artist}%20%u{album}"))) {
488 m_pictureSourceNames.removeOne(QLatin1String("Jamendo"));
489 }
490 m_pictureSourceUrls.replaceInStrings(
491 QLatin1String("http://images.google.com/images?q=%u{artist}%20%u{album}"),
492 QLatin1String("http://www.google.com/search?tbm=isch&q=%u{artist}%20%u{album}"));
493 for (auto it = m_matchPictureUrlMap.begin(); it != m_matchPictureUrlMap.end();) {
494 if (it->first == QLatin1String(
495 "http://images.google.com/.*imgurl=([^&]+)&.*") ||
496 it->first == QLatin1String(
497 "http://www.google.com/.*imgurl=([^&]+)&.*") ||
498 it->first == QLatin1String(
499 "http://www.google.(?:[^/]+)/.*imgurl=([^&]+)&.*")) {
500 *it = {QLatin1String("https?://www.google.(?:[^/]+)/.*imgurl=([^&]+)&.*"),
501 QLatin1String("\\1")};
502 } else if (it->first == QLatin1String(
503 "http://rds.yahoo.com/.*&imgurl=([^&]+)&.*")) {
504 *it = {QLatin1String(
505 "http://images.search.yahoo.com/.*&imgurl=([^&]+)&.*"),
506 QLatin1String("http%3A%2F%2F\\1")};
507 } else if (it->first == QLatin1String(
508 "http://rds.yahoo.com/.*%26imgurl=((?:[^%]|%(?!26))+).*") ||
509 it->first == QLatin1String(
510 R"(http://cdbaby.com/cd/(\w)(\w)(\w+))") ||
511 it->first == QLatin1String(
512 "http://www.jamendo.com/en/album/(\\d+)")) {
513 it = m_matchPictureUrlMap.erase(it);
514 continue;
515 }
516 ++it;
517 }
518 }
519
setAvailablePlugins(const QStringList & availablePlugins)520 void ImportConfig::setAvailablePlugins(const QStringList& availablePlugins)
521 {
522 if (m_availablePlugins != availablePlugins) {
523 m_availablePlugins = availablePlugins;
524 emit availablePluginsChanged(m_availablePlugins);
525 }
526 }
527
setImportServer(int importServer)528 void ImportConfig::setImportServer(int importServer)
529 {
530 if (m_importServer != importServer) {
531 m_importServer = importServer;
532 emit importServerChanged(m_importServer);
533 }
534 }
535
setImportDest(Frame::TagVersion importDest)536 void ImportConfig::setImportDest(Frame::TagVersion importDest)
537 {
538 if (m_importDest != importDest) {
539 m_importDest = importDest;
540 emit importDestChanged(m_importDest);
541 }
542 }
543
setImportFormatNames(const QStringList & importFormatNames)544 void ImportConfig::setImportFormatNames(const QStringList& importFormatNames)
545 {
546 if (m_importFormatNames != importFormatNames) {
547 m_importFormatNames = importFormatNames;
548 emit importFormatNamesChanged(m_importFormatNames);
549 }
550 }
551
setImportFormatHeaders(const QStringList & importFormatHeaders)552 void ImportConfig::setImportFormatHeaders(const QStringList& importFormatHeaders)
553 {
554 if (m_importFormatHeaders != importFormatHeaders) {
555 m_importFormatHeaders = importFormatHeaders;
556 emit importFormatHeadersChanged(m_importFormatHeaders);
557 }
558 }
559
setImportFormatTracks(const QStringList & importFormatTracks)560 void ImportConfig::setImportFormatTracks(const QStringList& importFormatTracks)
561 {
562 if (m_importFormatTracks != importFormatTracks) {
563 m_importFormatTracks = importFormatTracks;
564 emit importFormatTracksChanged(m_importFormatTracks);
565 }
566 }
567
setImportFormatIndex(int importFormatIdx)568 void ImportConfig::setImportFormatIndex(int importFormatIdx)
569 {
570 if (m_importFormatIdx != importFormatIdx) {
571 m_importFormatIdx = importFormatIdx;
572 emit importFormatIndexChanged(m_importFormatIdx);
573 }
574 }
575
setMaxTimeDifference(int maxTimeDifference)576 void ImportConfig::setMaxTimeDifference(int maxTimeDifference)
577 {
578 if (m_maxTimeDifference != maxTimeDifference) {
579 m_maxTimeDifference = maxTimeDifference;
580 emit maxTimeDifferenceChanged(m_maxTimeDifference);
581 }
582 }
583
setImportVisibleColumns(quint64 importVisibleColumns)584 void ImportConfig::setImportVisibleColumns(quint64 importVisibleColumns)
585 {
586 if (m_importVisibleColumns != importVisibleColumns) {
587 m_importVisibleColumns = importVisibleColumns;
588 emit importVisibleColumnsChanged(m_importVisibleColumns);
589 }
590 }
591
setImportWindowGeometry(const QByteArray & importWindowGeometry)592 void ImportConfig::setImportWindowGeometry(const QByteArray& importWindowGeometry)
593 {
594 if (m_importWindowGeometry != importWindowGeometry) {
595 m_importWindowGeometry = importWindowGeometry;
596 emit importWindowGeometryChanged(m_importWindowGeometry);
597 }
598 }
599
setImportTagsNames(const QStringList & importTagsNames)600 void ImportConfig::setImportTagsNames(const QStringList& importTagsNames)
601 {
602 if (m_importTagsNames != importTagsNames) {
603 m_importTagsNames = importTagsNames;
604 emit importTagsNamesChanged(m_importTagsNames);
605 }
606 }
607
setImportTagsSources(const QStringList & importTagsSources)608 void ImportConfig::setImportTagsSources(const QStringList& importTagsSources)
609 {
610 if (m_importTagsSources != importTagsSources) {
611 m_importTagsSources = importTagsSources;
612 emit importTagsSourcesChanged(m_importTagsSources);
613 }
614 }
615
setImportTagsExtractions(const QStringList & importTagsExtractions)616 void ImportConfig::setImportTagsExtractions(const QStringList& importTagsExtractions)
617 {
618 if (m_importTagsExtractions != importTagsExtractions) {
619 m_importTagsExtractions = importTagsExtractions;
620 emit importTagsExtractionsChanged(m_importTagsExtractions);
621 }
622 }
623
setImportTagsIndex(int importTagsIdx)624 void ImportConfig::setImportTagsIndex(int importTagsIdx)
625 {
626 if (m_importTagsIdx != importTagsIdx) {
627 m_importTagsIdx = importTagsIdx;
628 emit importTagsIndexChanged(m_importTagsIdx);
629 }
630 }
631
setPictureSourceNames(const QStringList & pictureSourceNames)632 void ImportConfig::setPictureSourceNames(const QStringList& pictureSourceNames)
633 {
634 if (m_pictureSourceNames != pictureSourceNames) {
635 m_pictureSourceNames = pictureSourceNames;
636 emit pictureSourceNamesChanged(m_pictureSourceNames);
637 }
638 }
639
setPictureSourceUrls(const QStringList & pictureSourceUrls)640 void ImportConfig::setPictureSourceUrls(const QStringList& pictureSourceUrls)
641 {
642 if (m_pictureSourceUrls != pictureSourceUrls) {
643 m_pictureSourceUrls = pictureSourceUrls;
644 emit pictureSourceUrlsChanged(m_pictureSourceUrls);
645 }
646 }
647
648
setPictureSourceIndex(int pictureSourceIdx)649 void ImportConfig::setPictureSourceIndex(int pictureSourceIdx)
650 {
651 if (m_pictureSourceIdx != pictureSourceIdx) {
652 m_pictureSourceIdx = pictureSourceIdx;
653 emit pictureSourceIndexChanged(m_pictureSourceIdx);
654 }
655 }
656
setBrowseCoverArtWindowGeometry(const QByteArray & browseCoverArtWindowGeometry)657 void ImportConfig::setBrowseCoverArtWindowGeometry(const QByteArray& browseCoverArtWindowGeometry)
658 {
659 if (m_browseCoverArtWindowGeometry != browseCoverArtWindowGeometry) {
660 m_browseCoverArtWindowGeometry = browseCoverArtWindowGeometry;
661 emit browseCoverArtWindowGeometryChanged(m_browseCoverArtWindowGeometry);
662 }
663 }
664
setMatchPictureUrlMap(const QList<QPair<QString,QString>> & matchPictureUrlMap)665 void ImportConfig::setMatchPictureUrlMap(const QList<QPair<QString, QString>>& matchPictureUrlMap)
666 {
667 if (m_matchPictureUrlMap != matchPictureUrlMap) {
668 m_matchPictureUrlMap = matchPictureUrlMap;
669 emit matchPictureUrlMapChanged(m_matchPictureUrlMap);
670 }
671 }
672
matchPictureUrlStringList() const673 QStringList ImportConfig::matchPictureUrlStringList() const
674 {
675 QStringList lst;
676 QList<QPair<QString, QString>> urlMap = matchPictureUrlMap();
677 for (auto it = urlMap.constBegin(); it != urlMap.constEnd(); ++it) {
678 lst.append(it->first);
679 lst.append(it->second);
680 }
681 return lst;
682 }
683
setMatchPictureUrlStringList(const QStringList & lst)684 void ImportConfig::setMatchPictureUrlStringList(const QStringList& lst)
685 {
686 QList<QPair<QString, QString>> urlMap;
687 auto it = lst.constBegin();
688 while (it != lst.constEnd()) {
689 QString key = *it++;
690 if (it != lst.constEnd()) {
691 urlMap.append({key, *it++});
692 }
693 }
694 setMatchPictureUrlMap(urlMap);
695 }
696
setImportDir(const QString & importDir)697 void ImportConfig::setImportDir(const QString& importDir)
698 {
699 if (m_importDir != importDir) {
700 m_importDir = importDir;
701 emit importDirChanged(m_importDir);
702 }
703 }
704
setDisabledPlugins(const QStringList & disabledPlugins)705 void ImportConfig::setDisabledPlugins(const QStringList& disabledPlugins)
706 {
707 if (m_disabledPlugins != disabledPlugins) {
708 m_disabledPlugins = disabledPlugins;
709 emit disabledPluginsChanged(m_disabledPlugins);
710 }
711 }
712
setEnableTimeDifferenceCheck(bool enableTimeDifferenceCheck)713 void ImportConfig::setEnableTimeDifferenceCheck(bool enableTimeDifferenceCheck)
714 {
715 if (m_enableTimeDifferenceCheck != enableTimeDifferenceCheck) {
716 m_enableTimeDifferenceCheck = enableTimeDifferenceCheck;
717 emit enableTimeDifferenceCheckChanged(m_enableTimeDifferenceCheck);
718 }
719 }
720