TTKMusicPlayer  4.2.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 {
17 
18 }
19 
21 {
22  TTKEventLoop loop;
23  connect(this, SIGNAL(finished()), &loop, SLOT(quit()));
24 
26  connect(d, SIGNAL(downLoadRawDataChanged(QByteArray)), SLOT(downLoadKeyFinished(QByteArray)));
28  loop.exec();
29 
30  return !m_accessKey.isEmpty() && !m_accessSecret.isEmpty();
31 }
32 
33 
36 {
37 
38 }
39 
40 void MusicACRIdentifyRequest::startToRequest(const QString &path)
41 {
42  QFile file(path);
43  if(!file.open(QIODevice::ReadOnly))
44  {
45  TTK_ERROR_STREAM("Load input audio wav file error");
46  return;
47  }
48 
49  const QString &boundary = "----";
50  const QString &start = "--" + boundary;
51  const QString &end = "\r\n--" + boundary + "--\r\n";
52  const QString &contentType = "multipart/form-data; boundary=" + boundary;
53 
54  const QString &method = "POST";
55  const QString &endpoint = "/v1/identify";
56  const QString &type = "fingerprint";
57  const QString &version = "1";
58  const QString &timeStamp = QString::number(TTKDateTime::currentTimestamp());
59 
60  const QString &sign = method + "\n" + endpoint + "\n" + m_accessKey + "\n" + type + "\n" + version + "\n" + timeStamp;
61  QByteArray body = TTK::Algorithm::hmacSha1(sign.toUtf8(), m_accessSecret.toUtf8()).toBase64();
62 
63  QString value;
64  value += start + "\r\nContent-Disposition: form-data; name=\"access_key\"\r\n\r\n" + m_accessKey + "\r\n";
65  value += start + "\r\nContent-Disposition: form-data; name=\"data_type\"\r\n\r\n" + type + "\r\n";
66  value += start + "\r\nContent-Disposition: form-data; name=\"timestamp\"\r\n\r\n" + timeStamp + "\r\n";
67  value += start + "\r\nContent-Disposition: form-data; name=\"signature_version\"\r\n\r\n" + version + "\r\n";
68  value += start + "\r\nContent-Disposition: form-data; name=\"signature\"\r\n\r\n" + body + "\r\n";
69  value += start + "\r\nContent-Disposition: form-data; name=\"sample_bytes\"\r\n\r\n" + QString::number(file.size()) + "\r\n";
70  value += start + "\r\nContent-Disposition: form-data; name=\"sample\"; filename=\"" + file.fileName() + "\"\r\n";
71  value += "Content-Type: application/octet-stream\r\n\r\n";
72 
73  body.clear();
74  body.append(value.toUtf8());
75  body.append(file.readAll());
76  body.append(end.toUtf8());
77  file.close();
78 
79  QNetworkRequest request;
80  request.setUrl(TTK::Algorithm::mdII(ACR_QUERY_URL, false));
81  TTK::setSslConfiguration(&request);
82  TTK::makeContentTypeHeader(&request, contentType.toUtf8());
83 
84  m_reply = m_manager.post(request, body);
85  connect(m_reply, SIGNAL(finished()), SLOT(downLoadFinished()));
86  QtNetworkErrorConnect(m_reply, this, replyError, TTK_SLOT);
87 }
88 
90 {
91  TTK_INFO_STREAM(className() << __FUNCTION__);
92 
93  m_items.clear();
95 
96  if(m_reply && m_reply->error() == QNetworkReply::NoError)
97  {
98  QJsonParseError ok;
99  const QJsonDocument &json = QJsonDocument::fromJson(m_reply->readAll(), &ok);
101  {
102  QVariantMap value = json.toVariant().toMap();
103  if(value.contains("metadata"))
104  {
105  value = value["metadata"].toMap();
106 
107  const QVariantList &datas = value["music"].toList();
108  for(const QVariant &var : qAsConst(datas))
109  {
110  value = var.toMap();
112 
114  song.m_songName = value["title"].toString();
115  for(const QVariant &artists : value["artists"].toList())
116  {
117  value = artists.toMap();
118  song.m_artistName = TTK::String::charactersReplace(value["name"].toString());
119  break;
120  }
121 
122  m_items << song;
123  break;
124  }
125  }
126  else
127  {
128  TTK_INFO_STREAM("No result in acrcloud server");
129  }
130  }
131  }
132 
133  Q_EMIT downLoadDataChanged({});
134  deleteAll();
135 }
136 
137 void MusicACRIdentifyRequest::downLoadKeyFinished(const QByteArray &bytes)
138 {
139  if(bytes.isEmpty())
140  {
141  TTK_ERROR_STREAM("Input byte data is empty");
142  }
143  else
144  {
145  QJsonParseError ok;
146  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
148  {
149  const QVariantMap &value = json.toVariant().toMap();
150  m_accessKey = value["key"].toString();
151  m_accessSecret = value["secret"].toString();
152  }
153  }
154 
155  Q_EMIT finished();
156 }
157 
158 
161 {
162 
163 }
164 
165 void MusicXFIdentifyRequest::startToRequest(const QString &path)
166 {
167  QFile file(path);
168  if(!file.open(QIODevice::ReadOnly))
169  {
170  TTK_ERROR_STREAM("Load input audio wav file error");
171  return;
172  }
173 
174  const QByteArray &data = file.readAll();
175  file.close();
176 
177  const QByteArray &timeStamp = QByteArray::number(TTKDateTime::currentTimestamp() / 1000);
178  const QByteArray &audioBody = TTK::Algorithm::mdII(XF_QUERY_BODY, false).toUtf8().toBase64();
179  const QByteArray &md5 = TTK::Algorithm::md5(m_accessSecret.toUtf8() + timeStamp + audioBody);
180 
181  QNetworkRequest request;
182  request.setUrl(TTK::Algorithm::mdII(XF_QUERY_URL, false));
183  request.setRawHeader("X-CurTime", timeStamp);
184  request.setRawHeader("X-Param", audioBody);
185  request.setRawHeader("X-Appid", m_accessKey.toUtf8());
186  request.setRawHeader("X-CheckSum", md5);
187  TTK::setSslConfiguration(&request);
188  TTK::makeContentTypeHeader(&request);
189 
190  m_reply = m_manager.post(request, TTK::Algorithm::mdII(XF_QUERY_DATA, false).arg(data.toBase64().constData()).toUtf8());
191  connect(m_reply, SIGNAL(finished()), SLOT(downLoadFinished()));
193 }
194 
196 {
197  TTK_INFO_STREAM(className() << __FUNCTION__);
198 
199  m_items.clear();
201 
202  if(m_reply && m_reply->error() == QNetworkReply::NoError)
203  {
204  QJsonParseError ok;
205  const QJsonDocument &json = QJsonDocument::fromJson(m_reply->readAll(), &ok);
207  {
208  QVariantMap value = json.toVariant().toMap();
209  if(value["code"].toInt() == 0)
210  {
211  const QVariantList &datas = value["data"].toList();
212  for(const QVariant &var : qAsConst(datas))
213  {
214  value = var.toMap();
216 
218  song.m_songName = value["song"].toString();
219  song.m_artistName = value["singer"].toString();
220  m_items << song;
221  break;
222  }
223  }
224  else
225  {
226  TTK_INFO_STREAM("No result in xf server");
227  }
228  }
229  }
230 
231  Q_EMIT downLoadDataChanged({});
232  deleteAll();
233 }
234 
235 void MusicXFIdentifyRequest::downLoadKeyFinished(const QByteArray &bytes)
236 {
237  if(bytes.isEmpty())
238  {
239  TTK_ERROR_STREAM("Input byte data is empty");
240  }
241  else
242  {
243  QJsonParseError ok;
244  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
246  {
247  const QVariantMap &value = json.toVariant().toMap();
248  m_accessKey = value["xfid"].toString();
249  m_accessSecret = value["xfkey"].toString();
250  }
251  }
252 
253  Q_EMIT finished();
254 }
TTK_MODULE_EXPORT QString charactersReplace(const QString &value)
#define TTK_NETWORK_QUERY_CHECK(VALUE)
TTK_MODULE_EXPORT QByteArray md5(const QByteArray &data)
virtual void deleteAll()
void downLoadDataChanged(const QString &bytes)
TTK_MODULE_EXPORT void setSslConfiguration(QNetworkRequest *request, QSslSocket::PeerVerifyMode mode=QSslSocket::VerifyNone) noexcept
QNetworkReply * m_reply
void downLoadRawDataChanged(const QByteArray &bytes)
static qint64 currentTimestamp() noexcept
Definition: ttktime.cpp:249
QVariant toVariant() const
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=0)
MusicXFIdentifyRequest(QObject *parent=nullptr)
virtual void startToRequest(const QString &path) overridefinal
virtual void downLoadFinished() overridefinal
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 downLoadFinished()
The class of the ttk event loop.
Definition: ttkeventloop.h:29
The class of the song identify data item.
static constexpr const char * XF_QUERY_DATA
ParseError error
#define qAsConst
Definition: ttkqtglobal.h:57
TTK_MODULE_EXPORT void makeContentTypeHeader(QNetworkRequest *request, const QByteArray &data={}) noexcept
virtual void startToRequest(const QString &path) overridefinal
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:74
The class of the data source download request.
QNetworkAccessManager m_manager
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
virtual void downLoadFinished() overridefinal
virtual void downLoadKeyFinished(const QByteArray &bytes) overridefinal
The class of the abstract song identify query request.
virtual void downLoadKeyFinished(const QByteArray &bytes) overridefinal
MusicACRIdentifyRequest(QObject *parent=nullptr)
static constexpr const char * XF_QUERY_URL
static constexpr const char * ACR_QUERY_URL
virtual void downLoadKeyFinished(const QByteArray &bytes)=0
#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
MusicSongIdentifyDataList m_items
#define QtNetworkErrorConnect(p, q, f, s)
Network error connect.
Definition: ttkqtcompat.h:59