TTKMusicPlayer  4.3.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musicwyqueryinterface.cpp
Go to the documentation of this file.
3 #include "musicurlutils.h"
4 
6 
7 static constexpr const char *WY_USER_URL = "resource/user";
8 static constexpr const char *WY_UA_URL = "Vkloais0Z0Q4Smp1aElYSXFUVy96SXdoZ2VsTURzdDBpZEZjT21jMy9PRE1DMzdwQ0p5MllueTkrRGdzb2VkdlJMemJhWEFReHlUUk9uSEtMTHRLUzRxS3psczJiRW9LZ3BQbHh1Z3lGRlhEQk5JbVVGb1NDN1JzTDhZMjBybllLcndKSHlSNC94QzRJWXlL";
9 static constexpr const char *WY_COOKIE_URL = "eU5NVy9LRm5jWE9pdUU1MzNQNi9OcjVUbi9vSGhYcGVaQWc0NjlPbCt1WnNDbDlONDg1SSthTi9JUDQ1YVpsRg==";
10 static constexpr const char *WY_USER1_URL = "VzJpdUVPQ0xkZnp4VENJWjVIVFhQYzZKbnYrSU9pRTFmWXNkcXFaSWorRDRWMjJxUGdZaklZUDNzZXNweXJuczJMeGc2TVFRSEk4SkxCYkxXQ2FFUHpBbENUcjRZZ3RVNGpwRUloVkhVSWhSem50NTM3ZjFGMXdQVXFWN01mNE1GZUg2WFk3anl1Z1hxVkc0eXM3ZFZCVkpGNDZlNVA1MmhvYzZ6UT09";
11 static constexpr const char *WY_USER2_URL = "TE40MEZBWWJkbkhTbTM2OEVTMkE3VjlJOWZuUjVNQ3BFRGMwYjZ4NW9yeE5QdWozU0ZuSjJrQVdpQkdaT3B4enBMOGpTNUJiVXZDTUxmSWFNRkV5SGVqMXcxaS8rZnlsVmo2bkFJR1BvaGQ2c3llUFlyTVNITWdtcFRpMlA2SEl4VE40RnphRTRza2FPaG5RR3hkeGtZOHVGdHV6Nko3UHNBb25rdz09";
12 static constexpr const char *WY_USER3_URL = "c0s1RFpDY0Iya1hNOGFob2JLdGNiUFNxVCs0bE44MDBtQWtmTng4SDRqWlZOZWJXbUkySEtrSDNqVnhUOGMrUVpiNk9lc21MRlFTdFdNYlBwdWNtMmo2VUs4b1M4MFUvS2EzYkpjcnJTZHdZNGdsZ0JsU3lhWkoxaFY1czB4THF6anlDWWp5Ym1VKzJERjAvSmx1WXFPY0ErbjJrMnl2OFhGNGFBUT09";
13 static constexpr const char *WY_USER4_URL = "RGdEcVgrSERYQjErNUovY0hFOVU1dElWR00xRVNiRTRVenlHaVpiMkZ1Z0tXV2ZTZVpjL3RCV2pvajhLNjhINjFaUG5QWGdNcnZlcVlxZm93V01IUUgyWWM3NFFTdGE5K203MG5KeE0rNzFPV1ZFUmJHUnBSSHRXRUx1NEVYcU91VGgzWUh6M0hOcUVaUG9YQU9GNXFIaHlDVk5UVGNISmtmcHllQT09";
14 static constexpr const char *WY_USER5_URL = "ZmxqdmFXWFlmWFdtYzB2M212VVRaSDhIL1NhYnRySDg5dlV0eWx3YVdZUG82NFlMRlZMNnRHVGFlbVhqaFF0ckJ2YTVRSG12YnYrb1ZqaTJFY2ViK0Y3RG5WbWVHVldzVWk0enFweDd1dkhBNmF1dg==";
15 static constexpr const char *WY_RAND_URL = "V0Zsb2tGREU1R0thR29GYjRYdk5jbm5NZjEvN1d6WWNiQlZqb2k4eE1nTm9lTHlBRktkQTBOaXNjQ3ZHU0ZMSw==";
16 static constexpr const char *WY_BASE_URL = "MVNVTXo4bW9WdHhXR1dXeTZmU3k5dmFOcGlua1VOMlE=";
17 static constexpr const char *WY_SECKRY_URL = "411571dca16717d9af5ef1ac97a8d21cb740329890560688b1b624de43f49fdd7702493835141b06ae45f1326e264c98c24ce87199c1a776315e5f25c11056b02dd92791fcc012bff8dd4fc86e37888d5ccc060f7837b836607dbb28bddc703308a0ba67c24c6420dd08eec2b8111067486c907b6e53c027ae1e56c188bc568e";
18 
19 static constexpr const char *WY_SONG_PATH_V1_URL = "N2NkQWg4V3o0NXYvMlFHamVOWVZ5Y2NnTDk2cTNFdFVROVNwTndJV2REYXM0K01Yd2NIT1pwaGcyTGJ0QVVsNHVxT0lTZHFKNTI2QnlWMnVBWFNDdWYrb09Waz0=";
20 static constexpr const char *WY_SONG_PATH_V2_URL = "M21IV2dlSHNzaE1zZEpyb2hrQ0dqVEY3Ly9DZ3ZteDM1RStuSlJIRVVCRTljbWJKKzRBVnNZY3JEcEZKY045dEJ5KzM0WHArSDVCYXhrMHBoZmlTZXBWdHIvND0=";
21 static constexpr const char *WY_SONG_PATH_V2_DATA_URL = "ei9SdFJqZWlHWlh3eXBsWHJTS09FbUpRU1J4Zi9wZDlOQUMyVTVnL3c0YW9GSjVH";
22 static constexpr const char *WY_SONG_PATH_V3_URL = "cmNsdVp5dFI1TG5VMVg1N2w1bnZwOEx0TGlUazZuZ1JFMkg0dVcvS0ZKbExPL2d0UW9kT0RaZHNhMzFXcjZiVytiZmtLY2hvYjk0bVEyZDhWaldiTmx6V0pmaz0=";
23 static constexpr const char *WY_SONG_PATH_V3_QUERY_URL = "OCtmZUdQbVRENjVqWGo5eERUbnlnQ3BsLzVoa3p5WnFxYnJKcWZ3K1NCQWtiS01p";
24 static constexpr const char *WY_SONG_PATH_V3_DATA_URL = "TDlnVTZReGNvWk9YTkFFdVF4bDJJcUk4K1BHRFU1N2I3eHlNNmwwYnIzcEVRdDZVelpRVEpRODNjTDVWdXprVEJtcENlNmFmUHZXYUNsdXkxSHV6elE9PQ==";
25 
26 Q_GLOBAL_STATIC(QString, WY_USER_DATA)
27 
28 static QString makeUser() noexcept
29 {
31 }
32 
33 void ReqWYInterface::makeRequestRawHeader(QNetworkRequest *request) noexcept
34 {
35  if(WY_USER_DATA()->isEmpty())
36  {
37  QFile file(APPCACHE_DIR_FULL + WY_USER_URL);
38  if(file.open(QIODevice::ReadOnly))
39  {
40  *WY_USER_DATA() = QString::fromUtf8(file.readAll());
41  file.close();
42  }
43  else
44  {
45  *WY_USER_DATA() = makeUser();
46  }
47  }
48 
49  request->setRawHeader("Referer", TTK::Algorithm::mdII(WY_BASE_URL, false).toUtf8());
50  request->setRawHeader("Origin", TTK::Algorithm::mdII(WY_BASE_URL, false).toUtf8());
51  request->setRawHeader("User-Agent", TTK::Algorithm::mdII(WY_UA_URL, MDII_UA_KEY, false).toUtf8());
52  request->setRawHeader("Cookie", TTK::Algorithm::mdII(WY_COOKIE_URL, false).arg(*WY_USER_DATA(), TTK::Algorithm::mdII(WY_RAND_URL, MDII_UA_KEY, false)).toUtf8());
53 
54  TTK::setSslConfiguration(request);
56 }
57 
58 QString ReqWYInterface::makeSongArtist(const QString &in, const QString &name)
59 {
60  const QString &artistName = TTK::String::charactersReplace(name);
61  return in.isEmpty() ? artistName : (in + ";" + artistName);
62 }
63 
64 QString ReqWYInterface::makeCoverPixmapUrl(const QString &id)
65 {
66  static QByteArray magic = TTK::Algorithm::mdII("VHRXTE1NUmM3eGtOR25EWGpSYk1kVUg2U3A4Y2pmTkk=", false).toUtf8();
67 
68  QByteArray result;
69  const QByteArray &v = id.toUtf8();
70  for(int i = 0; i < v.length(); i++)
71  {
72  result.append(v[i] ^ magic[i % magic.length()]);
73  }
74 
75  result = TTK::Algorithm::md5(result, true);
76  result.replace('/', '_');
77  result.replace('+', "-");
78  return TTK::Algorithm::mdII("QWU4T2xhNmVNaDFVd1hKZ3JvUkJ5d1BCUHE2OU5CazV5TktERlBFaUYxQWhIMGVrUXBVWXl3PT0=", false).arg(result.constData(), id);
79 }
80 
81 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &query, const QString &data)
82 {
83  QAlgorithm::Aes aes;
84  QByteArray param = aes.encryptCBC(data.toUtf8(), "0CoJUm6Qyw8W8jud", "0102030405060708");
85  param = aes.encryptCBC(param, "a44e542eaac91dce", "0102030405060708");
86  TTK::Url::urlEncode(param);
87 
88  request->setUrl(query);
90  return "params=" + param + "&encSecKey=" + WY_SECKRY_URL;
91 }
92 
93 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &url, const QString &query, const QString &data)
94 {
95  const QString &message = "nobody" + query + "use" + data + "md5forencrypt";
96  const QByteArray &digest = QCryptographicHash::hash(message.toUtf8(), QCryptographicHash::Md5).toHex();
97  const QString &body = query + "-36cd479b6b5-" + data + "-36cd479b6b5-" + digest;
98 
99  QAlgorithm::Aes aes;
100  const QByteArray &param = aes.encryptECB(body.toUtf8(), "e82ckenh8dichen8", true);
101 
102  request->setUrl(url);
104  return "params=" + param.toUpper();
105 }
106 
107 static void parseSongPropertyV1(TTK::MusicSongInformation *info, int bitrate)
108 {
109  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
110  {
111  if(prop.m_bitrate == bitrate)
112  {
113  return;
114  }
115  }
116 
117  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v1 module");
118 
119  QNetworkRequest request;
120  request.setUrl(TTK::Algorithm::mdII(WY_SONG_PATH_V1_URL, false).arg(bitrate * 1000).arg(info->m_songId));
122 
123  const QByteArray &bytes = TTK::syncNetworkQueryForGet(&request);
124  if(bytes.isEmpty())
125  {
126  return;
127  }
128 
129  QJsonParseError ok;
130  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
132  {
133  QVariantMap value = json.toVariant().toMap();
134  if(value["code"].toInt() == 200 && value.contains("data"))
135  {
136  value = value["data"].toMap();
137  if(value.isEmpty())
138  {
139  return;
140  }
141 
142  const int rate = value["br"].toInt() / 1000;
143  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
144  {
146  prop.m_url = value["url"].toString();
147  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
148  prop.m_format = value["type"].toString();
149  prop.m_bitrate = bitrate;
150  info->m_songProps.append(prop);
151  }
152  }
153  }
154 }
155 
156 static void parseSongPropertyV2(TTK::MusicSongInformation *info, int bitrate)
157 {
158  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
159  {
160  if(prop.m_bitrate == bitrate)
161  {
162  return;
163  }
164  }
165 
166  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v2 module");
167 
168  QNetworkRequest request;
169  const QByteArray &parameter = ReqWYInterface::makeTokenRequest(&request,
171  TTK::Algorithm::mdII(WY_SONG_PATH_V2_DATA_URL, false).arg(info->m_songId).arg(bitrate * 1000));
172 
173  const QByteArray &bytes = TTK::syncNetworkQueryForPost(&request, parameter);
174  if(bytes.isEmpty())
175  {
176  return;
177  }
178 
179  QJsonParseError ok;
180  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
182  {
183  QVariantMap value = json.toVariant().toMap();
184  if(value["code"].toInt() == 200 && value.contains("data"))
185  {
186  const QVariantList &datas = value["data"].toList();
187  for(const QVariant &var : qAsConst(datas))
188  {
189  if(var.isNull())
190  {
191  continue;
192  }
193 
194  value = var.toMap();
195 
196  const int rate = value["br"].toInt() / 1000;
197  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
198  {
200  prop.m_url = value["url"].toString();
201  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
202  prop.m_format = value["type"].toString();
203  prop.m_bitrate = bitrate;
204  info->m_songProps.append(prop);
205  }
206  }
207  }
208  }
209 }
210 
211 static void parseSongPropertyV3(TTK::MusicSongInformation *info, int bitrate)
212 {
213  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
214  {
215  if(prop.m_bitrate == bitrate)
216  {
217  return;
218  }
219  }
220 
221  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v3 module");
222 
223  QString format;
224  switch(bitrate)
225  {
226  case TTK_BN_128: format = "standard"; break;
227  case TTK_BN_320: format = "exhigh"; break;
228  case TTK_BN_1000: format = "lossless"; break;
229  default: return;
230  }
231 
232  QNetworkRequest request;
233  const QByteArray &parameter = ReqWYInterface::makeTokenRequest(&request,
236  TTK::Algorithm::mdII(WY_SONG_PATH_V3_DATA_URL, false).arg(info->m_songId, format));
237 
238  const QByteArray &bytes = TTK::syncNetworkQueryForPost(&request, parameter);
239  if(bytes.isEmpty())
240  {
241  return;
242  }
243 
244  QJsonParseError ok;
245  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
247  {
248  QVariantMap value = json.toVariant().toMap();
249  if(value["code"].toInt() == 200 && value.contains("data"))
250  {
251  const QVariantList &datas = value["data"].toList();
252  for(const QVariant &var : qAsConst(datas))
253  {
254  if(var.isNull())
255  {
256  continue;
257  }
258 
259  value = var.toMap();
260 
261  const int rate = value["br"].toInt() / 1000;
262  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
263  {
265  prop.m_url = value["url"].toString();
266  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
267  prop.m_format = value["type"].toString();
268  prop.m_bitrate = bitrate;
269  info->m_songProps.append(prop);
270  }
271  }
272  }
273  }
274 }
275 
276 static void parseSongPropertyUnity(TTK::MusicSongInformation *info, int bitrate)
277 {
278  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
279  {
280  if(prop.m_bitrate == bitrate)
281  {
282  return;
283  }
284  }
285 
286  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in unity module");
287 
288  if(bitrate == TTK_BN_128 || bitrate == TTK_BN_320 || bitrate == TTK_BN_1000)
289  {
291  }
292 }
293 
294 static void parseSongProperty(TTK::MusicSongInformation *info, int bitrate)
295 {
297  {
298  parseSongPropertyUnity(info, bitrate);
299  parseSongPropertyV1(info, bitrate);
300  parseSongPropertyV2(info, bitrate);
301  parseSongPropertyV3(info, bitrate);
302  }
303  else
304  {
305  parseSongPropertyV1(info, bitrate);
306  parseSongPropertyV2(info, bitrate);
307  parseSongPropertyV3(info, bitrate);
308  parseSongPropertyUnity(info, bitrate);
309  }
310 }
311 
313 {
314  if(info->m_songId.isEmpty())
315  {
316  return;
317  }
318 
319  if(info->m_formatProps.isEmpty())
320  {
322  return;
323  }
324 
325  if(bitrate == TTK_BN_0)
326  {
327  const int maxBr = info->m_formatProps.toInt();
328  if(maxBr == TTK_BN_1000)
329  {
334  }
335  else if(maxBr == TTK_BN_320)
336  {
340  }
341  else if(maxBr == TTK_BN_192)
342  {
345  }
346  else
347  {
349  }
350  }
351  else
352  {
353  parseSongProperty(info, bitrate);
354  }
355 }
356 
358 {
359  int maxBr = TTK_BN_1000;
360  const QVariantMap &privilege = key["privilege"].toMap();
361  if(!privilege.isEmpty())
362  {
363  const QString &brStr = privilege["maxbr"].toString();
364  if(brStr == "999000")
365  {
366  maxBr = TTK_BN_1000;
367  }
368  else if(brStr == "320000" || brStr == "192000" || brStr == "190000")
369  {
370  maxBr = TTK_BN_320;
371  }
372  else if(brStr == "160000")
373  {
374  maxBr = TTK_BN_192;
375  }
376  else
377  {
378  maxBr = TTK_BN_128;
379  }
380  }
381 
382  info->m_formatProps = QString::number(maxBr);
383 }
TTK_MODULE_EXPORT QByteArray syncNetworkQueryForPost(QNetworkRequest *request, const QByteArray &data)
TTK_MODULE_EXPORT QString charactersReplace(const QString &value)
static constexpr const char * WY_COOKIE_URL
static constexpr const char * WY_SECKRY_URL
static QString message(const TTK::Attribute attr)
static constexpr const char * WY_USER1_URL
TTK_MODULE_EXPORT void setSslConfiguration(QNetworkRequest *request, QSslSocket::PeerVerifyMode mode=QSslSocket::VerifyNone) noexcept
TTK_MODULE_EXPORT QString urlEncode(QString &data)
QVariant toVariant() const
The class of the music song property.
Definition: musicobject.h:242
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=0)
static constexpr const char * WY_USER5_URL
static void parseSongPropertyUnity(TTK::MusicSongInformation *info, int bitrate)
QByteArray encryptECB(const QByteArray &in, const QByteArray &key, bool hex=false)
Definition: aeswrapper.cpp:6
static constexpr const char * WY_SONG_PATH_V3_DATA_URL
QString makeSongArtist(const QString &in, const QString &name)
static constexpr const char * WY_SONG_PATH_V3_QUERY_URL
MusicSongPropertyList m_songProps
Definition: musicobject.h:314
static constexpr const char * WY_USER_URL
TTK_MODULE_EXPORT QString sizeByteToLabel(qint64 size)
TTK_MODULE_EXPORT QByteArray syncNetworkQueryForGet(QNetworkRequest *request)
#define TTK_BN_1000
Definition: ttkglobal.h:434
static void parseSongPropertyV3(TTK::MusicSongInformation *info, int bitrate)
void makeRequestRawHeader(QNetworkRequest *request) noexcept
static constexpr const char * WY_USER3_URL
TTK_MODULE_EXPORT QByteArray md5(const QByteArray &data, bool base64=false)
QByteArray encryptCBC(const QByteArray &in, const QByteArray &key, const QByteArray &iv, bool hex=false)
Definition: aeswrapper.cpp:58
#define TTK_BN_500
Definition: ttkglobal.h:432
static constexpr const char * MDII_UA_KEY
ParseError error
#define APPCACHE_DIR_FULL
Definition: musicobject.h:140
#define qAsConst
Definition: ttkqtglobal.h:57
const char * name
Definition: http_parser.c:458
static constexpr const char * QUERY_WY_INTERFACE
static void parseSongProperty(TTK::MusicSongInformation *info, int bitrate)
static void parseSongPropertyV1(TTK::MusicSongInformation *info, int bitrate)
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:74
static constexpr const char * WY_SONG_PATH_V2_URL
static constexpr wchar_t key[]
The class of the aes wrapper.
Definition: aeswrapper.h:32
TTK_MODULE_EXPORT void setContentTypeHeader(QNetworkRequest *request, const QByteArray &data={}) noexcept
#define TTK_BN_0
Definition: ttkglobal.h:424
#define TTK_BN_320
Definition: ttkglobal.h:431
static QString makeUser() noexcept
static constexpr const char * WY_SONG_PATH_V3_URL
static constexpr const char * WY_USER4_URL
void parseFromSongProperty(TTK::MusicSongInformation *info, int bitrate)
static constexpr const char * WY_SONG_PATH_V2_DATA_URL
static constexpr const char * WY_USER2_URL
static constexpr const char * WY_SONG_PATH_V1_URL
#define TTK_BN_192
Definition: ttkglobal.h:429
static constexpr const char * WY_UA_URL
void parseFromSongProperty(TTK::MusicSongInformation *info, const QString &type, const QString &id, int bitrate)
QByteArray makeTokenRequest(QNetworkRequest *request, const QString &query, const QString &data)
static void parseSongPropertyV2(TTK::MusicSongInformation *info, int bitrate)
static constexpr const char * WY_RAND_URL
TTK_MODULE_EXPORT QString mdII(const QString &data, bool encode)
The class of the music song information.
Definition: musicobject.h:300
QString makeCoverPixmapUrl(const QString &id)
#define TTK_BN_128
Definition: ttkglobal.h:428
static constexpr const char * WY_BASE_URL
#define G_SETTING_PTR