00001
00002
00003 #include <stdint.h>
00004
00005 #include <algorithm>
00006 #include <set>
00007 using namespace std;
00008
00009 #include <QRegExp>
00010 #include <QImage>
00011 #include <QFile>
00012 #include <QReadWriteLock>
00013 #include <QHash>
00014
00015 #include "channelutil.h"
00016 #include "mythdb.h"
00017 #include "dvbtables.h"
00018 #include "tv.h"
00019
00020 #define LOC QString("ChanUtil: ")
00021
00022 const QString ChannelUtil::kATSCSeparators = "(_|-|#|\\.)";
00023
00024 static uint get_dtv_multiplex(uint db_source_id, QString sistandard,
00025 uint64_t frequency,
00026
00027 uint transport_id,
00028
00029
00030 uint network_id,
00031
00032 signed char polarity)
00033 {
00034 QString qstr =
00035 "SELECT mplexid "
00036 "FROM dtv_multiplex "
00037 "WHERE sourceid = :SOURCEID "
00038 " AND sistandard = :SISTANDARD ";
00039
00040 if (sistandard.toLower() != "dvb")
00041 qstr += "AND frequency = :FREQUENCY ";
00042 else
00043 {
00044 qstr += "AND transportid = :TRANSPORTID ";
00045 qstr += "AND networkid = :NETWORKID ";
00046 qstr += "AND polarity = :POLARITY ";
00047 }
00048
00049
00050 MSqlQuery query(MSqlQuery::InitCon());
00051 query.prepare(qstr);
00052
00053 query.bindValue(":SOURCEID", db_source_id);
00054 query.bindValue(":SISTANDARD", sistandard);
00055
00056 if (sistandard.toLower() != "dvb")
00057 query.bindValue(":FREQUENCY", QString::number(frequency));
00058 else
00059 {
00060 query.bindValue(":TRANSPORTID", transport_id);
00061 query.bindValue(":NETWORKID", network_id);
00062 query.bindValue(":POLARITY", QString(polarity));
00063 }
00064
00065 if (!query.exec() || !query.isActive())
00066 {
00067 MythDB::DBError("get_dtv_multiplex", query);
00068 return 0;
00069 }
00070
00071 if (query.next())
00072 return query.value(0).toUInt();
00073
00074 return 0;
00075 }
00076
00077 static uint insert_dtv_multiplex(
00078 int db_source_id, QString sistandard,
00079 uint64_t frequency, QString modulation,
00080
00081 int transport_id, int network_id,
00082 int symbol_rate, signed char bandwidth,
00083 signed char polarity, signed char inversion,
00084 signed char trans_mode,
00085 QString inner_FEC, QString constellation,
00086 signed char hierarchy, QString hp_code_rate,
00087 QString lp_code_rate, QString guard_interval,
00088 QString mod_sys, QString rolloff)
00089 {
00090 MSqlQuery query(MSqlQuery::InitCon());
00091
00092
00093 uint mplex = get_dtv_multiplex(
00094 db_source_id, sistandard, frequency,
00095
00096 transport_id, network_id, polarity);
00097
00098 LOG(VB_CHANSCAN, LOG_INFO, QString(
00099 "insert_dtv_multiplex(db_source_id: %1, sistandard: '%2', "
00100 "frequency: %3, modulation: %4, transport_id: %5, "
00101 "network_id: %6, polarity: %7...) mplexid:%8")
00102 .arg(db_source_id).arg(sistandard)
00103 .arg(frequency).arg(modulation)
00104 .arg(transport_id).arg(network_id)
00105 .arg(polarity).arg(mplex));
00106
00107 bool isDVB = (sistandard.toLower() == "dvb");
00108
00109 QString updateStr =
00110 "UPDATE dtv_multiplex "
00111 "SET frequency = :FREQUENCY1, ";
00112
00113 updateStr += (!modulation.isNull()) ?
00114 "modulation = :MODULATION, " : "";
00115 updateStr += (symbol_rate >= 0) ?
00116 "symbolrate = :SYMBOLRATE, " : "";
00117 updateStr += (bandwidth >= 0) ?
00118 "bandwidth = :BANDWIDTH, " : "";
00119 updateStr += (polarity >= 0) ?
00120 "polarity = :POLARITY, " : "";
00121 updateStr += (inversion >= 0) ?
00122 "inversion = :INVERSION, " : "";
00123 updateStr += (trans_mode >= 0) ?
00124 "transmission_mode= :TRANS_MODE, " : "";
00125 updateStr += (!inner_FEC.isNull()) ?
00126 "fec = :INNER_FEC, " : "";
00127 updateStr += (!constellation.isNull()) ?
00128 "constellation = :CONSTELLATION, " : "";
00129 updateStr += (hierarchy >= 0) ?
00130 "hierarchy = :HIERARCHY, " : "";
00131 updateStr += (!hp_code_rate.isNull()) ?
00132 "hp_code_rate = :HP_CODE_RATE, " : "";
00133 updateStr += (!lp_code_rate.isNull()) ?
00134 "lp_code_rate = :LP_CODE_RATE, " : "";
00135 updateStr += (!guard_interval.isNull()) ?
00136 "guard_interval = :GUARD_INTERVAL, " : "";
00137 updateStr += (!mod_sys.isNull()) ?
00138 "mod_sys = :MOD_SYS, " : "";
00139 updateStr += (symbol_rate >= 0) ?
00140 "rolloff = :ROLLOFF, " : "";
00141 updateStr += (transport_id && !isDVB) ?
00142 "transportid = :TRANSPORTID, " : "";
00143
00144 updateStr = updateStr.left(updateStr.length()-2) + " ";
00145
00146 updateStr +=
00147 "WHERE sourceid = :SOURCEID AND "
00148 " sistandard = :SISTANDARD AND ";
00149
00150 updateStr += (isDVB) ?
00151 " polarity = :WHEREPOLARITY AND "
00152 " transportid = :TRANSPORTID AND networkid = :NETWORKID " :
00153 " frequency = :FREQUENCY2 ";
00154
00155 QString insertStr =
00156 "INSERT INTO dtv_multiplex "
00157 " (sourceid, sistandard, frequency, ";
00158
00159 insertStr += (!modulation.isNull()) ? "modulation, " : "";
00160 insertStr += (transport_id || isDVB) ? "transportid, " : "";
00161 insertStr += (isDVB) ? "networkid, " : "";
00162 insertStr += (symbol_rate >= 0) ? "symbolrate, " : "";
00163 insertStr += (bandwidth >= 0) ? "bandwidth, " : "";
00164 insertStr += (polarity >= 0) ? "polarity, " : "";
00165 insertStr += (inversion >= 0) ? "inversion, " : "";
00166 insertStr += (trans_mode >= 0) ? "transmission_mode, " : "";
00167 insertStr += (!inner_FEC.isNull()) ? "fec, " : "";
00168 insertStr += (!constellation.isNull()) ? "constellation, " : "";
00169 insertStr += (hierarchy >= 0) ? "hierarchy, " : "";
00170 insertStr += (!hp_code_rate.isNull()) ? "hp_code_rate, " : "";
00171 insertStr += (!lp_code_rate.isNull()) ? "lp_code_rate, " : "";
00172 insertStr += (!guard_interval.isNull()) ? "guard_interval, " : "";
00173 insertStr += (!mod_sys.isNull()) ? "mod_sys, " : "";
00174 insertStr += (!rolloff.isNull()) ? "rolloff, " : "";
00175 insertStr = insertStr.left(insertStr.length()-2) + ") ";
00176
00177 insertStr +=
00178 "VALUES "
00179 " (:SOURCEID, :SISTANDARD, :FREQUENCY1, ";
00180 insertStr += (!modulation.isNull()) ? ":MODULATION, " : "";
00181 insertStr += (transport_id || isDVB) ? ":TRANSPORTID, " : "";
00182 insertStr += (isDVB) ? ":NETWORKID, " : "";
00183 insertStr += (symbol_rate >= 0) ? ":SYMBOLRATE, " : "";
00184 insertStr += (bandwidth >= 0) ? ":BANDWIDTH, " : "";
00185 insertStr += (polarity >= 0) ? ":POLARITY, " : "";
00186 insertStr += (inversion >= 0) ? ":INVERSION, " : "";
00187 insertStr += (trans_mode >= 0) ? ":TRANS_MODE, " : "";
00188 insertStr += (!inner_FEC.isNull()) ? ":INNER_FEC, " : "";
00189 insertStr += (!constellation.isNull()) ? ":CONSTELLATION, " : "";
00190 insertStr += (hierarchy >= 0) ? ":HIERARCHY, " : "";
00191 insertStr += (!hp_code_rate.isNull()) ? ":HP_CODE_RATE, " : "";
00192 insertStr += (!lp_code_rate.isNull()) ? ":LP_CODE_RATE, " : "";
00193 insertStr += (!guard_interval.isNull()) ? ":GUARD_INTERVAL, " : "";
00194 insertStr += (!mod_sys.isNull()) ? ":MOD_SYS, " : "";
00195 insertStr += (!rolloff.isNull()) ? ":ROLLOFF, " : "";
00196 insertStr = insertStr.left(insertStr.length()-2) + ");";
00197
00198 query.prepare((mplex) ? updateStr : insertStr);
00199
00200 query.bindValue(":SOURCEID", db_source_id);
00201 query.bindValue(":SISTANDARD", sistandard);
00202 query.bindValue(":FREQUENCY1", QString::number(frequency));
00203
00204 if (mplex)
00205 {
00206 if (isDVB)
00207 {
00208 query.bindValue(":TRANSPORTID", transport_id);
00209 query.bindValue(":NETWORKID", network_id);
00210 query.bindValue(":WHEREPOLARITY", QString(polarity));
00211 }
00212 else
00213 {
00214 query.bindValue(":FREQUENCY2", QString::number(frequency));
00215 if (transport_id)
00216 query.bindValue(":TRANSPORTID", transport_id);
00217 }
00218 }
00219 else
00220 {
00221 if (transport_id || isDVB)
00222 query.bindValue(":TRANSPORTID", transport_id);
00223 if (isDVB)
00224 query.bindValue(":NETWORKID", network_id);
00225 }
00226
00227 if (!modulation.isNull())
00228 query.bindValue(":MODULATION", modulation);
00229
00230 if (symbol_rate >= 0)
00231 query.bindValue(":SYMBOLRATE", symbol_rate);
00232 if (bandwidth >= 0)
00233 query.bindValue(":BANDWIDTH", QString("%1").arg((char)bandwidth));
00234 if (polarity >= 0)
00235 query.bindValue(":POLARITY", QString("%1").arg((char)polarity));
00236 if (inversion >= 0)
00237 query.bindValue(":INVERSION", QString("%1").arg((char)inversion));
00238 if (trans_mode >= 0)
00239 query.bindValue(":TRANS_MODE", QString("%1").arg((char)trans_mode));
00240
00241 if (!inner_FEC.isNull())
00242 query.bindValue(":INNER_FEC", inner_FEC);
00243 if (!constellation.isNull())
00244 query.bindValue(":CONSTELLATION", constellation);
00245 if (hierarchy >= 0)
00246 query.bindValue(":HIERARCHY", QString("%1").arg((char)hierarchy));
00247 if (!hp_code_rate.isNull())
00248 query.bindValue(":HP_CODE_RATE", hp_code_rate);
00249 if (!lp_code_rate.isNull())
00250 query.bindValue(":LP_CODE_RATE", lp_code_rate);
00251 if (!guard_interval.isNull())
00252 query.bindValue(":GUARD_INTERVAL",guard_interval);
00253 if (!mod_sys.isNull())
00254 query.bindValue(":MOD_SYS", mod_sys);
00255 if (!rolloff.isNull())
00256 query.bindValue(":ROLLOFF", rolloff);
00257
00258 if (!query.exec() || !query.isActive())
00259 {
00260 MythDB::DBError("Adding transport to Database.", query);
00261 return 0;
00262 }
00263
00264 if (mplex)
00265 return mplex;
00266
00267 mplex = get_dtv_multiplex(
00268 db_source_id, sistandard, frequency,
00269
00270 transport_id, network_id, polarity);
00271
00272 LOG(VB_CHANSCAN, LOG_INFO, QString("insert_dtv_multiplex -- ") +
00273 QString("inserted %1").arg(mplex));
00274
00275 return mplex;
00276 }
00277
00278 static void handle_transport_desc(vector<uint> &muxes,
00279 const MPEGDescriptor &desc,
00280 uint sourceid, uint tsid, uint netid)
00281 {
00282 uint tag = desc.DescriptorTag();
00283
00284 if (tag == DescriptorID::terrestrial_delivery_system)
00285 {
00286 const TerrestrialDeliverySystemDescriptor cd(desc);
00287 uint64_t freq = cd.FrequencyHz();
00288
00289
00290
00291 int mux = ChannelUtil::GetMplexID(sourceid, tsid, netid);
00292 if (mux > 0)
00293 {
00294 QString dummy_mod;
00295 QString dummy_sistd;
00296 uint dummy_tsid, dummy_netid;
00297 ChannelUtil::GetTuningParams(mux, dummy_mod, freq,
00298 dummy_tsid, dummy_netid, dummy_sistd);
00299 }
00300
00301 mux = ChannelUtil::CreateMultiplex(
00302 (int)sourceid, "dvb",
00303 freq, QString(),
00304
00305 (int)tsid, (int)netid,
00306 -1, cd.BandwidthString()[0].toAscii(),
00307 -1, 'a',
00308 cd.TransmissionModeString()[0].toAscii(),
00309 QString(), cd.ConstellationString(),
00310 cd.HierarchyString()[0].toAscii(), cd.CodeRateHPString(),
00311 cd.CodeRateLPString(), cd.GuardIntervalString(),
00312 QString(), QString());
00313
00314 if (mux)
00315 muxes.push_back(mux);
00316
00317
00318
00319
00320
00321
00322
00323
00324 }
00325 else if (tag == DescriptorID::satellite_delivery_system)
00326 {
00327 const SatelliteDeliverySystemDescriptor cd(desc);
00328
00329 uint mux = ChannelUtil::CreateMultiplex(
00330 sourceid, "dvb",
00331 cd.FrequencyHz(), cd.ModulationString(),
00332
00333 tsid, netid,
00334 cd.SymbolRateHz(), -1,
00335 cd.PolarizationString()[0].toAscii(), 'a',
00336 -1,
00337 cd.FECInnerString(), QString(),
00338 -1, QString(),
00339 QString(), QString(),
00340 cd.ModulationSystemString(), cd.RollOffString());
00341
00342 if (mux)
00343 muxes.push_back(mux);
00344
00345
00346
00347
00348 }
00349 else if (tag == DescriptorID::cable_delivery_system)
00350 {
00351 const CableDeliverySystemDescriptor cd(desc);
00352
00353 uint mux = ChannelUtil::CreateMultiplex(
00354 sourceid, "dvb",
00355 cd.FrequencyHz(), cd.ModulationString(),
00356
00357 tsid, netid,
00358 cd.SymbolRateHz(), -1,
00359 -1, 'a',
00360 -1,
00361 cd.FECInnerString(), QString::null,
00362 -1, QString::null,
00363 QString::null, QString::null,
00364 QString::null, QString::null);
00365
00366 if (mux)
00367 muxes.push_back(mux);
00368 }
00369 }
00370
00371 uint ChannelUtil::CreateMultiplex(int sourceid, QString sistandard,
00372 uint64_t frequency, QString modulation,
00373 int transport_id, int network_id)
00374 {
00375 return CreateMultiplex(
00376 sourceid, sistandard,
00377 frequency, modulation,
00378 transport_id, network_id,
00379 -1, -1,
00380 -1, -1,
00381 -1,
00382 QString::null, QString::null,
00383 -1, QString::null,
00384 QString::null, QString::null,
00385 QString::null, QString::null);
00386 }
00387
00388 uint ChannelUtil::CreateMultiplex(
00389 int sourceid, QString sistandard,
00390 uint64_t freq, QString modulation,
00391
00392 int transport_id, int network_id,
00393 int symbol_rate, signed char bandwidth,
00394 signed char polarity, signed char inversion,
00395 signed char trans_mode,
00396 QString inner_FEC, QString constellation,
00397 signed char hierarchy, QString hp_code_rate,
00398 QString lp_code_rate, QString guard_interval,
00399 QString mod_sys, QString rolloff)
00400 {
00401 return insert_dtv_multiplex(
00402 sourceid, sistandard,
00403 freq, modulation,
00404
00405 transport_id, network_id,
00406 symbol_rate, bandwidth,
00407 polarity, inversion,
00408 trans_mode,
00409 inner_FEC, constellation,
00410 hierarchy, hp_code_rate,
00411 lp_code_rate, guard_interval,
00412 mod_sys, rolloff);
00413 }
00414
00415 uint ChannelUtil::CreateMultiplex(uint sourceid, const DTVMultiplex &mux,
00416 int transport_id, int network_id)
00417 {
00418 return insert_dtv_multiplex(
00419 sourceid, mux.sistandard,
00420 mux.frequency, mux.modulation.toString(),
00421
00422 transport_id, network_id,
00423 mux.symbolrate, mux.bandwidth.toChar().toAscii(),
00424 mux.polarity.toChar().toAscii(), mux.inversion.toChar().toAscii(),
00425 mux.trans_mode.toChar().toAscii(),
00426 mux.fec.toString(), mux.modulation.toString(),
00427 mux.hierarchy.toChar().toAscii(), mux.hp_code_rate.toString(),
00428 mux.lp_code_rate.toString(), mux.guard_interval.toString(),
00429 mux.mod_sys.toString(), mux.rolloff.toString());
00430 }
00431
00432
00436 vector<uint> ChannelUtil::CreateMultiplexes(
00437 int sourceid, const NetworkInformationTable *nit)
00438 {
00439 vector<uint> muxes;
00440
00441 if (sourceid <= 0)
00442 return muxes;
00443
00444 for (uint i = 0; i < nit->TransportStreamCount(); ++i)
00445 {
00446 const desc_list_t& list =
00447 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
00448 nit->TransportDescriptorsLength(i));
00449
00450 uint tsid = nit->TSID(i);
00451 uint netid = nit->OriginalNetworkID(i);
00452 for (uint j = 0; j < list.size(); ++j)
00453 {
00454 const MPEGDescriptor desc(list[j]);
00455 handle_transport_desc(muxes, desc, sourceid, tsid, netid);
00456 }
00457 }
00458 return muxes;
00459 }
00460
00461 uint ChannelUtil::GetMplexID(uint sourceid, const QString &channum)
00462 {
00463 MSqlQuery query(MSqlQuery::InitCon());
00464
00465 query.prepare(
00466 "SELECT mplexid "
00467 "FROM channel "
00468 "WHERE sourceid = :SOURCEID AND "
00469 " channum = :CHANNUM");
00470
00471 query.bindValue(":SOURCEID", sourceid);
00472 query.bindValue(":CHANNUM", channum);
00473
00474 if (!query.exec() || !query.isActive())
00475 MythDB::DBError("GetMplexID 0", query);
00476 else if (query.next())
00477 return query.value(0).toInt();
00478
00479 return 0;
00480 }
00481
00482 int ChannelUtil::GetMplexID(uint sourceid, uint64_t frequency)
00483 {
00484 MSqlQuery query(MSqlQuery::InitCon());
00485
00486 query.prepare(
00487 "SELECT mplexid "
00488 "FROM dtv_multiplex "
00489 "WHERE sourceid = :SOURCEID AND "
00490 " frequency = :FREQUENCY");
00491
00492 query.bindValue(":SOURCEID", sourceid);
00493 query.bindValue(":FREQUENCY", QString::number(frequency));
00494
00495 if (!query.exec() || !query.isActive())
00496 {
00497 MythDB::DBError("GetMplexID 1", query);
00498 return -1;
00499 }
00500
00501 if (query.next())
00502 return query.value(0).toInt();
00503
00504 return -1;
00505 }
00506
00507 int ChannelUtil::GetMplexID(uint sourceid, uint64_t frequency,
00508 uint transport_id, uint network_id)
00509 {
00510 MSqlQuery query(MSqlQuery::InitCon());
00511
00512 query.prepare(
00513 "SELECT mplexid "
00514 "FROM dtv_multiplex "
00515 "WHERE networkid = :NETWORKID AND "
00516 " transportid = :TRANSPORTID AND "
00517 " frequency = :FREQUENCY AND "
00518 " sourceid = :SOURCEID");
00519
00520 query.bindValue(":SOURCEID", sourceid);
00521 query.bindValue(":NETWORKID", network_id);
00522 query.bindValue(":TRANSPORTID", transport_id);
00523 query.bindValue(":FREQUENCY", QString::number(frequency));
00524
00525 if (!query.exec() || !query.isActive())
00526 {
00527 MythDB::DBError("GetMplexID 2", query);
00528 return -1;
00529 }
00530
00531 if (query.next())
00532 return query.value(0).toInt();
00533
00534 return -1;
00535 }
00536
00537 int ChannelUtil::GetMplexID(uint sourceid,
00538 uint transport_id, uint network_id)
00539 {
00540 MSqlQuery query(MSqlQuery::InitCon());
00541
00542 query.prepare(
00543 "SELECT mplexid "
00544 "FROM dtv_multiplex "
00545 "WHERE networkid = :NETWORKID AND "
00546 " transportid = :TRANSPORTID AND "
00547 " sourceid = :SOURCEID");
00548
00549 query.bindValue(":SOURCEID", sourceid);
00550 query.bindValue(":NETWORKID", network_id);
00551 query.bindValue(":TRANSPORTID", transport_id);
00552
00553 if (!query.exec() || !query.isActive())
00554 {
00555 MythDB::DBError("GetMplexID 3", query);
00556 return -1;
00557 }
00558
00559 if (query.next())
00560 return query.value(0).toInt();
00561
00562 return -1;
00563 }
00564
00565 uint ChannelUtil::GetMplexID(uint chanid)
00566 {
00567 MSqlQuery query(MSqlQuery::InitCon());
00568
00569 query.prepare(
00570 "SELECT mplexid "
00571 "FROM channel "
00572 "WHERE chanid = :CHANID");
00573
00574 query.bindValue(":CHANID", chanid);
00575
00576 if (!query.exec())
00577 MythDB::DBError("GetMplexID 4", query);
00578 else if (query.next())
00579 return query.value(0).toInt();
00580
00581 return 0;
00582 }
00583
00606
00607
00608 int ChannelUtil::GetBetterMplexID(int current_mplexid,
00609 int transport_id,
00610 int network_id)
00611 {
00612 LOG(VB_CHANSCAN, LOG_INFO,
00613 QString("GetBetterMplexID(mplexId %1, tId %2, netId %3)")
00614 .arg(current_mplexid).arg(transport_id).arg(network_id));
00615
00616 int q_networkid = 0, q_transportid = 0;
00617 MSqlQuery query(MSqlQuery::InitCon());
00618
00619 query.prepare(QString("SELECT networkid, transportid "
00620 "FROM dtv_multiplex "
00621 "WHERE mplexid = %1").arg(current_mplexid));
00622
00623 if (!query.exec() || !query.isActive())
00624 MythDB::DBError("Getting mplexid global search", query);
00625 else if (query.next())
00626 {
00627 q_networkid = query.value(0).toInt();
00628 q_transportid = query.value(1).toInt();
00629 }
00630
00631
00632 if ((q_networkid == network_id) && (q_transportid == transport_id))
00633 {
00634 LOG(VB_CHANSCAN, LOG_INFO,
00635 QString("GetBetterMplexID(): Returning perfect match %1")
00636 .arg(current_mplexid));
00637 return current_mplexid;
00638 }
00639
00640
00641 if (!q_networkid && !q_transportid)
00642 {
00643 int qsize = query.size();
00644 query.prepare(QString("UPDATE dtv_multiplex "
00645 "SET networkid = %1, transportid = %2 "
00646 "WHERE mplexid = %3")
00647 .arg(network_id).arg(transport_id).arg(current_mplexid));
00648
00649 if (!query.exec() || !query.isActive())
00650 MythDB::DBError("Getting mplexid global search", query);
00651
00652 LOG(VB_CHANSCAN, LOG_INFO,
00653 QString("GetBetterMplexID(): net id and transport id "
00654 "are null, qsize(%1), Returning %2")
00655 .arg(qsize).arg(current_mplexid));
00656 return current_mplexid;
00657 }
00658
00659
00660 QString theQueries[2] =
00661 {
00662 QString("SELECT a.mplexid "
00663 "FROM dtv_multiplex a, dtv_multiplex b "
00664 "WHERE a.networkid = %1 AND "
00665 " a.transportid = %2 AND "
00666 " a.sourceid = b.sourceid AND "
00667 " b.mplexid = %3")
00668 .arg(network_id).arg(transport_id).arg(current_mplexid),
00669
00670 QString("SELECT mplexid "
00671 "FROM dtv_multiplex "
00672 "WHERE networkid = %1 AND "
00673 " transportid = %2")
00674 .arg(network_id).arg(transport_id),
00675 };
00676
00677 for (uint i=0; i<2; i++)
00678 {
00679 query.prepare(theQueries[i]);
00680
00681 if (!query.exec() || !query.isActive())
00682 MythDB::DBError("Finding matching mplexid", query);
00683
00684 if (query.size() == 1 && query.next())
00685 {
00686 LOG(VB_CHANSCAN, LOG_INFO,
00687 QString("GetBetterMplexID(): query#%1 qsize(%2) "
00688 "Returning %3")
00689 .arg(i).arg(query.size()).arg(current_mplexid));
00690 return query.value(0).toInt();
00691 }
00692
00693 if (query.next())
00694 {
00695 int ret = (i==0) ? current_mplexid : query.value(0).toInt();
00696 LOG(VB_CHANSCAN, LOG_INFO,
00697 QString("GetBetterMplexID(): query#%1 qsize(%2) "
00698 "Returning %3")
00699 .arg(i).arg(query.size()).arg(ret));
00700 return ret;
00701 }
00702 }
00703
00704
00705 LOG(VB_CHANSCAN, LOG_INFO, "GetBetterMplexID(): Returning -1");
00706 return -1;
00707 }
00708
00709 bool ChannelUtil::GetTuningParams(uint mplexid,
00710 QString &modulation,
00711 uint64_t &frequency,
00712 uint &dvb_transportid,
00713 uint &dvb_networkid,
00714 QString &si_std)
00715 {
00716 if (!mplexid || (mplexid == 32767))
00717 return false;
00718
00719 MSqlQuery query(MSqlQuery::InitCon());
00720 query.prepare(
00721 "SELECT transportid, networkid, frequency, modulation, sistandard "
00722 "FROM dtv_multiplex "
00723 "WHERE mplexid = :MPLEXID");
00724 query.bindValue(":MPLEXID", mplexid);
00725
00726 if (!query.exec() || !query.isActive())
00727 {
00728 MythDB::DBError("GetTuningParams failed ", query);
00729 return false;
00730 }
00731
00732 if (!query.next())
00733 return false;
00734
00735 dvb_transportid = query.value(0).toUInt();
00736 dvb_networkid = query.value(1).toUInt();
00737 frequency = query.value(2).toULongLong();
00738 modulation = query.value(3).toString();
00739 si_std = query.value(4).toString();
00740
00741 return true;
00742 }
00743
00744 QString ChannelUtil::GetChannelStringField(int chan_id, const QString &field)
00745 {
00746 if (chan_id < 0)
00747 return QString::null;
00748
00749 MSqlQuery query(MSqlQuery::InitCon());
00750 query.prepare(QString("SELECT %1 FROM channel "
00751 "WHERE chanid=%2").arg(field).arg(chan_id));
00752 if (!query.exec() || !query.isActive())
00753 {
00754 MythDB::DBError("Selecting channel/dtv_multiplex 1", query);
00755 return QString::null;
00756 }
00757
00758 if (!query.next())
00759 return QString::null;
00760
00761 return query.value(0).toString();
00762 }
00763
00764 QString ChannelUtil::GetChanNum(int chan_id)
00765 {
00766 return GetChannelStringField(chan_id, QString("channum"));
00767 }
00768
00769 QString ChannelUtil::GetCallsign(int chan_id)
00770 {
00771 return GetChannelStringField(chan_id, QString("callsign"));
00772 }
00773
00774 QString ChannelUtil::GetServiceName(int chan_id)
00775 {
00776 return GetChannelStringField(chan_id, QString("name"));
00777 }
00778
00779 int ChannelUtil::GetTimeOffset(int chan_id)
00780 {
00781 return GetChannelStringField(chan_id, QString("tmoffset")).toInt();
00782 }
00783
00784 int ChannelUtil::GetSourceID(int db_mplexid)
00785 {
00786 MSqlQuery query(MSqlQuery::InitCon());
00787
00788 query.prepare(QString("SELECT sourceid "
00789 "FROM dtv_multiplex "
00790 "WHERE mplexid = %1").arg(db_mplexid));
00791
00792 if (!query.exec() || !query.isActive())
00793 {
00794 MythDB::DBError("Selecting channel/dtv_multiplex", query);
00795 return -1;
00796 }
00797
00798 if (query.next())
00799 return query.value(0).toInt();
00800
00801 return -1;
00802 }
00803
00804 uint ChannelUtil::GetSourceIDForChannel(uint chanid)
00805 {
00806 MSqlQuery query(MSqlQuery::InitCon());
00807
00808 query.prepare(
00809 "SELECT sourceid "
00810 "FROM channel "
00811 "WHERE chanid = :CHANID");
00812 query.bindValue(":CHANID", chanid);
00813
00814 if (!query.exec())
00815 MythDB::DBError("Selecting channel/dtv_multiplex", query);
00816 else if (query.next())
00817 return query.value(0).toUInt();
00818
00819 return 0;
00820 }
00821
00822 int ChannelUtil::GetInputID(int source_id, int card_id)
00823 {
00824 int input_id = -1;
00825
00826 MSqlQuery query(MSqlQuery::InitCon());
00827 query.prepare("SELECT cardinputid"
00828 " FROM cardinput"
00829 " WHERE sourceid = :SOURCEID"
00830 " AND cardid = :CARDID");
00831 query.bindValue(":SOURCEID", source_id);
00832 query.bindValue(":CARDID", card_id);
00833
00834 if (query.exec() && query.isActive() && query.next())
00835 input_id = query.value(0).toInt();
00836
00837 return input_id;
00838 }
00839
00840 QStringList ChannelUtil::GetCardTypes(uint chanid)
00841 {
00842 MSqlQuery query(MSqlQuery::InitCon());
00843 query.prepare("SELECT cardtype "
00844 "FROM capturecard, cardinput, channel "
00845 "WHERE channel.chanid = :CHANID AND "
00846 " channel.sourceid = cardinput.sourceid AND "
00847 " cardinput.cardid = capturecard.cardid "
00848 "GROUP BY cardtype");
00849 query.bindValue(":CHANID", chanid);
00850
00851 QStringList list;
00852 if (!query.exec())
00853 {
00854 MythDB::DBError("ChannelUtil::GetCardTypes", query);
00855 return list;
00856 }
00857 while (query.next())
00858 list.push_back(query.value(0).toString());
00859 return list;
00860 }
00861
00862 static bool lt_pidcache(
00863 const pid_cache_item_t &a, const pid_cache_item_t &b)
00864 {
00865 return a.GetPID() < b.GetPID();
00866 }
00867
00874 bool ChannelUtil::GetCachedPids(uint chanid,
00875 pid_cache_t &pid_cache)
00876 {
00877 MSqlQuery query(MSqlQuery::InitCon());
00878 QString thequery = QString("SELECT pid, tableid FROM pidcache "
00879 "WHERE chanid='%1'").arg(chanid);
00880 query.prepare(thequery);
00881
00882 if (!query.exec() || !query.isActive())
00883 {
00884 MythDB::DBError("GetCachedPids: fetching pids", query);
00885 return false;
00886 }
00887
00888 while (query.next())
00889 {
00890 int pid = query.value(0).toInt(), tid = query.value(1).toInt();
00891 if ((pid >= 0) && (tid >= 0))
00892 pid_cache.push_back(pid_cache_item_t(pid, tid));
00893 }
00894 stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
00895
00896 return true;
00897 }
00898
00905 bool ChannelUtil::SaveCachedPids(uint chanid,
00906 const pid_cache_t &_pid_cache,
00907 bool delete_all)
00908 {
00909 MSqlQuery query(MSqlQuery::InitCon());
00910
00912 if (delete_all)
00913 query.prepare("DELETE FROM pidcache WHERE chanid = :CHANID");
00914 else
00915 query.prepare(
00916 "DELETE FROM pidcache "
00917 "WHERE chanid = :CHANID AND tableid < 65536");
00918
00919 query.bindValue(":CHANID", chanid);
00920
00921 if (!query.exec())
00922 {
00923 MythDB::DBError("GetCachedPids -- delete", query);
00924 return false;
00925 }
00926
00927 pid_cache_t old_cache;
00928 GetCachedPids(chanid, old_cache);
00929 pid_cache_t pid_cache = _pid_cache;
00930 stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
00931
00933 query.prepare(
00934 "INSERT INTO pidcache "
00935 "SET chanid = :CHANID, pid = :PID, tableid = :TABLEID");
00936 query.bindValue(":CHANID", chanid);
00937
00938 bool ok = true;
00939 pid_cache_t::const_iterator ito = old_cache.begin();
00940 pid_cache_t::const_iterator itn = pid_cache.begin();
00941 for (; itn != pid_cache.end(); ++itn)
00942 {
00943
00944 for (; ito != old_cache.end() && ito->GetPID() < itn->GetPID(); ++ito);
00945
00946
00947 if (ito != old_cache.end() && ito->GetPID() == itn->GetPID())
00948 continue;
00949
00950 query.bindValue(":PID", itn->GetPID());
00951 query.bindValue(":TABLEID", itn->GetComposite());
00952
00953 if (!query.exec())
00954 {
00955 MythDB::DBError("GetCachedPids -- insert", query);
00956 ok = false;
00957 }
00958 }
00959
00960 return ok;
00961 }
00962
00963 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
00964 uint cardid,
00965 const QString &input,
00966 const QString &channum)
00967 {
00968 QString retval = QString::null;
00969
00970 MSqlQuery query(MSqlQuery::InitCon());
00971
00972 query.prepare(
00973 QString(
00974 "SELECT channel.%1 "
00975 "FROM channel, capturecard, cardinput "
00976 "WHERE channel.channum = :CHANNUM AND "
00977 " channel.sourceid = cardinput.sourceid AND "
00978 " cardinput.inputname = :INPUT AND "
00979 " cardinput.cardid = capturecard.cardid AND "
00980 " capturecard.cardid = :CARDID ")
00981 .arg(channel_field));
00982
00983 query.bindValue(":CARDID", cardid);
00984 query.bindValue(":INPUT", input);
00985 query.bindValue(":CHANNUM", channum);
00986
00987 if (!query.exec() || !query.isActive())
00988 MythDB::DBError("getchannelvalue", query);
00989 else if (query.next())
00990 retval = query.value(0).toString();
00991
00992 return retval;
00993 }
00994
00995 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
00996 uint sourceid,
00997 const QString &channum)
00998 {
00999 QString retval = QString::null;
01000
01001 MSqlQuery query(MSqlQuery::InitCon());
01002
01003 query.prepare(
01004 QString(
01005 "SELECT channel.%1 "
01006 "FROM channel "
01007 "WHERE channum = :CHANNUM AND "
01008 " sourceid = :SOURCEID")
01009 .arg(channel_field));
01010
01011 query.bindValue(":SOURCEID", sourceid);
01012 query.bindValue(":CHANNUM", channum);
01013
01014 if (!query.exec() || !query.isActive())
01015 MythDB::DBError("getchannelvalue", query);
01016 else if (query.next())
01017 retval = query.value(0).toString();
01018
01019 return retval;
01020 }
01021
01022 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
01023 uint cardid,
01024 const QString &input,
01025 const QString &channum)
01026 {
01027 QString val = GetChannelValueStr(channel_field, cardid, input, channum);
01028
01029 int retval = 0;
01030 if (!val.isEmpty())
01031 retval = val.toInt();
01032
01033 return (retval) ? retval : -1;
01034 }
01035
01036 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
01037 uint sourceid,
01038 const QString &channum)
01039 {
01040 QString val = GetChannelValueStr(channel_field, sourceid, channum);
01041
01042 int retval = 0;
01043 if (!val.isEmpty())
01044 retval = val.toInt();
01045
01046 return (retval) ? retval : -1;
01047 }
01048
01049 bool ChannelUtil::IsOnSameMultiplex(uint srcid,
01050 const QString &new_channum,
01051 const QString &old_channum)
01052 {
01053 if (new_channum.isEmpty() || old_channum.isEmpty())
01054 return false;
01055
01056 if (new_channum == old_channum)
01057 return true;
01058
01059 uint old_mplexid = GetMplexID(srcid, old_channum);
01060 if (!old_mplexid)
01061 return false;
01062
01063 uint new_mplexid = GetMplexID(srcid, new_channum);
01064 if (!new_mplexid)
01065 return false;
01066
01067 LOG(VB_CHANNEL, LOG_INFO, QString("IsOnSameMultiplex? %1==%2 -> %3")
01068 .arg(old_mplexid).arg(new_mplexid)
01069 .arg(old_mplexid == new_mplexid));
01070
01071 return old_mplexid == new_mplexid;
01072 }
01073
01079 static QStringList get_valid_recorder_list(uint chanid)
01080 {
01081 QStringList reclist;
01082
01083
01084
01085 MSqlQuery query(MSqlQuery::InitCon());
01086
01087 query.prepare(
01088 "SELECT cardinput.cardid "
01089 "FROM channel "
01090 "LEFT JOIN cardinput ON channel.sourceid = cardinput.sourceid "
01091 "WHERE channel.chanid = :CHANID AND "
01092 " cardinput.livetvorder > 0 "
01093 "ORDER BY cardinput.livetvorder, cardinput.cardinputid");
01094 query.bindValue(":CHANID", chanid);
01095
01096 if (!query.exec() || !query.isActive())
01097 {
01098 MythDB::DBError("get_valid_recorder_list ChanID", query);
01099 return reclist;
01100 }
01101
01102 while (query.next())
01103 reclist << query.value(0).toString();
01104
01105 return reclist;
01106 }
01107
01113 static QStringList get_valid_recorder_list(const QString &channum)
01114 {
01115 QStringList reclist;
01116
01117
01118
01119 MSqlQuery query(MSqlQuery::InitCon());
01120
01121 query.prepare(
01122 "SELECT cardinput.cardid "
01123 "FROM channel "
01124 "LEFT JOIN cardinput ON channel.sourceid = cardinput.sourceid "
01125 "WHERE channel.channum = :CHANNUM AND "
01126 " cardinput.livetvorder > 0 "
01127 "ORDER BY cardinput.livetvorder, cardinput.cardinputid");
01128 query.bindValue(":CHANNUM", channum);
01129
01130 if (!query.exec() || !query.isActive())
01131 {
01132 MythDB::DBError("get_valid_recorder_list ChanNum", query);
01133 return reclist;
01134 }
01135
01136 while (query.next())
01137 reclist << query.value(0).toString();
01138
01139 return reclist;
01140 }
01141
01149 QStringList ChannelUtil::GetValidRecorderList(
01150 uint chanid, const QString &channum)
01151 {
01152 if (chanid)
01153 return get_valid_recorder_list(chanid);
01154 else if (!channum.isEmpty())
01155 return get_valid_recorder_list(channum);
01156 return QStringList();
01157 }
01158
01159
01160 vector<uint> ChannelUtil::GetConflicting(const QString &channum, uint sourceid)
01161 {
01162 MSqlQuery query(MSqlQuery::InitCon());
01163 vector<uint> conflicting;
01164
01165 if (sourceid)
01166 {
01167 query.prepare(
01168 "SELECT chanid from channel "
01169 "WHERE sourceid = :SOURCEID AND "
01170 " channum = :CHANNUM");
01171 query.bindValue(":SOURCEID", sourceid);
01172 }
01173 else
01174 {
01175 query.prepare(
01176 "SELECT chanid from channel "
01177 "WHERE channum = :CHANNUM");
01178 }
01179
01180 query.bindValue(":CHANNUM", channum);
01181 if (!query.exec())
01182 {
01183 MythDB::DBError("IsConflicting", query);
01184 conflicting.push_back(0);
01185 return conflicting;
01186 }
01187
01188 while (query.next())
01189 conflicting.push_back(query.value(0).toUInt());
01190
01191 return conflicting;
01192 }
01193
01194 bool ChannelUtil::SetChannelValue(const QString &field_name,
01195 QString value,
01196 uint sourceid,
01197 const QString &channum)
01198 {
01199 MSqlQuery query(MSqlQuery::InitCon());
01200
01201 query.prepare(
01202 QString("UPDATE channel SET channel.%1=:VALUE "
01203 "WHERE channel.channum = :CHANNUM AND "
01204 " channel.sourceid = :SOURCEID").arg(field_name));
01205
01206 query.bindValue(":VALUE", value);
01207 query.bindValue(":CHANNUM", channum);
01208 query.bindValue(":SOURCEID", sourceid);
01209
01210 return query.exec();
01211 }
01212
01213 bool ChannelUtil::SetChannelValue(const QString &field_name,
01214 QString value,
01215 int chanid)
01216 {
01217 MSqlQuery query(MSqlQuery::InitCon());
01218
01219 query.prepare(
01220 QString("UPDATE channel SET channel.%1=:VALUE "
01221 "WHERE channel.chanid = :CHANID").arg(field_name));
01222
01223 query.bindValue(":VALUE", value);
01224 query.bindValue(":CHANID", chanid);
01225
01226 return query.exec();
01227 }
01228
01230 QString ChannelUtil::GetDefaultAuthority(uint chanid)
01231 {
01232 static QReadWriteLock channel_default_authority_map_lock;
01233 static QMap<uint,QString> channel_default_authority_map;
01234 static bool run_init = true;
01235
01236 channel_default_authority_map_lock.lockForRead();
01237
01238 if (run_init)
01239 {
01240 channel_default_authority_map_lock.unlock();
01241 channel_default_authority_map_lock.lockForWrite();
01242 if (run_init)
01243 {
01244 MSqlQuery query(MSqlQuery::InitCon());
01245 query.prepare(
01246 "SELECT chanid, m.default_authority "
01247 "FROM channel c "
01248 "LEFT JOIN dtv_multiplex m "
01249 "ON (c.mplexid = m.mplexid)");
01250 if (query.exec())
01251 {
01252 while (query.next())
01253 {
01254 if (!query.value(1).toString().isEmpty())
01255 {
01256 channel_default_authority_map[query.value(0).toUInt()] =
01257 query.value(1).toString();
01258 }
01259 }
01260 run_init = false;
01261 }
01262 else
01263 {
01264 MythDB::DBError("GetDefaultAuthority 1", query);
01265 }
01266
01267 query.prepare(
01268 "SELECT chanid, default_authority "
01269 "FROM channel");
01270 if (query.exec())
01271 {
01272 while (query.next())
01273 {
01274 if (!query.value(1).toString().isEmpty())
01275 {
01276 channel_default_authority_map[query.value(0).toUInt()] =
01277 query.value(1).toString();
01278 }
01279 }
01280 run_init = false;
01281 }
01282 else
01283 {
01284 MythDB::DBError("GetDefaultAuthority 2", query);
01285 }
01286
01287 }
01288 }
01289
01290 QMap<uint,QString>::iterator it = channel_default_authority_map.find(chanid);
01291 QString ret = QString::null;
01292 if (it != channel_default_authority_map.end())
01293 {
01294 ret = *it;
01295 ret.detach();
01296 }
01297 channel_default_authority_map_lock.unlock();
01298
01299 return ret;
01300 }
01301
01302 QString ChannelUtil::GetIcon(uint chanid)
01303 {
01304 static QReadWriteLock channel_icon_map_lock;
01305 static QHash<uint,QString> channel_icon_map;
01306 static bool run_init = true;
01307
01308 channel_icon_map_lock.lockForRead();
01309
01310 QString ret(channel_icon_map.value(chanid, "_cold_"));
01311
01312 channel_icon_map_lock.unlock();
01313
01314 if (ret != "_cold_")
01315 return ret;
01316
01317 channel_icon_map_lock.lockForWrite();
01318
01319 MSqlQuery query(MSqlQuery::InitCon());
01320 QString iconquery = "SELECT chanid, icon FROM channel";
01321
01322 if (run_init)
01323 iconquery += " WHERE visible = 1";
01324 else
01325 iconquery += " WHERE chanid = :CHANID";
01326
01327 query.prepare(iconquery);
01328
01329 if (!run_init)
01330 query.bindValue(":CHANID", chanid);
01331
01332 if (query.exec())
01333 {
01334 if (run_init)
01335 {
01336 channel_icon_map.reserve(query.size());
01337 while (query.next())
01338 {
01339 channel_icon_map[query.value(0).toUInt()] =
01340 query.value(1).toString();
01341 }
01342 run_init = false;
01343 }
01344 else
01345 {
01346 channel_icon_map[chanid] = (query.next()) ?
01347 query.value(1).toString() : "";
01348 }
01349 }
01350 else
01351 {
01352 MythDB::DBError("GetIcon", query);
01353 }
01354
01355 ret = channel_icon_map.value(chanid, "");
01356
01357 channel_icon_map_lock.unlock();
01358
01359 return ret;
01360 }
01361
01362 QString ChannelUtil::GetUnknownCallsign(void)
01363 {
01364 QString tmp = QObject::tr("UNKNOWN", "Synthesized callsign");
01365 tmp.detach();
01366 return tmp;
01367 }
01368
01369 int ChannelUtil::GetChanID(int mplexid, int service_transport_id,
01370 int major_channel, int minor_channel,
01371 int program_number)
01372 {
01373 MSqlQuery query(MSqlQuery::InitCon());
01374
01375
01376 query.prepare("SELECT sourceid "
01377 "FROM dtv_multiplex "
01378 "WHERE mplexid = :MPLEXID");
01379 query.bindValue(":MPLEXID", mplexid);
01380 if (!query.exec())
01381 {
01382 MythDB::DBError("Selecting channel/dtv_multiplex 2", query);
01383 return -1;
01384 }
01385 if (!query.next())
01386 return -1;
01387
01388 int source_id = query.value(0).toInt();
01389
01390 QStringList qstr;
01391
01392
01393 qstr.push_back(
01394 QString("SELECT chanid FROM channel,dtv_multiplex "
01395 "WHERE channel.sourceid = %1 AND "
01396 " atsc_major_chan = %2 AND "
01397 " atsc_minor_chan = %3 AND "
01398 " dtv_multiplex.transportid = %4 AND "
01399 " dtv_multiplex.mplexid = %5 AND "
01400 " dtv_multiplex.sourceid = channel.sourceid AND "
01401 " dtv_multiplex.mplexid = channel.mplexid")
01402 .arg(source_id).arg(major_channel).arg(minor_channel)
01403 .arg(service_transport_id).arg(mplexid));
01404
01405
01406
01407 qstr.push_back(
01408 QString("SELECT chanid FROM channel "
01409 "WHERE sourceid=%1 AND "
01410 "atsc_major_chan=%2 AND "
01411 "atsc_minor_chan=%3")
01412 .arg(source_id).arg(major_channel).arg(minor_channel));
01413
01414
01415 qstr.push_back(
01416 QString("SELECT chanid FROM channel "
01417 "WHERE sourceid=%1 AND serviceID=%2 AND mplexid=%3")
01418 .arg(source_id).arg(program_number).arg(mplexid));
01419
01420 for (int i = 0; i < qstr.size(); i++)
01421 {
01422 query.prepare(qstr[i]);
01423 if (!query.exec())
01424 MythDB::DBError("Selecting channel/dtv_multiplex 3", query);
01425 else if (query.next())
01426 return query.value(0).toInt();
01427 }
01428
01429 return -1;
01430 }
01431
01432 uint ChannelUtil::FindChannel(uint sourceid, const QString &freqid)
01433 {
01434 MSqlQuery query(MSqlQuery::InitCon());
01435 query.prepare("SELECT chanid "
01436 "FROM channel "
01437 "WHERE sourceid = :SOURCEID AND "
01438 " freqid = :FREQID");
01439
01440 query.bindValue(":SOURCEID", sourceid);
01441 query.bindValue(":FREQID", freqid);
01442
01443 if (!query.exec() || !query.isActive())
01444 MythDB::DBError("FindChannel", query);
01445 else if (query.next())
01446 return query.value(0).toUInt();
01447
01448 return 0;
01449 }
01450
01451
01452 static uint get_max_chanid(uint sourceid)
01453 {
01454 QString qstr = "SELECT MAX(chanid) FROM channel ";
01455 qstr += (sourceid) ? "WHERE sourceid = :SOURCEID" : "";
01456
01457 MSqlQuery query(MSqlQuery::DDCon());
01458 query.prepare(qstr);
01459
01460 if (sourceid)
01461 query.bindValue(":SOURCEID", sourceid);
01462
01463 if (!query.exec() || !query.isActive())
01464 MythDB::DBError("Getting chanid for new channel (2)", query);
01465 else if (!query.next())
01466 LOG(VB_GENERAL, LOG_ERR, "Error getting chanid for new channel.");
01467 else
01468 return query.value(0).toUInt();
01469
01470 return 0;
01471 }
01472
01473 static bool chanid_available(uint chanid)
01474 {
01475 MSqlQuery query(MSqlQuery::DDCon());
01476 query.prepare(
01477 "SELECT chanid "
01478 "FROM channel "
01479 "WHERE chanid = :CHANID");
01480 query.bindValue(":CHANID", chanid);
01481
01482 if (!query.exec() || !query.isActive())
01483 MythDB::DBError("is_chan_id_available", query);
01484 else if (query.size() == 0)
01485 return true;
01486
01487 return false;
01488 }
01489
01494 int ChannelUtil::CreateChanID(uint sourceid, const QString &chan_num)
01495 {
01496
01497 uint chanid = 0;
01498 int chansep = chan_num.indexOf(QRegExp("\\D"));
01499 if (chansep > 0)
01500 {
01501 chanid =
01502 sourceid * 1000 +
01503 chan_num.left(chansep).toInt() * 10 +
01504 chan_num.right(chan_num.length()-chansep-1).toInt();
01505 }
01506 else
01507 {
01508 chanid = sourceid * 1000 + chan_num.toInt();
01509 }
01510
01511 if ((chanid > sourceid * 1000) && (chanid_available(chanid)))
01512 return chanid;
01513
01514
01515 chanid = max(get_max_chanid(sourceid) + 1, sourceid * 1000);
01516
01517 if (chanid_available(chanid))
01518 return chanid;
01519
01520
01521 chanid = get_max_chanid(0) + 1;
01522
01523 if (chanid_available(chanid))
01524 return chanid;
01525
01526
01527 return -1;
01528 }
01529
01530 bool ChannelUtil::CreateChannel(uint db_mplexid,
01531 uint db_sourceid,
01532 uint new_channel_id,
01533 const QString &callsign,
01534 const QString &service_name,
01535 const QString &chan_num,
01536 uint service_id,
01537 uint atsc_major_channel,
01538 uint atsc_minor_channel,
01539 bool use_on_air_guide,
01540 bool hidden,
01541 bool hidden_in_guide,
01542 const QString &freqid,
01543 QString icon,
01544 QString format,
01545 QString xmltvid,
01546 QString default_authority)
01547 {
01548 MSqlQuery query(MSqlQuery::InitCon());
01549
01550 QString chanNum = (chan_num == "-1") ?
01551 QString::number(service_id) : chan_num;
01552
01553 QString qstr =
01554 "INSERT INTO channel "
01555 " (chanid, channum, sourceid, "
01556 " callsign, name, serviceid, ";
01557 qstr += (db_mplexid > 0) ? "mplexid, " : "";
01558 qstr += (!freqid.isEmpty()) ? "freqid, " : "";
01559 qstr +=
01560 " atsc_major_chan, atsc_minor_chan, "
01561 " useonairguide, visible, tvformat, "
01562 " icon, xmltvid, default_authority) "
01563 "VALUES "
01564 " (:CHANID, :CHANNUM, :SOURCEID, "
01565 " :CALLSIGN, :NAME, :SERVICEID, ";
01566 qstr += (db_mplexid > 0) ? ":MPLEXID, " : "";
01567 qstr += (!freqid.isEmpty()) ? ":FREQID, " : "";
01568 qstr +=
01569 " :MAJORCHAN, :MINORCHAN, "
01570 " :USEOAG, :VISIBLE, :TVFORMAT, "
01571 " :ICON, :XMLTVID, :AUTHORITY) ";
01572
01573 query.prepare(qstr);
01574
01575 query.bindValue(":CHANID", new_channel_id);
01576 query.bindValue(":CHANNUM", chanNum);
01577 query.bindValue(":SOURCEID", db_sourceid);
01578 query.bindValue(":CALLSIGN", callsign);
01579 query.bindValue(":NAME", service_name);
01580
01581 if (db_mplexid > 0)
01582 query.bindValue(":MPLEXID", db_mplexid);
01583
01584 query.bindValue(":SERVICEID", service_id);
01585 query.bindValue(":MAJORCHAN", atsc_major_channel);
01586 query.bindValue(":MINORCHAN", atsc_minor_channel);
01587 query.bindValue(":USEOAG", use_on_air_guide);
01588 query.bindValue(":VISIBLE", !hidden);
01589 (void) hidden_in_guide;
01590
01591 if (!freqid.isEmpty())
01592 query.bindValue(":FREQID", freqid);
01593
01594 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01595 tvformat = tvformat.isNull() ? "" : tvformat;
01596 query.bindValue(":TVFORMAT", tvformat);
01597
01598 icon = (icon.isNull()) ? "" : icon;
01599 query.bindValue(":ICON", icon);
01600
01601 xmltvid = (xmltvid.isNull()) ? "" : xmltvid;
01602 query.bindValue(":XMLTVID", xmltvid);
01603
01604 default_authority = (default_authority.isNull()) ? "" : default_authority;
01605 query.bindValue(":AUTHORITY", default_authority);
01606
01607 if (!query.exec() || !query.isActive())
01608 {
01609 MythDB::DBError("Adding Service", query);
01610 return false;
01611 }
01612 return true;
01613 }
01614
01615 bool ChannelUtil::UpdateChannel(uint db_mplexid,
01616 uint source_id,
01617 uint channel_id,
01618 const QString &callsign,
01619 const QString &service_name,
01620 const QString &chan_num,
01621 uint service_id,
01622 uint atsc_major_channel,
01623 uint atsc_minor_channel,
01624 bool use_on_air_guide,
01625 bool hidden,
01626 bool hidden_in_guide,
01627 QString freqid,
01628 QString icon,
01629 QString format,
01630 QString xmltvid,
01631 QString default_authority)
01632 {
01633 if (!channel_id)
01634 return false;
01635
01636 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01637 bool set_channum = !chan_num.isEmpty() && chan_num != "-1";
01638 QString qstr = QString(
01639 "UPDATE channel "
01640 "SET %1 %2 %3 %4 %5 %6"
01641 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
01642 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
01643 " callsign = :CALLSIGN, name = :NAME, "
01644 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
01645 " visible = :VISIBLE "
01646 "WHERE chanid=:CHANID")
01647 .arg((!set_channum) ? "" : "channum = :CHANNUM, ")
01648 .arg((freqid.isEmpty()) ? "" : "freqid = :FREQID, ")
01649 .arg((icon.isEmpty()) ? "" : "icon = :ICON, ")
01650 .arg((tvformat.isEmpty()) ? "" : "tvformat = :TVFORMAT, ")
01651 .arg((xmltvid.isEmpty()) ? "" : "xmltvid = :XMLTVID, ")
01652 .arg((default_authority.isEmpty()) ?
01653 "" : "default_authority = :AUTHORITY,");
01654
01655 MSqlQuery query(MSqlQuery::InitCon());
01656 query.prepare(qstr);
01657
01658 query.bindValue(":CHANID", channel_id);
01659
01660 if (set_channum)
01661 query.bindValue(":CHANNUM", chan_num);
01662
01663 query.bindValue(":SOURCEID", source_id);
01664 query.bindValue(":CALLSIGN", callsign);
01665 query.bindValue(":NAME", service_name);
01666
01667 query.bindValue(":MPLEXID", db_mplexid);
01668
01669 query.bindValue(":SERVICEID", service_id);
01670 query.bindValue(":MAJORCHAN", atsc_major_channel);
01671 query.bindValue(":MINORCHAN", atsc_minor_channel);
01672 query.bindValue(":USEOAG", use_on_air_guide);
01673 query.bindValue(":VISIBLE", !hidden);
01674 (void) hidden_in_guide;
01675
01676 if (!freqid.isEmpty())
01677 query.bindValue(":FREQID", freqid);
01678
01679 if (!tvformat.isEmpty())
01680 query.bindValue(":TVFORMAT", tvformat);
01681
01682 if (!icon.isEmpty())
01683 query.bindValue(":ICON", icon);
01684 if (!xmltvid.isEmpty())
01685 query.bindValue(":XMLTVID", xmltvid);
01686 if (!default_authority.isEmpty())
01687 query.bindValue(":AUTHORITY", default_authority);
01688
01689 if (!query.exec())
01690 {
01691 MythDB::DBError("Updating Service", query);
01692 return false;
01693 }
01694 return true;
01695 }
01696
01697 void ChannelUtil::UpdateInsertInfoFromDB(ChannelInsertInfo &chan)
01698 {
01699 MSqlQuery query(MSqlQuery::InitCon());
01700 query.prepare(
01701 "SELECT xmltvid, useonairguide "
01702 "FROM channel "
01703 "WHERE chanid = :ID");
01704 query.bindValue(":ID", chan.channel_id);
01705
01706 if (!query.exec())
01707 {
01708 MythDB::DBError("UpdateInsertInfoFromDB", query);
01709 return;
01710 }
01711
01712 if (query.next())
01713 {
01714 QString xmltvid = query.value(0).toString();
01715 bool useeit = query.value(1).toInt();
01716
01717 if (!xmltvid.isEmpty())
01718 {
01719 if (useeit)
01720 LOG(VB_GENERAL, LOG_ERR,
01721 "Using EIT and xmltv for the same channel "
01722 "is a unsupported configuration.");
01723 chan.xmltvid = xmltvid;
01724 chan.use_on_air_guide = useeit;
01725 }
01726 }
01727 }
01728
01729 bool ChannelUtil::DeleteChannel(uint channel_id)
01730 {
01731 MSqlQuery query(MSqlQuery::InitCon());
01732 query.prepare(
01733 "DELETE FROM channel "
01734 "WHERE chanid = :ID");
01735 query.bindValue(":ID", channel_id);
01736
01737 if (!query.exec())
01738 {
01739 MythDB::DBError("Delete Channel", query);
01740 return false;
01741 }
01742
01743 return true;
01744 }
01745
01746 bool ChannelUtil::SetVisible(uint channel_id, bool visible)
01747 {
01748 MSqlQuery query(MSqlQuery::InitCon());
01749 query.prepare(
01750 "UPDATE channel "
01751 "SET visible = :VISIBLE "
01752 "WHERE chanid = :ID");
01753 query.bindValue(":ID", channel_id);
01754 query.bindValue(":VISIBLE", visible);
01755
01756 if (!query.exec())
01757 {
01758 MythDB::DBError("ChannelUtil::SetVisible", query);
01759 return false;
01760 }
01761
01762 return true;
01763 }
01764
01765 bool ChannelUtil::SetServiceVersion(int mplexid, int version)
01766 {
01767 MSqlQuery query(MSqlQuery::InitCon());
01768
01769 query.prepare(
01770 QString("UPDATE dtv_multiplex "
01771 "SET serviceversion = %1 "
01772 "WHERE mplexid = %2").arg(version).arg(mplexid));
01773
01774 if (!query.exec() || !query.isActive())
01775 {
01776 MythDB::DBError("Selecting channel/dtv_multiplex", query);
01777 return false;
01778 }
01779 return true;
01780 }
01781
01782 int ChannelUtil::GetServiceVersion(int mplexid)
01783 {
01784 MSqlQuery query(MSqlQuery::InitCon());
01785
01786 query.prepare(QString("SELECT serviceversion "
01787 "FROM dtv_multiplex "
01788 "WHERE mplexid = %1").arg(mplexid));
01789
01790 if (!query.exec() || !query.isActive())
01791 {
01792 MythDB::DBError("Selecting channel/dtv_multiplex", query);
01793 return false;
01794 }
01795
01796 if (query.next())
01797 return query.value(0).toInt();
01798
01799 return -1;
01800 }
01801
01802 bool ChannelUtil::GetATSCChannel(uint sourceid, const QString &channum,
01803 uint &major, uint &minor)
01804 {
01805 major = minor = 0;
01806
01807 MSqlQuery query(MSqlQuery::InitCon());
01808 query.prepare(
01809 "SELECT atsc_major_chan, atsc_minor_chan "
01810 "FROM channel "
01811 "WHERE channum = :CHANNUM AND "
01812 " sourceid = :SOURCEID");
01813
01814 query.bindValue(":SOURCEID", sourceid);
01815 query.bindValue(":CHANNUM", channum);
01816
01817 if (!query.exec() || !query.isActive())
01818 MythDB::DBError("getatscchannel", query);
01819 else if (query.next())
01820 {
01821 major = query.value(0).toUInt();
01822 minor = query.value(1).toUInt();
01823 return true;
01824 }
01825
01826 return false;
01827 }
01828
01829 bool ChannelUtil::GetChannelData(
01830 uint sourceid, const QString &channum,
01831 QString &tvformat, QString &modulation,
01832 QString &freqtable, QString &freqid,
01833 int &finetune, uint64_t &frequency,
01834 QString &dtv_si_std, int &mpeg_prog_num,
01835 uint &atsc_major, uint &atsc_minor,
01836 uint &dvb_transportid, uint &dvb_networkid,
01837 uint &mplexid,
01838 bool &commfree)
01839 {
01840 tvformat = modulation = freqtable = QString::null;
01841 freqid = dtv_si_std = QString::null;
01842 finetune = 0;
01843 frequency = 0;
01844 mpeg_prog_num = -1;
01845 atsc_major = atsc_minor = mplexid = 0;
01846 dvb_networkid = dvb_transportid = 0;
01847 commfree = false;
01848
01849 MSqlQuery query(MSqlQuery::InitCon());
01850 query.prepare(
01851 "SELECT finetune, freqid, tvformat, freqtable, "
01852 " commmethod, mplexid, "
01853 " atsc_major_chan, atsc_minor_chan, serviceid "
01854 "FROM channel, videosource "
01855 "WHERE videosource.sourceid = channel.sourceid AND "
01856 " channum = :CHANNUM AND "
01857 " channel.sourceid = :SOURCEID");
01858 query.bindValue(":CHANNUM", channum);
01859 query.bindValue(":SOURCEID", sourceid);
01860
01861 if (!query.exec() || !query.isActive())
01862 {
01863 MythDB::DBError("GetChannelData", query);
01864 return false;
01865 }
01866 else if (!query.next())
01867 {
01868 LOG(VB_GENERAL, LOG_ERR,
01869 QString("GetChannelData() failed because it could not\n"
01870 "\t\t\tfind channel number '%1' in DB for source '%2'.")
01871 .arg(channum).arg(sourceid));
01872 return false;
01873 }
01874
01875 finetune = query.value(0).toInt();
01876 freqid = query.value(1).toString();
01877 tvformat = query.value(2).toString();
01878 freqtable = query.value(3).toString();
01879 commfree = (query.value(4).toInt() == -2);
01880 mplexid = query.value(5).toUInt();
01881 atsc_major = query.value(6).toUInt();
01882 atsc_minor = query.value(7).toUInt();
01883 mpeg_prog_num = (query.value(8).isNull()) ? -1 : query.value(8).toInt();
01884
01885 if (!mplexid || (mplexid == 32767))
01886 return true;
01887
01888 return GetTuningParams(mplexid, modulation, frequency,
01889 dvb_transportid, dvb_networkid, dtv_si_std);
01890 }
01891
01892 bool ChannelUtil::GetExtendedChannelData(
01893 uint sourceid, const QString &channum,
01894 QString &tvformat, QString &modulation,
01895 QString &freqtable, QString &freqid,
01896 int &finetune, uint64_t &frequency,
01897 QString &dtv_si_std, int &mpeg_prog_num,
01898 uint &atsc_major, uint &atsc_minor,
01899 uint &dvb_transportid, uint &dvb_networkid,
01900 uint &mplexid, bool &commfree,
01901 bool &use_on_air_guide,bool &visible,
01902 QString &xmltvid, QString &default_authority,
01903 QString &icon)
01904 {
01905 tvformat = modulation = freqtable = QString::null;
01906 freqid = dtv_si_std = xmltvid = QString::null;
01907 default_authority = icon = QString::null;
01908 finetune = 0;
01909 frequency = 0;
01910 mpeg_prog_num = -1;
01911 atsc_major = atsc_minor = mplexid = 0;
01912 dvb_networkid = dvb_transportid = 0;
01913 commfree = false;
01914 use_on_air_guide = false;
01915 visible = true;
01916
01917 MSqlQuery query(MSqlQuery::InitCon());
01918 query.prepare(
01919 "SELECT finetune, freqid, tvformat, freqtable, "
01920 " commmethod, mplexid, "
01921 " atsc_major_chan, atsc_minor_chan, serviceid, "
01922 " useonairguide, visible, xmltvid, default_authority, icon "
01923 "FROM channel, videosource "
01924 "WHERE videosource.sourceid = channel.sourceid AND "
01925 " channum = :CHANNUM AND "
01926 " channel.sourceid = :SOURCEID");
01927 query.bindValue(":CHANNUM", channum);
01928 query.bindValue(":SOURCEID", sourceid);
01929
01930 if (!query.exec() || !query.isActive())
01931 {
01932 MythDB::DBError("GetChannelData", query);
01933 return false;
01934 }
01935 else if (!query.next())
01936 {
01937 LOG(VB_GENERAL, LOG_ERR,
01938 QString("GetChannelData() failed because it could not\n"
01939 "\t\t\tfind channel number '%1' in DB for source '%2'.")
01940 .arg(channum).arg(sourceid));
01941 return false;
01942 }
01943
01944 finetune = query.value(0).toInt();
01945 freqid = query.value(1).toString();
01946 tvformat = query.value(2).toString();
01947 freqtable = query.value(3).toString();
01948 commfree = (query.value(4).toInt() == -2);
01949 mplexid = query.value(5).toUInt();
01950 atsc_major = query.value(6).toUInt();
01951 atsc_minor = query.value(7).toUInt();
01952 mpeg_prog_num = query.value(8).toUInt();
01953 use_on_air_guide = query.value(9).toBool();
01954 visible = query.value(10).toBool();
01955 xmltvid = query.value(11).toString();
01956 default_authority = query.value(12).toString();
01957 icon = query.value(13).toString();
01958
01959 if (!mplexid || (mplexid == 32767))
01960 return true;
01961
01962 return GetTuningParams(mplexid, modulation, frequency,
01963 dvb_transportid, dvb_networkid, dtv_si_std);
01964 }
01965
01966 DBChanList ChannelUtil::GetChannelsInternal(
01967 uint sourceid, bool vis_only, bool include_disconnected,
01968 const QString &grp, uint changrpid)
01969 {
01970 DBChanList list;
01971
01972 MSqlQuery query(MSqlQuery::InitCon());
01973
01974 QString qstr = QString(
01975 "SELECT channum, callsign, channel.chanid, "
01976 " atsc_major_chan, atsc_minor_chan, "
01977 " name, icon, mplexid, visible, "
01978 " channel.sourceid, cardinput.cardid, channelgroup.grpid "
01979 "FROM channel "
01980 "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid "
01981 " %1 JOIN cardinput ON cardinput.sourceid = channel.sourceid "
01982 " %2 JOIN capturecard ON cardinput.cardid = capturecard.cardid ")
01983 .arg((include_disconnected) ? "LEFT" : "")
01984 .arg((include_disconnected) ? "LEFT" : "");
01985
01986 QString cond = " WHERE ";
01987
01988 if (sourceid)
01989 {
01990 qstr += QString("WHERE channel.sourceid='%1' ").arg(sourceid);
01991 cond = " AND ";
01992 }
01993
01994
01995 if (changrpid > 0)
01996 {
01997 qstr += QString("%1 channelgroup.grpid = '%2' ")
01998 .arg(cond).arg(changrpid);
01999 cond = " AND ";
02000 }
02001
02002 if (vis_only)
02003 {
02004 qstr += QString("%1 visible=1 ").arg(cond);
02005 cond = " AND ";
02006 }
02007
02008 if (!grp.isEmpty())
02009 qstr += QString(" GROUP BY %1 ").arg(grp);
02010
02011 query.prepare(qstr);
02012 if (!query.exec())
02013 {
02014 MythDB::DBError("ChannelUtil::GetChannels()", query);
02015 return list;
02016 }
02017
02018 while (query.next())
02019 {
02020 if (query.value(0).toString().isEmpty() || !query.value(2).toUInt())
02021 continue;
02022
02023 DBChannel chan(
02024 query.value(0).toString(),
02025 query.value(1).toString(),
02026 query.value(2).toUInt(),
02027 query.value(3).toUInt(),
02028 query.value(4).toUInt(),
02029 query.value(7).toUInt(),
02030 query.value(8).toBool(),
02031 query.value(5).toString(),
02032 query.value(6).toString(),
02033 query.value(9).toUInt(),
02034 query.value(11).toUInt(),
02035 query.value(10).toUInt());
02036
02037 list.push_back(chan);
02038 }
02039
02040 return list;
02041 }
02042
02043 vector<uint> ChannelUtil::GetChanIDs(int sourceid)
02044 {
02045 MSqlQuery query(MSqlQuery::InitCon());
02046
02047 QString select = "SELECT chanid FROM channel";
02048 if (sourceid > 0)
02049 select += " WHERE sourceid=" + QString::number(sourceid);
02050
02051 vector<uint> list;
02052 if (!query.exec(select))
02053 {
02054 MythDB::DBError("SourceUtil::GetChanIDs()", query);
02055 return list;
02056 }
02057
02058 while (query.next())
02059 list.push_back(query.value(0).toUInt());
02060
02061 return list;
02062 }
02063
02064 inline bool lt_callsign(const DBChannel &a, const DBChannel &b)
02065 {
02066 return QString::localeAwareCompare(a.callsign, b.callsign) < 0;
02067 }
02068
02069 inline bool lt_smart(const DBChannel &a, const DBChannel &b)
02070 {
02071 static QMutex sepExprLock;
02072 static const QRegExp sepExpr(ChannelUtil::kATSCSeparators);
02073
02074 int cmp = 0;
02075
02076 bool isIntA, isIntB;
02077 int a_int = a.channum.toUInt(&isIntA);
02078 int b_int = b.channum.toUInt(&isIntB);
02079 int a_major = a.major_chan;
02080 int b_major = b.major_chan;
02081 int a_minor = a.minor_chan;
02082 int b_minor = b.minor_chan;
02083
02084
02085 bool tmp1, tmp2;
02086 int idxA, idxB;
02087 {
02088 QMutexLocker locker(&sepExprLock);
02089 idxA = a.channum.indexOf(sepExpr);
02090 idxB = b.channum.indexOf(sepExpr);
02091 }
02092 if (idxA >= 0)
02093 {
02094 int major = a.channum.left(idxA).toUInt(&tmp1);
02095 int minor = a.channum.mid(idxA+1).toUInt(&tmp2);
02096 if (tmp1 && tmp2)
02097 (a_major = major), (a_minor = minor), (isIntA = false);
02098 }
02099
02100 if (idxB >= 0)
02101 {
02102 int major = b.channum.left(idxB).toUInt(&tmp1);
02103 int minor = b.channum.mid(idxB+1).toUInt(&tmp2);
02104 if (tmp1 && tmp2)
02105 (b_major = major), (b_minor = minor), (isIntB = false);
02106 }
02107
02108
02109 if ((a_minor > 0) && isIntA)
02110 {
02111 int atsc_int = (QString("%1%2").arg(a_major).arg(a_minor)).toInt();
02112 a_minor = (atsc_int == a_int) ? a_minor : 0;
02113 }
02114
02115 if ((b_minor > 0) && isIntB)
02116 {
02117 int atsc_int = (QString("%1%2").arg(b_major).arg(b_minor)).toInt();
02118 b_minor = (atsc_int == b_int) ? b_minor : 0;
02119 }
02120
02121
02122
02123 if ((a_minor || b_minor) &&
02124 (a_minor || isIntA) && (b_minor || isIntB))
02125 {
02126 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
02127 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
02128 if ((cmp = a_maj - b_maj))
02129 return cmp < 0;
02130
02131 if ((cmp = a_minor - b_minor))
02132 return cmp < 0;
02133 }
02134
02135 if (isIntA && isIntB)
02136 {
02137
02138 cmp = a_int - b_int;
02139 if (cmp)
02140 return cmp < 0;
02141 }
02142 else if (isIntA ^ isIntB)
02143 {
02144
02145 return isIntA;
02146 }
02147 else
02148 {
02149
02150 cmp = QString::localeAwareCompare(a.channum, b.channum);
02151 if (cmp)
02152 return cmp < 0;
02153 }
02154
02155 return lt_callsign(a,b);
02156 }
02157
02158 uint ChannelUtil::GetChannelCount(int sourceid)
02159 {
02160 MSqlQuery query(MSqlQuery::InitCon());
02161 QString select;
02162
02163
02164 select = "SELECT chanid FROM channel";
02165 if (sourceid >= 0)
02166 select += " WHERE sourceid=" + QString::number(sourceid);
02167 select += ';';
02168
02169 query.prepare(select);
02170
02171 if (!query.exec() || !query.isActive())
02172 return 0;
02173
02174 return query.size();
02175 }
02176
02177 void ChannelUtil::SortChannels(DBChanList &list, const QString &order,
02178 bool eliminate_duplicates)
02179 {
02180 bool cs = order.toLower() == "callsign";
02181 if (cs)
02182 stable_sort(list.begin(), list.end(), lt_callsign);
02183 else
02184 stable_sort(list.begin(), list.end(), lt_smart);
02185
02186 if (eliminate_duplicates && !list.empty())
02187 {
02188 DBChanList tmp;
02189 tmp.push_back(list[0]);
02190 for (uint i = 1; i < list.size(); i++)
02191 {
02192 if ((cs && lt_callsign(tmp.back(), list[i])) ||
02193 (!cs && lt_smart(tmp.back(), list[i])))
02194 {
02195 tmp.push_back(list[i]);
02196 }
02197 }
02198
02199 list = tmp;
02200 }
02201 }
02202
02203 uint ChannelUtil::GetNextChannel(
02204 const DBChanList &sorted,
02205 uint old_chanid,
02206 uint mplexid_restriction,
02207 int direction,
02208 bool skip_non_visible,
02209 bool skip_same_channum_and_callsign)
02210 {
02211 DBChanList::const_iterator it =
02212 find(sorted.begin(), sorted.end(), old_chanid);
02213
02214 if (it == sorted.end())
02215 it = sorted.begin();
02216
02217 if (it == sorted.end())
02218 return 0;
02219
02220 DBChanList::const_iterator start = it;
02221
02222 if (CHANNEL_DIRECTION_DOWN == direction)
02223 {
02224 do
02225 {
02226 if (it == sorted.begin())
02227 it = find(sorted.begin(), sorted.end(),
02228 sorted.rbegin()->chanid);
02229 else
02230 --it;
02231 }
02232 while ((it != start) &&
02233 ((skip_non_visible && !it->visible) ||
02234 (skip_same_channum_and_callsign &&
02235 it->channum == start->channum &&
02236 it->callsign == start->callsign) ||
02237 (mplexid_restriction &&
02238 (mplexid_restriction != it->mplexid))));
02239 }
02240 else if ((CHANNEL_DIRECTION_UP == direction) ||
02241 (CHANNEL_DIRECTION_FAVORITE == direction))
02242 {
02243 do
02244 {
02245 ++it;
02246 if (it == sorted.end())
02247 it = sorted.begin();
02248 }
02249 while ((it != start) &&
02250 ((skip_non_visible && !it->visible) ||
02251 (skip_same_channum_and_callsign &&
02252 it->channum == start->channum &&
02253 it->callsign == start->callsign) ||
02254 (mplexid_restriction &&
02255 (mplexid_restriction != it->mplexid))));
02256 }
02257
02258 return it->chanid;
02259 }
02260
02261