musicbrainzclient.cpp 18 KB
Newer Older
Urs Fleisch's avatar
Urs Fleisch committed
1
2
3
4
5
6
7
/**
 * \file musicbrainzclient.cpp
 * MusicBrainz client.
 *
 * \b Project: Kid3
 * \author Urs Fleisch
 * \date 15 Sep 2005
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Copyright (C) 2005-2007  Urs Fleisch
 *
 * This file is part of Kid3.
 *
 * Kid3 is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Kid3 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Urs Fleisch's avatar
Urs Fleisch committed
25
26
27
28
29
30
 */

#include "musicbrainzclient.h"
#ifdef HAVE_TUNEPIMP

#include <qfile.h>
Urs Fleisch's avatar
Urs Fleisch committed
31
#if QT_VERSION >= 0x040000
32
#include <QByteArray>
Urs Fleisch's avatar
Urs Fleisch committed
33
34
#endif
#if HAVE_TUNEPIMP >= 5
Urs Fleisch's avatar
Urs Fleisch committed
35
36
#include <qdom.h>
#endif
Urs Fleisch's avatar
Urs Fleisch committed
37
#include "freedbclient.h"
38
#include "importtrackdata.h"
Urs Fleisch's avatar
Urs Fleisch committed
39

Urs Fleisch's avatar
Urs Fleisch committed
40
41
42
43
44
45
46
47
48
49
50
#if HAVE_TUNEPIMP >= 5
/**
 * Constructor.
 *
 * @param numFiles   number of files to be queried
 * @param serverName server name
 * @param serverPort server port
 * @param proxyName  proxy name, empty if no proxy
 * @param proxyPort  proxy port
 */
LookupQuery::LookupQuery(int numFiles,
51
52
												 const QString& serverName, unsigned short serverPort,
												 const QString& proxyName, unsigned short proxyPort) :
Urs Fleisch's avatar
Urs Fleisch committed
53
54
55
	m_numFiles(numFiles), m_serverName(serverName), m_serverPort(serverPort),
	m_proxyName(proxyName), m_proxyPort(proxyPort),
	m_currentFile(-1), m_fileQueries(new FileQuery[numFiles]),
56
57
58
59
60
#if QT_VERSION >= 0x040000
	m_sock(new QTcpSocket)
#else
	m_sock(new QSocket)
#endif
Urs Fleisch's avatar
Urs Fleisch committed
61
62
63
64
65
66
67
{
	for (int i = 0; i < m_numFiles; ++i) {
		m_fileQueries[i].requested = false;
		m_fileQueries[i].puid = "";
	}
	connect(m_sock, SIGNAL(connected()),
			this, SLOT(socketConnected()));
68
69
70
71
72
73
#if QT_VERSION >= 0x040000
	connect(m_sock, SIGNAL(error(QAbstractSocket::SocketError)),
			this, SLOT(socketError(QAbstractSocket::SocketError)));
	connect(m_sock, SIGNAL(disconnected()),
			this, SLOT(socketConnectionClosed()));
#else
Urs Fleisch's avatar
Urs Fleisch committed
74
	connect(m_sock, SIGNAL(error(int)),
75
			this, SLOT(socketError(int)));
Urs Fleisch's avatar
Urs Fleisch committed
76
77
	connect(m_sock, SIGNAL(connectionClosed()),
			this, SLOT(socketConnectionClosed()));
78
#endif
Urs Fleisch's avatar
Urs Fleisch committed
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
}

/**
 * Destructor.
 */
LookupQuery::~LookupQuery()
{
	m_sock->close();
	m_sock->disconnect();
	delete m_sock;
	delete [] m_fileQueries;
}

/**
 * Connect to server to query information about the current file.
 */
void LookupQuery::socketQuery()
{
	if (m_currentFile >= 0 && m_currentFile < m_numFiles) {
		QString  destName = m_proxyName.isEmpty() ? m_serverName : m_proxyName;
99
		unsigned short destPort = m_proxyName.isEmpty() ? m_serverPort : m_proxyPort;
Urs Fleisch's avatar
Urs Fleisch committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
		m_request = "GET http://";
		m_request += m_serverName;
		if (m_serverPort != 80) {
			m_request += ':';
			m_request += QString::number(m_serverPort);
		}
		m_request += "/ws/1/track/?type=xml&puid=";
		m_request += m_fileQueries[m_currentFile].puid;
		m_request += " HTTP/1.0\r\nHost: ";
		m_request += m_serverName;
		m_request += "\r\nUser-agent: Kid3/" VERSION "\r\n\r\n";
		m_sock->connectToHost(destName, destPort);
		m_fileQueries[m_currentFile].requested = true;
	}
}

