TTKMusicPlayer  4.3.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musicidentifysongrequest.cpp
Go to the documentation of this file.
3 
4 #include "qsync/qsyncutils.h"
5 
6 #include <QFile>
7 
8 static constexpr const char *OS_ACRCLOUD_URL = "acrcloud";
9 static constexpr const char *ACR_QUERY_URL = "VzBxZCtBUDBKK1R6aHNiTGxMdy84SzlIUVA5a3cvbjdKQ1ZIVGdYRThBS0hZMTlZSnhRQ0Y5N0lZdi9QQ3VveVEyVDdXbll3ZUZvPQ==";
10 static constexpr const char *XF_QUERY_URL = "cFJiZUh0Z3FxalV6NzlBcEhUVmN5VGRzMm5NZ01rbzlWaFUzRE1ubzBoTU53WlI5cEZpNnVxT3l6OEE9";
11 static constexpr const char *XF_QUERY_BODY = "VHd2bFMwaTZGNFQxeDBuU0prYXE0SDIzOVYyWlVwMWk=";
12 static constexpr const char *XF_QUERY_DATA = "a29sU1NRVExPbzIzRDdiNjRlbWUwdz09";
13 
15  : MusicAbstractNetwork(parent),
16  m_items(nullptr)
17 {
18 
19 }
20 
21 
24 {
25 
26 }
27 
28 void MusicACRIdentifyRequest::startToRequest(const QString &path, const QVariantMap &keys)
29 {
30  QFile file(path);
31  if(!file.open(QIODevice::ReadOnly))
32  {
33  TTK_ERROR_STREAM("Load input audio wav file error");
34  return;
35  }
36 
37  const QString &accessKey = keys["key"].toString();
38  const QString &accessSecret = keys["secret"].toString();
39 
40  const QString &boundary = "----";
41  const QString &start = "--" + boundary;
42  const QString &end = "\r\n--" + boundary + "--\r\n";
43  const QString &contentType = "multipart/form-data; boundary=" + boundary;
44 
45  const QString &method = "POST";
46  const QString &endpoint = "/v1/identify";
47  const QString &type = "fingerprint";
48  const QString &version = "1";
49  const QString &timeStamp = QString::number(TTKDateTime::currentTimestamp());
50 
51  const QString &sign = method + "\n" + endpoint + "\n" + accessKey + "\n" + type + "\n" + version + "\n" + timeStamp;
52  QByteArray body = TTK::Algorithm::hmacSha1(sign.toUtf8(), accessSecret.toUtf8()).toBase64();
53 
54  QString value;
55  value += start + "\r\nContent-Disposition: form-data; name=\"access_key\"\r\n\r\n" + accessKey + "\r\n";
56  value += start + "\r\nContent-Disposition: form-data; name=\"data_type\"\r\n\r\n" + type + "\r\n";
57  value += start + "\r\nContent-Disposition: form-data; name=\"timestamp\"\r\n\r\n" + timeStamp + "\r\n";
58  value += start + "\r\nContent-Disposition: form-data; name=\"signature_version\"\r\n\r\n" + version + "\r\n";
59  value += start + "\r\nContent-Disposition: form-data; name=\"signature\"\r\n\r\n" + body + "\r\n";
60  value += start + "\r\nContent-Disposition: form-data; name=\"sample_bytes\"\r\n\r\n" + QString::number(file.size()) + "\r\n";
61  value += start + "\r\nContent-Disposition: form-data; name=\"sample\"; filename=\"" + file.fileName() + "\"\r\n";
62  value += "Content-Type: application/octet-stream\r\n\r\n";
63 
64  body.clear();
65  body.append(value.toUtf8());
66  body.append(file.readAll());
67  body.append(end.toUtf8());
68  file.close();
69 
70  QNetworkRequest request;
71  request.setUrl(TTK::Algorithm::mdII(ACR_QUERY_URL, false));
72  TTK::setSslConfiguration(&request);
73  TTK::setContentTypeHeader(&request, contentType.toUtf8());
74 
75  m_reply = m_manager.post(request, body);
76  connect(m_reply, SIGNAL(finished()), SLOT(downloadFinished()));
77  QtNetworkErrorConnect(m_reply, this, replyError, TTK_SLOT);
78 }
79 
81 {
82  TTK_INFO_STREAM(metaObject()->className() << __FUNCTION__);
83 
84  m_items->clear();
86 
87  if(m_reply && m_reply->error() == QNetworkReply::NoError)
88  {
89  QJsonParseError ok;
90  const QJsonDocument &json = QJsonDocument::fromJson(m_reply->readAll(), &ok);
92  {
93  QVariantMap value = json.toVariant().toMap();
94  if(value.contains("metadata"))
95  {
96  value = value["metadata"].toMap();
97 
98  const QVariantList &datas = value["music"].toList();
99  for(const QVariant &var : qAsConst(datas))
100  {
101  value = var.toMap();
103 
105  song.m_songName = value["title"].toString();
106  for(const QVariant &artists : value["artists"].toList())
107  {
108  value = artists.toMap();
109  song.m_artistName = TTK::String::charactersReplace(value["name"].toString());
110  break;
111  }
112 
113  m_items->append(song);
114  Q_EMIT downloadDataChanged("Found result");
115  deleteAll();
116  return;
117  }
118  }
119  else
120  {
121  TTK_INFO_STREAM("No result in acrcloud server");
122  }
123  }
124  }
125 
126  Q_EMIT downloadDataChanged({});
127  deleteAll();
128 }
129 
130 
133 {
134 
135 }
136 
137 void MusicXFIdentifyRequest::startToRequest(const QString &path, const QVariantMap &keys)
138 {
139  QFile file(path);
140  if(!file.open(QIODevice::ReadOnly))
141  {
142  TTK_ERROR_STREAM("Load input audio wav file error");
143  return;
144  }
145 
146  const QString &accessKey = keys["xfid"].toString();
147  const QString &accessSecret = keys["xfkey"].toString();
148 
149  const QByteArray &data = file.readAll();
150  file.close();
151 
152  const QByteArray &timeStamp = QByteArray::number(TTKDateTime::currentTimestamp() / 1000);
153  const QByteArray &audioBody = TTK::Algorithm::mdII(XF_QUERY_BODY, false).toUtf8().toBase64();
154  const QByteArray &md5 = TTK::Algorithm::md5(accessSecret.toUtf8() + timeStamp + audioBody);
155 
156  QNetworkRequest request;
157  request.setUrl(TTK::Algorithm::mdII(XF_QUERY_URL, false));
158  request.setRawHeader("X-CurTime", timeStamp);
159  request.setRawHeader("X-Param", audioBody);
160  request.setRawHeader("X-Appid", accessKey.toUtf8());
161  request.setRawHeader("X-CheckSum", md5);
162  TTK::setSslConfiguration(&request);
163  TTK::setContentTypeHeader(&request);
164 
165  m_reply = m_manager.post(request, TTK::Algorithm::mdII(XF_QUERY_DATA, false).arg(data.toBase64().constData()).toUtf8());
166  connect(m_reply, SIGNAL(finished()), SLOT(downloadFinished()));
168 }
169 
171 {
172  TTK_INFO_STREAM(metaObject()->className() << __FUNCTION__);
173 
174  m_items->clear();
176 
177  if(m_reply && m_reply->error() == QNetworkReply::NoError)
178  {
179  QJsonParseError ok;
180  const QJsonDocument &json = QJsonDocument::fromJson(m_reply->readAll(), &ok);
182  {
183  QVariantMap value = json.toVariant().toMap();
184  if(value["code"].toInt() == 0)
185  {
186  const QVariantList &datas = value["data"].toList();
187  for(const QVariant &var : qAsConst(datas))
188  {
189  value = var.toMap();
191 
193  song.m_songName = value["song"].toString();
194  song.m_artistName = value["singer"].toString();
195 
196  m_items->append(song);
197  Q_EMIT downloadDataChanged("Found result");
198  deleteAll();
199  return;
200  }
201  }
202  else
203  {
204  TTK_INFO_STREAM("No result in xf server");
205  }
206  }
207  }
208 
209  Q_EMIT downloadDataChanged({});
210  deleteAll();
211 }
212 
213 
215  : MusicAbstractNetwork(parent),
216  m_pluginSelector(-1)
217 {
218 
219 }
220 
222 {
223  TTKEventLoop loop;
224  connect(this, SIGNAL(finished()), &loop, SLOT(quit()));
225 
227  connect(req, SIGNAL(downloadRawDataChanged(QByteArray)), SLOT(downloadKeyFinished(QByteArray)));
229  loop.exec();
230 
231  return !m_rawData.isEmpty();
232 }
233 
235 {
236  m_path = path;
237  m_pluginSelector = -1;
238  findAllPlugins();
239 }
240 
242 {
243  if(bytes.isEmpty())
244  {
245  findAllPlugins();
246  return;
247  }
248 
249  Q_EMIT downloadDataChanged({});
250 }
251 
253 {
254  MusicAbstractIdentifyRequest *req = nullptr;
255  switch(++m_pluginSelector)
256  {
257  case 0: req = new MusicXFIdentifyRequest(this); break;
258  case 1: req = new MusicACRIdentifyRequest(this); break;
259  default: Q_EMIT downloadDataChanged({}); break;
260  }
261 
262  if(req)
263  {
264  connect(req, SIGNAL(downloadDataChanged(QString)), SLOT(downloadDataFinished(QString)));
265  //
266  req->setItems(&m_items);
268  }
269 }
270 
272 {
273  if(bytes.isEmpty())
274  {
275  TTK_ERROR_STREAM("Input key byte data is empty");
276  }
277  else
278  {
279  QJsonParseError ok;
280  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
282  {
283  m_rawData = json.toVariant().toMap();
284  }
285  }
286 
287  Q_EMIT finished();
288 }
TTK_MODULE_EXPORT QString charactersReplace(const QString &value)
virtual void startToRequest(const QString &path, const QVariantMap &keys) overridefinal
#define TTK_NETWORK_QUERY_CHECK(VALUE)
virtual void deleteAll()
TTK_MODULE_EXPORT void setSslConfiguration(QNetworkRequest *request, QSslSocket::PeerVerifyMode mode=QSslSocket::VerifyNone) noexcept
QNetworkReply * m_reply
static qint64 currentTimestamp() noexcept
Definition: ttktime.cpp:249
void downloadDataChanged(const QString &bytes)
QVariant toVariant() const
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=0)
MusicXFIdentifyRequest(QObject *parent=nullptr)
MusicSongIdentifyDataList * m_items
static constexpr const char * XF_QUERY_BODY
int exec(ProcessEventsFlags flags=AllEvents)
TTK_MODULE_EXPORT QByteArray hmacSha1(const QByteArray &data, const QByteArray &key)
virtual void startToRequest(const QString &path, const QVariantMap &keys)=0
virtual void downloadFinished() overridefinal
void downloadKeyFinished(const QByteArray &bytes)
TTK_MODULE_EXPORT QByteArray md5(const QByteArray &data, bool base64=false)
The class of the ttk event loop.
Definition: ttkeventloop.h:29
The class of the song identify data item.
virtual void startToRequest(const QString &path, const QVariantMap &keys) overridefinal
static constexpr const char * XF_QUERY_DATA
ParseError error
#define qAsConst
Definition: ttkqtglobal.h:57
MusicSongIdentifyDataList m_items
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:74
void startToRequest(const QString &path)
The class of the data source download request.
QNetworkAccessManager m_manager
TTK_MODULE_EXPORT void setContentTypeHeader(QNetworkRequest *request, const QByteArray &data={}) noexcept
virtual void replyError(QNetworkReply::NetworkError error) override
MusicAbstractIdentifyRequest(QObject *parent=nullptr)
#define TTK_SLOT
Definition: ttkqtglobal.h:177
The class of the abstract network.
static constexpr const char * OS_ACRCLOUD_URL
void startToRequest(const QString &url)
TTK_MODULE_EXPORT QString toString(Record type) noexcept
MusicIdentifySongRequest(QObject *parent=nullptr)
virtual void downloadFinished()
void downloadDataFinished(const QString &bytes)
void setItems(MusicSongIdentifyDataList *item) noexcept
The class of the abstract song identify query request.
MusicACRIdentifyRequest(QObject *parent=nullptr)
static constexpr const char * XF_QUERY_URL
static constexpr const char * ACR_QUERY_URL
The class of the xf song identify query request.
#define TTK_ERROR_STREAM(msg)
Definition: ttklogger.h:76
TTK_MODULE_EXPORT QString mdII(const QString &data, bool encode)
static QString makeDataBucketUrl()
Definition: qsyncutils.cpp:89
#define QtNetworkErrorConnect(p, q, f, s)
Network error connect.
Definition: ttkqtcompat.h:59
The class of the acr song identify query request.
virtual void downloadFinished() overridefinal
void downloadRawDataChanged(const QByteArray &bytes)