~ubuntu-branches/ubuntu/wily/kid3/wily

« back to all changes in this revision

Viewing changes to src/core/import/discogsimporter.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell, Patrick Matthäi, Mark Purcell
  • Date: 2013-11-30 15:44:59 UTC
  • mfrom: (1.1.16) (2.1.18 sid)
  • Revision ID: package-import@ubuntu.com-20131130154459-s6lpalx8yy2zq7gx
Tags: 3.0.2-1
* New upstream release 

[ Patrick Matthäi ]
* New upstream release.
  - Add new libreadline-dev build dependency.
* Don't explicitly request xz compression - dpkg 1.17 does this by default.
* Bump Standards-Version to 3.9.5 (no changes needed).
* Fix Vcs-Browser control field.

[ Mark Purcell ]
* Switch to dh - reduce debian/rules bloat
* kid3 Replaces kid3-qt - low popcon, reduce archive bloat
* Fix vcs-field-not-canonical
* debian/compat -> 9
* Update Description:

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * \file discogsimporter.cpp
3
 
 * Discogs importer.
4
 
 *
5
 
 * \b Project: Kid3
6
 
 * \author Urs Fleisch
7
 
 * \date 13 Oct 2006
8
 
 *
9
 
 * Copyright (C) 2006-2013  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 "discogsimporter.h"
28
 
#include <QUrl>
29
 
#include "serverimporterconfig.h"
30
 
#include "trackdatamodel.h"
31
 
#include "configstore.h"
32
 
#include "genres.h"
33
 
#include "jsonparser.h"
34
 
#include "qtcompatmac.h"
35
 
 
36
 
/**
37
 
 * Stores information about extra artists.
38
 
 * The information can be used to add frames to the appropriate tracks.
39
 
 */
40
 
class ExtraArtist {
41
 
public:
42
 
  /**
43
 
   * Constructor.
44
 
   * @param varMap variant map containing extra artist information
45
 
   */
46
 
  explicit ExtraArtist(const QVariantMap& varMap);
47
 
 
48
 
  /**
49
 
   * Add extra artist information to frames.
50
 
   * @param frames   frame collection
51
 
   * @param trackPos optional position, the extra artist information will
52
 
   *                 only be added if this track position is listed in the
53
 
   *                 track restrictions or is empty
54
 
   */
55
 
  void addToFrames(FrameCollection& frames,
56
 
                   const QString& trackPos = QString()) const;
57
 
 
58
 
  /**
59
 
   * Check if extra artist information is only valid for a subset of the tracks.
60
 
   * @return true if extra artist has track restriction.
61
 
   */
62
 
  bool hasTrackRestriction() const { return !m_tracks.isEmpty(); }
63
 
 
64
 
private:
65
 
  QString m_name;
66
 
  QString m_role;
67
 
  QStringList m_tracks;
68
 
};
69
 
 
70
 
 
71
 
