TTKMusicPlayer  4.1.3.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()
22 {
24 }
25 
26 void ReqWYInterface::makeRequestRawHeader(QNetworkRequest *request)
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  TTK::setSslConfiguration(request);
48 }
49 
50 QString ReqWYInterface::makeSongArtist(const QString &in, const QString &name)
51 {
52  const QString &artistName = TTK::String::charactersReplace(name);
53  return in.isEmpty() ? artistName : (in + ";" + artistName);
54 }
55 
56 QString ReqWYInterface::makeCoverPixmapUrl(const QString &url)
57 {
58  return url + TTK::Algorithm::mdII("dCt3T2JSbmJ2LzFuOUZBalAwTnUvNkRpc3dZPQ==", false);
59 }
60 
61 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &query, const QString &data)
62 {
63  QAlgorithm::Aes aes;
64  QByteArray param = aes.encryptCBC(data.toUtf8(), "0CoJUm6Qyw8W8jud", "0102030405060708");
65  param = aes.encryptCBC(param, "a44e542eaac91dce", "0102030405060708");
66  TTK::Url::urlEncode(param);
67 
68  request->setUrl(query);
70  return "params=" + param + "&encSecKey=" + WY_SECKRY_URL;
71 }
72 
73 QByteArray ReqWYInterface::makeTokenRequest(QNetworkRequest *request, const QString &url, const QString &query, const QString &data)
74 {
75  const QString &message = "nobody" + query + "use" + data + "md5forencrypt";
76  const QByteArray &digest = QCryptographicHash::hash(message.toUtf8(), QCryptographicHash::Md5).toHex();
77  const QString &body = query + "-36cd479b6b5-" + data + "-36cd479b6b5-" + digest;
78 
79  QAlgorithm::Aes aes;
80  const QByteArray &param = aes.encryptECB(body.toUtf8(), "e82ckenh8dichen8", true);
81 
82  request->setUrl(url);
84  return "params=" + param.toUpper();
85 }
86 
87 static void parseSongPropertyV1(TTK::MusicSongInformation *info, int bitrate)
88 {
89  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
90  {
91  if(prop.m_bitrate == bitrate)
92  {
93  return;
94  }
95  }
96 
97  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v1 module");
98 
99  QNetworkRequest request;
100  request.setUrl(TTK::Algorithm::mdII(WY_SONG_PATH_V1_URL, false).arg(bitrate * 1000).arg(info->m_songId));
102 
103  const QByteArray &bytes = TTK::syncNetworkQueryForGet(&request);
104  if(bytes.isEmpty())
105  {
106  return;
107  }
108 
109  QJson::Parser json;
110  bool ok = false;
111  const QVariant &data = json.parse(bytes, &ok);
112  if(ok)
113  {
114  QVariantMap value = data.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  QJson::Parser json;
161  bool ok = false;
162  const QVariant &data = json.parse(bytes, &ok);
163  if(ok)
164  {
165  QVariantMap value = data.toMap();
166  if(value["code"].toInt() == 200 && value.contains("data"))
167  {
168  const QVariantList &datas = value["data"].toList();
169  for(const QVariant &var : qAsConst(datas))
170  {
171  if(var.isNull())
172  {
173  continue;
174  }
175 
176  value = var.toMap();
177 
178  const int rate = value["br"].toInt() / 1000;
179  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
180  {
182  prop.m_url = value["url"].toString();
183  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
184  prop.m_format = value["type"].toString();
185  prop.m_bitrate = bitrate;
186  info->m_songProps.append(prop);
187  }
188  }
189  }
190  }
191 }
192 
193 static void parseSongPropertyV3(TTK::MusicSongInformation *info, int bitrate)
194 {
195  for(const TTK::MusicSongProperty &prop : qAsConst(info->m_songProps))
196  {
197  if(prop.m_bitrate == bitrate)
198  {
199  return;
200  }
201  }
202 
203  TTK_INFO_STREAM("parse song" << bitrate << "kbps property in v3 module");
204 
205  QString format;
206  switch(bitrate)
207  {
208  case TTK_BN_128: format = "standard"; break;
209  case TTK_BN_320: format = "exhigh"; break;
210  case TTK_BN_1000: format = "lossless"; break;
211  default: return;
212  }
213 
214  QNetworkRequest request;
215  const QByteArray &parameter = ReqWYInterface::makeTokenRequest(&request,
218  TTK::Algorithm::mdII(WY_SONG_PATH_V3_DATA_URL, false).arg(info->m_songId, format));
219 
220  const QByteArray &bytes = TTK::syncNetworkQueryForPost(&request, parameter);
221  if(bytes.isEmpty())
222  {
223  return;
224  }
225 
226  QJson::Parser json;
227  bool ok = false;
228  const QVariant &data = json.parse(bytes, &ok);
229  if(ok)
230  {
231  QVariantMap value = data.toMap();
232  if(value["code"].toInt() == 200 && value.contains("data"))
233  {
234  const QVariantList &datas = value["data"].toList();
235  for(const QVariant &var : qAsConst(datas))
236  {
237  if(var.isNull())
238  {
239  continue;
240  }
241 
242  value = var.toMap();
243 
244  const int rate = value["br"].toInt() / 1000;
245  if(rate == bitrate || (bitrate > TTK_BN_500 && rate > TTK_BN_500))
246  {
248  prop.m_url = value["url"].toString();
249  prop.m_size = TTK::Number::sizeByteToLabel(value["size"].toInt());
250  prop.m_format = value["type"].toString();
251  prop.m_bitrate = bitrate;
252  info->m_songProps.append(prop);
253  }
254  }
255  }
256  }
257 }
258 
259 static void parseSongProperty(TTK::MusicSongInformation *info, int bitrate)
260 {
261  parseSongPropertyV1(info, bitrate);
262  parseSongPropertyV2(info, bitrate);
263  parseSongPropertyV3(info, bitrate);
264 }
265 
267 {
268  if(info->m_songId.isEmpty())
269  {
270  return;
271  }
272 
273  if(info->m_formatProps.isEmpty())
274  {
276  return;
277  }
278 
279  if(bitrate == TTK_BN_0)
280  {
281  const int maxBr = info->m_formatProps.toInt();
282  if(maxBr == TTK_BN_1000)
283  {
288  }
289  else if(maxBr == TTK_BN_320)
290  {
294  }
295  else if(maxBr == TTK_BN_192)
296  {
299  }
300  else
301  {
303  }
304  }
305  else
306  {
307  parseSongProperty(info, bitrate);
308  }
309 }
310 
312 {
313  int maxBr = TTK_BN_1000;
314  const QVariantMap &privilege = key["privilege"].toMap();
315  if(!privilege.isEmpty())
316  {
317  const QString &brStr = privilege["maxbr"].toString();
318  if(brStr == "999000")
319  {
320  maxBr = TTK_BN_1000;
321  }
322  else if(brStr == "320000" || brStr == "192000" || brStr == "190000")
323  {
324  maxBr = TTK_BN_320;
325  }
326  else if(brStr == "160000")
327  {
328  maxBr = TTK_BN_192;
329  }
330  else
331  {
332  maxBr = TTK_BN_128;
333  }
334  }
335 
336  info->m_formatProps = QString::number(maxBr);
337 }
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 QString urlEncode(QString &data)
The class of the music song property.
Definition: musicobject.h:225
static constexpr const char * WY_USER5_URL
static constexpr wchar_t key[]
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)
TTK_MODULE_EXPORT void setSslConfiguration(QNetworkRequest *request, QSslSocket::PeerVerifyMode mode=QSslSocket::VerifyNone)
MusicSongPropertyList m_songProps
Definition: musicobject.h:297
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:359
static void parseSongPropertyV3(TTK::MusicSongInformation *info, int bitrate)
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:357
static constexpr const char * MDII_UA_KEY
#define APPCACHE_DIR_FULL
Definition: musicobject.h:123
#define qAsConst
Definition: ttkqtglobal.h:51
const char * name
Definition: http_parser.c:458
static void parseSongProperty(TTK::MusicSongInformation *info, int bitrate)
static void parseSongPropertyV1(TTK::MusicSongInformation *info, int bitrate)
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:68
void makeRequestRawHeader(QNetworkRequest *request)
static constexpr const char * WY_SONG_PATH_V1_URL
The class of the aes wrapper.
Definition: aeswrapper.h:32
static QString makeUser()
#define TTK_BN_0
Definition: ttkglobal.h:349
#define TTK_BN_320
Definition: ttkglobal.h:356
QVariant parse(QIODevice *io, bool *ok=0)
Read JSON string from the I/O Device and converts it to a QVariant object.
Definition: parser.cpp:69
static constexpr const char * WY_SONG_PATH_V2_DATA_URL
static constexpr const char * WY_USER4_URL
void parseFromSongProperty(TTK::MusicSongInformation *info, int bitrate)
static constexpr const char * WY_SONG_PATH_V3_QUERY_URL
TTK_MODULE_EXPORT void makeContentTypeHeader(QNetworkRequest *request, const QByteArray &data={})
static constexpr const char * WY_USER2_URL
QString makeCoverPixmapUrl(const QString &url)
Main class used to convert JSON data to QVariant objects.
Definition: parser.h:40
#define TTK_BN_192
Definition: ttkglobal.h:354
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:283
#define TTK_BN_128
Definition: ttkglobal.h:353
static constexpr const char * WY_BASE_URL