/**
 * Query the next file.
 */
void LookupQuery::queryNext()
{
	// handle the first pending query
	for (int i = 0; i < m_numFiles; ++i) {
		if (!m_fileQueries[i].requested &&
				!m_fileQueries[i].puid.isEmpty()) {
			m_currentFile = i;
			socketQuery();
			return;
		}
	}
	// no pending query => socketQuery() will be done in next query()
	m_currentFile = -1;
}

/**
 * Query a PUID from the server.
 *
 * @param puid  PUID
 * @param index index of file
 */
void LookupQuery::query(const char* puid, int index)
{
	m_fileQueries[index].puid = QString(puid);
	// if no request is being executed, start the current request
	if (m_currentFile < 0 || m_currentFile >= m_numFiles ||
			!m_fileQueries[m_currentFile].requested) {
		m_currentFile = index;
		socketQuery();
	}
}

/**
 * Send query when the socket is connected.
 */
void LookupQuery::socketConnected()
{
156
	m_sock->QCM_writeBlock(m_request.QCM_latin1(), m_request.length());
Urs Fleisch's avatar
Urs Fleisch committed
157
158
159
160
161
}

/**
 * Error on socket connection.
 */
162
163
164
165
166
167
168
169
170
171
#if QT_VERSION >= 0x040000
void LookupQuery::socketError(QAbstractSocket::SocketError err)
{
	if (err != QAbstractSocket::RemoteHostClosedError) {
		qDebug("Socket Error: %s", m_sock->errorString().QCM_latin1());
		queryNext();
	}
}
#else
void LookupQuery::socketError(int)
Urs Fleisch's avatar
Urs Fleisch committed
172
173
174
{
	queryNext();
}
175
#endif
Urs Fleisch's avatar
Urs Fleisch committed
176
177
178
179
180
181

/**
 * Read received data when the server has closed the connection.
 */
void LookupQuery::socketConnectionClosed()
{
182
183
	unsigned long len = m_sock->bytesAvailable();
	QCM_QCString buf;
Urs Fleisch's avatar
Urs Fleisch committed
184
	buf.resize(len + 1 );
185
	m_sock->QCM_readBlock(buf.data(), len);
Urs Fleisch's avatar
Urs Fleisch committed
186
187
	m_sock->close();

188
	int xmlStart = buf.QCM_indexOf("<?xml");
Urs Fleisch's avatar
Urs Fleisch committed
189
190
191
192
193
194
195
196
197
198
	if (xmlStart >= 0 &&
			m_currentFile >= 0 && m_currentFile < m_numFiles &&
			m_fileQueries[m_currentFile].requested) {
		emit queryResponseReceived(m_currentFile, buf.mid(xmlStart, len - xmlStart));
	}
	queryNext();
}

#endif

Urs Fleisch's avatar
Urs Fleisch committed
199
200
201
202
203
204
205
206
/**
 * Constructor.
 *
 * @param trackDataList track data to be filled with imported values,
 *                      is passed with filenames set
 */
MusicBrainzClient::MusicBrainzClient(ImportTrackDataVector& trackDataList) :
	m_trackDataVector(trackDataList), m_tp(0), m_ids(0), m_numFiles(0)
Urs Fleisch's avatar
Urs Fleisch committed
207
208
209
#if HAVE_TUNEPIMP >= 5
	, m_lookupQuery(0)
