10 #include <QTextStream>
21 #define LOC QString("IPTVChanFetch: ")
35 uint cardid, QString inputname,
uint sourceid,
37 m_scanMonitor(monitor),
38 m_cardId(cardid), m_inputName(std::move(inputname)),
39 m_sourceId(sourceid), m_isMpts(is_mpts),
40 m_thread(new
MThread(
"IPTVChannelFetcher", this))
42 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Has ScanMonitor %1")
43 .
arg(monitor?
"true":
"false"));
78 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Found %1 channels")
102 LOG(VB_CHANNEL, LOG_INFO,
LOC +
"Playlist URL was empty");
103 QMutexLocker locker(&
m_lock);
109 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Playlist URL: %1").
arg(url));
125 QCoreApplication::translate(
"(Common)",
"Error"));
129 QMutexLocker locker(&
m_lock);
150 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Found %1 channels")
155 fbox_chan_map_t::const_iterator it =
m_channels.cbegin();
158 const QString& channum = it.key();
159 QString name = (*it).m_name;
160 QString xmltvid = (*it).m_xmltvid.isEmpty() ?
"" : (*it).m_xmltvid;
161 uint programnumber = (*it).m_programNumber;
163 QString msg = tr(
"Channel #%1 : %2").arg(channum).arg(name);
165 LOG(VB_CHANNEL, LOG_INFO, QString(
"Handling channel %1 %2")
177 channum, programnumber, 0, 0,
179 QString(),
"Default", xmltvid);
187 tr(
"Updating %1").
arg(msg));
190 channum, programnumber, 0, 0,
192 QString(),
"Default", xmltvid);
208 QMutexLocker locker(&
m_lock);
216 uint range = 70 - minval;
225 uint range = 100 - minval;
240 if (url.startsWith(
"file", Qt::CaseInsensitive))
244 QFile
file(qurl.toLocalFile());
245 if (!
file.open(QIODevice::ReadOnly))
247 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Opening '%1'")
248 .
arg(qurl.toLocalFile()) +
ENO);
252 QTextStream stream(&
file);
253 while (!stream.atEnd())
254 ret += stream.readLine() +
"\n";
266 LOG(VB_GENERAL, LOG_INFO,
LOC +
267 QString(
"DownloadPlaylist failed to "
268 "download from %1").
arg(url));
273 return tmp.isNull() ?
tmp : QString::fromUtf8(
tmp.toLatin1().constData());
282 QString url = rawdata.section(
"\n", numLine, numLine, QString::SectionSkipEmpty);
287 if (!url.startsWith(
"#"))
298 QString rawdata = reallyrawdata;
299 rawdata.replace(
"\r\n",
"\n");
302 QString header = rawdata.section(
"\n", 0, 0);
303 if (!header.startsWith(
"#EXTM3U"))
305 LOG(VB_GENERAL, LOG_ERR,
LOC +
306 QString(
"Invalid channel list header (%1)").
arg(header));
311 tr(
"ERROR: M3U channel list is malformed"));
323 LOG(VB_CHANNEL, LOG_INFO,
LOC +
324 QString(
"Estimating there are %1 channels in playlist")
332 QString sql =
"select MAX(CONVERT(channum, UNSIGNED INTEGER)) from channel where sourceid = :SOURCEID;";
346 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Next available channel number from DB is: %1").
arg(nextChanNum));
351 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No channels found for this source, using default channel number: %1").
arg(nextChanNum));
358 for (
uint i = 1;
true; ++i)
366 QString msg = tr(
"Encountered malformed channel");
367 if (!channum.isEmpty())
369 chanmap[channum] = info;
371 msg = QString(
"Parsing Channel #%1 : %2 : %3")
372 .arg(channum).arg(info.
m_name)
374 LOG(VB_CHANNEL, LOG_INFO,
LOC + msg);
410 QMap<QString,QString> values;
414 QString line = rawdata.section(
"\n", lineNum, lineNum, QString::SectionSkipEmpty);
419 if (line.startsWith(
"#"))
421 if (line.startsWith(
"#EXTINF:"))
423 parse_extinf(line.mid(line.indexOf(
':')+1), channum, name, nextChanNum);
425 else if (line.startsWith(
"#EXTMYTHTV:"))
427 QString data = line.mid(line.indexOf(
':')+1);
428 QString key = data.left(data.indexOf(
'='));
430 values[key] = data.mid(data.indexOf(
'=')+1);
432 else if (line.startsWith(
"#EXTVLCOPT:program="))
434 values[
"programnumber"] = line.mid(line.indexOf(
'=')+1);
442 for (
auto it = values.cbegin(); it != values.cend(); ++it)
444 LOG(VB_GENERAL, LOG_INFO,
LOC +
445 QString(
"parse_chan_info [%1]='%2'")
446 .
arg(it.key()).arg(*it));
449 name, values[
"xmltvid"],
450 line, values[
"bitrate"].toUInt(),
452 values[
"fecurl0"], values[
"fecbitrate0"].toUInt(),
453 values[
"fecurl1"], values[
"fecbitrate1"].toUInt(),
454 values[
"programnumber"].toUInt());
465 QRegExp chanNumName1(R
"(^-?\d+,(\d+)(?:\.\s|\s-\s)(.*)$)");
466 int pos = chanNumName1.indexIn(line);
469 channum = chanNumName1.cap(1);
470 name = chanNumName1.cap(2);
475 QRegExp chanNumName2(
"^-?\\d+\\s+[^,]*tvg-num=\"(\\d+)\"[^,]*,(.*)$");
476 pos = chanNumName2.indexIn(line);
479 channum = chanNumName2.cap(1);
480 name = chanNumName2.cap(2);
485 QRegExp chanNumName3(R
"(^-?\d+,\[(\d+)\]\s+(.*)$)");
486 pos = chanNumName3.indexIn(line);
489 channum = chanNumName3.cap(1);
490 name = chanNumName3.cap(2);
495 QRegExp chanNumName4(R
"(^-?\d+,(.*)\s+\[(\d+)\]$)");
496 pos = chanNumName4.indexIn(line);
499 channum = chanNumName4.cap(2);
500 name = chanNumName4.cap(1);
505 QRegExp chanNumName5(R
"(^(-?\d+)\s+[^,]*,\s*(.*)$)");
506 pos = chanNumName5.indexIn(line);
509 channum = chanNumName5.cap(1).simplified();
510 name = chanNumName5.cap(2).simplified();
512 int channel_number = channum.toInt (&ok);
513 if (ok && (channel_number > 0))
521 QRegExp chanNumName6(
"(^-?\\d+)\\s+[^,]*[^,]*,(.*)$");
522 pos = chanNumName6.indexIn(line);
525 channum = chanNumName6.cap(1).simplified();
526 name = chanNumName6.cap(2).simplified();
529 int channel_number = channum.toInt(&ok);
530 if (ok && channel_number > 0)
532 if (channel_number >= nextChanNum)
533 nextChanNum = channel_number + 1;
538 LOG(VB_GENERAL, LOG_ERR, QString(
"No channel number found, using next available: %1 for channel: %2").
arg(nextChanNum).
arg(name));
539 channum = QString::number(nextChanNum);
545 QString msg =
LOC + QString(
"Invalid header in channel list line \n\t\t\tEXTINF:%1").arg(line);
546 LOG(VB_GENERAL, LOG_ERR, msg);