91
* Remove trailing stars and numbers like (2) from a string.
95
* @return fixed up string.
97
static QString fixUpArtist(QString str)
99
str.replace(QRegExp(",(\\S)"), ", \\1");
100
str.replace("* / ", " / ");
101
str.replace("*,", ",");
102
str.remove(QRegExp("\\*$"));
103
str.remove(QRegExp("[*\\s]*\\(\\d+\\)\\(tracks:[^)]+\\)"));
104
str.replace(QRegExp("[*\\s]*\\((?:\\d+|tracks:[^)]+)\\) / "), " / ");
105
str.replace(QRegExp("[*\\s]*\\((?:\\d+|tracks:[^)]+)\\),"), ",");
106
return str.remove(QRegExp("[*\\s]*\\((?:\\d+|tracks:[^)]+)\\)$"));
111
* Add involved people to a frame.
112
* The format used is (should be converted according to tag specifications):
113
* involvee 1 (involvement 1)\n
114
* involvee 2 (involvement 2)\n
116
* involvee n (involvement n)
118
* @param frames frame collection
119
* @param type type of frame
120
* @param involvement involvement (e.g. instrument)
121
* @param involvee name of involvee (e.g. musician)
123
static void addInvolvedPeople(
124
FrameCollection& frames, Frame::Type type,
125
const QString& involvement, const QString& involvee)
127
QString value = frames.getValue(type);
128
if (!value.isEmpty()) value += Frame::stringListSeparator();
129
value += involvement;
130
value += Frame::stringListSeparator();
132
frames.setValue(type, value);
136
* Set tags from a string with credits lines.
137
* The string must have lines like "Composed By - Iommi", separated by \\n.
139
* @param str credits string
140
* @param frames tags will be added to these frames
142
* @return true if credits found.
144
static bool parseCredits(const QString& str, FrameCollection& frames)
147
QStringList lines = QCM_split("\n", str);
148
for (QStringList::const_iterator it = lines.begin();
151
int nameStart = (*it).QCM_indexOf(" - ");
152
if (nameStart != -1) {
153
QString name(fixUpArtist((*it).mid(nameStart + 3)));
154
QStringList credits = QCM_split(", ", (*it).left(nameStart));
155
for (QStringList::const_iterator cit = credits.begin();
156
cit != credits.end();
158
static const struct {
162
{ "Composed By", Frame::FT_Composer },
163
{ "Conductor", Frame::FT_Conductor },
164
{ "Orchestra", Frame::FT_AlbumArtist },
165
{ "Lyrics By", Frame::FT_Lyricist },
166
{ "Written-By", Frame::FT_Author },
167
{ "Written By", Frame::FT_Author },
168
{ "Remix", Frame::FT_Remixer },
169
{ "Music By", Frame::FT_Composer },
170
{ "Songwriter", Frame::FT_Composer }
174
i < sizeof(creditToType) / sizeof(creditToType[0]);
176
if (*cit == creditToType[i].credit) {
177
frames.setValue(creditToType[i].type, name);
185
static const struct {
187
const char* arrangement;
188
} creditToArrangement[] = {
189
{ "Arranged By", "Arranger" },
190
{ "Mixed By", "Mixer" },
191
{ "DJ Mix", "DJMixer" },
192
{ "Dj Mix", "DJMixer" },
193
{ "Engineer", "Engineer" },
194
{ "Mastered By", "Engineer" },
195
{ "Producer", "Producer" },
196
{ "Co-producer", "Producer" },
197
{ "Executive Producer", "Producer" }
200
i < sizeof(creditToArrangement) / sizeof(creditToArrangement[0]);
202
if ((*cit).startsWith(creditToArrangement[i].credit)) {
203
addInvolvedPeople(frames, Frame::FT_Arranger,
204
creditToArrangement[i].arrangement, name);
213
static const char* const instruments[] = {
214
"Performer", "Vocals", "Voice", "Featuring", "Choir", "Chorus",
215
"Baritone", "Tenor", "Rap", "Scratches", "Drums", "Percussion",
216
"Keyboards", "Cello", "Piano", "Organ", "Synthesizer", "Keys",
217
"Wurlitzer", "Rhodes", "Harmonica", "Xylophone", "Guitar", "Bass",
218
"Strings", "Violin", "Viola", "Banjo", "Harp", "Mandolin",
219
"Clarinet", "Horn", "Cornet", "Flute", "Oboe", "Saxophone",
220
"Trumpet", "Tuba", "Trombone"
223
i < sizeof(instruments) / sizeof(instruments[0]);
225
if ((*cit).contains(instruments[i])) {
226
addInvolvedPeople(frames, Frame::FT_Performer, *cit, name);
90
242
* Parse result of album request and populate m_trackDataVector with results.
92
244
* @param albumStr album data received
182
333
if (genreNum != 255) {
183
stHdr.genre = Genres::getName(genreNum);
334
framesHdr.setGenre(Genres::getName(genreNum));
184
335
} else if (!genreList.empty()) {
185
stHdr.genre = genreList.front();
336
framesHdr.setGenre(genreList.front());
339
const bool additionalTags = getAdditionalTags();
340
if (additionalTags) {
342
* publisher can be found in "Label:"
344
start = str.QCM_indexOf("Label:");
346
start += 6; // skip "Label:"
347
end = str.QCM_indexOf("</tr>", start);
349
QString labelStr = str.mid(start, end - start);
350
labelStr.replace(nlSpaceRe, ""); // strip new lines and space after them
351
labelStr.replace(htmlTagRe, ""); // strip HTML tags
352
labelStr = fixUpArtist(labelStr);
353
if (labelStr != "Not On Label") {
354
framesHdr.setValue(Frame::FT_Publisher, labelStr);
360
* media can be found in "Format:"
362
start = str.QCM_indexOf("Format:");
364
start += 7; // skip "Format:"
365
end = str.QCM_indexOf("</tr>", start);
367
QString mediaStr = str.mid(start, end - start);
368
mediaStr.replace(nlSpaceRe, ""); // strip new lines and space after them
369
mediaStr.replace(htmlTagRe, ""); // strip HTML tags
370
framesHdr.setValue(Frame::FT_Media, mediaStr);
375
* credits can be found in "Credits:"
377
start = str.QCM_indexOf("Credits:");
379
start += 8; // skip "Credits:"
380
end = str.QCM_indexOf("</tr>", start);
382
QString creditsStr = str.mid(start, end - start);
383
creditsStr.replace(nlSpaceRe, ""); // strip new lines and space after them
384
creditsStr.replace("<br>", "\n");
385
creditsStr.replace(htmlTagRe, ""); // strip HTML tags
386
parseCredits(creditsStr, framesHdr);
223
426
QString title(str.mid(titleStart, end - titleStart));
427
if (additionalTags) {
428
int artistStart = str.QCM_indexOf("<a href=\"/artist/", start);
429
if (artistStart > start && artistStart < titleStart) {
430
artistStart = str.QCM_indexOf('>', artistStart);
431
if (artistStart > start && artistStart < titleStart) {
432
++artistStart; // skip '>'
433
int artistEnd = str.QCM_indexOf("</a>", artistStart);
434
if (artistEnd > artistStart && artistEnd < titleStart) {
435
// use the artist in the header as the album artist
436
// and the artist in the track as the artist
438
fixUpArtist(str.mid(artistStart, artistEnd - artistStart)));
439
frames.setValue(Frame::FT_AlbumArtist, framesHdr.getArtist());
224
444
start = end + 10; // skip </td></tr>
225
445
if (title.QCM_indexOf("</") != -1 || title.QCM_indexOf("<a href") != -1) {
226
446
// strange entry instead of track => skip
447
if (additionalTags) {
448
if (title.startsWith("<b>") && title.endsWith("</b>")) {
449
// a bold title is a set subtitle
450
QString subtitle(title.mid(3, title.length() - 7));
451
subtitle.remove(htmlTagRe); // strip HTML tags
453
subtitle.remove(QRegExp("\\s*\\(\\d+:\\d+\\)$"));
454
framesHdr.setValue(Frame::FT_Part, subtitle);
455
frames.setValue(Frame::FT_Part, subtitle);
461
if (additionalTags) {
462
int nextEnd, nextTitleStart = -1;
463
if ((nextEnd = str.QCM_indexOf("</td></tr>", start)) > start &&
464
(nextTitleStart = str.QCM_lastIndexOf("<td>", nextEnd)) > start) {
465
QString nextTitle(str.mid(nextTitleStart, nextEnd - nextTitleStart));
466
if (nextTitle.QCM_indexOf("</") != -1 ||
467
nextTitle.QCM_indexOf("<a href") != -1) {
468
// additional track info like "Music By, Lyrics By - "
469
nextTitle.replace("<br>", "\n");
470
nextTitle.replace(htmlTagRe, ""); // strip HTML tags
471
nextTitle.remove(" ");
472
if (parseCredits(nextTitle, frames)) {
473
start = nextEnd + 10; // skip </td></tr>
229
479
int duration = 0;
230
480
if (titleTimeRe.exactMatch(title)) {
231
481
duration = titleTimeRe.cap(2).toInt() * 60 +
232
482
titleTimeRe.cap(3).toInt();
233
483
title = titleTimeRe.cap(1);
485
frames.setTrack(trackNr);
486
frames.setTitle(title);
237
487
if (atTrackDataListEnd) {
238
488
ImportTrackData trackData;
239
trackData.setStandardTags(st);
489
trackData.setFrameCollection(frames);
240
490
trackData.setImportDuration(duration);
241
491
m_trackDataVector.push_back(trackData);
243
(*it).setStandardTags(st);
493
(*it).setFrameCollection(frames);
244
494
(*it).setImportDuration(duration);
246
496
atTrackDataListEnd = (it == m_trackDataVector.end());
252
502
// handle redundant tracks
254
504
while (!atTrackDataListEnd) {
255
505
if ((*it).getFileDuration() == 0) {
256
506
it = m_trackDataVector.erase(it);
258
(*it).setStandardTags(st);
508
(*it).setFrameCollection(frames);
259
509
(*it).setImportDuration(0);