TTKMusicPlayer  4.2.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musiclrcparser.cpp
Go to the documentation of this file.
1 #include "musiclrcparser.h"
2 #include "ttkabstractxml.h"
3 
4 #include <QFile>
5 #include <sys/stat.h>
6 
7 #include "zlib/zconf.h"
8 #include "zlib/zlib.h"
9 
10 const QByteArray &MusicLrcFromInterface::data() const noexcept
11 {
12  return m_data;
13 }
14 
15 
16 bool MusicLrcFromPlain::decode(const QString &input)
17 {
18  QFile file(input);
19  if(!file.open(QIODevice::ReadOnly))
20  {
21  return false;
22  }
23 
24  m_data = file.readAll();
25  file.close();
26  return true;
27 }
28 
29 
30 static constexpr wchar_t key[] = {
31  L'@', L'G', L'a', L'w', L'^', L'2',
32  L't', L'G', L'Q', L'6', L'1', L'-',
33  L'Î', L'Ò', L'n', L'i'
34 };
35 
36 
39  m_resultBytes(new uchar[TTK_SN_MB2BT])
40 {
41 
42 }
43 
45 {
46  delete[] m_resultBytes;
47 }
48 
49 bool MusicLrcFromKrc::decode(const QString &input)
50 {
51  return decode(input, {});
52 }
53 
54 bool MusicLrcFromKrc::decode(const QString &input, const QString &output)
55 {
56  FILE *fp = nullptr;
57  struct stat st;
58  size_t dstsize;
59 
60  if((fp = fopen(qPrintable(input), "rb")) == nullptr)
61  {
62  TTK_ERROR_STREAM("Open file error");
63  return false;
64  }
65 
66  if(fstat(fileno(fp), &st))
67  {
68  TTK_ERROR_STREAM("Fstat file error");
69  fclose(fp);
70  return false;
71  }
72 
73  uchar *src = new uchar[st.st_size];
74  uchar *ptr = src;
75 
76  if(fread(src, sizeof(uchar), st.st_size, fp) != (size_t)st.st_size)
77  {
78  TTK_ERROR_STREAM("Fread file error");
79  delete[] src;
80  fclose(fp);
81  return false;
82  }
83 
84  if(memcmp(src, "krc1", 4) != 0)
85  {
86  TTK_ERROR_STREAM("Error file format");
87  delete[] src;
88  fclose(fp);
89  return false;
90  }
91 
92  src += 4;
93  for(int i = 0; i < st.st_size; ++i)
94  {
95  src[i] = (uchar)(src[i] ^ key[i % 16]);
96  }
97 
98  decompression(src, st.st_size, &dstsize);
99  createLrc(m_resultBytes, TTKStaticCast(int, dstsize));
100 
101  delete[] ptr;
102  fclose(fp);
103 
104  if(!output.isEmpty())
105  {
106  QFile file(output);
107  if(file.open(QIODevice::WriteOnly))
108  {
109  QTextStream outstream(&file);
110  outstream.setCodec("UTF-8");
111  outstream << m_data;
112  outstream << QtNamespace(endl);
113  file.close();
114  }
115  }
116  return true;
117 }
118 
119 int MusicLrcFromKrc::sncasecmp(char *s1, char *s2, size_t n)
120 {
121  uint c1, c2;
122  while(n)
123  {
124  c1 = (uint) *s1++;
125  c2 = (uint) *s2++;
126 
127  c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
128  c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
129 
130  if(c1 == c2)
131  {
132  if(c1)
133  {
134  n--;
135  continue;
136  }
137  return 0;
138  }
139  return c1 - c2;
140  }
141  return 0;
142 }
143 
144 int MusicLrcFromKrc::decompression(uchar *src, size_t srcsize, size_t *dstsize)
145 {
146  *dstsize = TTK_SN_MB2BT;
147  if(Z_OK != uncompress(m_resultBytes, (uLongf*)dstsize, src, srcsize))
148  {
149  return -1;
150  }
151  return 0;
152 }
153 
155 {
156  if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[id").c_str()), 3))
157  {
158  return 1;
159  }
160  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[by").c_str()), 3))
161  {
162  return 1;
163  }
164  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[hash").c_str()), 5))
165  {
166  return 1;
167  }
168  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[al").c_str()), 3))
169  {
170  return 1;
171  }
172  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[sign").c_str()), 5))
173  {
174  return 1;
175  }
176  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[total").c_str()), 6))
177  {
178  return 1;
179  }
180  else if(!sncasecmp(tok, TTKConstCast(char*, TTKString("[offset").c_str()), 7))
181  {
182  return 1;
183  }
184  return 0;
185 }
186 
187 void MusicLrcFromKrc::createLrc(uchar *lrc, int lrclen)
188 {
189  m_data.clear();
190  int top = 0;
191  for(int i = 0; i < lrclen; ++i)
192  {
193  int len;
194  if(top == 0)
195  {
196  switch(lrc[i])
197  {
198  case '<':
199  top++;
200  break;
201  case '[':
202  len = (strchr((char*)&lrc[i], ']') - (char*)&lrc[i]) + 1;
203  for(int j = 0; j < len; ++j)
204  {
205  if(lrc[i + j] == ':')
206  {
207  if(isfilter((char*)&lrc[i]))
208  {
209  while(lrc[++i] != '\n' && i < lrclen)
210  {
211 
212  }
213  }
214  goto filter_done;
215  }
216  }
217 
218  for(int j = 0; j < len; ++j)
219  {
220  int ms;
221  if(lrc[i + j] == ',')
222  {
223  char ftime[14];
224  lrc[i + j] = 0;
225  ms = atoi((char*)&lrc[i + 1]);
226  sprintf(ftime, "[%.2d:%.2d.%.2d]", (ms % TTK_DN_H2MS) / TTK_DN_M2MS, (ms % TTK_DN_M2MS) / TTK_DN_S2MS, (ms % TTK_DN_M2MS) % 100);
227 
228  for(j = 0; j < 10; ++j)
229  {
230  m_data.append(ftime[j]);
231  }
232  i = i + len - 1;
233  break;
234  }
235  }
236  break;
237  filter_done:
238  default:
239  m_data.append(lrc[i]);
240  break;
241  }
242 
243  }
244  else if(top == 1 && lrc[i] == '>')
245  {
246  top--;
247  }
248  }
249 }
250 
251 
252 bool MusicLrcFromQrc::decode(const QString &input)
253 {
254  QFile file(input);
255  if(!file.open(QIODevice::ReadOnly))
256  {
257  return false;
258  }
259 
260  m_data = file.readAll();
261  file.close();
262 
263  TTKAbstractXml xml;
264  if(xml.fromByteArray(m_data))
265  {
266  const QString &data = xml.readAttributeByTagName("Lyric_1", "LyricContent");
267  if(!data.isEmpty())
268  {
269  m_data.clear();
270 
271  for(QString &text : data.split(TTK_LINEFEED))
272  {
273  const QRegExp regx("\\[(\\d+),\\d+\\]");
274  if(regx.indexIn(text) != -1)
275  {
276  text.replace(regx, "[" + TTKTime::toString(regx.cap(1).toInt(), "mm:ss.zzz") + "]");
277  }
278 
279  text.remove(QRegExp("\\(\\d+,\\d+\\)"));
280  m_data.append(text.toUtf8() + TTK_LINEFEED);
281  }
282  }
283  }
284  return true;
285 }
286 
287 
288 bool MusicLrcFromTrc::decode(const QString &input)
289 {
290  QFile file(input);
291  if(!file.open(QIODevice::ReadOnly))
292  {
293  return false;
294  }
295 
296  m_data = file.readAll();
297  file.close();
298 
299  const QString &data = QString::fromUtf8(m_data);
300  m_data.clear();
301 
302  for(QString &text : data.split(TTK_LINEFEED))
303  {
304  text.remove(QRegExp("<\\d+>"));
305  m_data.append(text.toUtf8() + TTK_LINEFEED);
306  }
307  return true;
308 }
309 
310 
311 bool MusicLrcFromYrc::decode(const QString &input)
312 {
313  QFile file(input);
314  if(!file.open(QIODevice::ReadOnly))
315  {
316  return false;
317  }
318 
319  m_data = file.readAll();
320  file.close();
321 
322  const QString &data = QString::fromUtf8(m_data);
323  m_data.clear();
324 
325  for(QString &text : data.split(TTK_LINEFEED))
326  {
327  if(text.startsWith("{")) // json info
328  {
329  continue;
330  }
331 
332  const QRegExp regx("\\[(\\d+),\\d+\\]");
333  if(regx.indexIn(text) != -1)
334  {
335  text.replace(regx, "[" + TTKTime::toString(regx.cap(1).toInt(), "mm:ss.zzz") + "]");
336  }
337 
338  text.remove(QRegExp("\\(\\d+,\\d+,\\d+\\)"));
339  m_data.append(text.toUtf8() + TTK_LINEFEED);
340  }
341  return true;
342 }
343 
#define TTKStaticCast(x, y)
Definition: ttkglobal.h:231
#define TTKConstCast(x, y)
Definition: ttkglobal.h:213
virtual bool decode(const QString &input) overridefinal
The class of the ttk xml interface.
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: uncompr.c:82
const QByteArray & data() const noexcept
virtual bool decode(const QString &input) overridefinal
#define TTK_SN_MB2BT
Definition: ttkglobal.h:394
#define TTK_DN_M2MS
Definition: ttkglobal.h:361
#define qPrintable(s)
Definition: ttkqtglobal.h:35
int sncasecmp(char *s1, char *s2, size_t n)
#define TTK_DN_H2MS
Definition: ttkglobal.h:368
int isfilter(char *tok)
std::string TTKString
Definition: ttkglobal.h:168
static constexpr wchar_t key[]
bool fromByteArray(const QByteArray &data)
QString readAttributeByTagName(const QString &tagName, const QString &attrName="value") const
virtual bool decode(const QString &input) overridefinal
The class of the base lrc interface.
#define QtNamespace(p)
Qt use namespace.
Definition: ttkqtcompat.h:115
void createLrc(uchar *lrc, int lrclen)
virtual bool decode(const QString &input) overridefinal
int decompression(uchar *src, size_t srcsize, size_t *dstsize)
#define TTK_DN_S2MS
Definition: ttkglobal.h:355
virtual bool decode(const QString &input) overridefinal
uLong FAR uLongf
Definition: zconf.h:407
#define Z_OK
Definition: zlib.h:177
#define TTK_LINEFEED
Definition: ttkglobal.h:271
static QString toString(qint64 time, const QString &format) noexcept
Definition: ttktime.cpp:72
#define const
Definition: zconf.h:233
#define TTK_ERROR_STREAM(msg)
Definition: ttklogger.h:76