#endif
Urs Fleisch's avatar
Urs Fleisch committed
210
{
211
212
213
214
	m_tp = tp_New("kid3", VERSION);
#ifdef WIN32
	tp_WSAInit(m_tp);
#endif
Urs Fleisch's avatar
Urs Fleisch committed
215
#if HAVE_TUNEPIMP >= 4
216
	tp_SetID3Encoding(m_tp, eUTF8);
Urs Fleisch's avatar
Urs Fleisch committed
217
218
#else
	tp_SetUseUTF8(m_tp, 1);
219
#endif
Urs Fleisch's avatar
Urs Fleisch committed
220
221
222
#if HAVE_TUNEPIMP >= 5
	tp_SetMusicDNSClientId(m_tp, "a95f5c7cd37fd4bce12dc86d196fb4fe");
#else
Urs Fleisch's avatar
Urs Fleisch committed
223
	tp_SetAutoFileLookup(m_tp, 1);
Urs Fleisch's avatar
Urs Fleisch committed
224
#endif
Urs Fleisch's avatar
Urs Fleisch committed
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	tp_SetRenameFiles(m_tp, 0);
	tp_SetMoveFiles(m_tp, 0);
	tp_SetWriteID3v1(m_tp, 0);
	tp_SetClearTags(m_tp, 0);
	tp_SetAutoSaveThreshold(m_tp, -1);
	tp_SetAutoRemovedSavedFiles(m_tp, 0);
}

/**
 * Destructor.
 */
MusicBrainzClient::~MusicBrainzClient()
{
	removeFiles();
	if (m_tp) {
240
241
242
#ifdef WIN32
		tp_WSAStop(m_tp);
#endif
Urs Fleisch's avatar
Urs Fleisch committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
		tp_Delete(m_tp);
	}
}

/**
 * Get i for m_id[i] == id.
 *
 * @return index, -1 if not found.
 */
int MusicBrainzClient::getIndexOfId(int id) const
{
	for (int i = 0; i < m_numFiles; ++i) {
		if (m_ids[i] == id) {
			return i;
		}
	}
	return -1;
}

/**
 * Get the file name for an ID.
 *
 * @param id ID of file
 *
 * @return absolute file name, QString::null if not found.
 */
QString MusicBrainzClient::getFilename(int id) const
{
	int idx = getIndexOfId(id);
	if (idx >= 0) {
		return m_trackDataVector[idx].getAbsFilename();
	}
	return QString::null;
}

/**
 * Get a text for a file status.
 *
 * @param statusCode file status code
 *
 * @return status text, 0 if not found.
 */
static const char* getFileStatusText(TPFileStatus statusCode)
{
Urs Fleisch's avatar
Urs Fleisch committed
287
	static const struct id_str_s { TPFileStatus id; const char* str; }
Urs Fleisch's avatar
Urs Fleisch committed
288
	id_str[] = {
Urs Fleisch's avatar
Urs Fleisch committed
289
#if HAVE_TUNEPIMP >= 4
290
		{ eMetadataRead,  I18N_NOOP("Metadata Read") },
Urs Fleisch's avatar
Urs Fleisch committed
291
#endif
292
293
294
		{ eUnrecognized,  I18N_NOOP("Unrecognized") },
		{ eRecognized,    I18N_NOOP("Recognized") },
		{ ePending,       I18N_NOOP("Pending") },
Urs Fleisch's avatar
Urs Fleisch committed
295
#if HAVE_TUNEPIMP >= 5
296
297
		{ ePUIDLookup,     I18N_NOOP("PUID Lookup") },
		{ ePUIDCollision,  I18N_NOOP("PUID Collision") },
Urs Fleisch's avatar
Urs Fleisch committed
298
#else
299
300
		{ eTRMLookup,     I18N_NOOP("TRM Lookup") },
		{ eTRMCollision,  I18N_NOOP("TRM Collision") },
Urs Fleisch's avatar
Urs Fleisch committed
301
#endif
302
303
304
305
306
307
		{ eFileLookup,    I18N_NOOP("File Lookup") },
		{ eUserSelection, I18N_NOOP("User Selection") },
		{ eVerified,      I18N_NOOP("Verified") },
		{ eSaved,         I18N_NOOP("Saved") },
		{ eDeleted,       I18N_NOOP("Deleted") },
		{ eError,         I18N_NOOP("Error") },
Urs Fleisch's avatar
Urs Fleisch committed
308
309
310
		{ eLastStatus,    0 }
	};

Urs Fleisch's avatar
Urs Fleisch committed
311
	const struct id_str_s* is = &id_str[0];
Urs Fleisch's avatar
Urs Fleisch committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	while (is->str) {
		if (is->id == statusCode) {
			break;
		}
		++is;
	}
	return is->str;
}

/**
 * Poll the status of the MusicBrainz query.
 */