namespace {
72
 
 
73
 
const char discogsServer[] = "api.discogs.com:80";
74
 
 
75
 
/**
76
 
 * Replace unicode escape sequences (e.g. "\u2022") by unicode characters.
77
 
 * @param str string containing unicode escape sequences
78
 
 * @return string with replaced unicode escape sequences.
79
 
 */
80
 
QString replaceEscapedUnicodeCharacters(QString str)
81
 
{
82
 
  QRegExp unicodeRe(QLatin1String("\\\\u([0-9a-fA-F]{4})"));
83
 
  int offset = 0;
84
 
  while (offset >= 0) {
85
 
    offset = unicodeRe.indexIn(str, offset);
86
 
    if (offset >= 0) {
87
 
      str.replace(offset, unicodeRe.matchedLength(),
88
 
                  QChar(unicodeRe.cap(1).toUInt(0, 16)));
89
 
      ++offset;
90
 
    }
91
 
  }
92
 
  return str;
93
 
}
94
 
 
95
 
/**
96
 
 * Remove trailing stars and numbers like (2) from a string.
97
 
 *
98
 
 * @param str string
99
 
 *
100
 
 * @return fixed up string.
101
 
 */
102
 
QString fixUpArtist(QString str)
103
 
{
104
 
  str.remove(QRegExp(QLatin1String("[*\\s]*\\(\\d+\\)")));
105
 
  str.replace(QRegExp(QLatin1String("\\*($| - |, | / )")), QLatin1String("\\1"));
106
 
 
107
 
  return str;
108
 
}
109
 
 
110
 
/**
111
 
 * Create a string with artists contained in an artist list.
112
 
 * @param artists list containing artist maps
113
 
 * @return string with artists joined appropriately.
114
 
 */
115
 
QString getArtistString(const QVariantList& artists)
116
 
{
117
 
  QString artist;
118
 
  if (!artists.isEmpty()) {
119
 
    QString join;
120
 
    foreach (const QVariant& var, artists) {
121
 
      QVariantMap varMap = var.toMap();
122
 
      if (!artist.isEmpty()) {
123
 
        artist += join;
124
 
      }
125
 
      artist += fixUpArtist(varMap.value(QLatin1String("name")).toString());
126
 
      join = varMap.value(QLatin1String("join")).toString();
127
 
      if (join.isEmpty() || join == QLatin1String(",")) {
128
 
        join = QLatin1String(", ");
129
 
      } else {
130
 
        join = QLatin1Char(' ') + join + QLatin1Char(' ');
131
 
      }
132
 
    }
133
 
  }
134
 
  return artist;
135
 
}
136
 
 
137
 
/**
138
 
 * Add involved people to a frame.
139
 
 * The format used is (should be converted according to tag specifications):
140
 
 * involvee 1 (involvement 1)\n
141
 
 * involvee 2 (involvement 2)\n
142
 
 * ...
143
 
 * involvee n (involvement n)
144
 
 *
145
 
 * @param frames      frame collection
146
 
 * @param type        type of frame
147
 
 * @param involvement involvement (e.g. instrument)
148
 
 * @param involvee    name of involvee (e.g. musician)
149
 
 */
150
 
void addInvolvedPeople(
151
 
  FrameCollection& frames, Frame::Type type,
152
 
  const QString& involvement, const QString& involvee)
153
 
{
154
 
  QString value = frames.getValue(type);
155
 
  if (!value.isEmpty()) value += Frame::stringListSeparator();
156
 
  value += involvement;
157
 
  value += Frame::stringListSeparator();
158
 
  value += involvee;
159
 
  frames.setValue(type, value);
160
 
}
161
 
 
162
 
/**
163
 
 * Add name to frame with credits.
164
 
 * @param frames frame collection
165
 
 * @param type   type of frame
166
 
 * @param name   name of person to credit
167
 
 */
168
 
void addCredit(FrameCollection& frames, Frame::Type type, const QString& name)
169
 
{
170
 
  QString value = frames.getValue(type);
171
 
  if (!value.isEmpty()) value += QLatin1String(", ");
172
 
  value += name;
173
 
  frames.setValue(type, value);
174
 
}
175
 
 
176
 
}
177
 
 
178
 
/**
179
 
 * Constructor.
180
 
 * @param varMap variant map containing extra artist information
181
 
 */
182
 
ExtraArtist::ExtraArtist(const QVariantMap& varMap) :
183
 
  m_name(fixUpArtist(varMap.value(QLatin1String("name")).toString())),
184
 
  m_role(varMap.value(QLatin1String("role")).toString())
185
 
{
186
 
  static const QRegExp tracksSepRe(QLatin1String(",\\s*"));
187
 
  QString tracks = varMap.value(QLatin1String("tracks")).toString();
188
 
  if (!tracks.isEmpty()) {
189
 
    m_tracks = tracks.split(tracksSepRe);
190
 
  }
191
 
}
192
 
 
193
 
