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.size())
00626 {
00627 query.next();
00628 q_networkid = query.value(0).toInt();
00629 q_transportid = query.value(1).toInt();
00630 }
00631
00632
00633 if ((q_networkid == network_id) && (q_transportid == transport_id))
00634 {
00635 LOG(VB_CHANSCAN, LOG_INFO,
00636 QString("GetBetterMplexID(): Returning perfect match %1")
00637 .arg(current_mplexid));
00638 return current_mplexid;
00639 }
00640
00641
00642 if (!q_networkid && !q_transportid)
00643 {
00644 int qsize = query.size();
00645 query.prepare(QString("UPDATE dtv_multiplex "
00646 "SET networkid = %1, transportid = %2 "
00647 "WHERE mplexid = %3")
00648 .arg(network_id).arg(transport_id).arg(current_mplexid));
00649
00650 if (!query.exec() || !query.isActive())
00651 MythDB::DBError("Getting mplexid global search", query);
00652
00653 LOG(VB_CHANSCAN, LOG_INFO,
00654 QString("GetBetterMplexID(): net id and transport id "
00655 "are null, qsize(%1), Returning %2")
00656 .arg(qsize).arg(current_mplexid));
00657 return current_mplexid;
00658 }
00659
00660
00661 QString theQueries[2] =
00662 {
00663 QString("SELECT a.mplexid "
00664 "FROM dtv_multiplex a, dtv_multiplex b "
00665 "WHERE a.networkid = %1 AND "
00666 " a.transportid = %2 AND "
00667 " a.sourceid = b.sourceid AND "
00668 " b.mplexid = %3")
00669 .arg(network_id).arg(transport_id).arg(current_mplexid),
00670
00671 QString("SELECT mplexid "
00672 "FROM dtv_multiplex "
00673 "WHERE networkid = %1 AND "
00674 " transportid = %2")
00675 .arg(network_id).arg(transport_id),
00676 };
00677
00678 for (uint i=0; i<2; i++)
00679 {
00680 query.prepare(theQueries[i]);
00681
00682 if (!query.exec() || !query.isActive())
00683 MythDB::DBError("Finding matching mplexid", query);
00684
00685 if (query.size() == 1)
00686 {
00687 LOG(VB_CHANSCAN, LOG_INFO,
00688 QString("GetBetterMplexID(): query#%1 qsize(%2) "
00689 "Returning %3")
00690 .arg(i).arg(query.size()).arg(current_mplexid));
00691 query.next();
00692 return query.value(0).toInt();
00693 }
00694
00695 if (query.size() > 1)
00696 {
00697 query.next();
00698 int ret = (i==0) ? current_mplexid : query.value(0).toInt();
00699 LOG(VB_CHANSCAN, LOG_INFO,
00700 QString("GetBetterMplexID(): query#%1 qsize(%2) "
00701 "Returning %3")
00702 .arg(i).arg(query.size()).arg(ret));
00703 return ret;
00704 }
00705 }
00706
00707
00708 LOG(VB_CHANSCAN, LOG_INFO, "GetBetterMplexID(): Returning -1");
00709 return -1;
00710 }
00711
00712 bool ChannelUtil::GetTuningParams(uint mplexid,
00713 QString &modulation,
00714 uint64_t &frequency,
00715 uint &dvb_transportid,
00716 uint &dvb_networkid,
00717 QString &si_std)
00718 {
00719 if (!mplexid || (mplexid == 32767))
00720 return false;
00721
00722 MSqlQuery query(MSqlQuery::InitCon());
00723 query.prepare(
00724 "SELECT transportid, networkid, frequency, modulation, sistandard "
00725 "FROM dtv_multiplex "
00726 "WHERE mplexid = :MPLEXID");
00727 query.bindValue(":MPLEXID", mplexid);
00728
00729 if (!query.exec() || !query.isActive())
00730 {
00731 MythDB::DBError("GetTuningParams failed ", query);
00732 return false;
00733 }
00734
00735 if (!query.next())
00736 return false;
00737
00738 dvb_transportid = query.value(0).toUInt();
00739 dvb_networkid = query.value(1).toUInt();
00740 frequency = query.value(2).toULongLong();
00741 modulation = query.value(3).toString();
00742 si_std = query.value(4).toString();
00743
00744 return true;
00745 }
00746
00747 QString ChannelUtil::GetChannelStringField(int chan_id, const QString &field)
00748 {
00749 if (chan_id < 0)
00750 return QString::null;
00751
00752 MSqlQuery query(MSqlQuery::InitCon());
00753 query.prepare(QString("SELECT %1 FROM channel "
00754 "WHERE chanid=%2").arg(field).arg(chan_id));
00755 if (!query.exec() || !query.isActive())
00756 {
00757 MythDB::DBError("Selecting channel/dtv_multiplex 1", query);
00758 return QString::null;
00759 }
00760 if (!query.size())
00761 return QString::null;
00762
00763 query.next();
00764 return query.value(0).toString();
00765 }
00766
00767 QString ChannelUtil::GetChanNum(int chan_id)
00768 {
00769 return GetChannelStringField(chan_id, QString("channum"));
00770 }
00771
00772 QString ChannelUtil::GetCallsign(int chan_id)
00773 {
00774 return GetChannelStringField(chan_id, QString("callsign"));
00775 }
00776
00777 QString ChannelUtil::GetServiceName(int chan_id)
00778 {
00779 return GetChannelStringField(chan_id, QString("name"));
00780 }
00781
00782 int ChannelUtil::GetTimeOffset(int chan_id)
00783 {
00784 return GetChannelStringField(chan_id, QString("tmoffset")).toInt();
00785 }
00786
00787 int ChannelUtil::GetSourceID(int db_mplexid)
00788 {
00789 MSqlQuery query(MSqlQuery::InitCon());
00790
00791 query.prepare(QString("SELECT sourceid "
00792 "FROM dtv_multiplex "
00793 "WHERE mplexid = %1").arg(db_mplexid));
00794
00795 if (!query.exec() || !query.isActive())
00796 {
00797 MythDB::DBError("Selecting channel/dtv_multiplex", query);
00798 return -1;
00799 }
00800
00801 if (query.size() > 0)
00802 {
00803 query.next();
00804 return query.value(0).toInt();
00805 }
00806 return -1;
00807 }
00808
00809 uint ChannelUtil::GetSourceIDForChannel(uint chanid)
00810 {
00811 MSqlQuery query(MSqlQuery::InitCon());
00812
00813 query.prepare(
00814 "SELECT sourceid "
00815 "FROM channel "
00816 "WHERE chanid = :CHANID");
00817 query.bindValue(":CHANID", chanid);
00818
00819 if (!query.exec())
00820 MythDB::DBError("Selecting channel/dtv_multiplex", query);
00821 else if (query.next())
00822 return query.value(0).toUInt();
00823
00824 return 0;
00825 }
00826
00827 int ChannelUtil::GetInputID(int source_id, int card_id)
00828 {
00829 int input_id = -1;
00830
00831 MSqlQuery query(MSqlQuery::InitCon());
00832 query.prepare("SELECT cardinputid"
00833 " FROM cardinput"
00834 " WHERE sourceid = :SOURCEID"
00835 " AND cardid = :CARDID");
00836 query.bindValue(":SOURCEID", source_id);
00837 query.bindValue(":CARDID", card_id);
00838
00839 if (query.exec() && query.isActive() && query.next())
00840 input_id = query.value(0).toInt();
00841
00842 return input_id;
00843 }
00844
00845 QStringList ChannelUtil::GetCardTypes(uint chanid)
00846 {
00847 MSqlQuery query(MSqlQuery::InitCon());
00848 query.prepare("SELECT cardtype "
00849 "FROM capturecard, cardinput, channel "
00850 "WHERE channel.chanid = :CHANID AND "
00851 " channel.sourceid = cardinput.sourceid AND "
00852 " cardinput.cardid = capturecard.cardid "
00853 "GROUP BY cardtype");
00854 query.bindValue(":CHANID", chanid);
00855
00856 QStringList list;
00857 if (!query.exec())
00858 {
00859 MythDB::DBError("ChannelUtil::GetCardTypes", query);
00860 return list;
00861 }
00862 while (query.next())
00863 list.push_back(query.value(0).toString());
00864 return list;
00865 }
00866
00867 static bool lt_pidcache(
00868 const pid_cache_item_t &a, const pid_cache_item_t &b)
00869 {
00870 return a.GetPID() < b.GetPID();
00871 }
00872
00879 bool ChannelUtil::GetCachedPids(uint chanid,
00880 pid_cache_t &pid_cache)
00881 {
00882 MSqlQuery query(MSqlQuery::InitCon());
00883 QString thequery = QString("SELECT pid, tableid FROM pidcache "
00884 "WHERE chanid='%1'").arg(chanid);
00885 query.prepare(thequery);
00886
00887 if (!query.exec() || !query.isActive())
00888 {
00889 MythDB::DBError("GetCachedPids: fetching pids", query);
00890 return false;
00891 }
00892
00893 while (query.next())
00894 {
00895 int pid = query.value(0).toInt(), tid = query.value(1).toInt();
00896 if ((pid >= 0) && (tid >= 0))
00897 pid_cache.push_back(pid_cache_item_t(pid, tid));
00898 }
00899 stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
00900
00901 return true;
00902 }
00903
00910 bool ChannelUtil::SaveCachedPids(uint chanid,
00911 const pid_cache_t &_pid_cache,
00912 bool delete_all)
00913 {
00914 MSqlQuery query(MSqlQuery::InitCon());
00915
00917 if (delete_all)
00918 query.prepare("DELETE FROM pidcache WHERE chanid = :CHANID");
00919 else
00920 query.prepare(
00921 "DELETE FROM pidcache "
00922 "WHERE chanid = :CHANID AND tableid < 65536");
00923
00924 query.bindValue(":CHANID", chanid);
00925
00926 if (!query.exec())
00927 {
00928 MythDB::DBError("GetCachedPids -- delete", query);
00929 return false;
00930 }
00931
00932 pid_cache_t old_cache;
00933 GetCachedPids(chanid, old_cache);
00934 pid_cache_t pid_cache = _pid_cache;
00935 stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
00936
00938 query.prepare(
00939 "INSERT INTO pidcache "
00940 "SET chanid = :CHANID, pid = :PID, tableid = :TABLEID");
00941 query.bindValue(":CHANID", chanid);
00942
00943 bool ok = true;
00944 pid_cache_t::const_iterator ito = old_cache.begin();
00945 pid_cache_t::const_iterator itn = pid_cache.begin();
00946 for (; itn != pid_cache.end(); ++itn)
00947 {
00948
00949 for (; ito != old_cache.end() && ito->GetPID() < itn->GetPID(); ++ito);
00950
00951
00952 if (ito != old_cache.end() && ito->GetPID() == itn->GetPID())
00953 continue;
00954
00955 query.bindValue(":PID", itn->GetPID());
00956 query.bindValue(":TABLEID", itn->GetComposite());
00957
00958 if (!query.exec())
00959 {
00960 MythDB::DBError("GetCachedPids -- insert", query);
00961 ok = false;
00962 }
00963 }
00964
00965 return ok;
00966 }
00967
00968 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
00969 uint cardid,
00970 const QString &input,
00971 const QString &channum)
00972 {
00973 QString retval = QString::null;
00974
00975 MSqlQuery query(MSqlQuery::InitCon());
00976
00977 query.prepare(
00978 QString(
00979 "SELECT channel.%1 "
00980 "FROM channel, capturecard, cardinput "
00981 "WHERE channel.channum = :CHANNUM AND "
00982 " channel.sourceid = cardinput.sourceid AND "
00983 " cardinput.inputname = :INPUT AND "
00984 " cardinput.cardid = capturecard.cardid AND "
00985 " capturecard.cardid = :CARDID ")
00986 .arg(channel_field));
00987
00988 query.bindValue(":CARDID", cardid);
00989 query.bindValue(":INPUT", input);
00990 query.bindValue(":CHANNUM", channum);
00991
00992 if (!query.exec() || !query.isActive())
00993 MythDB::DBError("getchannelvalue", query);
00994 else if (query.next())
00995 retval = query.value(0).toString();
00996
00997 return retval;
00998 }
00999
01000 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
01001 uint sourceid,
01002 const QString &channum)
01003 {
01004 QString retval = QString::null;
01005
01006 MSqlQuery query(MSqlQuery::InitCon());
01007
01008 query.prepare(
01009 QString(
01010 "SELECT channel.%1 "
01011 "FROM channel "
01012 "WHERE channum = :CHANNUM AND "
01013 " sourceid = :SOURCEID")
01014 .arg(channel_field));
01015
01016 query.bindValue(":SOURCEID", sourceid);
01017 query.bindValue(":CHANNUM", channum);
01018
01019 if (!query.exec() || !query.isActive())
01020 MythDB::DBError("getchannelvalue", query);
01021 else if (query.next())
01022 retval = query.value(0).toString();
01023
01024 return retval;
01025 }
01026
01027 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
01028 uint cardid,
01029 const QString &input,
01030 const QString &channum)
01031 {
01032 QString val = GetChannelValueStr(channel_field, cardid, input, channum);
01033
01034 int retval = 0;
01035 if (!val.isEmpty())
01036 retval = val.toInt();
01037
01038 return (retval) ? retval : -1;
01039 }
01040
01041 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
01042 uint sourceid,
01043 const QString &channum)
01044 {
01045 QString val = GetChannelValueStr(channel_field, sourceid, channum);
01046
01047 int retval = 0;
01048 if (!val.isEmpty())
01049 retval = val.toInt();
01050
01051 return (retval) ? retval : -1;
01052 }
01053
01054 bool ChannelUtil::IsOnSameMultiplex(uint srcid,
01055 const QString &new_channum,
01056 const QString &old_channum)
01057 {
01058 if (new_channum.isEmpty() || old_channum.isEmpty())
01059 return false;
01060
01061 if (new_channum == old_channum)
01062 return true;
01063
01064 uint old_mplexid = GetMplexID(srcid, old_channum);
01065 if (!old_mplexid)
01066 return false;
01067
01068 uint new_mplexid = GetMplexID(srcid, new_channum);
01069 if (!new_mplexid)
01070 return false;
01071
01072 LOG(VB_CHANNEL, LOG_INFO, QString("IsOnSameMultiplex? %1==%2 -> %3")
01073 .arg(old_mplexid).arg(new_mplexid)
01074 .arg(old_mplexid == new_mplexid));
01075
01076 return old_mplexid == new_mplexid;
01077 }
01078
01084 static QStringList get_valid_recorder_list(uint chanid)
01085 {
01086 QStringList reclist;
01087
01088
01089
01090 MSqlQuery query(MSqlQuery::InitCon());
01091
01092 query.prepare(
01093 "SELECT cardinput.cardid "
01094 "FROM channel "
01095 "LEFT JOIN cardinput ON channel.sourceid = cardinput.sourceid "
01096 "WHERE channel.chanid = :CHANID AND "
01097 " cardinput.livetvorder > 0 "
01098 "ORDER BY cardinput.livetvorder, cardinput.cardinputid");
01099 query.bindValue(":CHANID", chanid);
01100
01101 if (!query.exec() || !query.isActive())
01102 {
01103 MythDB::DBError("get_valid_recorder_list ChanID", query);
01104 return reclist;
01105 }
01106
01107 while (query.next())
01108 reclist << query.value(0).toString();
01109
01110 return reclist;
01111 }
01112
01118 static QStringList get_valid_recorder_list(const QString &channum)
01119 {
01120 QStringList reclist;
01121
01122
01123
01124 MSqlQuery query(MSqlQuery::InitCon());
01125
01126 query.prepare(
01127 "SELECT cardinput.cardid "
01128 "FROM channel "
01129 "LEFT JOIN cardinput ON channel.sourceid = cardinput.sourceid "
01130 "WHERE channel.channum = :CHANNUM AND "
01131 " cardinput.livetvorder > 0 "
01132 "ORDER BY cardinput.livetvorder, cardinput.cardinputid");
01133 query.bindValue(":CHANNUM", channum);
01134
01135 if (!query.exec() || !query.isActive())
01136 {
01137 MythDB::DBError("get_valid_recorder_list ChanNum", query);
01138 return reclist;
01139 }
01140
01141 while (query.next())
01142 reclist << query.value(0).toString();
01143
01144 return reclist;
01145 }
01146
01154 QStringList ChannelUtil::GetValidRecorderList(
01155 uint chanid, const QString &channum)
01156 {
01157 if (chanid)
01158 return get_valid_recorder_list(chanid);
01159 else if (!channum.isEmpty())
01160 return get_valid_recorder_list(channum);
01161 return QStringList();
01162 }
01163
01164
01165 vector<uint> ChannelUtil::GetConflicting(const QString &channum, uint sourceid)
01166 {
01167 MSqlQuery query(MSqlQuery::InitCon());
01168 vector<uint> conflicting;
01169
01170 if (sourceid)
01171 {
01172 query.prepare(
01173 "SELECT chanid from channel "
01174 "WHERE sourceid = :SOURCEID AND "
01175 " channum = :CHANNUM");
01176 query.bindValue(":SOURCEID", sourceid);
01177 }
01178 else
01179 {
01180 query.prepare(
01181 "SELECT chanid from channel "
01182 "WHERE channum = :CHANNUM");
01183 }
01184
01185 query.bindValue(":CHANNUM", channum);
01186 if (!query.exec())
01187 {
01188 MythDB::DBError("IsConflicting", query);
01189 conflicting.push_back(0);
01190 return conflicting;
01191 }
01192
01193 while (query.next())
01194 conflicting.push_back(query.value(0).toUInt());
01195
01196 return conflicting;
01197 }
01198
01199 bool ChannelUtil::SetChannelValue(const QString &field_name,
01200 QString value,
01201 uint sourceid,
01202 const QString &channum)
01203 {
01204 MSqlQuery query(MSqlQuery::InitCon());
01205
01206 query.prepare(
01207 QString("UPDATE channel SET channel.%1=:VALUE "
01208 "WHERE channel.channum = :CHANNUM AND "
01209 " channel.sourceid = :SOURCEID").arg(field_name));
01210
01211 query.bindValue(":VALUE", value);
01212 query.bindValue(":CHANNUM", channum);
01213 query.bindValue(":SOURCEID", sourceid);
01214
01215 return query.exec();
01216 }
01217
01218 bool ChannelUtil::SetChannelValue(const QString &field_name,
01219 QString value,
01220 int chanid)
01221 {
01222 MSqlQuery query(MSqlQuery::InitCon());
01223
01224 query.prepare(
01225 QString("UPDATE channel SET channel.%1=:VALUE "
01226 "WHERE channel.chanid = :CHANID").arg(field_name));
01227
01228 query.bindValue(":VALUE", value);
01229 query.bindValue(":CHANID", chanid);
01230
01231 return query.exec();
01232 }
01233
01235 QString ChannelUtil::GetDefaultAuthority(uint chanid)
01236 {
01237 static QReadWriteLock channel_default_authority_map_lock;
01238 static QMap<uint,QString> channel_default_authority_map;
01239 static bool run_init = true;
01240
01241 channel_default_authority_map_lock.lockForRead();
01242
01243 if (run_init)
01244 {
01245 channel_default_authority_map_lock.unlock();
01246 channel_default_authority_map_lock.lockForWrite();
01247 if (run_init)
01248 {
01249 MSqlQuery query(MSqlQuery::InitCon());
01250 query.prepare(
01251 "SELECT chanid, m.default_authority "
01252 "FROM channel c "
01253 "LEFT JOIN dtv_multiplex m "
01254 "ON (c.mplexid = m.mplexid)");
01255 if (query.exec())
01256 {
01257 while (query.next())
01258 {
01259 if (!query.value(1).toString().isEmpty())
01260 {
01261 channel_default_authority_map[query.value(0).toUInt()] =
01262 query.value(1).toString();
01263 }
01264 }
01265 run_init = false;
01266 }
01267 else
01268 {
01269 MythDB::DBError("GetDefaultAuthority 1", query);
01270 }
01271
01272 query.prepare(
01273 "SELECT chanid, default_authority "
01274 "FROM channel");
01275 if (query.exec())
01276 {
01277 while (query.next())
01278 {
01279 if (!query.value(1).toString().isEmpty())
01280 {
01281 channel_default_authority_map[query.value(0).toUInt()] =
01282 query.value(1).toString();
01283 }
01284 }
01285 run_init = false;
01286 }
01287 else
01288 {
01289 MythDB::DBError("GetDefaultAuthority 2", query);
01290 }
01291
01292 }
01293 }
01294
01295 QMap<uint,QString>::iterator it = channel_default_authority_map.find(chanid);
01296 QString ret = QString::null;
01297 if (it != channel_default_authority_map.end())
01298 {
01299 ret = *it;
01300 ret.detach();
01301 }
01302 channel_default_authority_map_lock.unlock();
01303
01304 return ret;
01305 }
01306
01307 QString ChannelUtil::GetIcon(uint chanid)
01308 {
01309 static QReadWriteLock channel_icon_map_lock;
01310 static QHash<uint,QString> channel_icon_map;
01311 static bool run_init = true;
01312
01313 channel_icon_map_lock.lockForRead();
01314
01315 QString ret(channel_icon_map.value(chanid, "_cold_"));
01316
01317 channel_icon_map_lock.unlock();
01318
01319 if (ret != "_cold_")
01320 return ret;
01321
01322 channel_icon_map_lock.lockForWrite();
01323
01324 MSqlQuery query(MSqlQuery::InitCon());
01325 QString iconquery = "SELECT chanid, icon FROM channel";
01326
01327 if (run_init)
01328 iconquery += " WHERE visible = 1";
01329 else
01330 iconquery += " WHERE chanid = :CHANID";
01331
01332 query.prepare(iconquery);
01333
01334 if (!run_init)
01335 query.bindValue(":CHANID", chanid);
01336
01337 if (query.exec())
01338 {
01339 if (run_init)
01340 {
01341 channel_icon_map.reserve(query.size());
01342 while (query.next())
01343 {
01344 channel_icon_map[query.value(0).toUInt()] =
01345 query.value(1).toString();
01346 }
01347 run_init = false;
01348 }
01349 else
01350 {
01351 channel_icon_map[chanid] = (query.next()) ?
01352 query.value(1).toString() : "";
01353 }
01354 }
01355 else
01356 {
01357 MythDB::DBError("GetIcon", query);
01358 }
01359
01360 ret = channel_icon_map.value(chanid, "");
01361
01362 channel_icon_map_lock.unlock();
01363
01364 return ret;
01365 }
01366
01367 QString ChannelUtil::GetUnknownCallsign(void)
01368 {
01369 QString tmp = QObject::tr("UNKNOWN", "Synthesized callsign");
01370 tmp.detach();
01371 return tmp;
01372 }
01373
01374 int ChannelUtil::GetChanID(int mplexid, int service_transport_id,
01375 int major_channel, int minor_channel,
01376 int program_number)
01377 {
01378 MSqlQuery query(MSqlQuery::InitCon());
01379
01380
01381 query.prepare("SELECT sourceid "
01382 "FROM dtv_multiplex "
01383 "WHERE mplexid = :MPLEXID");
01384 query.bindValue(":MPLEXID", mplexid);
01385 if (!query.exec())
01386 {
01387 MythDB::DBError("Selecting channel/dtv_multiplex 2", query);
01388 return -1;
01389 }
01390 if (!query.next())
01391 return -1;
01392
01393 int source_id = query.value(0).toInt();
01394
01395 QStringList qstr;
01396
01397
01398 qstr.push_back(
01399 QString("SELECT chanid FROM channel,dtv_multiplex "
01400 "WHERE channel.sourceid = %1 AND "
01401 " atsc_major_chan = %2 AND "
01402 " atsc_minor_chan = %3 AND "
01403 " dtv_multiplex.transportid = %4 AND "
01404 " dtv_multiplex.mplexid = %5 AND "
01405 " dtv_multiplex.sourceid = channel.sourceid AND "
01406 " dtv_multiplex.mplexid = channel.mplexid")
01407 .arg(source_id).arg(major_channel).arg(minor_channel)
01408 .arg(service_transport_id).arg(mplexid));
01409
01410
01411
01412 qstr.push_back(
01413 QString("SELECT chanid FROM channel "
01414 "WHERE sourceid=%1 AND "
01415 "atsc_major_chan=%2 AND "
01416 "atsc_minor_chan=%3")
01417 .arg(source_id).arg(major_channel).arg(minor_channel));
01418
01419
01420 qstr.push_back(
01421 QString("SELECT chanid FROM channel "
01422 "WHERE sourceid=%1 AND serviceID=%2 AND mplexid=%3")
01423 .arg(source_id).arg(program_number).arg(mplexid));
01424
01425 for (int i = 0; i < qstr.size(); i++)
01426 {
01427 query.prepare(qstr[i]);
01428 if (!query.exec())
01429 MythDB::DBError("Selecting channel/dtv_multiplex 3", query);
01430 else if (query.next())
01431 return query.value(0).toInt();
01432 }
01433
01434 return -1;
01435 }
01436
01437 uint ChannelUtil::FindChannel(uint sourceid, const QString &freqid)
01438 {
01439 MSqlQuery query(MSqlQuery::InitCon());
01440 query.prepare("SELECT chanid "
01441 "FROM channel "
01442 "WHERE sourceid = :SOURCEID AND "
01443 " freqid = :FREQID");
01444
01445 query.bindValue(":SOURCEID", sourceid);
01446 query.bindValue(":FREQID", freqid);
01447
01448 if (!query.exec() || !query.isActive())
01449 MythDB::DBError("FindChannel", query);
01450 else if (query.next())
01451 return query.value(0).toUInt();
01452
01453 return 0;
01454 }
01455
01456
01457 static uint get_max_chanid(uint sourceid)
01458 {
01459 QString qstr = "SELECT MAX(chanid) FROM channel ";
01460 qstr += (sourceid) ? "WHERE sourceid = :SOURCEID" : "";
01461
01462 MSqlQuery query(MSqlQuery::DDCon());
01463 query.prepare(qstr);
01464
01465 if (sourceid)
01466 query.bindValue(":SOURCEID", sourceid);
01467
01468 if (!query.exec() || !query.isActive())
01469 MythDB::DBError("Getting chanid for new channel (2)", query);
01470 else if (!query.next())
01471 LOG(VB_GENERAL, LOG_ERR, "Error getting chanid for new channel.");
01472 else
01473 return query.value(0).toUInt();
01474
01475 return 0;
01476 }
01477
01478 static bool chanid_available(uint chanid)
01479 {
01480 MSqlQuery query(MSqlQuery::DDCon());
01481 query.prepare(
01482 "SELECT chanid "
01483 "FROM channel "
01484 "WHERE chanid = :CHANID");
01485 query.bindValue(":CHANID", chanid);
01486
01487 if (!query.exec() || !query.isActive())
01488 MythDB::DBError("is_chan_id_available", query);
01489 else if (query.size() == 0)
01490 return true;
01491
01492 return false;
01493 }
01494
01499 int ChannelUtil::CreateChanID(uint sourceid, const QString &chan_num)
01500 {
01501
01502 uint chanid = 0;
01503 int chansep = chan_num.indexOf(QRegExp("\\D"));
01504 if (chansep > 0)
01505 {
01506 chanid =
01507 sourceid * 1000 +
01508 chan_num.left(chansep).toInt() * 10 +
01509 chan_num.right(chan_num.length()-chansep-1).toInt();
01510 }
01511 else
01512 {
01513 chanid = sourceid * 1000 + chan_num.toInt();
01514 }
01515
01516 if ((chanid > sourceid * 1000) && (chanid_available(chanid)))
01517 return chanid;
01518
01519
01520 chanid = max(get_max_chanid(sourceid) + 1, sourceid * 1000);
01521
01522 if (chanid_available(chanid))
01523 return chanid;
01524
01525
01526 chanid = get_max_chanid(0) + 1;
01527
01528 if (chanid_available(chanid))
01529 return chanid;
01530
01531
01532 return -1;
01533 }
01534
01535 bool ChannelUtil::CreateChannel(uint db_mplexid,
01536 uint db_sourceid,
01537 uint new_channel_id,
01538 const QString &callsign,
01539 const QString &service_name,
01540 const QString &chan_num,
01541 uint service_id,
01542 uint atsc_major_channel,
01543 uint atsc_minor_channel,
01544 bool use_on_air_guide,
01545 bool hidden,
01546 bool hidden_in_guide,
01547 const QString &freqid,
01548 QString icon,
01549 QString format,
01550 QString xmltvid,
01551 QString default_authority)
01552 {
01553 MSqlQuery query(MSqlQuery::InitCon());
01554
01555 QString chanNum = (chan_num == "-1") ?
01556 QString::number(service_id) : chan_num;
01557
01558 QString qstr =
01559 "INSERT INTO channel "
01560 " (chanid, channum, sourceid, "
01561 " callsign, name, serviceid, ";
01562 qstr += (db_mplexid > 0) ? "mplexid, " : "";
01563 qstr += (!freqid.isEmpty()) ? "freqid, " : "";
01564 qstr +=
01565 " atsc_major_chan, atsc_minor_chan, "
01566 " useonairguide, visible, tvformat, "
01567 " icon, xmltvid, default_authority) "
01568 "VALUES "
01569 " (:CHANID, :CHANNUM, :SOURCEID, "
01570 " :CALLSIGN, :NAME, :SERVICEID, ";
01571 qstr += (db_mplexid > 0) ? ":MPLEXID, " : "";
01572 qstr += (!freqid.isEmpty()) ? ":FREQID, " : "";
01573 qstr +=
01574 " :MAJORCHAN, :MINORCHAN, "
01575 " :USEOAG, :VISIBLE, :TVFORMAT, "
01576 " :ICON, :XMLTVID, :AUTHORITY) ";
01577
01578 query.prepare(qstr);
01579
01580 query.bindValue(":CHANID", new_channel_id);
01581 query.bindValue(":CHANNUM", chanNum);
01582 query.bindValue(":SOURCEID", db_sourceid);
01583 query.bindValue(":CALLSIGN", callsign);
01584 query.bindValue(":NAME", service_name);
01585
01586 if (db_mplexid > 0)
01587 query.bindValue(":MPLEXID", db_mplexid);
01588
01589 query.bindValue(":SERVICEID", service_id);
01590 query.bindValue(":MAJORCHAN", atsc_major_channel);
01591 query.bindValue(":MINORCHAN", atsc_minor_channel);
01592 query.bindValue(":USEOAG", use_on_air_guide);
01593 query.bindValue(":VISIBLE", !hidden);
01594 (void) hidden_in_guide;
01595
01596 if (!freqid.isEmpty())
01597 query.bindValue(":FREQID", freqid);
01598
01599 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01600 tvformat = tvformat.isNull() ? "" : tvformat;
01601 query.bindValue(":TVFORMAT", tvformat);
01602
01603 icon = (icon.isNull()) ? "" : icon;
01604 query.bindValue(":ICON", icon);
01605
01606 xmltvid = (xmltvid.isNull()) ? "" : xmltvid;
01607 query.bindValue(":XMLTVID", xmltvid);
01608
01609 default_authority = (default_authority.isNull()) ? "" : default_authority;
01610 query.bindValue(":AUTHORITY", default_authority);
01611
01612 if (!query.exec() || !query.isActive())
01613 {
01614 MythDB::DBError("Adding Service", query);
01615 return false;
01616 }
01617 return true;
01618 }
01619
01620 bool ChannelUtil::UpdateChannel(uint db_mplexid,
01621 uint source_id,
01622 uint channel_id,
01623 const QString &callsign,
01624 const QString &service_name,
01625 const QString &chan_num,
01626 uint service_id,
01627 uint atsc_major_channel,
01628 uint atsc_minor_channel,
01629 bool use_on_air_guide,
01630 bool hidden,
01631 bool hidden_in_guide,
01632 QString freqid,
01633 QString icon,
01634 QString format,
01635 QString xmltvid,
01636 QString default_authority)
01637 {
01638 if (!channel_id)
01639 return false;
01640
01641 QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : format;
01642 bool set_channum = !chan_num.isEmpty() && chan_num != "-1";
01643 QString qstr = QString(
01644 "UPDATE channel "
01645 "SET %1 %2 %3 %4 %5 %6"
01646 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
01647 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
01648 " callsign = :CALLSIGN, name = :NAME, "
01649 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
01650 " visible = :VISIBLE "
01651 "WHERE chanid=:CHANID")
01652 .arg((!set_channum) ? "" : "channum = :CHANNUM, ")
01653 .arg((freqid.isEmpty()) ? "" : "freqid = :FREQID, ")
01654 .arg((icon.isEmpty()) ? "" : "icon = :ICON, ")
01655 .arg((tvformat.isEmpty()) ? "" : "tvformat = :TVFORMAT, ")
01656 .arg((xmltvid.isEmpty()) ? "" : "xmltvid = :XMLTVID, ")
01657 .arg((default_authority.isEmpty()) ?
01658 "" : "default_authority = :AUTHORITY,");
01659
01660 MSqlQuery query(MSqlQuery::InitCon());
01661 query.prepare(qstr);
01662
01663 query.bindValue(":CHANID", channel_id);
01664
01665 if (set_channum)
01666 query.bindValue(":CHANNUM", chan_num);
01667
01668 query.bindValue(":SOURCEID", source_id);
01669 query.bindValue(":CALLSIGN", callsign);
01670 query.bindValue(":NAME", service_name);
01671
01672 query.bindValue(":MPLEXID", db_mplexid);
01673
01674 query.bindValue(":SERVICEID", service_id);
01675 query.bindValue(":MAJORCHAN", atsc_major_channel);
01676 query.bindValue(":MINORCHAN", atsc_minor_channel);
01677 query.bindValue(":USEOAG", use_on_air_guide);
01678 query.bindValue(":VISIBLE", !hidden);
01679 (void) hidden_in_guide;
01680
01681 if (!freqid.isEmpty())
01682 query.bindValue(":FREQID", freqid);
01683
01684 if (!tvformat.isEmpty())
01685 query.bindValue(":TVFORMAT", tvformat);
01686
01687 if (!icon.isEmpty())
01688 query.bindValue(":ICON", icon);
01689 if (!xmltvid.isEmpty())
01690 query.bindValue(":XMLTVID", xmltvid);
01691 if (!default_authority.isEmpty())
01692 query.bindValue(":AUTHORITY", default_authority);
01693
01694 if (!query.exec())
01695 {
01696 MythDB::DBError("Updating Service", query);
01697 return false;
01698 }
01699 return true;
01700 }
01701
01702 void ChannelUtil::UpdateInsertInfoFromDB(ChannelInsertInfo &chan)
01703 {
01704 MSqlQuery query(MSqlQuery::InitCon());
01705 query.prepare(
01706 "SELECT xmltvid, useonairguide "
01707 "FROM channel "
01708 "WHERE chanid = :ID");
01709 query.bindValue(":ID", chan.channel_id);
01710
01711 if (!query.exec())
01712 {
01713 MythDB::DBError("UpdateInsertInfoFromDB", query);
01714 return;
01715 }
01716
01717 if (query.next())
01718 {
01719 QString xmltvid = query.value(0).toString();
01720 bool useeit = query.value(1).toInt();
01721
01722 if (!xmltvid.isEmpty())
01723 {
01724 if (useeit)
01725 LOG(VB_GENERAL, LOG_ERR,
01726 "Using EIT and xmltv for the same channel "
01727 "is a unsupported configuration.");
01728 chan.xmltvid = xmltvid;
01729 chan.use_on_air_guide = useeit;
01730 }
01731 }
01732 }
01733
01734 bool ChannelUtil::DeleteChannel(uint channel_id)
01735 {
01736 MSqlQuery query(MSqlQuery::InitCon());
01737 query.prepare(
01738 "DELETE FROM channel "
01739 "WHERE chanid = :ID");
01740 query.bindValue(":ID", channel_id);
01741
01742 if (!query.exec())
01743 {
01744 MythDB::DBError("Delete Channel", query);
01745 return false;
01746 }
01747
01748 return true;
01749 }
01750
01751 bool ChannelUtil::SetVisible(uint channel_id, bool visible)
01752 {
01753 MSqlQuery query(MSqlQuery::InitCon());
01754 query.prepare(
01755 "UPDATE channel "
01756 "SET visible = :VISIBLE "
01757 "WHERE chanid = :ID");
01758 query.bindValue(":ID", channel_id);
01759 query.bindValue(":VISIBLE", visible);
01760
01761 if (!query.exec())
01762 {
01763 MythDB::DBError("ChannelUtil::SetVisible", query);
01764 return false;
01765 }
01766
01767 return true;
01768 }
01769
01770 bool ChannelUtil::SetServiceVersion(int mplexid, int version)
01771 {
01772 MSqlQuery query(MSqlQuery::InitCon());
01773
01774 query.prepare(
01775 QString("UPDATE dtv_multiplex "
01776 "SET serviceversion = %1 "
01777 "WHERE mplexid = %2").arg(version).arg(mplexid));
01778
01779 if (!query.exec() || !query.isActive())
01780 {
01781 MythDB::DBError("Selecting channel/dtv_multiplex", query);
01782 return false;
01783 }
01784 return true;
01785 }
01786
01787 int ChannelUtil::GetServiceVersion(int mplexid)
01788 {
01789 MSqlQuery query(MSqlQuery::InitCon());
01790
01791 query.prepare(QString("SELECT serviceversion "
01792 "FROM dtv_multiplex "
01793 "WHERE mplexid = %1").arg(mplexid));
01794
01795 if (!query.exec() || !query.isActive())
01796 {
01797 MythDB::DBError("Selecting channel/dtv_multiplex", query);
01798 return false;
01799 }
01800
01801 if (query.size() > 0)
01802 {
01803 query.next();
01804 return query.value(0).toInt();
01805 }
01806 return -1;
01807 }
01808
01809 bool ChannelUtil::GetATSCChannel(uint sourceid, const QString &channum,
01810 uint &major, uint &minor)
01811 {
01812 major = minor = 0;
01813
01814 MSqlQuery query(MSqlQuery::InitCon());
01815 query.prepare(
01816 "SELECT atsc_major_chan, atsc_minor_chan "
01817 "FROM channel "
01818 "WHERE channum = :CHANNUM AND "
01819 " sourceid = :SOURCEID");
01820
01821 query.bindValue(":SOURCEID", sourceid);
01822 query.bindValue(":CHANNUM", channum);
01823
01824 if (!query.exec() || !query.isActive())
01825 MythDB::DBError("getatscchannel", query);
01826 else if (query.next())
01827 {
01828 major = query.value(0).toUInt();
01829 minor = query.value(1).toUInt();
01830 return true;
01831 }
01832
01833 return false;
01834 }
01835
01836 bool ChannelUtil::GetChannelData(
01837 uint sourceid, const QString &channum,
01838 QString &tvformat, QString &modulation,
01839 QString &freqtable, QString &freqid,
01840 int &finetune, uint64_t &frequency,
01841 QString &dtv_si_std, int &mpeg_prog_num,
01842 uint &atsc_major, uint &atsc_minor,
01843 uint &dvb_transportid, uint &dvb_networkid,
01844 uint &mplexid,
01845 bool &commfree)
01846 {
01847 tvformat = modulation = freqtable = QString::null;
01848 freqid = dtv_si_std = QString::null;
01849 finetune = 0;
01850 frequency = 0;
01851 mpeg_prog_num = -1;
01852 atsc_major = atsc_minor = mplexid = 0;
01853 dvb_networkid = dvb_transportid = 0;
01854 commfree = false;
01855
01856 MSqlQuery query(MSqlQuery::InitCon());
01857 query.prepare(
01858 "SELECT finetune, freqid, tvformat, freqtable, "
01859 " commmethod, mplexid, "
01860 " atsc_major_chan, atsc_minor_chan, serviceid "
01861 "FROM channel, videosource "
01862 "WHERE videosource.sourceid = channel.sourceid AND "
01863 " channum = :CHANNUM AND "
01864 " channel.sourceid = :SOURCEID");
01865 query.bindValue(":CHANNUM", channum);
01866 query.bindValue(":SOURCEID", sourceid);
01867
01868 if (!query.exec() || !query.isActive())
01869 {
01870 MythDB::DBError("GetChannelData", query);
01871 return false;
01872 }
01873 else if (!query.next())
01874 {
01875 LOG(VB_GENERAL, LOG_ERR,
01876 QString("GetChannelData() failed because it could not\n"
01877 "\t\t\tfind channel number '%1' in DB for source '%2'.")
01878 .arg(channum).arg(sourceid));
01879 return false;
01880 }
01881
01882 finetune = query.value(0).toInt();
01883 freqid = query.value(1).toString();
01884 tvformat = query.value(2).toString();
01885 freqtable = query.value(3).toString();
01886 commfree = (query.value(4).toInt() == -2);
01887 mplexid = query.value(5).toUInt();
01888 atsc_major = query.value(6).toUInt();
01889 atsc_minor = query.value(7).toUInt();
01890 mpeg_prog_num = (query.value(8).isNull()) ? -1 : query.value(8).toInt();
01891
01892 if (!mplexid || (mplexid == 32767))
01893 return true;
01894
01895 return GetTuningParams(mplexid, modulation, frequency,
01896 dvb_transportid, dvb_networkid, dtv_si_std);
01897 }
01898
01899 bool ChannelUtil::GetExtendedChannelData(
01900 uint sourceid, const QString &channum,
01901 QString &tvformat, QString &modulation,
01902 QString &freqtable, QString &freqid,
01903 int &finetune, uint64_t &frequency,
01904 QString &dtv_si_std, int &mpeg_prog_num,
01905 uint &atsc_major, uint &atsc_minor,
01906 uint &dvb_transportid, uint &dvb_networkid,
01907 uint &mplexid, bool &commfree,
01908 bool &use_on_air_guide,bool &visible,
01909 QString &xmltvid, QString &default_authority,
01910 QString &icon)
01911 {
01912 tvformat = modulation = freqtable = QString::null;
01913 freqid = dtv_si_std = xmltvid = QString::null;
01914 default_authority = icon = QString::null;
01915 finetune = 0;
01916 frequency = 0;
01917 mpeg_prog_num = -1;
01918 atsc_major = atsc_minor = mplexid = 0;
01919 dvb_networkid = dvb_transportid = 0;
01920 commfree = false;
01921 use_on_air_guide = false;
01922 visible = true;
01923
01924 MSqlQuery query(MSqlQuery::InitCon());
01925 query.prepare(
01926 "SELECT finetune, freqid, tvformat, freqtable, "
01927 " commmethod, mplexid, "
01928 " atsc_major_chan, atsc_minor_chan, serviceid, "
01929 " useonairguide, visible, xmltvid, default_authority, icon "
01930 "FROM channel, videosource "
01931 "WHERE videosource.sourceid = channel.sourceid AND "
01932 " channum = :CHANNUM AND "
01933 " channel.sourceid = :SOURCEID");
01934 query.bindValue(":CHANNUM", channum);
01935 query.bindValue(":SOURCEID", sourceid);
01936
01937 if (!query.exec() || !query.isActive())
01938 {
01939 MythDB::DBError("GetChannelData", query);
01940 return false;
01941 }
01942 else if (!query.next())
01943 {
01944 LOG(VB_GENERAL, LOG_ERR,
01945 QString("GetChannelData() failed because it could not\n"
01946 "\t\t\tfind channel number '%1' in DB for source '%2'.")
01947 .arg(channum).arg(sourceid));
01948 return false;
01949 }
01950
01951 finetune = query.value(0).toInt();
01952 freqid = query.value(1).toString();
01953 tvformat = query.value(2).toString();
01954 freqtable = query.value(3).toString();
01955 commfree = (query.value(4).toInt() == -2);
01956 mplexid = query.value(5).toUInt();
01957 atsc_major = query.value(6).toUInt();
01958 atsc_minor = query.value(7).toUInt();
01959 mpeg_prog_num = query.value(8).toUInt();
01960 use_on_air_guide = query.value(9).toBool();
01961 visible = query.value(10).toBool();
01962 xmltvid = query.value(11).toString();
01963 default_authority = query.value(12).toString();
01964 icon = query.value(13).toString();
01965
01966 if (!mplexid || (mplexid == 32767))
01967 return true;
01968
01969 return GetTuningParams(mplexid, modulation, frequency,
01970 dvb_transportid, dvb_networkid, dtv_si_std);
01971 }
01972
01973 DBChanList ChannelUtil::GetChannelsInternal(
01974 uint sourceid, bool vis_only, bool include_disconnected,
01975 const QString &grp, uint changrpid)
01976 {
01977 DBChanList list;
01978
01979 MSqlQuery query(MSqlQuery::InitCon());
01980
01981 QString qstr = QString(
01982 "SELECT channum, callsign, channel.chanid, "
01983 " atsc_major_chan, atsc_minor_chan, "
01984 " name, icon, mplexid, visible, "
01985 " channel.sourceid, cardinput.cardid, channelgroup.grpid "
01986 "FROM channel "
01987 "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid "
01988 " %1 JOIN cardinput ON cardinput.sourceid = channel.sourceid "
01989 " %2 JOIN capturecard ON cardinput.cardid = capturecard.cardid ")
01990 .arg((include_disconnected) ? "LEFT" : "")
01991 .arg((include_disconnected) ? "LEFT" : "");
01992
01993 QString cond = " WHERE ";
01994
01995 if (sourceid)
01996 {
01997 qstr += QString("WHERE channel.sourceid='%1' ").arg(sourceid);
01998 cond = " AND ";
01999 }
02000
02001
02002 if (changrpid > 0)
02003 {
02004 qstr += QString("%1 channelgroup.grpid = '%2' ")
02005 .arg(cond).arg(changrpid);
02006 cond = " AND ";
02007 }
02008
02009 if (vis_only)
02010 {
02011 qstr += QString("%1 visible=1 ").arg(cond);
02012 cond = " AND ";
02013 }
02014
02015 if (!grp.isEmpty())
02016 qstr += QString(" GROUP BY %1 ").arg(grp);
02017
02018 query.prepare(qstr);
02019 if (!query.exec())
02020 {
02021 MythDB::DBError("ChannelUtil::GetChannels()", query);
02022 return list;
02023 }
02024
02025 while (query.next())
02026 {
02027 if (query.value(0).toString().isEmpty() || !query.value(2).toUInt())
02028 continue;
02029
02030 DBChannel chan(
02031 query.value(0).toString(),
02032 query.value(1).toString(),
02033 query.value(2).toUInt(),
02034 query.value(3).toUInt(),
02035 query.value(4).toUInt(),
02036 query.value(7).toUInt(),
02037 query.value(8).toBool(),
02038 query.value(5).toString(),
02039 query.value(6).toString(),
02040 query.value(9).toUInt(),
02041 query.value(11).toUInt(),
02042 query.value(10).toUInt());
02043
02044 list.push_back(chan);
02045 }
02046
02047 return list;
02048 }
02049
02050 vector<uint> ChannelUtil::GetChanIDs(int sourceid)
02051 {
02052 MSqlQuery query(MSqlQuery::InitCon());
02053
02054 QString select = "SELECT chanid FROM channel";
02055 if (sourceid > 0)
02056 select += " WHERE sourceid=" + QString::number(sourceid);
02057
02058 vector<uint> list;
02059 if (!query.exec(select))
02060 {
02061 MythDB::DBError("SourceUtil::GetChanIDs()", query);
02062 return list;
02063 }
02064
02065 while (query.next())
02066 list.push_back(query.value(0).toUInt());
02067
02068 return list;
02069 }
02070
02071 inline bool lt_callsign(const DBChannel &a, const DBChannel &b)
02072 {
02073 return QString::localeAwareCompare(a.callsign, b.callsign) < 0;
02074 }
02075
02076 inline bool lt_smart(const DBChannel &a, const DBChannel &b)
02077 {
02078 static QMutex sepExprLock;
02079 static const QRegExp sepExpr(ChannelUtil::kATSCSeparators);
02080
02081 int cmp = 0;
02082
02083 bool isIntA, isIntB;
02084 int a_int = a.channum.toUInt(&isIntA);
02085 int b_int = b.channum.toUInt(&isIntB);
02086 int a_major = a.major_chan;
02087 int b_major = b.major_chan;
02088 int a_minor = a.minor_chan;
02089 int b_minor = b.minor_chan;
02090
02091
02092 bool tmp1, tmp2;
02093 int idxA, idxB;
02094 {
02095 QMutexLocker locker(&sepExprLock);
02096 idxA = a.channum.indexOf(sepExpr);
02097 idxB = b.channum.indexOf(sepExpr);
02098 }
02099 if (idxA >= 0)
02100 {
02101 int major = a.channum.left(idxA).toUInt(&tmp1);
02102 int minor = a.channum.mid(idxA+1).toUInt(&tmp2);
02103 if (tmp1 && tmp2)
02104 (a_major = major), (a_minor = minor), (isIntA = false);
02105 }
02106
02107 if (idxB >= 0)
02108 {
02109 int major = b.channum.left(idxB).toUInt(&tmp1);
02110 int minor = b.channum.mid(idxB+1).toUInt(&tmp2);
02111 if (tmp1 && tmp2)
02112 (b_major = major), (b_minor = minor), (isIntB = false);
02113 }
02114
02115
02116 if ((a_minor > 0) && isIntA)
02117 {
02118 int atsc_int = (QString("%1%2").arg(a_major).arg(a_minor)).toInt();
02119 a_minor = (atsc_int == a_int) ? a_minor : 0;
02120 }
02121
02122 if ((b_minor > 0) && isIntB)
02123 {
02124 int atsc_int = (QString("%1%2").arg(b_major).arg(b_minor)).toInt();
02125 b_minor = (atsc_int == b_int) ? b_minor : 0;
02126 }
02127
02128
02129
02130 if ((a_minor || b_minor) &&
02131 (a_minor || isIntA) && (b_minor || isIntB))
02132 {
02133 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
02134 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
02135 if ((cmp = a_maj - b_maj))
02136 return cmp < 0;
02137
02138 if ((cmp = a_minor - b_minor))
02139 return cmp < 0;
02140 }
02141
02142 if (isIntA && isIntB)
02143 {
02144
02145 cmp = a_int - b_int;
02146 if (cmp)
02147 return cmp < 0;
02148 }
02149 else if (isIntA ^ isIntB)
02150 {
02151
02152 return isIntA;
02153 }
02154 else
02155 {
02156
02157 cmp = QString::localeAwareCompare(a.channum, b.channum);
02158 if (cmp)
02159 return cmp < 0;
02160 }
02161
02162 return lt_callsign(a,b);
02163 }
02164
02165 uint ChannelUtil::GetChannelCount(int sourceid)
02166 {
02167 MSqlQuery query(MSqlQuery::InitCon());
02168 QString select;
02169
02170
02171 select = "SELECT chanid FROM channel";
02172 if (sourceid >= 0)
02173 select += " WHERE sourceid=" + QString::number(sourceid);
02174 select += ';';
02175
02176 query.prepare(select);
02177
02178 if (!query.exec() || !query.isActive())
02179 return 0;
02180
02181 return query.size();
02182 }
02183
02184 void ChannelUtil::SortChannels(DBChanList &list, const QString &order,
02185 bool eliminate_duplicates)
02186 {
02187 bool cs = order.toLower() == "callsign";
02188 if (cs)
02189 stable_sort(list.begin(), list.end(), lt_callsign);
02190 else
02191 stable_sort(list.begin(), list.end(), lt_smart);
02192
02193 if (eliminate_duplicates && !list.empty())
02194 {
02195 DBChanList tmp;
02196 tmp.push_back(list[0]);
02197 for (uint i = 1; i < list.size(); i++)
02198 {
02199 if ((cs && lt_callsign(tmp.back(), list[i])) ||
02200 (!cs && lt_smart(tmp.back(), list[i])))
02201 {
02202 tmp.push_back(list[i]);
02203 }
02204 }
02205
02206 list = tmp;
02207 }
02208 }
02209
02210 uint ChannelUtil::GetNextChannel(
02211 const DBChanList &sorted,
02212 uint old_chanid,
02213 uint mplexid_restriction,
02214 int direction,
02215 bool skip_non_visible,
02216 bool skip_same_channum_and_callsign)
02217 {
02218 DBChanList::const_iterator it =
02219 find(sorted.begin(), sorted.end(), old_chanid);
02220
02221 if (it == sorted.end())
02222 it = sorted.begin();
02223
02224 if (it == sorted.end())
02225 return 0;
02226
02227 DBChanList::const_iterator start = it;
02228
02229 if (CHANNEL_DIRECTION_DOWN == direction)
02230 {
02231 do
02232 {
02233 if (it == sorted.begin())
02234 it = find(sorted.begin(), sorted.end(),
02235 sorted.rbegin()->chanid);
02236 else
02237 --it;
02238 }
02239 while ((it != start) &&
02240 ((skip_non_visible && !it->visible) ||
02241 (skip_same_channum_and_callsign &&
02242 it->channum == start->channum &&
02243 it->callsign == start->callsign) ||
02244 (mplexid_restriction &&
02245 (mplexid_restriction != it->mplexid))));
02246 }
02247 else if ((CHANNEL_DIRECTION_UP == direction) ||
02248 (CHANNEL_DIRECTION_FAVORITE == direction))
02249 {
02250 do
02251 {
02252 ++it;
02253 if (it == sorted.end())
02254 it = sorted.begin();
02255 }
02256 while ((it != start) &&
02257 ((skip_non_visible && !it->visible) ||
02258 (skip_same_channum_and_callsign &&
02259 it->channum == start->channum &&
02260 it->callsign == start->callsign) ||
02261 (mplexid_restriction &&
02262 (mplexid_restriction != it->mplexid))));
02263 }
02264
02265 return it->chanid;
02266 }
02267
02268