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