/**
194
 
 * Add extra artist information to frames.
195
 
 * @param frames   frame collection
196
 
 * @param trackPos optional position, the extra artist information will
197
 
 *                 only be added if this track position is listed in the
198
 
 *                 track restrictions or is empty
199
 
 */
200
 
void ExtraArtist::addToFrames(FrameCollection& frames,
201
 
                              const QString& trackPos) const
202
 
{
203
 
  if (!trackPos.isEmpty() && !m_tracks.contains(trackPos))
204
 
    return;
205
 
 
206
 
  if (m_role.contains(QLatin1String("Composed By")) || m_role.contains(QLatin1String("Music By")) ||
207
 
      m_role.contains(QLatin1String("Songwriter"))) {
208
 
    addCredit(frames, Frame::FT_Composer, m_name);
209
 
  }
210
 
  if (m_role.contains(QLatin1String("Written-By")) || m_role.contains(QLatin1String("Written By"))) {
211
 
    addCredit(frames, Frame::FT_Author, m_name);
212
 
  }
213
 
  if (m_role.contains(QLatin1String("Lyrics By"))) {
214
 
    addCredit(frames, Frame::FT_Lyricist, m_name);
215
 
  }
216
 
  if (m_role.contains(QLatin1String("Conductor"))) {
217
 
    addCredit(frames, Frame::FT_Conductor, m_name);
218
 
  }
219
 
  if (m_role.contains(QLatin1String("Orchestra"))) {
220
 
    addCredit(frames, Frame::FT_AlbumArtist, m_name);
221
 
  }
222
 
  if (m_role.contains(QLatin1String("Remix"))) {
223
 
    addCredit(frames, Frame::FT_Remixer, m_name);
224
 
  }
225
 
 
226
 
  if (m_role.contains(QLatin1String("Arranged By"))) {
227
 
    addInvolvedPeople(frames, Frame::FT_Arranger,
228
 
                      QLatin1String("Arranger"), m_name);
229
 
  }
230
 
  if (m_role.contains(QLatin1String("Mixed By"))) {
231
 
    addInvolvedPeople(frames, Frame::FT_Arranger,
232
 
                      QLatin1String("Mixer"), m_name);
233
 
  }
234
 
  if (m_role.contains(QLatin1String("DJ Mix")) || m_role.contains(QLatin1String("Dj Mix"))) {
235
 
    addInvolvedPeople(frames, Frame::FT_Arranger,
236
 
                      QLatin1String("DJMixer"), m_name);
237
 
  }
238
 
  if (m_role.contains(QLatin1String("Engineer")) || m_role.contains(QLatin1String("Mastered By"))) {
239
 
    addInvolvedPeople(frames, Frame::FT_Arranger,
240
 
                      QLatin1String("Engineer"), m_name);
241
 
  }
242
 
  if (m_role.contains(QLatin1String("Producer")) || m_role.contains(QLatin1String("Co-producer")) ||
243
 
      m_role.contains(QLatin1String("Executive Producer"))) {
244
 
    addInvolvedPeople(frames, Frame::FT_Arranger,
245
 
                      QLatin1String("Producer"), m_name);
246
 
  }
247
 
 
248
 
  static const char* const instruments[] = {
249
 
    "Performer", "Vocals", "Voice", "Featuring", "Choir", "Chorus",
250
 
    "Baritone", "Tenor", "Rap", "Scratches", "Drums", "Percussion",
251
 
    "Keyboards", "Cello", "Piano", "Organ", "Synthesizer", "Keys",
252
 
    "Wurlitzer", "Rhodes", "Harmonica", "Xylophone", "Guitar", "Bass",
253
 
    "Strings", "Violin", "Viola", "Banjo", "Harp", "Mandolin",
254
 
    "Clarinet", "Horn", "Cornet", "Flute", "Oboe", "Saxophone",
255
 
    "Trumpet", "Tuba", "Trombone"
256
 
  };
257
 
  for (unsigned i = 0;
258
 
       i < sizeof(instruments) / sizeof(instruments[0]);
259
 
       ++i) {
260
 
    if (m_role.contains(QString::fromLatin1(instruments[i]))) {
261
 
      addInvolvedPeople(frames, Frame::FT_Performer, m_role, m_name);
262
 
      break;
263
 
    }
264
 
  }
265
 
}
266
 
 
267
 
 
268
 