void MusicBrainzClient::pollStatus()
{
	TPCallbackEnum type;
	int id;
Urs Fleisch's avatar
Urs Fleisch committed
328
329
330
#if HAVE_TUNEPIMP >= 4
	TPFileStatus statusCode;
	while (tp_GetNotification(m_tp, &type, &id, &statusCode))
331
#else
Urs Fleisch's avatar
Urs Fleisch committed
332
	while (tp_GetNotification(m_tp, &type, &id))
333
334
#endif
	{
Urs Fleisch's avatar
Urs Fleisch committed
335
336
337
338
339
340
341
342
343
344
345
		QString fn = getFilename(id);
		int index = getIndexOfId(id);
		switch (type) {
			case tpFileAdded:
				emit statusChanged(index, i18n("Pending"));
				break;
			case tpFileRemoved:
				emit statusChanged(index, i18n("Removed"));
				break;
			case tpFileChanged:
			{
Urs Fleisch's avatar
Urs Fleisch committed
346
347
348
349
350
351
352
#if HAVE_TUNEPIMP >= 4
				if (statusCode == eUnrecognized) {
					char trm[255];
					trm[0] = '\0';
					track_t track = tp_GetTrack(m_tp, id);
					if (track) {
						tr_Lock(track);
Urs Fleisch's avatar
Urs Fleisch committed
353
354
355
#if HAVE_TUNEPIMP >= 5
						tr_GetPUID(track, trm, sizeof(trm));
#else
Urs Fleisch's avatar
Urs Fleisch committed
356
						tr_GetTRM(track, trm, sizeof(trm));
Urs Fleisch's avatar
Urs Fleisch committed
357
#endif
Urs Fleisch's avatar
Urs Fleisch committed
358
359
360
361
362
363
364
365
366
367
						if (trm[0] == '\0') {
							tr_SetStatus(track, ePending);
							tp_Wake(m_tp, track);
						}
						tr_Unlock(track);
						tp_ReleaseTrack(m_tp, track);
					}
				}
#else
				TPFileStatus statusCode = eLastStatus;
Urs Fleisch's avatar
Urs Fleisch committed
368
369
370
				track_t track = tp_GetTrack(m_tp, id);
				if (track) {
					tr_Lock(track);
Urs Fleisch's avatar
Urs Fleisch committed
371
					statusCode = tr_GetStatus(track);
Urs Fleisch's avatar
Urs Fleisch committed
372
373
					tr_Unlock(track);
					tp_ReleaseTrack(m_tp, track);
Urs Fleisch's avatar
Urs Fleisch committed
374
375
376
				}
#endif
				if (statusCode != eLastStatus) {
Urs Fleisch's avatar
Urs Fleisch committed
377
					const char* statusText = getFileStatusText(statusCode);
378
					emit statusChanged(index, QCM_translate(statusText));
Urs Fleisch's avatar
Urs Fleisch committed
379
380
381
382
					if (statusCode == eRecognized) {
						ImportTrackData trackData;
						getMetaData(id, trackData);
						emit metaDataReceived(index, trackData);
Urs Fleisch's avatar
Urs Fleisch committed
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
					}
#if HAVE_TUNEPIMP >= 5
					else if (statusCode == ePUIDLookup ||
									 statusCode == ePUIDCollision ||
									 statusCode == eFileLookup) {
						char puid[255];
						puid[0] = '\0';
						track_t track = tp_GetTrack(m_tp, id);
						if (track) {
							tr_Lock(track);
							tr_GetPUID(track, puid, sizeof(puid));
							tr_Unlock(track);
							tp_ReleaseTrack(m_tp, track);
						}
						if (m_lookupQuery) {
							m_lookupQuery->query(puid, index);
						}
					}
#else
					else if (statusCode == eTRMCollision ||
									 statusCode == eUserSelection) {
Urs Fleisch's avatar
Urs Fleisch committed
404
405
406
407
408
						ImportTrackDataVector trackDataList;
						if (getResults(id, trackDataList)) {
							emit resultsReceived(index, trackDataList);
						}
					}
Urs Fleisch's avatar
Urs Fleisch committed
409
#endif
Urs Fleisch's avatar
Urs Fleisch committed
410
411
412
413
414
415
416
417
418
419
420
421
422
				}
				break;
			}
			case tpWriteTagsComplete:
				emit statusChanged(index, i18n("Written"));
				break;
			default:
				break;
		}
	}
}

