TTKMusicPlayer  4.2.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.
2 #include "musicurlutils.h"
3 #include "musicabstractnetwork.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 Q_GLOBAL_STATIC(QString, WY_USER_DATA)
20 
21 static QString makeUser() noexcept
22 {
24 }
25 
26 void ReqWYInterface::makeRequestRawHeader(QNetworkRequest *request) noexcept
27 {
28  if(WY_USER_DATA()->isEmpty())
29  {
30  QFile file(APPCACHE_DIR_FULL + WY_USER_URL);
31  if(file.open(QIODevice::ReadOnly))
32  {
33  *WY_USER_DATA() = QString::fromUtf8(file.readAll());
34  file.close();
35  }
36  else
37  {
38  *WY_USER_DATA() = makeUser();
39  }
40  }
41 
42  request->setRawHeader("Referer", TTK::Algorithm::mdII(WY_BASE_URL, false).toUtf8());
43  request->setRawHeader("Origin", TTK::Algorithm::mdII(WY_BASE_URL, false).toUtf8());
44  request->setRawHeader("User-Agent", TTK::Algorithm::mdII(WY_UA_URL, MDII_UA_KEY, false).toUtf8());
45  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());
46 
47  TTK::setSslConfiguration(request);
49 }
50 
51 QString ReqWYInterface::makeSongArtist(const QString &in, const QString &name)
52 {
53  const QString &artistName = TTK::String::charactersReplace(name);
54  return in.isEmpty() ? artistName : (in + ";" + artistName);
55 }
56 
57 QString ReqWYInterface::makeCoverPixmapUrl(const QString &url)
58 {
59  return url + TTK::Algorithm::mdII("dCt3T2JSbmJ2LzFuOUZBalAwTnUvNkRpc3dZPQ==", false);
60 }
61 
62 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &query, const QString &data)
63 {
64  QAlgorithm::Aes aes;
65  QByteArray param = aes.encryptCBC(data.toUtf8(), "0CoJUm6Qyw8W8jud", "0102030405060708");
66  param = aes.encryptCBC(param, "a44e542eaac91dce", "0102030405060708");
67  TTK::Url::urlEncode(param);
68 
69  request->setUrl(query);
71  return "params=" + param + "&encSecKey=" + WY_SECKRY_URL;
72 }
73 
74 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &url, const QString &query, const QString &data)
75 {
76  const QString &message = "nobody" + query + "use" + data + "md5forencrypt";
77  const QByteArray &digest = QCryptographicHash::hash(message.toUtf8(), QCryptographicHash::Md5).toHex();
78  const QString &body = query + "-36cd479b6b5-" + data + "-36cd479b6b5-" + digest;
79 
80  QAlgorithm::Aes aes;
81  const QByteArray &param = aes.encryptECB(body.toUtf8(), "e82ckenh8dichen8", true);
82 
83  request->setUrl(url);
85  return "params=" + param.toUpper();
86 }
87 
88 static void parseSongPropertyV1(TTK::MusicSongInformation *info, int bitrate)
89 {
90  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
91  {
92  if(prop.m_bitrate == bitrate)
93  {
94  return;
95  }
96  }
97 
98  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v1 module");
99 
100  QNetworkRequest request;
101  request.setUrl(TTK::Algorithm::mdII(WY_SONG_PATH_V1_URL, false).arg(bitrate * 1000).arg(info->m_songId));
103 
104  const QByteArray &bytes = TTK::syncNetworkQueryForGet(&request);
105  if(bytes.isEmpty())
106  {
107  return;
108  }
109 
110  QJsonParseError ok;
111  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
113  {
114  QVariantMap value = json.toVariant().toMap();
115  if(value["code"].toInt() == 200 && value.contains("data"))
116  {
117  value = value["data"].toMap();
118  if(value.isEmpty())
119  {
120  return;
121  }
122 
123  const int rate = value["br"].toInt() / 1000;
124  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
125  {
127  prop.m_url = value["url"].toString();
128  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
129  prop.m_format = value["type"].toString();
130  prop.m_bitrate = bitrate;
131  info->m_songProps.append(prop);
132  }
133  }
134  }
135 }
136 
137 static void parseSongPropertyV2(TTK::MusicSongInformation *info, int bitrate)
138 {
139  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
140  {
141  if(prop.m_bitrate == bitrate)
142  {
143  return;
144  }
145  }
146 
147  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v2 module");
148 
149  QNetworkRequest request;
150  const QByteArray &parameter = ReqWYInterface::makeTokenRequest(&request,
152  TTK::Algorithm::mdII(WY_SONG_PATH_V2_DATA_URL, false).arg(info->m_songId).arg(bitrate * 1000));
153 
154  const QByteArray &bytes = TTK::syncNetworkQueryForPost(&request, parameter);
155  if(bytes.isEmpty())
156  {
157  return;
158  }
159 
160  QJsonParseError ok;
161  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
163  {
164  QVariantMap value = json.toVariant().toMap();
165  if(value["code"].toInt() == 200 && value.contains("data"))
166  {
167  const QVariantList &datas = value["data"].toList();
168  for(const QVariant &var : qAsConst(datas))
169  {
170  if(var.isNull())
171  {
172  continue;
173  }
174 
175  value = var.toMap();
176 
177  const int rate = value["br"].toInt() / 1000;
178  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
179  {
181  prop.m_url = value["url"].toString();
182  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
183  prop.m_format = value["type"].toString();
184  prop.m_bitrate = bitrate;
185  info->m_songProps.append(prop);
186  }
187  }
188  }
189  }
190 }
191 
192 static void parseSongPropertyV3(TTK::MusicSongInformation *info, int bitrate)
193 {
194  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
195  {
196  if(prop.m_bitrate == bitrate)
197  {
198  return;
199  }
200  }
201 
202  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v3 module");
203 
204  QString format;
205  switch(bitrate)
206  {
207  case TTK_BN_128: format = "standard"; break;
208  case TTK_BN_320: format = "exhigh"; break;
209  case TTK_BN_1000: format = "lossless"; break;
210  default: return;
211  }
212 
213  QNetworkRequest request;
214  const QByteArray &parameter = ReqWYInterface::makeTokenRequest(&request,
217  TTK::Algorithm::mdII(WY_SONG_PATH_V3_DATA_URL, false).arg(info->m_songId, format));
218 
219  const QByteArray &bytes = TTK::syncNetworkQueryForPost(&request, parameter);
220  if(bytes.isEmpty())
221  {
222  return;
223  }
224 
225  QJsonParseError ok;
226  const QJsonDocument &json = QJsonDocument::fromJson(bytes, &ok);
228  {
229  QVariantMap value = json.toVariant().toMap();
230  if(value["code"].toInt() == 200 && value.contains("data"))
231  {
232  const QVariantList &datas = value["data"].toList();
233  for(const QVariant &var : qAsConst(datas))
234  {
235  if(var.isNull())
236  {
237  continue;
238  }
239 
240  value = var.toMap();
241 
242  const int rate = value["br"].toInt() / 1000;
243  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
244  {
246  prop.m_url = value["url"].toString();
247  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
248  prop.m_format = value["type"].toString();
249  prop.m_bitrate = bitrate;
250  info->m_songProps.append(prop);
251  }
252  }
253  }
254  }
255 }
256 
257 static void parseSongProperty(TTK::MusicSongInformation *info, int bitrate)
258 {
259  parseSongPropertyV1(info, bitrate);
260  parseSongPropertyV2(info, bitrate);
261  parseSongPropertyV3(info, bitrate);
262 }
263 
265 {
266  if(info->m_songId.isEmpty())
267  {
268  return;
269  }
270 
271  if(info->m_formatProps.isEmpty())
272  {
274  return;
275  }
276 
277  if(bitrate == TTK_BN_0)
278  {
279  const int maxBr = info->m_formatProps.toInt();
280  if(maxBr == TTK_BN_1000)
281  {
286  }
287  else if(maxBr == TTK_BN_320)
288  {
292  }
293  else if(maxBr == TTK_BN_192)
294  {
297  }
298  else
299  {
301  }
302  }
303  else
304  {
305  parseSongProperty(info, bitrate);
306  }
307 }
308 
310 {
311  int maxBr = TTK_BN_1000;
312  const QVariantMap &privilege = key["privilege"].toMap();
313  if(!privilege.isEmpty())
314  {
315  const QString &brStr = privilege["maxbr"].toString();
316  if(brStr == "999000")
317  {
318  maxBr = TTK_BN_1000;
319  }
320  else if(brStr == "320000" || brStr == "192000" || brStr == "190000")
321  {
322  maxBr = TTK_BN_320;
323  }
324  else if(brStr == "160000")
325  {
326  maxBr = TTK_BN_192;
327  }
328  else
329  {
330  maxBr = TTK_BN_128;
331  }
332  }
333 
334  info->m_formatProps = QString::number(maxBr);
335 }
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 constexpr const char * WY_SONG_PATH_V3_URL
static constexpr const char * WY_USER1_URL
static constexpr const char * WY_SONG_PATH_V3_DATA_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:237
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=0)
static constexpr const char * WY_USER5_URL
QByteArray encryptECB(const QByteArray &in, const QByteArray &key, bool hex=false)
Definition: aeswrapper.cpp:6
static constexpr const char * WY_SONG_PATH_V2_URL
QString makeSongArtist(const QString &in, const QString &name)
MusicSongPropertyList m_songProps
Definition: musicobject.h:309
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
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:135
#define qAsConst
Definition: ttkqtglobal.h:57
const char * name
Definition: http_parser.c:458
TTK_MODULE_EXPORT void makeContentTypeHeader(QNetworkRequest *request, const QByteArray &data={}) noexcept
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_V1_URL
static constexpr wchar_t key[]
The class of the aes wrapper.
Definition: aeswrapper.h:32
#define TTK_BN_0
Definition: ttkglobal.h:424
#define TTK_BN_320
Definition: ttkglobal.h:431
static constexpr const char * WY_SONG_PATH_V2_DATA_URL
static QString makeUser() noexcept
static constexpr const char * WY_USER4_URL
void parseFromSongProperty(TTK::MusicSongInformation *info, int bitrate)
static constexpr const char * WY_SONG_PATH_V3_QUERY_URL
static constexpr const char * WY_USER2_URL
QString makeCoverPixmapUrl(const QString &url)
#define TTK_BN_192
Definition: ttkglobal.h:429
static constexpr const char * WY_UA_URL
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:295
#define TTK_BN_128
Definition: ttkglobal.h:428
static constexpr const char * WY_BASE_URL