/**
269
 
 * Constructor.
270
 
 *
271
 
 * @param netMgr network access manager
272
 
 * @param trackDataModel track data to be filled with imported values
273
 
 */
274
 
DiscogsImporter::DiscogsImporter(QNetworkAccessManager* netMgr,
275
 
                                 TrackDataModel* trackDataModel) :
276
 
  ServerImporter(netMgr, trackDataModel)
277
 
{
278
 
  setObjectName(QLatin1String("DiscogsImporter"));
279
 
  m_discogsHeaders["User-Agent"] = "Kid3/" VERSION
280
 
      " +http://kid3.sourceforge.net";
281
 
}
282
 
 
283
 
/**
284
 
 * Destructor.
285
 
 */
286
 
DiscogsImporter::~DiscogsImporter()
287
 
{
288
 
}
289
 
 
290
 
/**
291
 
 * Name of import source.
292
 
 * @return name.
293
 
 */
294
 
const char* DiscogsImporter::name() const { return I18N_NOOP("Discogs"); }
295
 
 
296
 
/** anchor to online help, 0 to disable */
297
 
const char* DiscogsImporter::helpAnchor() const { return "import-discogs"; }
298
 
 
299
 
/** configuration, 0 if not used */
300
 
ServerImporterConfig* DiscogsImporter::config() const { return &ConfigStore::s_discogsCfg; }
301
 
 
302
 
/** additional tags option, false if not used */
303
 
bool DiscogsImporter::additionalTags() const { return true; }
304
 
 
305
 
/**
306
 
 * Process finished findCddbAlbum request.
307
 
 *
308
 
 * @param searchStr search data received
309
 
 */
310
 
void DiscogsImporter::parseFindResults(const QByteArray& searchStr)
311
 
{
312
 
  // search results have the format (JSON, simplified):
313
 
  // {"results": [{"style": ["Heavy Metal"], "title": "Wizard (23) - Odin",
314
 
  //               "type": "release", "id": 2487778}]}
315
 
  QString str = replaceEscapedUnicodeCharacters(QString::fromUtf8(searchStr));
316
 
 
317
 
  QVariantMap map = JsonParser::deserialize(str).toMap();
318
 
  m_albumListModel->clear();
319
 
  foreach (const QVariant& var, map.value(QLatin1String("results")).toList()) {
320
 
    QVariantMap result = var.toMap();
321
 
    QString title = fixUpArtist(result.value(QLatin1String("title")).toString());
322
 
    if (!title.isEmpty()) {
323
 
      m_albumListModel->appendRow(new AlbumListItem(
324
 
        title,
325
 
        QLatin1String("releases"),
326
 
        QString::number(result.value(QLatin1String("id")).toInt())));
327
 
    }
328
 
  }
329
 
}
330
 
 
331
 
/**
332
 
 * Parse result of album request and populate m_trackDataModel with results.
333
 
 *
334
 
 * @param albumStr album data received
335
 
 */
336
 
void DiscogsImporter::parseAlbumResults(const QByteArray& albumStr)
337
 