/**
423
 * Set configuration.
Urs Fleisch's avatar
Urs Fleisch committed
424
 *
425
426
427
 * @param server   server
 * @param proxy    proxy
 * @param useProxy true if proxy has to be used
Urs Fleisch's avatar
Urs Fleisch committed
428
 */
429
430
void MusicBrainzClient::setConfig(
	const QString& server, const QString& proxy, bool useProxy)
Urs Fleisch's avatar
Urs Fleisch committed
431
432
433
{
	int port;
	QString ip;
434
	FreedbClient::splitNamePort(server, ip, port);
435
	tp_SetServer(m_tp, ip.QCM_latin1(), port);
Urs Fleisch's avatar
Urs Fleisch committed
436

437
438
	if (useProxy) {
		FreedbClient::splitNamePort(proxy, ip, port);
439
		tp_SetProxy(m_tp, ip.QCM_latin1(), port);
Urs Fleisch's avatar
Urs Fleisch committed
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
	}	else {
		tp_SetProxy(m_tp, "", 80);
	}
}

/**
 * Add the files in the file list.
 */
void MusicBrainzClient::addFiles()
{
	if (m_ids) {
		removeFiles();
	}
	m_numFiles = m_trackDataVector.size();
	m_ids = new int[m_numFiles];
Urs Fleisch's avatar
Urs Fleisch committed
455
456
457
458
459
460
461
#if HAVE_TUNEPIMP >= 5
	char serverName[80], proxyName[80];
	short serverPort, proxyPort;
	tp_GetServer(m_tp, serverName, sizeof(serverName) - 1, &serverPort);
	tp_GetProxy(m_tp, proxyName, sizeof(proxyName) - 1, &proxyPort);
	m_lookupQuery = new LookupQuery(m_numFiles, serverName, serverPort,
																	proxyName, proxyPort);
Urs Fleisch's avatar
Urs Fleisch committed
462
463
	connect(m_lookupQuery, SIGNAL(queryResponseReceived(int, const QByteArray&)),
					this, SLOT(parseLookupResponse(int, const QByteArray&)));
Urs Fleisch's avatar
Urs Fleisch committed
464
#endif
Urs Fleisch's avatar
Urs Fleisch committed
465
	int i = 0;
Urs Fleisch's avatar
Urs Fleisch committed
466
	for (ImportTrackDataVector::const_iterator it = m_trackDataVector.begin();
Urs Fleisch's avatar
Urs Fleisch committed
467
468
			 it != m_trackDataVector.end();
			 ++it) {
Urs Fleisch's avatar
Urs Fleisch committed
469
470
#if HAVE_TUNEPIMP >= 4
		m_ids[i++] = tp_AddFile(m_tp, QFile::encodeName((*it).getAbsFilename()), 0);
471
#else
Urs Fleisch's avatar
Urs Fleisch committed
472
		m_ids[i++] = tp_AddFile(m_tp, QFile::encodeName((*it).getAbsFilename()));
473
#endif
Urs Fleisch's avatar
Urs Fleisch committed
474
475
476
477
478
479
480
481
482
483
484
485
486
487
	}
}

/**
 * Remove all files.
 */
void MusicBrainzClient::removeFiles()
{
	if (m_ids && m_numFiles > 0) {
		for (int i = 0; i < m_numFiles; ++i) {
			tp_Remove(m_tp, m_ids[i]);
		}
		delete [] m_ids;
		m_ids = 0;
Urs Fleisch's avatar
Urs Fleisch committed
488
489
490
491
#if HAVE_TUNEPIMP >= 5
		delete m_lookupQuery;
		m_lookupQuery = 0;
#endif
Urs Fleisch's avatar
Urs Fleisch committed
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
		m_numFiles = 0;
	}
}

/**
 * Get meta data for recognized file.
 *
 * @param id        ID of file
 * @param trackData the meta data is returned here
 */
