MythTV  master
iptvchannelfetcher.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // Std C headers
4 #include <cmath>
5 #include <unistd.h>
6 #include <utility>
7 
8 // Qt headers
9 #include <QFile>
10 #include <QTextStream>
11 
12 // MythTV headers
13 #include "libmyth/mythcontext.h"
16 
17 #include "cardutil.h"
18 #include "channelutil.h"
19 #include "iptvchannelfetcher.h"
20 #include "scanmonitor.h"
21 
22 #define LOC QString("IPTVChanFetch: ")
23 
24 static bool parse_chan_info(const QString &rawdata,
25  IPTVChannelInfo &info,
26  QString &channum,
27  int &nextChanNum,
28  uint &lineNum);
29 
30 static bool parse_extinf(const QString &line,
31  QString &channum,
32  QString &name,
33  int &nextChanNum);
34 
36  uint cardid, QString inputname, uint sourceid,
37  bool is_mpts, ScanMonitor *monitor) :
38  m_scanMonitor(monitor),
39  m_cardId(cardid), m_inputName(std::move(inputname)),
40  m_sourceId(sourceid), m_isMpts(is_mpts),
41  m_thread(new MThread("IPTVChannelFetcher", this))
42 {
43  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Has ScanMonitor %1")
44  .arg(monitor?"true":"false"));
45 }
46 
48 {
49  Stop();
50  delete m_thread;
51  m_thread = nullptr;
52 }
53 
58 {
59  m_lock.lock();
60 
61  while (m_threadRunning)
62  {
63  m_stopNow = true;
64  m_lock.unlock();
65  m_thread->wait(5ms);
66  m_lock.lock();
67  }
68 
69  m_lock.unlock();
70 
71  m_thread->wait();
72 }
73 
75 {
76  while (!m_thread->isFinished())
77  m_thread->wait(500ms);
78 
79  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Found %1 channels")
80  .arg(m_channels.size()));
81  return m_channels;
82 }
83 
86 {
87  Stop();
88  m_stopNow = false;
89  m_thread->start();
90 }
91 
93 {
94  m_lock.lock();
95  m_threadRunning = true;
96  m_lock.unlock();
97 
98  // Step 1/4 : Get info from DB
99  QString url = CardUtil::GetVideoDevice(m_cardId);
100 
101  if (m_stopNow || url.isEmpty())
102  {
103  LOG(VB_CHANNEL, LOG_INFO, LOC + "Playlist URL was empty");
104  QMutexLocker locker(&m_lock);
105  m_threadRunning = false;
106  m_stopNow = true;
107  return;
108  }
109 
110  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Playlist URL: %1").arg(url));
111 
112  // Step 2/4 : Download
113  if (m_scanMonitor)
114  {
116  m_scanMonitor->ScanAppendTextToLog(tr("Downloading Playlist"));
117  }
118 
119  QString playlist = DownloadPlaylist(url);
120 
121  if (m_stopNow || playlist.isEmpty())
122  {
123  if (playlist.isNull() && m_scanMonitor)
124  {
126  QCoreApplication::translate("(Common)", "Error"));
128  m_scanMonitor->ScanErrored(tr("Downloading Playlist Failed"));
129  }
130  QMutexLocker locker(&m_lock);
131  m_threadRunning = false;
132  m_stopNow = true;
133  return;
134  }
135 
136  // Step 3/4 : Process
137  if (m_scanMonitor)
138  {
140  m_scanMonitor->ScanAppendTextToLog(tr("Processing Playlist"));
141  }
142 
143  m_channels.clear();
144  m_channels = ParsePlaylist(playlist, this);
145 
146  // Step 4/4 : Finish up
147  if (m_scanMonitor)
148  m_scanMonitor->ScanAppendTextToLog(tr("Adding Channels"));
150 
151  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Found %1 channels")
152  .arg(m_channels.size()));
153 
154  if (!m_isMpts)
155  {
156  fbox_chan_map_t::const_iterator it = m_channels.cbegin();
157  for (uint i = 1; it != m_channels.cend(); ++it, ++i)
158  {
159  const QString& channum = it.key();
160  QString name = (*it).m_name;
161  QString xmltvid = (*it).m_xmltvid.isEmpty() ? "" : (*it).m_xmltvid;
162  uint programnumber = (*it).m_programNumber;
163  //: %1 is the channel number, %2 is the channel name
164  QString msg = tr("Channel #%1 : %2").arg(channum, name);
165 
166  LOG(VB_CHANNEL, LOG_INFO, QString("Handling channel %1 %2")
167  .arg(channum, name));
168 
169  int chanid = ChannelUtil::GetChanID(m_sourceId, channum);
170  if (chanid <= 0)
171  {
172  if (m_scanMonitor)
173  {
174  m_scanMonitor->ScanAppendTextToLog(tr("Adding %1").arg(msg));
175  }
176  chanid = ChannelUtil::CreateChanID(m_sourceId, channum);
177  ChannelUtil::CreateChannel(0, m_sourceId, chanid, name, name,
178  channum, programnumber, 0, 0,
179  false, kChannelVisible, QString(),
180  QString(), "Default", xmltvid);
181  ChannelUtil::CreateIPTVTuningData(chanid, (*it).m_tuning);
182  }
183  else
184  {
185  if (m_scanMonitor)
186  {
188  tr("Updating %1").arg(msg));
189  }
190  ChannelUtil::UpdateChannel(0, m_sourceId, chanid, name, name,
191  channum, programnumber, 0, 0,
192  false, kChannelVisible, QString(),
193  QString(), "Default", xmltvid);
194  ChannelUtil::UpdateIPTVTuningData(chanid, (*it).m_tuning);
195  }
196 
198  }
199 
200  if (m_scanMonitor)
201  {
202  m_scanMonitor->ScanAppendTextToLog(tr("Done"));
206  }
207  }
208 
209  QMutexLocker locker(&m_lock);
210  m_threadRunning = false;
211  m_stopNow = true;
212 }
213 
215 {
216  uint minval = 35;
217  uint range = 70 - minval;
218  uint pct = minval + (uint) truncf((((float)val) / m_chanCnt) * range);
219  if (m_scanMonitor)
221 }
222 
224 {
225  uint minval = 70;
226  uint range = 100 - minval;
227  uint pct = minval + (uint) truncf((((float)val) / m_chanCnt) * range);
228  if (m_scanMonitor)
230 }
231 
232 void IPTVChannelFetcher::SetMessage(const QString &status)
233 {
234  if (m_scanMonitor)
236 }
237 
238 // This function is always called from a thread context.
239 QString IPTVChannelFetcher::DownloadPlaylist(const QString &url)
240 {
241  if (url.startsWith("file", Qt::CaseInsensitive))
242  {
243  QString ret = "";
244  QUrl qurl(url);
245  QFile file(qurl.toLocalFile());
246  if (!file.open(QIODevice::ReadOnly))
247  {
248  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Opening '%1'")
249  .arg(qurl.toLocalFile()) + ENO);
250  return ret;
251  }
252 
253  QTextStream stream(&file);
254  while (!stream.atEnd())
255  ret += stream.readLine() + "\n";
256 
257  file.close();
258  return ret;
259  }
260 
261  // Use MythDownloadManager for http URLs
262  QByteArray data;
263  QString tmp;
264 
265  if (!GetMythDownloadManager()->download(url, &data))
266  {
267  LOG(VB_GENERAL, LOG_INFO, LOC +
268  QString("DownloadPlaylist failed to "
269  "download from %1").arg(url));
270  }
271  else
272  tmp = QString(data);
273 
274  return tmp.isNull() ? tmp : QString::fromUtf8(tmp.toLatin1().constData());
275 }
276 
277 static uint estimate_number_of_channels(const QString &rawdata)
278 {
279  uint result = 0;
280  uint numLine = 1;
281  while (true)
282  {
283  QString url = rawdata.section("\n", numLine, numLine, QString::SectionSkipEmpty);
284  if (url.isEmpty())
285  return result;
286 
287  ++numLine;
288  if (!url.startsWith("#")) // ignore comments
289  ++result;
290  }
291 }
292 
294  const QString &reallyrawdata, IPTVChannelFetcher *fetcher)
295 {
296  fbox_chan_map_t chanmap;
297  int nextChanNum = 1;
298 
299  QString rawdata = reallyrawdata;
300  rawdata.replace("\r\n", "\n");
301 
302  // Verify header is ok
303  QString header = rawdata.section("\n", 0, 0);
304  if (!header.startsWith("#EXTM3U"))
305  {
306  LOG(VB_GENERAL, LOG_ERR, LOC +
307  QString("Invalid channel list header (%1)").arg(header));
308 
309  if (fetcher)
310  {
311  fetcher->SetMessage(
312  tr("ERROR: M3U channel list is malformed"));
313  }
314 
315  return chanmap;
316  }
317 
318  // estimate number of channels
319  if (fetcher)
320  {
321  uint num_channels = estimate_number_of_channels(rawdata);
322  fetcher->SetTotalNumChannels(num_channels);
323 
324  LOG(VB_CHANNEL, LOG_INFO, LOC +
325  QString("Estimating there are %1 channels in playlist")
326  .arg(num_channels));
327  }
328 
329  // get the next available channel number for the source (only used if we can't find one in the playlist)
330  if (fetcher)
331  {
332  MSqlQuery query(MSqlQuery::InitCon());
333  QString sql = "select MAX(CONVERT(channum, UNSIGNED INTEGER)) from channel where sourceid = :SOURCEID;";
334 
335  query.prepare(sql);
336  query.bindValue(":SOURCEID", fetcher->m_sourceId);
337 
338  if (!query.exec())
339  {
340  MythDB::DBError("Get next max channel number", query);
341  }
342  else
343  {
344  if (query.first())
345  {
346  nextChanNum = query.value(0).toInt() + 1;
347  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Next available channel number from DB is: %1").arg(nextChanNum));
348  }
349  else
350  {
351  nextChanNum = 1;
352  LOG(VB_GENERAL, LOG_INFO, LOC + QString("No channels found for this source, using default channel number: %1").arg(nextChanNum));
353  }
354  }
355  }
356 
357  // Parse each channel
358  uint lineNum = 1;
359  for (uint i = 1; true; ++i)
360  {
361  IPTVChannelInfo info;
362  QString channum;
363 
364  if (!parse_chan_info(rawdata, info, channum, nextChanNum, lineNum))
365  break;
366 
367  QString msg = tr("Encountered malformed channel");
368  if (!channum.isEmpty())
369  {
370  chanmap[channum] = info;
371 
372  msg = QString("Parsing Channel #%1 : %2 : %3")
373  .arg(channum, info.m_name,
374  info.m_tuning.GetDataURL().toString());
375  LOG(VB_CHANNEL, LOG_INFO, LOC + msg);
376 
377  msg.clear(); // don't tell fetcher
378  }
379 
380  if (fetcher)
381  {
382  if (!msg.isEmpty())
383  fetcher->SetMessage(msg);
384  fetcher->SetNumChannelsParsed(i);
385  }
386  }
387 
388  return chanmap;
389 }
390 
391 static bool parse_chan_info(const QString &rawdata,
392  IPTVChannelInfo &info,
393  QString &channum,
394  int &nextChanNum,
395  uint &lineNum)
396 {
397  // #EXTINF:0,2 - France 2 <-- duration,channum - channame
398  // #EXTMYTHTV:xmltvid=C2.telepoche.com <-- optional line (myth specific)
399  // #EXTMYTHTV:bitrate=BITRATE <-- optional line (myth specific)
400  // #EXTMYTHTV:fectype=FECTYPE <-- optional line (myth specific)
401  // The FECTYPE can be rfc2733, rfc5109, or smpte2022
402  // #EXTMYTHTV:fecurl0=URL <-- optional line (myth specific)
403  // #EXTMYTHTV:fecurl1=URL <-- optional line (myth specific)
404  // #EXTMYTHTV:fecbitrate0=BITRATE <-- optional line (myth specific)
405  // #EXTMYTHTV:fecbitrate1=BITRATE <-- optional line (myth specific)
406  // #EXTVLCOPT:program=program_number <-- optional line (used by MythTV and VLC)
407  // #... <-- ignored comments
408  // rtsp://maiptv.iptv.fr/iptvtv/201 <-- url
409 
410  QString name;
411  QMap<QString,QString> values;
412 
413  while (true)
414  {
415  QString line = rawdata.section("\n", lineNum, lineNum, QString::SectionSkipEmpty);
416  if (line.isEmpty())
417  return false;
418 
419  ++lineNum;
420  if (line.startsWith("#"))
421  {
422  if (line.startsWith("#EXTINF:"))
423  {
424  parse_extinf(line.mid(line.indexOf(':')+1), channum, name, nextChanNum);
425  }
426  else if (line.startsWith("#EXTMYTHTV:"))
427  {
428  QString data = line.mid(line.indexOf(':')+1);
429  QString key = data.left(data.indexOf('='));
430  if (!key.isEmpty())
431  {
432  if (key == "name")
433  name = data.mid(data.indexOf('=')+1);
434  else if (key == "channum")
435  channum = data.mid(data.indexOf('=')+1);
436  else
437  values[key] = data.mid(data.indexOf('=')+1);
438  }
439  }
440  else if (line.startsWith("#EXTVLCOPT:program="))
441  {
442  values["programnumber"] = line.mid(line.indexOf('=')+1);
443  }
444  continue;
445  }
446 
447  if (name.isEmpty())
448  return false;
449 
450  LOG(VB_GENERAL, LOG_INFO, LOC +
451  QString("parse_chan_info name='%2'").arg(name));
452  LOG(VB_GENERAL, LOG_INFO, LOC +
453  QString("parse_chan_info channum='%2'").arg(channum));
454  for (auto it = values.cbegin(); it != values.cend(); ++it)
455  {
456  LOG(VB_GENERAL, LOG_INFO, LOC +
457  QString("parse_chan_info [%1]='%2'")
458  .arg(it.key(), *it));
459  }
460  info = IPTVChannelInfo(
461  name, values["xmltvid"],
462  line, values["bitrate"].toUInt(),
463  values["fectype"],
464  values["fecurl0"], values["fecbitrate0"].toUInt(),
465  values["fecurl1"], values["fecbitrate1"].toUInt(),
466  values["programnumber"].toUInt());
467  return true;
468  }
469 }
470 
471 static bool parse_extinf(const QString &line,
472  QString &channum,
473  QString &name,
474  int &nextChanNum)
475 {
476  // Parse extension portion, Freebox or SAT>IP format
477  static const QRegularExpression chanNumName1
478  { R"(^-?\d+,(\d+)(?:\.\s|\s-\s)(.*)$)" };
479  auto match = chanNumName1.match(line);
480  if (match.hasMatch())
481  {
482  channum = match.captured(1);
483  name = match.captured(2);
484  return true;
485  }
486 
487  // Parse extension portion, A1 TV format
488  static const QRegularExpression chanNumName2
489  { "^-?\\d+\\s+[^,]*tvg-num=\"(\\d+)\"[^,]*,(.*)$" };
490  match = chanNumName2.match(line);
491  if (match.hasMatch())
492  {
493  channum = match.captured(1);
494  name = match.captured(2);
495  return true;
496  }
497 
498  // Parse extension portion, Moviestar TV number then name
499  static const QRegularExpression chanNumName3
500  { R"(^-?\d+,\[(\d+)\]\s+(.*)$)" };
501  match = chanNumName3.match(line);
502  if (match.hasMatch())
503  {
504  channum = match.captured(1);
505  name = match.captured(2);
506  return true;
507  }
508 
509  // Parse extension portion, Moviestar TV name then number
510  static const QRegularExpression chanNumName4
511  { R"(^-?\d+,(.*)\s+\[(\d+)\]$)" };
512  match = chanNumName4.match(line);
513  if (match.hasMatch())
514  {
515  channum = match.captured(2);
516  name = match.captured(1);
517  return true;
518  }
519 
520  // Parse extension portion, russion iptv plugin style
521  static const QRegularExpression chanNumName5
522  { R"(^(-?\d+)\s+[^,]*,\s*(.*)$)" };
523  match = chanNumName5.match(line);
524  if (match.hasMatch())
525  {
526  channum = match.captured(1).simplified();
527  name = match.captured(2).simplified();
528  bool ok = false;
529  int channel_number = channum.toInt (&ok);
530  if (ok && (channel_number > 0))
531  {
532  return true;
533  }
534  }
535 
536  // Parse extension portion, https://github.com/iptv-org/iptv/blob/master/channels/ style
537  // EG. #EXTINF:-1 tvg-id="" tvg-name="" tvg-logo="https://i.imgur.com/VejnhiB.png" group-title="News",BBC News
538  static const QRegularExpression chanNumName6
539  { "(^-?\\d+)\\s+[^,]*[^,]*,(.*)$" };
540  match = chanNumName6.match(line);
541  if (match.hasMatch())
542  {
543  channum = match.captured(1).simplified();
544  name = match.captured(2).simplified();
545 
546  bool ok = false;
547  int channel_number = channum.toInt(&ok);
548  if (ok && channel_number > 0)
549  {
550  if (channel_number >= nextChanNum)
551  nextChanNum = channel_number + 1;
552  return true;
553  }
554 
555  // no valid channel number found use the default next one
556  LOG(VB_GENERAL, LOG_ERR, QString("No channel number found, using next available: %1 for channel: %2").arg(nextChanNum).arg(name));
557  channum = QString::number(nextChanNum);
558  nextChanNum++;
559  return true;
560  }
561 
562  // not one of the formats we support
563  QString msg = LOC + QString("Invalid header in channel list line \n\t\t\tEXTINF:%1").arg(line);
564  LOG(VB_GENERAL, LOG_ERR, msg);
565  return false;
566 }
567 
568 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
IPTVChannelFetcher::m_sourceId
uint m_sourceId
Definition: iptvchannelfetcher.h:94
IPTVChannelFetcher::m_channels
fbox_chan_map_t m_channels
Definition: iptvchannelfetcher.h:96
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
IPTVChannelInfo::m_name
QString m_name
Definition: iptvchannelfetcher.h:57
IPTVChannelFetcher::m_cardId
uint m_cardId
Definition: iptvchannelfetcher.h:92
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
IPTVChannelFetcher::m_thread
MThread * m_thread
Definition: iptvchannelfetcher.h:100
parse_extinf
static bool parse_extinf(const QString &line, QString &channum, QString &name, int &nextChanNum)
Definition: iptvchannelfetcher.cpp:471
IPTVChannelFetcher::SetNumChannelsInserted
void SetNumChannelsInserted(uint val)
Definition: iptvchannelfetcher.cpp:223
ScanMonitor::ScanPercentComplete
void ScanPercentComplete(int pct)
Definition: scanmonitor.cpp:103
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
IPTVChannelFetcher::SetMessage
void SetMessage(const QString &status)
Definition: iptvchannelfetcher.cpp:232
IPTVChannelFetcher::m_threadRunning
bool m_threadRunning
Definition: iptvchannelfetcher.h:98
IPTVTuningData::GetDataURL
QUrl GetDataURL(void) const
Definition: iptvtuningdata.h:139
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
parse_chan_info
static bool parse_chan_info(const QString &rawdata, IPTVChannelInfo &info, QString &channum, int &nextChanNum, uint &lineNum)
Definition: iptvchannelfetcher.cpp:391
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
IPTVChannelFetcher::Scan
void Scan(void)
Scans the given frequency list.
Definition: iptvchannelfetcher.cpp:85
build_compdb.file
file
Definition: build_compdb.py:55
ChannelUtil::CreateChannel
static bool CreateChannel(uint db_mplexid, uint db_sourceid, uint new_channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0)
Definition: channelutil.cpp:1483
IPTVChannelFetcher::IPTVChannelFetcher
IPTVChannelFetcher(uint cardid, QString inputname, uint sourceid, bool is_mpts, ScanMonitor *monitor=nullptr)
Definition: iptvchannelfetcher.cpp:35
IPTVChannelFetcher::run
void run(void) override
Definition: iptvchannelfetcher.cpp:92
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ScanMonitor::ScanErrored
void ScanErrored(const QString &error)
Definition: scanmonitor.cpp:128
scanmonitor.h
IPTVChannelFetcher::Stop
void Stop(void)
Stops the scanning thread running.
Definition: iptvchannelfetcher.cpp:57
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1310
mythlogging.h
IPTVChannelFetcher::m_chanCnt
uint m_chanCnt
Definition: iptvchannelfetcher.h:97
IPTVChannelInfo
Definition: iptvchannelfetcher.h:26
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:817
LOC
#define LOC
Definition: iptvchannelfetcher.cpp:22
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
IPTVChannelFetcher
Definition: iptvchannelfetcher.h:64
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
ChannelUtil::CreateChanID
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
Definition: channelutil.cpp:1446
MThread::isFinished
bool isFinished(void) const
Definition: mthread.cpp:258
uint
unsigned int uint
Definition: compat.h:79
ScanMonitor::ScanAppendTextToLog
void ScanAppendTextToLog(const QString &status)
Definition: scanmonitor.cpp:109
channelutil.h
IPTVChannelFetcher::m_lock
QMutex m_lock
Definition: iptvchannelfetcher.h:101
ChannelUtil::UpdateChannel
static bool UpdateChannel(uint db_mplexid, uint source_id, uint channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid=QString(), const QString &icon=QString(), QString format=QString(), const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0)
Definition: channelutil.cpp:1563
kChannelVisible
@ kChannelVisible
Definition: channelinfo.h:23
cardutil.h
ScanMonitor::ScanComplete
void ScanComplete(void)
Definition: scanmonitor.cpp:98
ChannelUtil::CreateIPTVTuningData
static bool CreateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.h:147
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
std
Definition: mythchrono.h:23
IPTVChannelFetcher::m_scanMonitor
ScanMonitor * m_scanMonitor
Definition: iptvchannelfetcher.h:91
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
IPTVChannelFetcher::m_isMpts
bool m_isMpts
Definition: iptvchannelfetcher.h:95
IPTVChannelFetcher::~IPTVChannelFetcher
~IPTVChannelFetcher() override
Definition: iptvchannelfetcher.cpp:47
IPTVChannelFetcher::GetChannels
fbox_chan_map_t GetChannels(void)
Definition: iptvchannelfetcher.cpp:74
IPTVChannelFetcher::m_stopNow
bool m_stopNow
Definition: iptvchannelfetcher.h:99
estimate_number_of_channels
static uint estimate_number_of_channels(const QString &rawdata)
Definition: iptvchannelfetcher.cpp:277
IPTVChannelFetcher::DownloadPlaylist
static QString DownloadPlaylist(const QString &url)
Definition: iptvchannelfetcher.cpp:239
mythdownloadmanager.h
iptvchannelfetcher.h
fbox_chan_map_t
QMap< QString, IPTVChannelInfo > fbox_chan_map_t
Definition: iptvchannelfetcher.h:62
IPTVChannelInfo::m_tuning
IPTVTuningData m_tuning
Definition: iptvchannelfetcher.h:60
ScanMonitor
Definition: scanmonitor.h:44
IPTVChannelFetcher::SetTotalNumChannels
void SetTotalNumChannels(uint val)
Definition: iptvchannelfetcher.h:82
IPTVChannelFetcher::SetNumChannelsParsed
void SetNumChannelsParsed(uint val)
Definition: iptvchannelfetcher.cpp:214
CardUtil::GetVideoDevice
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:289
IPTVChannelFetcher::ParsePlaylist
static fbox_chan_map_t ParsePlaylist(const QString &rawdata, IPTVChannelFetcher *fetcher=nullptr)
Definition: iptvchannelfetcher.cpp:293
ChannelUtil::UpdateIPTVTuningData
static bool UpdateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.cpp:1709
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832