{
338
 
  // releases have the format (JSON, simplified):
339
 
  // { "styles": ["Heavy Metal"],
340
 
  //   "labels": [{"name": "LMP"}],
341
 
  //   "year": 2003,
342
 
  //   "artists": [{"name": "Wizard (23)"}],
343
 
  //   "images": [
344
 
  //   { "uri": "http://api.discogs.com/image/R-2487778-1293847958.jpeg",
345
 
  //     "type": "primary" },
346
 
  //   { "uri": "http://api.discogs.com/image/R-2487778-1293847967.jpeg",
347
 
  //     "type": "secondary" }],
348
 
  //   "id": 2487778,
349
 
  //   "genres": ["Rock"],
350
 
  //   "thumb": "http://api.discogs.com/image/R-150-2487778-1293847958.jpeg",
351
 
  //   "extraartists": [],
352
 
  //   "title": "Odin",
353
 
  //   "tracklist": [
354
 
  //     {"duration": "5:19", "position": "1", "title": "The Prophecy"},
355
 
  //     {"duration": "", "position": "Video", "title": "Betrayer"}
356
 
  //   ],
357
 
  //   "released": "2003",
358
 
  //   "formats": [{"name": "CD"}]
359
 
  // }
360
 
  QRegExp discTrackPosRe(QLatin1String("(\\d+)-(\\d+)"));
361
 
  QRegExp yearRe(QLatin1String("^\\d{4}-\\d{2}"));
362
 
  QString str = replaceEscapedUnicodeCharacters(QString::fromUtf8(albumStr));
363
 
  QVariantMap map = JsonParser::deserialize(str).toMap();
364
 
 
365
 
  QList<ExtraArtist> trackExtraArtists;
366
 
  ImportTrackDataVector trackDataVector(m_trackDataModel->getTrackData());
367
 
  FrameCollection framesHdr;
368
 
  const bool standardTags = getStandardTags();
369
 
  if (standardTags) {
370
 
    framesHdr.setAlbum(map.value(QLatin1String("title")).toString());
371
 
    framesHdr.setArtist(getArtistString(map.value(QLatin1String("artists")).toList()));
372
 
 
373
 
    // The year can be found in "released".
374
 
    QString released(map.value(QLatin1String("released")).toString());
375
 
    if (yearRe.indexIn(released) == 0) {
376
 
      released.truncate(4);
377
 
    }
378
 
    framesHdr.setYear(released.toInt());
379
 
 
380
 
    // The genre can be found in "genre" or "style".
381
 
    // All genres found are checked for an ID3v1 number, starting with those
382
 
    // in the style field.
383
 
    QVariantList genreList(map.value(QLatin1String("styles")).toList() +
384
 
                           map.value(QLatin1String("genres")).toList());
385
 
    int genreNum = 255;
386
 
    foreach (const QVariant& var, genreList) {
387
 
      genreNum = Genres::getNumber(var.toString());
388
 
      if (genreNum != 255) {
389
 
        break;
390
 
      }
391
 
    }
392
 
    if (genreNum != 255) {
393
 
      framesHdr.setGenre(QString::fromLatin1(Genres::getName(genreNum)));
394
 
    } else if (!genreList.isEmpty()) {
395
 
      framesHdr.setGenre(genreList.first().toString());
396
 
    }
397
 
  }
398
 
 
399
 
  trackDataVector.setCoverArtUrl(QString());
400
 
  const bool coverArt = getCoverArt();
401
 
  if (coverArt) {
402
 
    // Cover art can be found in "images"
403
 
    QVariantList images = map.value(QLatin1String("images")).toList();
404
 
    if (!images.isEmpty()) {
405
 
      trackDataVector.setCoverArtUrl(images.first().toMap().value(QLatin1String("uri")).
406
 
                                     toString());
407
 
    }
408
 
  }
409
 
 
410
 
  const bool additionalTags = getAdditionalTags();
411
 
  if (additionalTags) {
412
 
    // Publisher can be found in "label"
413
 
    QVariantList labels = map.value(QLatin1String("labels")).toList();
414
 
    if (!labels.isEmpty()) {
415
 
      QVariantMap firstLabelMap = labels.first().toMap();
416
 
      framesHdr.setValue(Frame::FT_Publisher,
417
 
          fixUpArtist(firstLabelMap.value(QLatin1String("name")).toString()));
418
 
      QString catNo = firstLabelMap.value(QLatin1String("catno")).toString();
419
 
      if (!catNo.isEmpty() && catNo.toLower() != QLatin1String("none")) {
420
 
        framesHdr.setValue(Frame::FT_CatalogNumber, catNo);
421
 
      }
422
 
    }
423
 
    // Media can be found in "formats"
424
 
    QVariantList formats = map.value(QLatin1String("formats")).toList();
425
 
    if (!formats.isEmpty()) {
426
 
      framesHdr.setValue(Frame::FT_Media,
427
 
                         formats.first().toMap().value(QLatin1String("name")).toString());
428
 
    }
429
 
    // Credits can be found in "extraartists"
430
 
    QVariantList extraartists = map.value(QLatin1String("extraartists")).toList();
431
 
    if (!extraartists.isEmpty()) {
432
 
      foreach (const QVariant& var, extraartists) {
433
 
        ExtraArtist extraArtist(var.toMap());
434
 
        if (extraArtist.hasTrackRestriction()) {
435
 
          trackExtraArtists.append(extraArtist);
436
 
        } else {
437
 
          extraArtist.addToFrames(framesHdr);
438
 
        }
439
 
      }
440
 
    }
441
 
    // Release country can be found in "country"
442
 
    QString country(map.value(QLatin1String("country")).toString());
443
 
    if (!country.isEmpty()) {
444
 
      framesHdr.setValue(Frame::FT_ReleaseCountry, country);
445
 
    }
446
 
  }
447
 
 
448
 
  FrameCollection frames(framesHdr);
449
 
  ImportTrackDataVector::iterator it = trackDataVector.begin();
450
 
  bool atTrackDataListEnd = (it == trackDataVector.end());
451
 
  int trackNr = 1;
452
 
  QVariantList trackList = map.value(QLatin1String("tracklist")).toList();
453
 
 
454
 
  // Check if all positions are empty.
455
 
  bool allPositionsEmpty = true;
456
 
  foreach (const QVariant& var, trackList) {
457
 
    if (!var.toMap().value(QLatin1String("position")).toString().isEmpty()) {
458
 
      allPositionsEmpty = false;
459
 
      break;
460
 
    }
461
 
  }
462
 
 
463
 
  foreach (const QVariant& var, trackList) {
464
 
    QVariantMap track = var.toMap();
465
 
 
466
 
    QString position(track.value(QLatin1String("position")).toString());
467
 
    bool ok;
468
 
    int pos = position.toInt(&ok);
469
 
    if (!ok) {
470
 
      if (discTrackPosRe.exactMatch(position)) {
471
 
        if (additionalTags) {
472
 
          frames.setValue(Frame::FT_Disc, discTrackPosRe.cap(1));
473
 
        }
474
 
        pos = discTrackPosRe.cap(2).toInt();
475
 
      } else {
476
 
        pos = trackNr;
477
 
      }
478
 
    }
479
 
    QString title(track.value(QLatin1String("title")).toString());
480
 
 
481
 
    QStringList durationHms = track.value(QLatin1String("duration")).toString().split(QLatin1Char(':'));
482
 
    int duration = 0;
483
 
    foreach (const QString& var, durationHms) {
484
 
      duration *= 60;
485
 
      duration += var.toInt();
486
 
    }
487
 
    if (!allPositionsEmpty && position.isEmpty()) {
488
 
      if (additionalTags) {
489
 
        framesHdr.setValue(Frame::FT_Part, title);
490
 
      }
491
 
    } else if (!title.isEmpty() || duration != 0) {
492
 
      if (standardTags) {
493
 
        frames.setTrack(pos);
494
 
        frames.setTitle(title);
495
 
      }
496
 
      QVariantList artists(track.value(QLatin1String("artists")).toList());
497
 
      if (!artists.isEmpty()) {
498
 
        if (standardTags) {
499
 
          frames.setArtist(getArtistString(artists));
500
 
        }
501
 
        if (additionalTags) {
502
 
          frames.setValue(Frame::FT_AlbumArtist, framesHdr.getArtist());
503
 
        }
504
 
      }
505
 
      if (additionalTags) {
506
 
        QVariantList extraartists(track.value(QLatin1String("extraartists")).toList());
507
 
        if (!extraartists.isEmpty()) {
508
 
          foreach (const QVariant& var, extraartists) {
509
 
            ExtraArtist extraArtist(var.toMap());
510
 
            extraArtist.addToFrames(frames);
511
 
          }
512
 
        }
513
 
      }
514
 
      foreach (const ExtraArtist& extraArtist, trackExtraArtists) {
515
 
        extraArtist.addToFrames(frames, position);
516
 
      }
517
 
 
518
 
      if (atTrackDataListEnd) {
519
 
        ImportTrackData trackData;
520
 
        trackData.setFrameCollection(frames);
521
 
        trackData.setImportDuration(duration);
522
 
        trackDataVector.append(trackData);
523
 
      } else {
524
 
        while (!atTrackDataListEnd && !it->isEnabled()) {
525
 
          ++it;
526
 
          atTrackDataListEnd = (it == trackDataVector.end());
527
 
        }
528
 
        if (!atTrackDataListEnd) {
529
 
          (*it).setFrameCollection(frames);
530
 
          (*it).setImportDuration(duration);
531
 
          ++it;
532
 
          atTrackDataListEnd = (it == trackDataVector.end());
533
 
        }
534
 
      }
535
 
      ++trackNr;
536
 
    }
537
 
    frames = framesHdr;
538
 
  }
539
 
  // handle redundant tracks
540
 
  frames.clear();
541
 
  while (!atTrackDataListEnd) {
542
 
    if (it->isEnabled()) {
543
 
      if ((*it).getFileDuration() == 0) {
544
 
        it = trackDataVector.erase(it);
545
 
      } else {
546
 
        (*it).setFrameCollection(frames);
547
 
        (*it).setImportDuration(0);
548
 
        ++it;
549
 
      }
550
 
    } else {
551
 
      ++it;
552
 
    }
553
 
    atTrackDataListEnd = (it == trackDataVector.end());
554
 
  }
555
 
  m_trackDataModel->setTrackData(trackDataVector);
556
 
}
557
 
 
558
 