void MusicBrainzClient::getMetaData(int id, ImportTrackData& trackData)
{
	metadata_t* data = md_New();
	if (data) {
		track_t track = tp_GetTrack(m_tp, id);
		if (track) {
			tr_Lock(track);
			md_Clear(data);
			tr_GetServerMetadata(track, data);
511
512
513
514
515
			trackData.setTitle(QString::fromUtf8(data->track));
			trackData.setArtist(QString::fromUtf8(data->artist));
			trackData.setAlbum(QString::fromUtf8(data->album));
			trackData.setTrack(data->trackNum);
			trackData.setYear(data->releaseYear);
Urs Fleisch's avatar
Urs Fleisch committed
516
517
			// year does not seem to work, so at least we should not
			// overwrite it with 0
518
519
			if (trackData.getYear() == 0) {
				trackData.setYear(-1);
Urs Fleisch's avatar
Urs Fleisch committed
520
521
522
523
524
525
526
527
528
			}
			trackData.setImportDuration(data->duration / 1000);
			tr_Unlock(track);
			tp_ReleaseTrack(m_tp, track);
		}
		md_Delete(data);
	}
}

Urs Fleisch's avatar
Urs Fleisch committed
529
530
531
532
533
534
535
536
537
538
539
540
#if HAVE_TUNEPIMP >= 5

bool MusicBrainzClient::getResults(int, ImportTrackDataVector&) {
	return false;
}

/**
 * Process server response with lookup data.
 *
 * @param index    index of file
 * @param response response from server
 */
Urs Fleisch's avatar
Urs Fleisch committed
541
void MusicBrainzClient::parseLookupResponse(int index, const QByteArray& response)
Urs Fleisch's avatar
Urs Fleisch committed
542
543
544
{
	ImportTrackDataVector trackDataList;
	QDomDocument doc;
Urs Fleisch's avatar
Urs Fleisch committed
545
546
547
548
549
550
551
#if QT_VERSION >= 0x040000
	QByteArray xmlStr = response;
	int end = xmlStr.indexOf("</metadata>");
#else
	QCString xmlStr(response.data(), response.size());
	int end = xmlStr.find("</metadata>");
#endif
552
553
	if (end >= 0 && end + 12 < static_cast<int>(xmlStr.size())) {
		xmlStr.resize(end + 12);
Urs Fleisch's avatar
Urs Fleisch committed
554
555
	}
	if (doc.setContent(xmlStr, false)) {
Urs Fleisch's avatar
Urs Fleisch committed
556
557
558
559
560
561
562
563
564
		QDomElement trackList =
			doc.namedItem("metadata").toElement().namedItem("track-list").toElement();

		for (QDomNode trackNode = trackList.namedItem("track");
				 !trackNode.isNull();
				 trackNode = trackNode.nextSibling()) {
			QDomElement track = trackNode.toElement();

			ImportTrackData trackData;
565
566
567
			trackData.setArtist(
				track.namedItem("artist").toElement().namedItem("name").toElement().text());
			trackData.setTitle(track.namedItem("title").toElement().text());
Urs Fleisch's avatar
Urs Fleisch committed
568
569
570
571
572
573
574

			for (QDomNode releaseNode =
						 track.namedItem("release-list").toElement().namedItem("release");
					 !releaseNode.isNull();
					 releaseNode = releaseNode.nextSibling() ) {
				QDomElement release = releaseNode.toElement();

575
576
				trackData.setAlbum(release.namedItem("title").toElement().text());
				trackData.setTrack(-1);
Urs Fleisch's avatar
Urs Fleisch committed
577
578
579
580
				QDomNode releaseTrackNode = release.namedItem("track-list");
				if (!releaseTrackNode.isNull()) {
					QDomElement releaseTrack = releaseTrackNode.toElement();
					if (!releaseTrack.attribute("offset").isEmpty())
581
						trackData.setTrack(releaseTrack.attribute("offset").toInt() + 1);
Urs Fleisch's avatar
Urs Fleisch committed
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
				}
			}
			trackDataList.append(trackData);
		}
	}

	if (trackDataList.size() > 1) {
		emit resultsReceived(index, trackDataList);
		emit statusChanged(index, i18n("User Selection"));
	} else if (trackDataList.size() == 1) {
		emit metaDataReceived(index, *trackDataList.begin());
		emit statusChanged(index, i18n("Recognized"));
	} else {
		emit statusChanged(index, i18n("Unrecognized"));
	}
}

#else

