MythTV  master
sourceutil.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // Qt headers
4 #include <QRegExp>
5 
6 // MythTV headers
7 #include "sourceutil.h"
8 #include "cardutil.h"
9 #include "mythdb.h"
10 #include "mythdirs.h"
11 #include "mythlogging.h"
12 #include "mythsystemlegacy.h"
13 
15 {
17 
18  query.prepare(
19  "SELECT mplexid, atsc_minor_chan, serviceid "
20  "FROM channel "
21  "WHERE sourceid = :SOURCEID");
22  query.bindValue(":SOURCEID", sourceid);
23 
24  if (!query.exec())
25  {
26  MythDB::DBError("SourceUtil::HasDigitalChannel()", query);
27  return false;
28  }
29 
30  while (query.next())
31  {
32  uint mplexid = query.value(0).toUInt();
33  uint minor = query.value(1).toUInt();
34  uint prognum = query.value(2).toUInt();
35  mplexid = (32767 == mplexid) ? 0 : mplexid;
36 
37  if (mplexid && (minor || prognum))
38  return true;
39  }
40 
41  return false;
42 }
43 
45 {
47 
48  query.prepare(
49  "SELECT name "
50  "FROM videosource "
51  "WHERE sourceid = :SOURCEID");
52  query.bindValue(":SOURCEID", sourceid);
53 
54  if (!query.exec())
55  {
56  MythDB::DBError("SourceUtil::GetSourceName()", query);
57  return QString();
58  }
59  if (!query.next())
60  {
61  return QString();
62  }
63 
64  return query.value(0).toString();
65 }
66 
68 {
70  query.prepare("SELECT channum "
71  "FROM channel "
72  "WHERE sourceid = :SOURCEID");
73  query.bindValue(":SOURCEID", sourceid);
74 
75  if (query.exec() && query.isActive() && query.size() > 0)
76  {
77  QMap<QString,uint> counts;
78  const QRegExp sepExpr("(_|-|#|\\.)");
79  while (query.next())
80  {
81  const QString channum = query.value(0).toString();
82  const int where = channum.indexOf(sepExpr);
83  if (channum.right(2).startsWith("0"))
84  counts["0"]++;
85  else
86  counts[(where < 0) ? "" : QString(channum.at(where))]++;
87  }
88  QString sep = "_";
89  uint max = counts["_"];
90  static const char *spacers[6] = { "", "-", "#", ".", "0", nullptr };
91  for (uint i=0; (spacers[i] != nullptr); ++i)
92  {
93  if (counts[spacers[i]] > max)
94  {
95  max = counts[spacers[i]];
96  sep = spacers[i];
97  }
98  }
99  return sep;
100  }
101  return "_"; // default on failure
102 }
103 
105 {
106  return QString("%1") + GetChannelSeparator(sourceid) + QString("%2");
107 }
108 
110 {
111  MSqlQuery query(MSqlQuery::InitCon());
112  query.prepare("SELECT sum(1) "
113  "FROM channel "
114  "WHERE sourceid = :SOURCEID");
115  query.bindValue(":SOURCEID", sourceid);
116  if (query.exec() && query.isActive() && query.next())
117  return query.value(0).toUInt();
118  return 0;
119 }
120 
121 vector<uint> SourceUtil::GetMplexIDs(uint sourceid)
122 {
123  MSqlQuery query(MSqlQuery::InitCon());
124 
125  query.prepare(
126  "SELECT mplexid "
127  "FROM dtv_multiplex "
128  "WHERE sourceid = :SOURCEID");
129  query.bindValue(":SOURCEID", sourceid);
130 
131  vector<uint> list;
132  if (!query.exec())
133  {
134  MythDB::DBError("SourceUtil::GetMplexIDs()", query);
135  return list;
136  }
137 
138  while (query.next())
139  list.push_back(query.value(0).toUInt());
140 
141  return list;
142 }
143 
145  QString &grabber, QString &userid,
146  QString &passwd, QString &lineupid)
147 {
148  MSqlQuery query(MSqlQuery::InitCon());
149  query.prepare(
150  "SELECT xmltvgrabber, userid, password, lineupid "
151  "FROM videosource "
152  "WHERE sourceid = :SOURCEID");
153  query.bindValue(":SOURCEID", sourceid);
154 
155  if (!query.exec() || !query.isActive())
156  {
157  MythDB::DBError("SourceUtil::GetListingsLoginData()", query);
158  return false;
159  }
160 
161  if (!query.next())
162  return false;
163 
164  grabber = query.value(0).toString();
165  userid = query.value(1).toString();
166  passwd = query.value(2).toString();
167  lineupid = query.value(3).toString();
168 
169  return true;
170 }
171 
172 static QStringList get_inputtypes(uint sourceid)
173 {
174  QStringList list;
175 
176  MSqlQuery query(MSqlQuery::InitCon());
177  query.prepare(
178  "SELECT cardtype, inputname "
179  "FROM capturecard "
180  "WHERE capturecard.sourceid = :SOURCEID");
181  query.bindValue(":SOURCEID", sourceid);
182 
183  if (!query.exec() || !query.isActive())
184  MythDB::DBError("get_inputtypes()", query);
185  else
186  {
187  while (query.next())
188  {
190  QString inputtype = query.value(0).toString().toUpper();
191  QString inputname = query.value(1).toString().toUpper();
192  inputtype = ((inputtype == "DVB") && (!inputname.startsWith("DVB"))) ?
193  "V4L" : inputtype;
195  list += inputtype;
196  }
197  }
198 
199  return list;
200 }
201 
203 {
204  QStringList types = get_inputtypes(sourceid);
205  return types.size();
206 }
207 
208 bool SourceUtil::IsProperlyConnected(uint sourceid, bool strict)
209 {
210  QStringList types = get_inputtypes(sourceid);
211  QMap<QString,uint> counts;
212  QStringList::const_iterator it = types.begin();
213  for (; it != types.end(); ++it)
214  {
215  counts[*it]++;
216 
217  counts[CardUtil::IsEncoder(*it) ? "ENCODER" : "NOT_ENCODER"]++;
218  counts[CardUtil::IsUnscanable(*it) ? "NO_SCAN" : "SCAN"]++;
219 
220  if (CardUtil::IsTuningAnalog(*it))
221  counts["ANALOG_TUNING"]++;
222  else if (CardUtil::IsTuningDigital(*it))
223  counts["DIGITAL_TUNING"]++;
224  else if (CardUtil::IsTuningVirtual(*it))
225  counts["VIRTUAL_TUNING"]++;
226  }
227 
228  bool tune_mismatch =
229  (counts["ANALOG_TUNING"] && counts["DIGITAL_TUNING"]) ||
230  (counts["VIRTUAL_TUNING"] && counts["DIGITAL_TUNING"]);
231  bool enc_mismatch = counts["ENCODER"] && counts["NOT_ENCODER"];
232  bool scan_mismatch = counts["SCAN"] && counts["NO_SCAN"];
233 
234  if (tune_mismatch)
235  {
236  uint a = counts["ANALOG_TUNERS"];
237  uint d = counts["DIGITAL_TUNERS"];
238  uint v = counts["VIRTUAL_TUNERS"];
239  LOG(VB_GENERAL, LOG_NOTICE,
240  QString("SourceUtil::IsProperlyConnected(): ") +
241  QString("Connected to %1 analog, %2 digital and %3 virtual "
242  "tuners\n\t\t\t").arg(a).arg(d).arg(v) +
243  QString("Can not mix digital with other tuning information."));
244  }
245 
246  if (enc_mismatch)
247  {
248  uint a = counts["ENCODER"];
249  uint d = counts["NOT_ENCODER"];
250  LOG(VB_GENERAL, LOG_NOTICE,
251  QString("SourceUtil::IsProperlyConnected(): ") +
252  QString("Source ID %1 ").arg(sourceid) +
253  QString("appears to be connected\n\t\t\tto %1 encoder%2, ")
254  .arg(a).arg((1 == a) ? "":"s") +
255  QString("and %1 non-encoder%2. ")
256  .arg(d).arg((1 == d) ? "":"s") +
257  QString("This is probably a bad idea."));
258  }
259 
260  if (scan_mismatch)
261  {
262  uint a = counts["SCAN"];
263  uint d = counts["NO_SCAN"];
264  LOG(VB_GENERAL, LOG_NOTICE,
265  QString("SourceUtil::IsProperlyConnected(): ") +
266  QString("Source ID %1 ").arg(sourceid) +
267  QString("appears to be connected\n\t\t\t"
268  "to %1 scanable input%2, ")
269  .arg(a).arg((1 == a) ? "":"s") +
270  QString("and %1 non-scanable input%2. ")
271  .arg(d).arg((1 == d) ? "":"s") +
272  QString("This may be a problem."));
273  }
274 
275  if (!strict)
276  return !tune_mismatch;
277 
278  return !tune_mismatch && !enc_mismatch && !scan_mismatch;
279 }
280 
281 bool SourceUtil::IsEncoder(uint sourceid, bool strict)
282 {
283  bool encoder = true;
284 
285  QStringList types = get_inputtypes(sourceid);
286  QStringList::const_iterator it = types.begin();
287  for (; it != types.end(); ++it)
288  encoder &= CardUtil::IsEncoder(*it);
289 
290  // Source is connected, go by input types for type determination
291  if (!types.empty())
292  return encoder;
293 
294  // Try looking at channels if source is not connected,
295  MSqlQuery query(MSqlQuery::InitCon());
296  query.prepare(
297  "SELECT atsc_minor_chan, serviceid "
298  "FROM channel "
299  "WHERE sourceid = :SOURCEID");
300  query.bindValue(":SOURCEID", sourceid);
301 
302  bool has_any_chan = false;
303  if (!query.exec() || !query.isActive())
304  MythDB::DBError("SourceUtil::IsEncoder", query);
305  else
306  {
307  while (query.next())
308  {
309  encoder &= !query.value(0).toBool() && !query.value(1).toBool();
310  has_any_chan = true;
311  }
312  }
313 
314  return (strict && !has_any_chan) ? false: encoder;
315 }
316 
318 {
319  bool unscanable = true;
320  QStringList types = get_inputtypes(sourceid);
321  QStringList::const_iterator it = types.begin();
322  for (; it != types.end(); ++it)
323  unscanable &= CardUtil::IsUnscanable(*it);
324 
325  return types.empty() || unscanable;
326 }
327 
329 {
330  bool ccpresent = false;
331  vector<uint> inputs = CardUtil::GetInputIDs(sourceid);
332  vector<uint>::iterator it = inputs.begin();
333  for (; it != inputs.end(); ++it)
334  {
336  || CardUtil::GetRawInputType(*it) == "HDHOMERUN")
337  ccpresent = true;
338  }
339 
340  return ccpresent;
341 }
342 
344 {
345  MSqlQuery query(MSqlQuery::InitCon());
346  query.prepare("SELECT sourceid FROM videosource");
347 
348  if (!query.exec() || !query.isActive())
349  {
350  MythDB::DBError("SourceUtil::IsAnySourceScanable", query);
351  return false;
352  }
353 
354  while (query.next())
355  {
356  if (!IsUnscanable(query.value(0).toUInt()))
357  return true;
358  }
359 
360  return false;
361 }
362 
363 bool SourceUtil::UpdateChannelsFromListings(uint sourceid, const QString& inputtype, bool wait)
364 {
365  if (wait)
366  {
367  QString cmd = GetAppBinDir() +
368  "mythfilldatabase";
369  QStringList args;
370  args.append("--only-update-channels");
371 
372  if (sourceid)
373  {
374  args.append(QString("--sourceid"));
375  args.append(QString::number(sourceid));
376  }
377  if (!inputtype.isEmpty())
378  {
379  args.append(QString("--cardtype"));
380  args.append(inputtype);
381  }
382 
384  getchan.Run();
385  getchan.Wait();
386  }
387  else
388  {
389  QString cmd = GetAppBinDir() +
390  "mythfilldatabase --only-update-channels";
391  if (sourceid)
392  cmd += QString(" --sourceid %1").arg(sourceid);
393  if (!inputtype.isEmpty())
394  cmd += QString(" --cardtype %1").arg(inputtype);
395  cmd += logPropagateArgs;
396 
397  myth_system(cmd);
398  }
399 
400  return true;
401 }
402 
403 bool SourceUtil::UpdateSource( uint sourceid, const QString& sourcename,
404  const QString& grabber, const QString& userid,
405  const QString& freqtable, const QString& lineupid,
406  const QString& password, bool useeit,
407  const QString& configpath, int nitid)
408 {
409  MSqlQuery query(MSqlQuery::InitCon());
410 
411  query.prepare("UPDATE videosource SET name = :NAME, xmltvgrabber = :XMLTVGRABBER, "
412  "userid = :USERID, freqtable = :FREQTABLE, lineupid = :LINEUPID,"
413  "password = :PASSWORD, useeit = :USEEIT, configpath = :CONFIGPATH, "
414  "dvb_nit_id = :NITID WHERE sourceid = :SOURCEID");
415 
416  query.bindValue(":NAME", sourcename);
417  query.bindValue(":XMLTVGRABBER", grabber);
418  query.bindValue(":USERID", userid);
419  query.bindValue(":FREQTABLE", freqtable);
420  query.bindValue(":LINEUPID", lineupid);
421  query.bindValue(":PASSWORD", password);
422  query.bindValue(":USEEIT", useeit);
423  query.bindValue(":CONFIGPATH", configpath);
424  query.bindValue(":NITID", nitid);
425  query.bindValue(":SOURCEID", sourceid);
426 
427  if (!query.exec() || !query.isActive())
428  {
429  MythDB::DBError("Updating Video Source", query);
430  return false;
431  }
432 
433  return true;
434 }
435 
436 int SourceUtil::CreateSource( const QString& sourcename,
437  const QString& grabber, const QString& userid,
438  const QString& freqtable, const QString& lineupid,
439  const QString& password, bool useeit,
440  const QString& configpath, int nitid)
441 {
442  MSqlQuery query(MSqlQuery::InitCon());
443 
444  query.prepare("INSERT INTO videosource (name,xmltvgrabber,userid,freqtable,lineupid,"
445  "password,useeit,configpath,dvb_nit_id) VALUES (:NAME, :XMLTVGRABBER, "
446  ":USERID, :FREQTABLE, :LINEUPID, :PASSWORD, :USEEIT, :CONFIGPATH, :NITID)");
447 
448  query.bindValue(":NAME", sourcename);
449  query.bindValue(":XMLTVGRABBER", grabber);
450  query.bindValue(":USERID", userid);
451  query.bindValue(":FREQTABLE", freqtable);
452  query.bindValue(":LINEUPID", lineupid);
453  query.bindValue(":PASSWORD", password);
454  query.bindValue(":USEEIT", useeit);
455  query.bindValue(":CONFIGPATH", configpath);
456  query.bindValue(":NITID", nitid);
457 
458  if (!query.exec() || !query.isActive())
459  {
460  MythDB::DBError("Adding Video Source", query);
461  return -1;
462  }
463 
464  query.prepare("SELECT MAX(sourceid) FROM videosource");
465 
466  if (!query.exec())
467  {
468  MythDB::DBError("CreateSource maxsource", query);
469  return -1;
470  }
471 
472  int sourceid = -1; /* must be int not uint because of return type. */
473 
474  if (query.next())
475  sourceid = query.value(0).toInt();
476 
477  return sourceid;
478 }
479 
481 {
482  MSqlQuery query(MSqlQuery::InitCon());
483 
484  // Delete the channels associated with the source
485  query.prepare("DELETE FROM channel "
486  "WHERE sourceid = :SOURCEID");
487  query.bindValue(":SOURCEID", sourceid);
488 
489  if (!query.exec() || !query.isActive())
490  {
491  MythDB::DBError("Deleting Channels", query);
492  return false;
493  }
494 
495  // Delete the multiplexes associated with the source
496  query.prepare("DELETE FROM dtv_multiplex "
497  "WHERE sourceid = :SOURCEID");
498  query.bindValue(":SOURCEID", sourceid);
499 
500  if (!query.exec() || !query.isActive())
501  {
502  MythDB::DBError("Deleting Multiplexes", query);
503  return false;
504  }
505 
506  // Detach the inputs associated with the source
507  query.prepare("UPDATE capturecard "
508  "SET sourceid = 0 "
509  "WHERE sourceid = :SOURCEID");
510  query.bindValue(":SOURCEID", sourceid);
511 
512  if (!query.exec() || !query.isActive())
513  {
514  MythDB::DBError("Deleting inputs", query);
515  return false;
516  }
517 
518  // Delete the source itself
519  query.prepare("DELETE FROM videosource "
520  "WHERE sourceid = :SOURCEID");
521  query.bindValue(":SOURCEID", sourceid);
522 
523  if (!query.exec() || !query.isActive())
524  {
525  MythDB::DBError("Deleting VideoSource", query);
526  return false;
527  }
528 
529  return true;
530 }
531 
533 {
534  MSqlQuery query(MSqlQuery::InitCon());
535 
536  // Detach all inputs from any source
537  query.prepare("UPDATE capturecard "
538  "SET sourceid = 0");
539  if (!query.exec() || !query.isActive())
540  {
541  MythDB::DBError("Deleting sources", query);
542  return false;
543  }
544 
545  return (query.exec("TRUNCATE TABLE channel") &&
546  query.exec("TRUNCATE TABLE program") &&
547  query.exec("TRUNCATE TABLE videosource") &&
548  query.exec("TRUNCATE TABLE credits") &&
549  query.exec("TRUNCATE TABLE programrating") &&
550  query.exec("TRUNCATE TABLE programgenres") &&
551  query.exec("TRUNCATE TABLE dtv_multiplex") &&
552  query.exec("TRUNCATE TABLE diseqc_config") &&
553  query.exec("TRUNCATE TABLE diseqc_tree") &&
554  query.exec("TRUNCATE TABLE eit_cache") &&
555  query.exec("TRUNCATE TABLE channelgroup") &&
556  query.exec("TRUNCATE TABLE channelgroupnames"));
557 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
static vector< uint > GetMplexIDs(uint sourceid)
Definition: sourceutil.cpp:121
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
static bool IsCableCardPresent(uint sourceid)
Definition: sourceutil.cpp:328
automatically delete if backgrounded
Definition: mythsystem.h:43
static uint GetChannelCount(uint sourceid)
Definition: sourceutil.cpp:109
static bool DeleteSource(uint sourceid)
Definition: sourceutil.cpp:480
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
QString logPropagateArgs
Definition: logging.cpp:89
static bool IsAnySourceScanable(void)
Definition: sourceutil.cpp:343
int size(void) const
Definition: mythdbcon.h:203
static bool IsUnscanable(const QString &rawtype)
Definition: cardutil.h:144
unsigned int uint
Definition: compat.h:140
static bool IsUnscanable(uint sourceid)
Definition: sourceutil.cpp:317
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:121
static QString GetSourceName(uint sourceid)
Definition: sourceutil.cpp:44
QVariant value(int i) const
Definition: mythdbcon.h:198
static QString GetChannelFormat(uint sourceid)
Definition: sourceutil.cpp:104
static bool UpdateSource(uint sourceid, const QString &sourcename, const QString &grabber, const QString &userid, const QString &freqtable, const QString &lineupid, const QString &password, bool useeit, const QString &configpath, int nitid)
Definition: sourceutil.cpp:403
static QStringList get_inputtypes(uint sourceid)
Definition: sourceutil.cpp:172
static bool HasDigitalChannel(uint sourceid)
Definition: sourceutil.cpp:14
static const uint16_t * d
QString GetAppBinDir(void)
Definition: mythdirs.cpp:221
run process through shell
Definition: mythsystem.h:41
static QString GetChannelSeparator(uint sourceid)
Definition: sourceutil.cpp:67
static bool IsCableCardPresent(uint inputid, const QString &inputType)
Definition: cardutil.cpp:117
#define minor(X)
Definition: compat.h:138
static bool UpdateChannelsFromListings(uint sourceid, const QString &inputtype=QString(), bool wait=false)
Definition: sourceutil.cpp:363
bool isActive(void) const
Definition: mythdbcon.h:204
static vector< uint > GetInputIDs(const QString &videodevice=QString(), const QString &rawtype=QString(), const QString &inputname=QString(), QString hostname=QString())
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
Definition: cardutil.cpp:1244
static bool IsTuningDigital(const QString &rawtype)
Definition: cardutil.h:174
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
uint myth_system(const QString &command, uint flags, uint timeout)
static uint GetConnectionCount(uint sourceid)
Definition: sourceutil.cpp:202
uint Wait(time_t timeout=0)
static int CreateSource(const QString &sourcename, const QString &grabber, const QString &userid, const QString &freqtable, const QString &lineupid, const QString &password, bool useeit, const QString &configpath, int nitid)
Definition: sourceutil.cpp:436
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static bool IsTuningVirtual(const QString &rawtype)
Definition: cardutil.h:189
static bool DeleteAllSources(void)
Definition: sourceutil.cpp:532
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:271
static bool IsTuningAnalog(const QString &rawtype)
Definition: cardutil.h:182
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static bool IsEncoder(uint sourceid, bool strict=false)
Definition: sourceutil.cpp:281
static bool GetListingsLoginData(uint sourceid, QString &grabber, QString &userid, QString &passwd, QString &lineupid)
Definition: sourceutil.cpp:144
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
static bool IsProperlyConnected(uint sourceid, bool strict=false)
Definition: sourceutil.cpp:208