/**
559
 
 * Send a query command to search on the server.
560
 
 *
561
 
 * @param cfg      import source configuration
562
 
 * @param artist   artist to search
563
 
 * @param album    album to search
564
 
 */
565
 
void DiscogsImporter::sendFindQuery(
566
 
  const ServerImporterConfig*,
567
 
  const QString& artist, const QString& album)
568
 
{
569
 
  /*
570
 
   * Query looks like this:
571
 
   * http://api.discogs.com//database/search?type=release&title&q=amon+amarth+avenger
572
 
   */
573
 
  sendRequest(QString::fromLatin1(discogsServer),
574
 
              QLatin1String("/database/search?type=release&title&q=") +
575
 
              encodeUrlQuery(artist + QLatin1Char(' ') + album), m_discogsHeaders);
576
 
}
577
 
 
578
 
/**
579
 
 * Send a query command to fetch the track list
580
 
 * from the server.
581
 
 *
582
 
 * @param cfg      import source configuration
583
 
 * @param cat      category
584
 
 * @param id       ID
585
 
 */
586
 
void DiscogsImporter::sendTrackListQuery(
587
 
  const ServerImporterConfig*, const QString& cat, const QString& id)
588
 
{
589
 
  /*
590
 
   * Query looks like this:
591
 
   * http://api.discogs.com/releases/761529
592
 
   */
593
 
  sendRequest(QString::fromLatin1(discogsServer), QLatin1Char('/') + QString::fromLatin1(QUrl::toPercentEncoding(cat)) + QLatin1Char('/')
594
 
              + id, m_discogsHeaders);
595
 
}