Urs Fleisch's avatar
Urs Fleisch committed
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
/**
 * Get results for an ambiguous file.
 *
 * @param id            ID of file
 * @param trackDataList the results are returned here
 *
 * @return true if some results were received,
 *         false if no results available.
 */
bool MusicBrainzClient::getResults(int id, ImportTrackDataVector& trackDataList)
{
	bool resultsAvailable = false;
	track_t track = tp_GetTrack(m_tp, id);
	if (track) {
		tr_Lock(track);
		int num = tr_GetNumResults(track);
		result_t* results;
		if (num > 0 && (results = new result_t[num]) != 0) {
			TPResultType type;
			tr_GetResults(track, &type, results, &num);
			if (type == eTrackList) {
				albumtrackresult_t** albumTrackResults =
					reinterpret_cast<albumtrackresult_t**>(results);
				for (int i = 0; i < num; ++i) {
					albumtrackresult_t* res = *albumTrackResults++;
					ImportTrackData trackData;
627
					trackData.setTitle(QString::fromUtf8(res->name));
Urs Fleisch's avatar
Urs Fleisch committed
628
#if HAVE_TUNEPIMP >= 4
629
630
631
					trackData.setArtist(QString::fromUtf8(res->artist.name));
					trackData.setAlbum(QString::fromUtf8(res->album.name));
					trackData.setYear(res->album.releaseYear);
Urs Fleisch's avatar
Urs Fleisch committed
632
#else
633
634
635
					trackData.setArtist(QString::fromUtf8(res->artist->name));
					trackData.setAlbum(QString::fromUtf8(res->album->name));
					trackData.setYear(res->album->releaseYear);
636
#endif
637
					trackData.setTrack(res->trackNum);
Urs Fleisch's avatar
Urs Fleisch committed
638
639
					// year does not seem to work, so at least we should not
					// overwrite it with 0
640
641
					if (trackData.getYear() == 0) {
						trackData.setYear(-1);
Urs Fleisch's avatar
Urs Fleisch committed
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
					}
					trackData.setImportDuration(res->duration / 1000);
					trackDataList.push_back(trackData);
					resultsAvailable = true;
				}
			}
// Handling eArtistList and eAlbumList results does not help much,
// so it is not done.
//			else if (type == eArtistList) {
//				artistresult_t** artistResults =
//					reinterpret_cast<artistresult_t**>(results);
//				qDebug("Artist List for %d:", id);
//				for (int i = 0; i < num; ++i) {
//					artistresult_t* res = *artistResults++;
//					qDebug("%2d. %d%% %s", i, res->relevance, res->name);
//				}
//			}	else if (type == eAlbumList) {
//				albumresult_t** albumResults =
//					reinterpret_cast<albumresult_t**>(results);
//				qDebug("Album List for %d:", id);
//				for (int i = 0; i < num; ++i) {
//					albumresult_t* res = *albumResults++;
//					qDebug("%2d. %d%% %s - %s", i, res->relevance, res->artist->name, res->name);
//				}
//			}

			rs_Delete(type, results, num);
			delete [] results;
		}
		tr_Unlock(track);
		tp_ReleaseTrack(m_tp, track);
	}
	return resultsAvailable;
}

Urs Fleisch's avatar
Urs Fleisch committed
677
678
#endif

Urs Fleisch's avatar
Urs Fleisch committed
679
680
681
682
683
684
#else // HAVE_TUNEPIMP

MusicBrainzClient::MusicBrainzClient(ImportTrackDataVector&) {}
MusicBrainzClient::~MusicBrainzClient() {}

#endif // HAVE_TUNEPIMP
685

686
#if !(defined HAVE_TUNEPIMP && HAVE_TUNEPIMP >= 5)
687

688
LookupQuery::LookupQuery(int, const QString&, unsigned short, const QString&, unsigned short) {}
689
690
LookupQuery::~LookupQuery() {}
void LookupQuery::socketConnected() {}
691
692
693
694
695
#if QT_VERSION >= 0x040000
void LookupQuery::socketError(QAbstractSocket::SocketError) {}
#else
void LookupQuery::socketError(int) {}
#endif
696
void LookupQuery::socketConnectionClosed() {}
Urs Fleisch's avatar
Urs Fleisch committed
697
void MusicBrainzClient::parseLookupResponse(int, const QByteArray&) {}
698
699

#endif