00001
00002
00003
00004 #include <QRegExp>
00005
00006
00007 #include "sourceutil.h"
00008 #include "cardutil.h"
00009 #include "mythdb.h"
00010 #include "mythdirs.h"
00011 #include "mythlogging.h"
00012 #include "mythmiscutil.h"
00013
00014 bool SourceUtil::HasDigitalChannel(uint sourceid)
00015 {
00016 MSqlQuery query(MSqlQuery::InitCon());
00017
00018 query.prepare(
00019 "SELECT mplexid, atsc_minor_chan, serviceid "
00020 "FROM channel "
00021 "WHERE sourceid = :SOURCEID");
00022 query.bindValue(":SOURCEID", sourceid);
00023
00024 if (!query.exec())
00025 {
00026 MythDB::DBError("SourceUtil::HasDigitalChannel()", query);
00027 return false;
00028 }
00029
00030 while (query.next())
00031 {
00032 uint mplexid = query.value(0).toUInt();
00033 uint minor = query.value(1).toUInt();
00034 uint prognum = query.value(2).toUInt();
00035 mplexid = (32767 == mplexid) ? 0 : mplexid;
00036
00037 if (mplexid && (minor || prognum))
00038 return true;
00039 }
00040
00041 return false;
00042 }
00043
00044 QString SourceUtil::GetSourceName(uint sourceid)
00045 {
00046 MSqlQuery query(MSqlQuery::InitCon());
00047
00048 query.prepare(
00049 "SELECT name "
00050 "FROM videosource "
00051 "WHERE sourceid = :SOURCEID");
00052 query.bindValue(":SOURCEID", sourceid);
00053
00054 if (!query.exec())
00055 {
00056 MythDB::DBError("SourceUtil::GetSourceName()", query);
00057 return QString::null;
00058 }
00059 else if (!query.next())
00060 {
00061 return QString::null;
00062 }
00063
00064 return query.value(0).toString();
00065 }
00066
00067 QString SourceUtil::GetChannelSeparator(uint sourceid)
00068 {
00069 MSqlQuery query(MSqlQuery::InitCon());
00070 query.prepare("SELECT channum "
00071 "FROM channel "
00072 "WHERE sourceid = :SOURCEID");
00073 query.bindValue(":SOURCEID", sourceid);
00074
00075 if (query.exec() && query.isActive() && query.size() > 0)
00076 {
00077 QMap<QString,uint> counts;
00078 const QRegExp sepExpr("(_|-|#|\\.)");
00079 while (query.next())
00080 {
00081 const QString channum = query.value(0).toString();
00082 const int where = channum.indexOf(sepExpr);
00083 if (channum.right(2).left(1) == "0")
00084 counts["0"]++;
00085 else
00086 counts[(where < 0) ? "" : QString(channum.at(where))]++;
00087 }
00088 QString sep = "_";
00089 uint max = counts["_"];
00090 static const char *spacers[6] = { "", "-", "#", ".", "0", NULL };
00091 for (uint i=0; (spacers[i] != NULL); ++i)
00092 {
00093 if (counts[spacers[i]] > max)
00094 {
00095 max = counts[spacers[i]];
00096 sep = spacers[i];
00097 }
00098 }
00099 return sep;
00100 }
00101 return "_";
00102 }
00103
00104 QString SourceUtil::GetChannelFormat(uint sourceid)
00105 {
00106 return QString("%1") + GetChannelSeparator(sourceid) + QString("%2");
00107 }
00108
00109 uint SourceUtil::GetChannelCount(uint sourceid)
00110 {
00111 MSqlQuery query(MSqlQuery::InitCon());
00112 query.prepare("SELECT sum(1) "
00113 "FROM channel "
00114 "WHERE sourceid = :SOURCEID");
00115 query.bindValue(":SOURCEID", sourceid);
00116 if (query.exec() && query.isActive() && query.next())
00117 return query.value(0).toUInt();
00118 return 0;
00119 }
00120
00121 vector<uint> SourceUtil::GetMplexIDs(uint sourceid)
00122 {
00123 MSqlQuery query(MSqlQuery::InitCon());
00124
00125 query.prepare(
00126 "SELECT mplexid "
00127 "FROM dtv_multiplex "
00128 "WHERE sourceid = :SOURCEID");
00129 query.bindValue(":SOURCEID", sourceid);
00130
00131 vector<uint> list;
00132 if (!query.exec())
00133 {
00134 MythDB::DBError("SourceUtil::GetMplexIDs()", query);
00135 return list;
00136 }
00137
00138 while (query.next())
00139 list.push_back(query.value(0).toUInt());
00140
00141 return list;
00142 }
00143
00144 bool SourceUtil::GetListingsLoginData(uint sourceid,
00145 QString &grabber, QString &userid,
00146 QString &passwd, QString &lineupid)
00147 {
00148 MSqlQuery query(MSqlQuery::InitCon());
00149 query.prepare(
00150 "SELECT xmltvgrabber, userid, password, lineupid "
00151 "FROM videosource "
00152 "WHERE sourceid = :SOURCEID");
00153 query.bindValue(":SOURCEID", sourceid);
00154
00155 if (!query.exec() || !query.isActive())
00156 {
00157 MythDB::DBError("SourceUtil::GetListingsLoginData()", query);
00158 return false;
00159 }
00160
00161 if (!query.next())
00162 return false;
00163
00164 grabber = query.value(0).toString();
00165 userid = query.value(1).toString();
00166 passwd = query.value(2).toString();
00167 lineupid = query.value(3).toString();
00168
00169 return true;
00170 }
00171
00172 static QStringList get_cardtypes(uint sourceid)
00173 {
00174 QStringList list;
00175
00176 MSqlQuery query(MSqlQuery::InitCon());
00177 query.prepare(
00178 "SELECT cardtype, inputname "
00179 "FROM capturecard, cardinput "
00180 "WHERE capturecard.cardid = cardinput.cardid AND "
00181 " cardinput.sourceid = :SOURCEID");
00182 query.bindValue(":SOURCEID", sourceid);
00183
00184 if (!query.exec() || !query.isActive())
00185 MythDB::DBError("get_cardtypes()", query);
00186 else
00187 {
00188 while (query.next())
00189 {
00191 QString cardtype = query.value(0).toString().toUpper();
00192 QString inputname = query.value(1).toString().toUpper();
00193 cardtype = ((cardtype == "DVB") && (inputname.left(3) != "DVB")) ?
00194 "V4L" : cardtype;
00196 list += cardtype;
00197 }
00198 }
00199
00200 return list;
00201 }
00202
00203 uint SourceUtil::GetConnectionCount(uint sourceid)
00204 {
00205 QStringList types = get_cardtypes(sourceid);
00206 return types.size();
00207 }
00208
00209 bool SourceUtil::IsProperlyConnected(uint sourceid, bool strict)
00210 {
00211 QStringList types = get_cardtypes(sourceid);
00212 QMap<QString,uint> counts;
00213 QStringList::const_iterator it = types.begin();
00214 for (; it != types.end(); ++it)
00215 {
00216 counts[*it]++;
00217
00218 counts[CardUtil::IsEncoder(*it) ? "ENCODER" : "NOT_ENCODER"]++;
00219 counts[CardUtil::IsUnscanable(*it) ? "NO_SCAN" : "SCAN"]++;
00220
00221 if (CardUtil::IsTuningAnalog(*it))
00222 counts["ANALOG_TUNING"]++;
00223 else if (CardUtil::IsTuningDigital(*it))
00224 counts["DIGITAL_TUNING"]++;
00225 else if (CardUtil::IsTuningVirtual(*it))
00226 counts["VIRTUAL_TUNING"]++;
00227 }
00228
00229 bool tune_mismatch =
00230 (counts["ANALOG_TUNING"] && counts["DIGITAL_TUNING"]) ||
00231 (counts["VIRTUAL_TUNING"] && counts["DIGITAL_TUNING"]);
00232 bool enc_mismatch = counts["ENCODER"] && counts["NOT_ENCODER"];
00233 bool scan_mismatch = counts["SCAN"] && counts["NO_SCAN"];
00234
00235 if (tune_mismatch)
00236 {
00237 uint a = counts["ANALOG_TUNERS"];
00238 uint d = counts["DIGITAL_TUNERS"];
00239 uint v = counts["VIRTUAL_TUNERS"];
00240 LOG(VB_GENERAL, LOG_NOTICE,
00241 QString("SourceUtil::IsProperlyConnected(): ") +
00242 QString("Connected to %1 analog, %2 digital and %3 virtual "
00243 "tuners\n\t\t\t").arg(a).arg(d).arg(v) +
00244 QString("Can not mix digital with other tuning information."));
00245 }
00246
00247 if (enc_mismatch)
00248 {
00249 uint a = counts["ENCODER"];
00250 uint d = counts["NOT_ENCODER"];
00251 LOG(VB_GENERAL, LOG_NOTICE,
00252 QString("SourceUtil::IsProperlyConnected(): ") +
00253 QString("Source ID %1 ").arg(sourceid) +
00254 QString("appears to be connected\n\t\t\tto %1 encoder%2, ")
00255 .arg(a).arg((1 == a) ? "":"s") +
00256 QString("and %1 non-encoder%2. ")
00257 .arg(d).arg((1 == d) ? "":"s") +
00258 QString("This is probably a bad idea."));
00259 }
00260
00261 if (scan_mismatch)
00262 {
00263 uint a = counts["SCAN"];
00264 uint d = counts["NO_SCAN"];
00265 LOG(VB_GENERAL, LOG_NOTICE,
00266 QString("SourceUtil::IsProperlyConnected(): ") +
00267 QString("Source ID %1 ").arg(sourceid) +
00268 QString("appears to be connected\n\t\t\t"
00269 "to %1 scanable input%2, ")
00270 .arg(a).arg((1 == a) ? "":"s") +
00271 QString("and %1 non-scanable input%2. ")
00272 .arg(d).arg((1 == d) ? "":"s") +
00273 QString("This may be a problem."));
00274 }
00275
00276 if (!strict)
00277 return !tune_mismatch;
00278
00279 return !tune_mismatch && !enc_mismatch && !scan_mismatch;
00280 }
00281
00282 bool SourceUtil::IsEncoder(uint sourceid, bool strict)
00283 {
00284 bool encoder = true;
00285
00286 QStringList types = get_cardtypes(sourceid);
00287 QStringList::const_iterator it = types.begin();
00288 for (; it != types.end(); ++it)
00289 encoder &= CardUtil::IsEncoder(*it);
00290
00291
00292 if (!types.empty())
00293 return encoder;
00294
00295
00296 MSqlQuery query(MSqlQuery::InitCon());
00297 query.prepare(
00298 "SELECT atsc_minor_chan, serviceid "
00299 "FROM channel "
00300 "WHERE sourceid = :SOURCEID");
00301 query.bindValue(":SOURCEID", sourceid);
00302
00303 bool has_any_chan = false;
00304 if (!query.exec() || !query.isActive())
00305 MythDB::DBError("SourceUtil::IsEncoder", query);
00306 else
00307 {
00308 while (query.next())
00309 {
00310 encoder &= !query.value(0).toInt() && !query.value(1).toInt();
00311 has_any_chan = true;
00312 }
00313 }
00314
00315 return (strict && !has_any_chan) ? false: encoder;
00316 }
00317
00318 bool SourceUtil::IsUnscanable(uint sourceid)
00319 {
00320 bool unscanable = true;
00321 QStringList types = get_cardtypes(sourceid);
00322 QStringList::const_iterator it = types.begin();
00323 for (; it != types.end(); ++it)
00324 unscanable &= CardUtil::IsUnscanable(*it);
00325
00326 return types.empty() || unscanable;
00327 }
00328
00329 bool SourceUtil::IsCableCardPresent(uint sourceid)
00330 {
00331 bool ccpresent = false;
00332 vector<uint> cards = CardUtil::GetCardIDs(sourceid);
00333 vector<uint>::iterator it = cards.begin();
00334 for (; it != cards.end(); ++it)
00335 {
00336 if (CardUtil::IsCableCardPresent(*it, CardUtil::GetRawCardType(*it)))
00337 ccpresent = true;
00338 }
00339
00340 return ccpresent;
00341 }
00342
00343 bool SourceUtil::IsAnySourceScanable(void)
00344 {
00345 MSqlQuery query(MSqlQuery::InitCon());
00346 query.prepare("SELECT sourceid FROM videosource");
00347
00348 if (!query.exec() || !query.isActive())
00349 {
00350 MythDB::DBError("SourceUtil::IsAnySourceScanable", query);
00351 return false;
00352 }
00353
00354 while (query.next())
00355 {
00356 if (!IsUnscanable(query.value(0).toUInt()))
00357 return true;
00358 }
00359
00360 return false;
00361 }
00362
00363 bool SourceUtil::UpdateChannelsFromListings(uint sourceid, QString cardtype, bool wait)
00364 {
00365 if (wait)
00366 {
00367 QString cmd = GetInstallPrefix() +
00368 "/bin/mythfilldatabase";
00369 QStringList args;
00370 args.append("--only-update-channels");
00371
00372 if (sourceid)
00373 {
00374 args.append(QString("--sourceid"));
00375 args.append(QString::number(sourceid));
00376 }
00377 if (!cardtype.isEmpty())
00378 {
00379 args.append(QString("--cardtype"));
00380 args.append(cardtype);
00381 }
00382
00383 MythSystem getchan(cmd, args, kMSRunShell | kMSAutoCleanup );
00384 getchan.Run();
00385 getchan.Wait();
00386 }
00387 else
00388 {
00389 QString cmd = GetInstallPrefix() +
00390 "/bin/mythfilldatabase --only-update-channels";
00391 if (sourceid)
00392 cmd += QString(" --sourceid %1").arg(sourceid);
00393 if (!cardtype.isEmpty())
00394 cmd += QString(" --cardtype %1").arg(cardtype);
00395 cmd += logPropagateArgs;
00396
00397 myth_system(cmd);
00398 }
00399
00400 return true;
00401 }
00402
00403 bool SourceUtil::UpdateSource( uint sourceid, QString sourcename,
00404 QString grabber, QString userid,
00405 QString freqtable, QString lineupid,
00406 QString password, bool useeit,
00407 QString configpath, int nitid)
00408 {
00409 MSqlQuery query(MSqlQuery::InitCon());
00410
00411 query.prepare("UPDATE videosource SET name = :NAME, xmltvgrabber = :XMLTVGRABBER, "
00412 "userid = :USERID, freqtable = :FREQTABLE, lineupid = :LINEUPID,"
00413 "password = :PASSWORD, useeit = :USEEIT, configpath = :CONFIGPATH, "
00414 "dvb_nit_id = :NITID WHERE sourceid = :SOURCEID");
00415
00416 query.bindValue(":NAME", sourcename);
00417 query.bindValue(":XMLTVGRABBER", grabber);
00418 query.bindValue(":USERID", userid);
00419 query.bindValue(":FREQTABLE", freqtable);
00420 query.bindValue(":LINEUPID", lineupid);
00421 query.bindValue(":PASSWORD", password);
00422 query.bindValue(":USEEIT", useeit);
00423 query.bindValue(":CONFIGPATH", configpath);
00424 query.bindValue(":NITID", nitid);
00425 query.bindValue(":SOURCEID", sourceid);
00426
00427 if (!query.exec() || !query.isActive())
00428 {
00429 MythDB::DBError("Updating Video Source", query);
00430 return false;
00431 }
00432
00433 return true;
00434 }
00435
00436 int SourceUtil::CreateSource( QString sourcename,
00437 QString grabber, QString userid,
00438 QString freqtable, QString lineupid,
00439 QString password, bool useeit,
00440 QString configpath, int nitid)
00441 {
00442 MSqlQuery query(MSqlQuery::InitCon());
00443
00444 query.prepare("INSERT INTO videosource (name,xmltvgrabber,userid,freqtable,lineupid,"
00445 "password,useeit,configpath,dvb_nit_id) VALUES (:NAME, :XMLTVGRABBER, "
00446 ":USERID, :FREQTABLE, :LINEUPID, :PASSWORD, :USEEIT, :CONFIGPATH, :NITID)");
00447
00448 query.bindValue(":NAME", sourcename);
00449 query.bindValue(":XMLTVGRABBER", grabber);
00450 query.bindValue(":USERID", userid);
00451 query.bindValue(":FREQTABLE", freqtable);
00452 query.bindValue(":LINEUPID", lineupid);
00453 query.bindValue(":PASSWORD", password);
00454 query.bindValue(":USEEIT", useeit);
00455 query.bindValue(":CONFIGPATH", configpath);
00456 query.bindValue(":NITID", nitid);
00457
00458 if (!query.exec() || !query.isActive())
00459 {
00460 MythDB::DBError("Adding Video Source", query);
00461 return -1;
00462 }
00463
00464 query.prepare("SELECT MAX(sourceid) FROM videosource");
00465
00466 if (!query.exec())
00467 {
00468 MythDB::DBError("CreateSource maxsource", query);
00469 return -1;
00470 }
00471
00472 uint sourceid = -1;
00473
00474 if (query.next())
00475 sourceid = query.value(0).toUInt();
00476
00477 return sourceid;
00478 }
00479
00480 bool SourceUtil::DeleteSource(uint sourceid)
00481 {
00482 MSqlQuery query(MSqlQuery::InitCon());
00483
00484
00485 query.prepare("DELETE FROM channel "
00486 "WHERE sourceid = :SOURCEID");
00487 query.bindValue(":SOURCEID", sourceid);
00488
00489 if (!query.exec() || !query.isActive())
00490 {
00491 MythDB::DBError("Deleting Channels", query);
00492 return false;
00493 }
00494
00495
00496 query.prepare("DELETE FROM dtv_multiplex "
00497 "WHERE sourceid = :SOURCEID");
00498 query.bindValue(":SOURCEID", sourceid);
00499
00500 if (!query.exec() || !query.isActive())
00501 {
00502 MythDB::DBError("Deleting Multiplexes", query);
00503 return false;
00504 }
00505
00506
00507 query.prepare("DELETE FROM cardinput "
00508 "WHERE sourceid = :SOURCEID");
00509 query.bindValue(":SOURCEID", sourceid);
00510
00511 if (!query.exec() || !query.isActive())
00512 {
00513 MythDB::DBError("Deleting cardinputs", query);
00514 return false;
00515 }
00516
00517
00518 query.prepare("DELETE FROM videosource "
00519 "WHERE sourceid = :SOURCEID");
00520 query.bindValue(":SOURCEID", sourceid);
00521
00522 if (!query.exec() || !query.isActive())
00523 {
00524 MythDB::DBError("Deleting VideoSource", query);
00525 return false;
00526 }
00527
00528
00529 CardUtil::DeleteOrphanInputs();
00530 CardUtil::UnlinkInputGroup(0,0);
00531
00532 return true;
00533 }
00534
00535 bool SourceUtil::DeleteAllSources(void)
00536 {
00537 MSqlQuery query(MSqlQuery::InitCon());
00538 return (query.exec("TRUNCATE TABLE channel") &&
00539 query.exec("TRUNCATE TABLE program") &&
00540 query.exec("TRUNCATE TABLE videosource") &&
00541 query.exec("TRUNCATE TABLE credits") &&
00542 query.exec("TRUNCATE TABLE programrating") &&
00543 query.exec("TRUNCATE TABLE programgenres") &&
00544 query.exec("TRUNCATE TABLE dtv_multiplex") &&
00545 query.exec("TRUNCATE TABLE inputgroup") &&
00546 query.exec("TRUNCATE TABLE diseqc_config") &&
00547 query.exec("TRUNCATE TABLE diseqc_tree") &&
00548 query.exec("TRUNCATE TABLE eit_cache") &&
00549 query.exec("TRUNCATE TABLE channelgroup") &&
00550 query.exec("TRUNCATE TABLE channelgroupnames") &&
00551 query.exec("TRUNCATE TABLE cardinput"));
00552 }