11 #include <QReadWriteLock>
20 #define LOC QString("ChanUtil: ")
37 "WHERE sourceid = :SOURCEID "
38 " AND sistandard = :SISTANDARD ";
40 if (sistandard.toLower() !=
"dvb")
41 qstr +=
"AND frequency = :FREQUENCY ";
44 qstr +=
"AND transportid = :TRANSPORTID ";
45 qstr +=
"AND networkid = :NETWORKID ";
46 qstr +=
"AND polarity = :POLARITY ";
53 query.
bindValue(
":SOURCEID", db_source_id);
54 query.
bindValue(
":SISTANDARD", sistandard);
56 if (sistandard.toLower() !=
"dvb")
57 query.
bindValue(
":FREQUENCY", QString::number(frequency));
60 query.
bindValue(
":TRANSPORTID", transport_id);
61 query.
bindValue(
":NETWORKID", network_id);
62 query.
bindValue(
":POLARITY", QChar(polarity));
72 return query.
value(0).toUInt();
78 int db_source_id,
const QString& sistandard,
79 uint64_t frequency,
const QString& modulation,
81 int transport_id,
int network_id,
82 int symbol_rate,
signed char bandwidth,
83 signed char polarity,
signed char inversion,
84 signed char trans_mode,
85 const QString& inner_FEC,
const QString& constellation,
86 signed char hierarchy,
const QString& hp_code_rate,
87 const QString& lp_code_rate,
const QString& guard_interval,
88 const QString& mod_sys,
const QString& rolloff)
94 db_source_id, sistandard, frequency,
96 transport_id, network_id, polarity);
98 LOG(VB_CHANSCAN, LOG_INFO,
"insert_dtv_multiplex(" +
99 QString(
"dbid:%1 std:'%2' ").arg(db_source_id).arg(sistandard) +
100 QString(
"freq:%1 mod:%2 ").arg(frequency).arg(modulation) +
101 QString(
"tid:%1 nid:%2 ").arg(transport_id).arg(network_id) +
102 QString(
"pol:%1 msys:%2 ...)").arg(QChar(polarity)).arg(mod_sys) +
103 QString(
"mplexid:%1").arg(mplex));
105 bool isDVB = (sistandard.toLower() ==
"dvb");
108 "UPDATE dtv_multiplex "
109 "SET frequency = :FREQUENCY1, ";
111 updateStr += (!modulation.isNull()) ?
112 "modulation = :MODULATION, " :
"";
113 updateStr += (symbol_rate >= 0) ?
114 "symbolrate = :SYMBOLRATE, " :
"";
115 updateStr += (bandwidth >= 0) ?
116 "bandwidth = :BANDWIDTH, " :
"";
117 updateStr += (polarity >= 0) ?
118 "polarity = :POLARITY, " :
"";
119 updateStr += (inversion >= 0) ?
120 "inversion = :INVERSION, " :
"";
121 updateStr += (trans_mode >= 0) ?
122 "transmission_mode= :TRANS_MODE, " :
"";
123 updateStr += (!inner_FEC.isNull()) ?
124 "fec = :INNER_FEC, " :
"";
125 updateStr += (!constellation.isNull()) ?
126 "constellation = :CONSTELLATION, " :
"";
127 updateStr += (hierarchy >= 0) ?
128 "hierarchy = :HIERARCHY, " :
"";
129 updateStr += (!hp_code_rate.isNull()) ?
130 "hp_code_rate = :HP_CODE_RATE, " :
"";
131 updateStr += (!lp_code_rate.isNull()) ?
132 "lp_code_rate = :LP_CODE_RATE, " :
"";
133 updateStr += (!guard_interval.isNull()) ?
134 "guard_interval = :GUARD_INTERVAL, " :
"";
135 updateStr += (!mod_sys.isNull()) ?
136 "mod_sys = :MOD_SYS, " :
"";
137 updateStr += (symbol_rate >= 0) ?
138 "rolloff = :ROLLOFF, " :
"";
139 updateStr += (transport_id && !isDVB) ?
140 "transportid = :TRANSPORTID, " :
"";
142 updateStr = updateStr.left(updateStr.length()-2) +
" ";
145 "WHERE sourceid = :SOURCEID AND "
146 " sistandard = :SISTANDARD AND ";
148 updateStr += (isDVB) ?
149 " polarity = :WHEREPOLARITY AND "
150 " transportid = :TRANSPORTID AND networkid = :NETWORKID " :
151 " frequency = :FREQUENCY2 ";
154 "INSERT INTO dtv_multiplex "
155 " (sourceid, sistandard, frequency, ";
157 insertStr += (!modulation.isNull()) ?
"modulation, " :
"";
158 insertStr += (transport_id || isDVB) ?
"transportid, " :
"";
159 insertStr += (isDVB) ?
"networkid, " :
"";
160 insertStr += (symbol_rate >= 0) ?
"symbolrate, " :
"";
161 insertStr += (bandwidth >= 0) ?
"bandwidth, " :
"";
162 insertStr += (polarity >= 0) ?
"polarity, " :
"";
163 insertStr += (inversion >= 0) ?
"inversion, " :
"";
164 insertStr += (trans_mode >= 0) ?
"transmission_mode, " :
"";
165 insertStr += (!inner_FEC.isNull()) ?
"fec, " :
"";
166 insertStr += (!constellation.isNull()) ?
"constellation, " :
"";
167 insertStr += (hierarchy >= 0) ?
"hierarchy, " :
"";
168 insertStr += (!hp_code_rate.isNull()) ?
"hp_code_rate, " :
"";
169 insertStr += (!lp_code_rate.isNull()) ?
"lp_code_rate, " :
"";
170 insertStr += (!guard_interval.isNull()) ?
"guard_interval, " :
"";
171 insertStr += (!mod_sys.isNull()) ?
"mod_sys, " :
"";
172 insertStr += (!rolloff.isNull()) ?
"rolloff, " :
"";
173 insertStr = insertStr.left(insertStr.length()-2) +
") ";
177 " (:SOURCEID, :SISTANDARD, :FREQUENCY1, ";
178 insertStr += (!modulation.isNull()) ?
":MODULATION, " :
"";
179 insertStr += (transport_id || isDVB) ?
":TRANSPORTID, " :
"";
180 insertStr += (isDVB) ?
":NETWORKID, " :
"";
181 insertStr += (symbol_rate >= 0) ?
":SYMBOLRATE, " :
"";
182 insertStr += (bandwidth >= 0) ?
":BANDWIDTH, " :
"";
183 insertStr += (polarity >= 0) ?
":POLARITY, " :
"";
184 insertStr += (inversion >= 0) ?
":INVERSION, " :
"";
185 insertStr += (trans_mode >= 0) ?
":TRANS_MODE, " :
"";
186 insertStr += (!inner_FEC.isNull()) ?
":INNER_FEC, " :
"";
187 insertStr += (!constellation.isNull()) ?
":CONSTELLATION, " :
"";
188 insertStr += (hierarchy >= 0) ?
":HIERARCHY, " :
"";
189 insertStr += (!hp_code_rate.isNull()) ?
":HP_CODE_RATE, " :
"";
190 insertStr += (!lp_code_rate.isNull()) ?
":LP_CODE_RATE, " :
"";
191 insertStr += (!guard_interval.isNull()) ?
":GUARD_INTERVAL, " :
"";
192 insertStr += (!mod_sys.isNull()) ?
":MOD_SYS, " :
"";
193 insertStr += (!rolloff.isNull()) ?
":ROLLOFF, " :
"";
194 insertStr = insertStr.left(insertStr.length()-2) +
");";
196 query.
prepare((mplex) ? updateStr : insertStr);
198 query.
bindValue(
":SOURCEID", db_source_id);
199 query.
bindValue(
":SISTANDARD", sistandard);
200 query.
bindValue(
":FREQUENCY1", QString::number(frequency));
206 query.
bindValue(
":TRANSPORTID", transport_id);
207 query.
bindValue(
":NETWORKID", network_id);
208 query.
bindValue(
":WHEREPOLARITY", QChar(polarity));
212 query.
bindValue(
":FREQUENCY2", QString::number(frequency));
214 query.
bindValue(
":TRANSPORTID", transport_id);
219 if (transport_id || isDVB)
220 query.
bindValue(
":TRANSPORTID", transport_id);
222 query.
bindValue(
":NETWORKID", network_id);
225 if (!modulation.isNull())
226 query.
bindValue(
":MODULATION", modulation);
228 if (symbol_rate >= 0)
229 query.
bindValue(
":SYMBOLRATE", symbol_rate);
231 query.
bindValue(
":BANDWIDTH", QString(
"%1").arg((
char)bandwidth));
233 query.
bindValue(
":POLARITY", QString(
"%1").arg((
char)polarity));
235 query.
bindValue(
":INVERSION", QString(
"%1").arg((
char)inversion));
237 query.
bindValue(
":TRANS_MODE", QString(
"%1").arg((
char)trans_mode));
239 if (!inner_FEC.isNull())
240 query.
bindValue(
":INNER_FEC", inner_FEC);
241 if (!constellation.isNull())
242 query.
bindValue(
":CONSTELLATION", constellation);
244 query.
bindValue(
":HIERARCHY", QString(
"%1").arg((
char)hierarchy));
245 if (!hp_code_rate.isNull())
246 query.
bindValue(
":HP_CODE_RATE", hp_code_rate);
247 if (!lp_code_rate.isNull())
248 query.
bindValue(
":LP_CODE_RATE", lp_code_rate);
249 if (!guard_interval.isNull())
250 query.
bindValue(
":GUARD_INTERVAL",guard_interval);
251 if (!mod_sys.isNull())
253 if (!rolloff.isNull())
266 db_source_id, sistandard, frequency,
268 transport_id, network_id, polarity);
270 LOG(VB_CHANSCAN, LOG_INFO, QString(
"insert_dtv_multiplex -- ") +
271 QString(
"inserted mplexid %1").arg(mplex));
295 uint dummy_netid = 0;
297 dummy_tsid, dummy_netid, dummy_sistd);
301 (
int)sourceid,
"dvb",
304 (
int)tsid, (
int)netid,
311 QString(), QString());
314 muxes.push_back(mux);
338 QString(), QString(),
342 muxes.push_back(mux);
362 QString(), QString(),
363 QString(), QString());
366 muxes.push_back(mux);
371 uint64_t frequency,
const QString& modulation,
372 int transport_id,
int network_id)
375 sourceid, sistandard,
376 frequency, modulation,
377 transport_id, network_id,
381 QString(), QString(),
383 QString(), QString(),
384 QString(), QString());
388 int sourceid,
const QString& sistandard,
389 uint64_t
freq,
const QString& modulation,
391 int transport_id,
int network_id,
392 int symbol_rate,
signed char bandwidth,
393 signed char polarity,
signed char inversion,
394 signed char trans_mode,
395 const QString& inner_FEC,
const QString& constellation,
396 signed char hierarchy,
const QString& hp_code_rate,
397 const QString& lp_code_rate,
const QString& guard_interval,
398 const QString& mod_sys,
const QString& rolloff)
401 sourceid, sistandard,
404 transport_id, network_id,
405 symbol_rate, bandwidth,
408 inner_FEC, constellation,
409 hierarchy, hp_code_rate,
410 lp_code_rate, guard_interval,
415 int transport_id,
int network_id)
421 transport_id, network_id,
438 std::vector<uint> muxes;
451 for (
const auto *j : list)
467 "WHERE deleted IS NULL AND "
468 " sourceid = :SOURCEID AND "
469 " channum = :CHANNUM");
476 else if (query.
next())
477 return query.
value(0).toInt();
488 "FROM dtv_multiplex "
489 "WHERE sourceid = :SOURCEID AND "
490 " frequency = :FREQUENCY");
493 query.
bindValue(
":FREQUENCY", QString::number(frequency));
502 return query.
value(0).toInt();
514 "FROM dtv_multiplex "
515 "WHERE networkid = :NETWORKID AND "
516 " transportid = :TRANSPORTID AND "
517 " frequency = :FREQUENCY AND "
518 " sourceid = :SOURCEID");
521 query.
bindValue(
":NETWORKID", network_id);
522 query.
bindValue(
":TRANSPORTID", transport_id);
523 query.
bindValue(
":FREQUENCY", QString::number(frequency));
532 return query.
value(0).toInt();
544 "FROM dtv_multiplex "
545 "WHERE networkid = :NETWORKID AND "
546 " transportid = :TRANSPORTID AND "
547 " sourceid = :SOURCEID");
550 query.
bindValue(
":NETWORKID", network_id);
551 query.
bindValue(
":TRANSPORTID", transport_id);
560 return query.
value(0).toInt();
572 "WHERE chanid = :CHANID");
578 else if (query.
next())
579 return query.
value(0).toInt();
612 LOG(VB_CHANSCAN, LOG_INFO,
613 QString(
"GetBetterMplexID(mplexId %1, tId %2, netId %3)")
614 .arg(current_mplexid).arg(transport_id).arg(network_id));
617 int q_transportid = 0;
620 query.
prepare(
"SELECT networkid, transportid "
621 "FROM dtv_multiplex "
622 "WHERE mplexid = :MPLEX_ID");
624 query.
bindValue(
":MPLEX_ID", current_mplexid);
628 else if (query.
next())
630 q_networkid = query.
value(0).toInt();
631 q_transportid = query.
value(1).toInt();
635 if ((q_networkid == network_id) && (q_transportid == transport_id))
637 LOG(VB_CHANSCAN, LOG_INFO,
638 QString(
"GetBetterMplexID(): Returning perfect match %1")
639 .arg(current_mplexid));
640 return current_mplexid;
644 if (!q_networkid && !q_transportid)
646 int qsize = query.
size();
647 query.
prepare(
"UPDATE dtv_multiplex "
648 "SET networkid = :NETWORK_ID, "
649 " transportid = :TRANSPORT_ID "
650 "WHERE mplexid = :MPLEX_ID");
652 query.
bindValue(
":NETWORK_ID", network_id);
653 query.
bindValue(
":TRANSPORT_ID", transport_id);
654 query.
bindValue(
":MPLEX_ID", current_mplexid);
659 LOG(VB_CHANSCAN, LOG_INFO,
660 QString(
"GetBetterMplexID(): net id and transport id "
661 "are null, qsize(%1), Returning %2")
662 .arg(qsize).arg(current_mplexid));
663 return current_mplexid;
667 std::array<QString,2> theQueries
669 QString(
"SELECT a.mplexid "
670 "FROM dtv_multiplex a, dtv_multiplex b "
671 "WHERE a.networkid = :NETWORK_ID AND "
672 " a.transportid = :TRANSPORT_ID AND "
673 " a.sourceid = b.sourceid AND "
674 " b.mplexid = :MPLEX_ID"),
676 QString(
"SELECT mplexid "
677 "FROM dtv_multiplex "
678 "WHERE networkid = :NETWORK_ID AND "
679 " transportid = :TRANSPORT_ID"),
682 for (
uint i=0; i<2; i++)
686 query.
bindValue(
":NETWORK_ID", network_id);
687 query.
bindValue(
":TRANSPORT_ID", transport_id);
689 query.
bindValue(
":MPLEX_ID", current_mplexid);
694 if (query.
size() == 1 && query.
next())
696 LOG(VB_CHANSCAN, LOG_INFO,
697 QString(
"GetBetterMplexID(): query#%1 qsize(%2) "
699 .arg(i).arg(query.
size()).arg(current_mplexid));
700 return query.
value(0).toInt();
705 int ret = (i==0) ? current_mplexid : query.
value(0).toInt();
706 LOG(VB_CHANSCAN, LOG_INFO,
707 QString(
"GetBetterMplexID(): query#%1 qsize(%2) "
709 .arg(i).arg(query.
size()).arg(ret));
715 LOG(VB_CHANSCAN, LOG_INFO,
"GetBetterMplexID(): Returning -1");
722 uint &dvb_transportid,
726 if (!mplexid || (mplexid == 32767))
731 "SELECT transportid, networkid, frequency, modulation, sistandard "
732 "FROM dtv_multiplex "
733 "WHERE mplexid = :MPLEXID");
745 dvb_transportid = query.
value(0).toUInt();
746 dvb_networkid = query.
value(1).toUInt();
747 frequency = query.
value(2).toULongLong();
748 modulation = query.
value(3).toString();
749 si_std = query.
value(4).toString();
760 query.
prepare(QString(
"SELECT %1 FROM channel "
761 "WHERE chanid = :CHANID").arg(field));
772 return query.
value(0).toString();
789 query.
prepare(
"SELECT sourceid "
790 "FROM dtv_multiplex "
791 "WHERE mplexid = :MPLEXID");
800 return query.
value(0).toInt();
812 "WHERE chanid = :CHANID");
817 else if (query.
next())
818 return query.
value(0).toUInt();
826 query.
prepare(
"SELECT cardtype "
827 "FROM capturecard, channel "
828 "WHERE channel.chanid = :CHANID AND "
829 " channel.sourceid = capturecard.sourceid "
830 "GROUP BY cardtype");
840 list.push_back(query.
value(0).toString());
860 query.
prepare(
"SELECT pid, tableid FROM pidcache "
861 "WHERE chanid = :CHANID");
873 int pid = query.
value(0).toInt();
874 int tid = query.
value(1).toInt();
875 if ((pid >= 0) && (tid >= 0))
876 pid_cache.emplace_back(pid, tid);
878 stable_sort(pid_cache.begin(), pid_cache.end(),
lt_pidcache);
897 query.
prepare(
"DELETE FROM pidcache WHERE chanid = :CHANID");
901 "DELETE FROM pidcache "
902 "WHERE chanid = :CHANID AND tableid < 65536");
916 stable_sort(pid_cache.begin(), pid_cache.end(),
lt_pidcache);
920 "INSERT INTO pidcache "
921 "SET chanid = :CHANID, pid = :PID, tableid = :TABLEID");
925 auto ito = old_cache.begin();
926 for (
const auto& itn : pid_cache)
929 for (; ito != old_cache.end() && ito->GetPID() < itn.GetPID(); ++ito);
932 if (ito != old_cache.end() && ito->GetPID() == itn.GetPID())
936 query.
bindValue(
":TABLEID", itn.GetComposite());
950 const QString &channum)
960 "WHERE deleted IS NULL AND "
961 " channum = :CHANNUM AND "
962 " sourceid = :SOURCEID")
963 .arg(channel_field));
970 else if (query.
next())
971 retval = query.
value(0).toString();
978 const QString &channum)
984 retval = val.toInt();
986 return (retval) ? retval : -1;
990 const QString &new_channum,
991 const QString &old_channum)
993 if (new_channum.isEmpty() || old_channum.isEmpty())
996 if (new_channum == old_channum)
1007 LOG(VB_CHANNEL, LOG_INFO, QString(
"IsOnSameMultiplex? %1==%2 -> %3")
1008 .arg(old_mplexid).arg(new_mplexid)
1009 .arg(old_mplexid == new_mplexid));
1011 return old_mplexid == new_mplexid;
1021 QStringList reclist;
1028 "SELECT capturecard.cardid "
1030 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1031 "WHERE channel.chanid = :CHANID AND "
1032 " capturecard.livetvorder > 0 "
1033 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1042 while (query.
next())
1043 reclist << query.
value(0).toString();
1055 QStringList reclist;
1062 "SELECT capturecard.cardid "
1064 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1065 "WHERE channel.deleted IS NULL AND "
1066 " channel.channum = :CHANNUM AND "
1067 " capturecard.livetvorder > 0 "
1068 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1077 while (query.
next())
1078 reclist << query.
value(0).toString();
1091 uint chanid,
const QString &channum)
1095 if (!channum.isEmpty())
1104 std::vector<uint> conflicting;
1109 "SELECT chanid from channel "
1110 "WHERE deleted IS NULL AND "
1111 " sourceid = :SOURCEID AND "
1112 " channum = :CHANNUM");
1118 "SELECT chanid from channel "
1119 "WHERE deleted IS NULL AND "
1120 " channum = :CHANNUM");
1127 conflicting.push_back(0);
1131 while (query.
next())
1132 conflicting.push_back(query.
value(0).toUInt());
1138 const QString& value,
1140 const QString &channum)
1145 QString(
"UPDATE channel SET channel.%1=:VALUE "
1146 "WHERE channel.channum = :CHANNUM AND "
1147 " channel.sourceid = :SOURCEID").arg(field_name));
1153 return query.
exec();
1157 const QString& value,
1163 QString(
"UPDATE channel SET channel.%1=:VALUE "
1164 "WHERE channel.chanid = :CHANID").arg(field_name));
1169 return query.
exec();
1190 "SELECT chanid, m.default_authority "
1192 "LEFT JOIN dtv_multiplex m "
1193 "ON (c.mplexid = m.mplexid) "
1194 "WHERE deleted IS NULL");
1197 while (query.
next())
1199 if (!query.
value(1).toString().isEmpty())
1202 query.
value(1).toString();
1213 "SELECT chanid, default_authority "
1215 "WHERE deleted IS NULL");
1218 while (query.
next())
1220 if (!query.
value(1).toString().isEmpty())
1223 query.
value(1).toString();
1247 static QReadWriteLock s_channelIconMapLock;
1248 static QHash<uint,QString> s_channelIconMap;
1249 static bool s_runInit =
true;
1251 s_channelIconMapLock.lockForRead();
1253 QString ret(s_channelIconMap.value(chanid,
"_cold_"));
1255 s_channelIconMapLock.unlock();
1257 if (ret !=
"_cold_")
1260 s_channelIconMapLock.lockForWrite();
1263 QString iconquery =
"SELECT chanid, icon FROM channel";
1266 iconquery +=
" WHERE visible > 0";
1268 iconquery +=
" WHERE chanid = :CHANID";
1279 s_channelIconMap.reserve(query.
size());
1280 while (query.
next())
1282 s_channelIconMap[query.
value(0).toUInt()] =
1283 query.
value(1).toString();
1289 s_channelIconMap[chanid] = (query.
next()) ?
1290 query.
value(1).toString() :
"";
1298 ret = s_channelIconMap.value(chanid,
"");
1300 s_channelIconMapLock.unlock();
1307 return tr(
"UNKNOWN",
"Synthesized callsign");
1311 int major_channel,
int minor_channel,
1317 query.
prepare(
"SELECT sourceid "
1318 "FROM dtv_multiplex "
1319 "WHERE mplexid = :MPLEXID");
1329 int source_id = query.
value(0).toInt();
1332 query.
prepare(
"SELECT chanid FROM channel,dtv_multiplex "
1333 "WHERE channel.deleted IS NULL AND "
1334 " channel.sourceid = :SOURCEID AND "
1335 " atsc_major_chan = :MAJORCHAN AND "
1336 " atsc_minor_chan = :MINORCHAN AND "
1337 " dtv_multiplex.transportid = :TRANSPORTID AND "
1338 " dtv_multiplex.mplexid = :MPLEXID AND "
1339 " dtv_multiplex.sourceid = channel.sourceid AND "
1340 " dtv_multiplex.mplexid = channel.mplexid");
1342 query.
bindValue(
":SOURCEID", source_id);
1343 query.
bindValue(
":MAJORCHAN", major_channel);
1344 query.
bindValue(
":MINORCHAN", minor_channel);
1345 query.
bindValue(
":TRANSPORTID", service_transport_id);
1349 return query.
value(0).toInt();
1353 query.
prepare(
"SELECT chanid FROM channel "
1354 "WHERE deleted IS NULL AND "
1355 "sourceid = :SOURCEID AND "
1356 "atsc_major_chan = :MAJORCHAN AND "
1357 "atsc_minor_chan = :MINORCHAN");
1359 query.
bindValue(
":SOURCEID", source_id);
1360 query.
bindValue(
":MAJORCHAN", major_channel);
1361 query.
bindValue(
":MINORCHAN", minor_channel);
1364 return query.
value(0).toInt();
1367 query.
prepare(
"SELECT chanid FROM channel "
1368 "WHERE deleted IS NULL AND "
1369 "sourceid = :SOURCEID AND "
1370 "serviceID = :SERVICEID AND "
1371 "mplexid = :MPLEXID");
1373 query.
bindValue(
":SOURCEID", source_id);
1374 query.
bindValue(
":SERVICEID", program_number);
1378 return query.
value(0).toInt();
1386 query.
prepare(
"SELECT chanid "
1388 "WHERE deleted IS NULL AND "
1389 " sourceid = :SOURCEID AND "
1390 " freqid = :FREQID");
1397 else if (query.
next())
1398 return query.
value(0).toUInt();
1406 QString qstr =
"SELECT MAX(chanid) FROM channel ";
1407 qstr += (sourceid) ?
"WHERE sourceid = :SOURCEID" :
"";
1417 else if (!query.
next())
1418 LOG(VB_GENERAL, LOG_ERR,
"Error getting chanid for new channel.");
1420 return query.
value(0).toUInt();
1431 "WHERE chanid = :CHANID");
1436 else if (query.
size() == 0)
1449 static const QRegularExpression kNonDigitRE { R
"(\D)" };
1451 int chansep = chan_num.indexOf(kNonDigitRE);
1456 chan_num.left(chansep).toInt() * 100 +
1457 chan_num.right(chan_num.length() - chansep - 1).toInt();
1461 chanid = sourceid * 10000 + chan_num.toInt();
1468 chanid = std::max(
get_max_chanid(sourceid) + 1, sourceid * 10000);
1485 uint new_channel_id,
1486 const QString &callsign,
1487 const QString &service_name,
1488 const QString &chan_num,
1490 uint atsc_major_channel,
1491 uint atsc_minor_channel,
1492 bool use_on_air_guide,
1494 const QString &freqid,
1495 const QString& icon,
1497 const QString& xmltvid,
1498 const QString& default_authority,
1506 QString chanNum = (chan_num ==
"-1") ?
1507 QString::number(service_id) : chan_num;
1510 "INSERT INTO channel "
1511 " (chanid, channum, sourceid, "
1512 " callsign, name, serviceid, ";
1513 qstr += (db_mplexid > 0) ?
"mplexid, " :
"";
1514 qstr += (!freqid.isEmpty()) ?
"freqid, " :
"";
1516 " atsc_major_chan, atsc_minor_chan, "
1517 " useonairguide, visible, tvformat, "
1518 " icon, xmltvid, default_authority, "
1519 " service_type, recpriority, tmoffset, "
1522 " (:CHANID, :CHANNUM, :SOURCEID, "
1523 " :CALLSIGN, :NAME, :SERVICEID, ";
1524 qstr += (db_mplexid > 0) ?
":MPLEXID, " :
"";
1525 qstr += (!freqid.isEmpty()) ?
":FREQID, " :
"";
1527 " :MAJORCHAN, :MINORCHAN, "
1528 " :USEOAG, :VISIBLE, :TVFORMAT, "
1529 " :ICON, :XMLTVID, :AUTHORITY, "
1530 " :SERVICETYPE, :RECPRIORITY, :TMOFFSET, "
1535 query.
bindValue (
":CHANID", new_channel_id);
1537 query.
bindValue (
":SOURCEID", db_sourceid);
1542 query.
bindValue(
":MPLEXID", db_mplexid);
1544 query.
bindValue(
":SERVICEID", service_id);
1545 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1546 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1547 query.
bindValue(
":USEOAG", use_on_air_guide);
1550 if (!freqid.isEmpty())
1553 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1558 query.
bindValue (
":SERVICETYPE", service_type);
1559 query.
bindValue (
":RECPRIORITY", recpriority);
1560 query.
bindValue (
":TMOFFSET", tmOffset);
1561 query.
bindValue (
":COMMMETHOD", commMethod);
1574 const QString &callsign,
1575 const QString &service_name,
1576 const QString &chan_num,
1578 uint atsc_major_channel,
1579 uint atsc_minor_channel,
1580 bool use_on_air_guide,
1582 const QString& freqid,
1583 const QString& icon,
1585 const QString& xmltvid,
1586 const QString& default_authority,
1595 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1596 bool set_channum = !chan_num.isEmpty() && chan_num !=
"-1";
1597 QString qstr = QString(
1599 "SET %1 %2 %3 %4 %5 %6 %7 %8 %9 "
1600 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
1601 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
1602 " callsign = :CALLSIGN, name = :NAME, "
1603 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
1604 " visible = :VISIBLE, service_type = :SERVICETYPE "
1605 "WHERE chanid=:CHANID")
1606 .arg((!set_channum) ?
"" :
"channum = :CHANNUM, ",
1607 (freqid.isNull()) ?
"" :
"freqid = :FREQID, ",
1608 (icon.isNull()) ?
"" :
"icon = :ICON, ",
1609 (tvformat.isNull()) ?
"" :
"tvformat = :TVFORMAT, ",
1610 (xmltvid.isNull()) ?
"" :
"xmltvid = :XMLTVID, ",
1611 (default_authority.isNull()) ?
1612 "" :
"default_authority = :AUTHORITY,",
1613 (recpriority == INT_MIN) ?
"" :
"recpriority = :RECPRIORITY, ",
1614 (tmOffset == INT_MIN) ?
"" :
"tmOffset = :TMOFFSET, ",
1615 (commMethod == INT_MIN) ?
"" :
"commmethod = :COMMMETHOD, ");
1625 query.
bindValue (
":SOURCEID", source_id);
1629 query.
bindValue(
":MPLEXID", db_mplexid);
1630 query.
bindValue(
":SERVICEID", service_id);
1631 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1632 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1633 query.
bindValue(
":USEOAG", use_on_air_guide);
1635 query.
bindValue(
":SERVICETYPE", service_type);
1637 if (!freqid.isNull())
1639 if (!tvformat.isNull())
1643 if (!xmltvid.isNull())
1645 if (!default_authority.isNull())
1646 query.
bindValue(
":AUTHORITY", default_authority);
1647 if (recpriority != INT_MIN)
1648 query.
bindValue(
":RECPRIORITY", recpriority);
1649 if (tmOffset != INT_MIN)
1651 if (commMethod != INT_MIN)
1652 query.
bindValue(
":COMMMETHOD", commMethod);
1668 "WHERE chanid = :ID");
1679 QString channum = query.
value(0).toString();
1681 if (!channum.isEmpty())
1692 "SELECT xmltvid, useonairguide, visible "
1694 "WHERE chanid = :ID");
1705 QString xmltvid = query.
value(0).toString();
1706 bool useeit = query.
value(1).toBool();
1710 if (!xmltvid.isEmpty())
1714 LOG(VB_GENERAL, LOG_ERR,
1715 "Using EIT and xmltv for the same channel "
1716 "is an unsupported configuration.");
1733 "DELETE FROM iptv_channel "
1734 "WHERE chanid=:CHANID");
1744 "INSERT INTO iptv_channel (chanid, url, type, bitrate) "
1745 "VALUES (:CHANID, :URL, :TYPE, :BITRATE)");
1790 "SET deleted = NOW() "
1791 "WHERE chanid = :ID");
1801 "DELETE FROM iptv_channel "
1802 "WHERE chanid = :ID");
1819 "SET visible = :VISIBLE "
1820 "WHERE chanid = :ID");
1837 query.
prepare(
"UPDATE dtv_multiplex "
1838 "SET serviceversion = :VERSION "
1839 "WHERE mplexid = :MPLEXID");
1856 query.
prepare(
"SELECT serviceversion "
1857 "FROM dtv_multiplex "
1858 "WHERE mplexid = :MPLEXID");
1869 return query.
value(0).toInt();
1881 "SELECT atsc_major_chan, atsc_minor_chan "
1883 "WHERE deleted IS NULL AND "
1884 " channum = :CHANNUM AND "
1885 " sourceid = :SOURCEID");
1892 else if (query.
next())
1894 major = query.
value(0).toUInt();
1904 uint &chanid,
const QString &channum,
1905 QString &tvformat, QString &modulation,
1906 QString &freqtable, QString &freqid,
1907 int &finetune, uint64_t &frequency,
1908 QString &dtv_si_std,
int &mpeg_prog_num,
1909 uint &atsc_major,
uint &atsc_minor,
1910 uint &dvb_transportid,
uint &dvb_networkid,
1923 atsc_major = atsc_minor = mplexid = 0;
1924 dvb_networkid = dvb_transportid = 0;
1930 "SELECT finetune, freqid, tvformat, freqtable, "
1931 " commmethod, mplexid, "
1932 " atsc_major_chan, atsc_minor_chan, serviceid, "
1934 "FROM channel, videosource "
1935 "WHERE channel.deleted IS NULL AND "
1936 " videosource.sourceid = channel.sourceid AND "
1937 " channum = :CHANNUM AND "
1938 " channel.sourceid = :SOURCEID "
1939 "ORDER BY channel.visible > 0 DESC, channel.chanid ");
1951 finetune = query.
value(0).toInt();
1952 freqid = query.
value(1).toString();
1953 tvformat = query.
value(2).toString();
1954 freqtable = query.
value(3).toString();
1955 commfree = (query.
value(4).toInt() == -2);
1956 mplexid = query.
value(5).toUInt();
1957 atsc_major = query.
value(6).toUInt();
1958 atsc_minor = query.
value(7).toUInt();
1959 mpeg_prog_num = (query.
value(8).isNull()) ? -1
1960 : query.
value(8).toInt();
1961 chanid = query.
value(9).toUInt();
1963 found += query.
value(10).toInt();
1966 while (query.
next())
1967 found += query.
value(10).toInt();
1969 if (found == 0 && chanid)
1971 LOG(VB_GENERAL, LOG_WARNING,
1972 QString(
"No visible channels for %1, using invisble chanid %2")
1973 .arg(channum).arg(chanid));
1978 LOG(VB_GENERAL, LOG_WARNING,
1979 QString(
"Found multiple visible channels for %1, using chanid %2")
1980 .arg(channum).arg(chanid));
1985 LOG(VB_GENERAL, LOG_ERR,
1986 QString(
"Could not find channel '%1' in DB for source '%2'.")
1987 .arg(channum).arg(sourceid));
1991 if (!mplexid || (mplexid == 32767))
1995 dvb_transportid, dvb_networkid, dtv_si_std);
2002 "SELECT type+0, url, bitrate "
2003 "FROM iptv_channel "
2004 "WHERE chanid = :CHANID "
2018 std::array<uint,3> bitrate { 0, 0, 0, };
2019 while (query.
next())
2022 query.
value(0).toUInt();
2026 data_url = query.
value(1).toString();
2027 bitrate[0] = query.
value(2).toUInt();
2032 fec_url0 = query.
value(1).toString();
2033 bitrate[1] = query.
value(2).toUInt();
2038 fec_url1 = query.
value(1).toString();
2039 bitrate[2] = query.
value(2).toUInt();
2063 fec_url0, bitrate[1], fec_url1, bitrate[2]);
2064 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %1 for %2")
2075 uint sourceid,
bool visible_only,
bool include_disconnected,
2076 const QString &group_by,
uint channel_groupid)
2082 QString qstr = QString(
2083 "SELECT videosource.sourceid, GROUP_CONCAT(capturecard.cardid) "
2085 "%1 JOIN capturecard ON capturecard.sourceid = videosource.sourceid "
2086 "GROUP BY videosource.sourceid")
2087 .arg((include_disconnected) ?
"LEFT" :
"");
2096 QMap<uint, QList<uint>> inputIdLists;
2097 while (query.
next())
2099 uint qSourceId = query.
value(0).toUInt();
2100 QList<uint> &inputIdList = inputIdLists[qSourceId];
2101 QStringList inputIds = query.
value(1).toString().split(
",");
2102 while (!inputIds.isEmpty())
2103 inputIdList.append(inputIds.takeFirst().toUInt());
2107 "SELECT channum, callsign, channel.chanid, "
2108 " atsc_major_chan, atsc_minor_chan, "
2109 " name, icon, mplexid, visible, "
2110 " channel.sourceid, "
2111 " GROUP_CONCAT(DISTINCT channelgroup.grpid), "
2114 "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid ");
2116 qstr +=
"WHERE deleted IS NULL ";
2119 qstr += QString(
"AND channel.sourceid='%1' ").arg(sourceid);
2122 if (channel_groupid > 0)
2123 qstr += QString(
"AND channelgroup.grpid = '%1' ").arg(channel_groupid);
2126 qstr += QString(
"AND visible > 0 ");
2128 qstr +=
" GROUP BY chanid";
2130 if (!group_by.isEmpty())
2131 qstr += QString(
", %1").arg(group_by);
2140 while (query.
next())
2142 if (query.
value(0).toString().isEmpty() || !query.
value(2).toBool())
2145 uint qSourceID = query.
value(9).toUInt();
2147 query.
value(0).toString(),
2148 query.
value(1).toString(),
2149 query.
value(2).toUInt(),
2150 query.
value(3).toUInt(),
2151 query.
value(4).toUInt(),
2152 query.
value(7).toUInt(),
2155 query.
value(5).toString(),
2156 query.
value(6).toString(),
2161 for (
auto inputId : qAsConst(inputIdLists[qSourceID]))
2164 QStringList groupIDs = query.
value(10).toString().split(
",");
2165 while (!groupIDs.isEmpty())
2166 chan.
AddGroupId(groupIDs.takeFirst().toUInt());
2168 list.push_back(chan);
2179 QString select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2181 if (onlyVisible || sourceid > 0)
2184 select +=
"AND visible > 0 ";
2186 select +=
"AND sourceid=" + QString::number(sourceid);
2189 std::vector<uint> list;
2197 while (query.
next())
2198 list.push_back(query.
value(0).toUInt());
2210 static QMutex s_sepExprLock;
2213 bool isIntA =
false;
2214 bool isIntB =
false;
2215 int a_int = a.
m_chanNum.toUInt(&isIntA);
2216 int b_int = b.
m_chanNum.toUInt(&isIntB);
2226 QMutexLocker locker(&s_sepExprLock);
2234 int major = a.
m_chanNum.left(idxA).toUInt(&tmp1);
2237 (a_major = major), (a_minor =
minor), (isIntA =
false);
2244 int major = b.
m_chanNum.left(idxB).toUInt(&tmp1);
2247 (b_major = major), (b_minor =
minor), (isIntB =
false);
2251 if ((a_minor > 0) && isIntA)
2253 int atsc_int = (QString(
"%1%2").arg(a_major).arg(a_minor)).toInt();
2254 a_minor = (atsc_int == a_int) ? a_minor : 0;
2257 if ((b_minor > 0) && isIntB)
2259 int atsc_int = (QString(
"%1%2").arg(b_major).arg(b_minor)).toInt();
2260 b_minor = (atsc_int == b_int) ? b_minor : 0;
2265 if ((a_minor || b_minor) &&
2266 (a_minor || isIntA) && (b_minor || isIntB))
2268 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
2269 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
2271 if ((cmp = a_maj - b_maj))
2274 if ((cmp = a_minor - b_minor))
2278 if (isIntA && isIntB)
2281 int cmp = a_int - b_int;
2285 else if (isIntA ^ isIntB)
2307 select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2309 select +=
"AND sourceid=" + QString::number(sourceid);
2317 return query.
size();
2321 bool eliminate_duplicates)
2323 bool cs = order.toLower() ==
"callsign";
2325 stable_sort(list.begin(), list.end(),
lt_callsign);
2327 stable_sort(list.begin(), list.end(),
lt_smart);
2329 if (eliminate_duplicates && !list.empty())
2332 tmp.push_back(list[0]);
2333 for (
size_t i = 1; i < list.size(); i++)
2338 tmp.push_back(list[i]);
2354 const QString &channum)
2359 for (
int i = 0; i < (int)list.size(); ++i)
2380 uint mplexid_restriction,
2381 uint chanid_restriction,
2383 bool skip_non_visible,
2384 bool skip_same_channum_and_callsign,
2385 bool skip_other_sources)
2387 auto it =
find(sorted.cbegin(), sorted.cend(), old_chanid);
2389 if (it == sorted.end())
2390 it = sorted.begin();
2392 if (it == sorted.end())
2401 if (it == sorted.begin())
2403 it =
find(sorted.begin(), sorted.end(),
2404 sorted.rbegin()->m_chanId);
2405 if (it == sorted.end())
2413 while ((it != start) &&
2415 (skip_other_sources &&
2416 it->m_sourceId != start->m_sourceId) ||
2417 (skip_same_channum_and_callsign &&
2418 it->m_chanNum == start->m_chanNum &&
2419 it->m_callSign == start->m_callSign) ||
2420 ((mplexid_restriction != 0U) &&
2421 (mplexid_restriction != it->m_mplexId)) ||
2422 ((chanid_restriction != 0U) &&
2423 (chanid_restriction != it->m_chanId))));
2431 if (it == sorted.end())
2432 it = sorted.begin();
2434 while ((it != start) &&
2436 (skip_other_sources &&
2437 it->m_sourceId != start->m_sourceId) ||
2438 (skip_same_channum_and_callsign &&
2439 it->m_chanNum == start->m_chanNum &&
2440 it->m_callSign == start->m_callSign) ||
2441 ((mplexid_restriction != 0U) &&
2442 (mplexid_restriction != it->m_mplexId)) ||
2443 ((chanid_restriction != 0U) &&
2444 (chanid_restriction != it->m_chanId))));
2447 return it->m_chanId;
2451 uint &totalAvailable,
2456 uint channelGroupID,
2458 const QString& callsign,
2459 const QString& channum,
2460 bool ignoreUntunable)
2466 QString sql = QString(
2467 "SELECT parentid, GROUP_CONCAT(cardid ORDER BY cardid) "
2469 "WHERE parentid <> 0 "
2470 "GROUP BY parentid ");
2479 QMap<uint, QList<uint>> childIdLists;
2480 while (query.
next())
2482 auto parentId = query.
value(0).toUInt();
2483 auto &childIdList = childIdLists[parentId];
2484 auto childIds = query.
value(1).toString().split(
",");
2485 while (!childIds.isEmpty())
2486 childIdList.append(childIds.takeFirst().toUInt());
2489 sql =
"SELECT %1 channum, freqid, channel.sourceid, "
2490 "callsign, name, icon, finetune, videofilters, xmltvid, "
2491 "channel.recpriority, channel.contrast, channel.brightness, "
2492 "channel.colour, channel.hue, tvformat, "
2493 "visible, outputfilters, useonairguide, mplexid, "
2494 "serviceid, atsc_major_chan, atsc_minor_chan, last_record, "
2495 "default_authority, commmethod, tmoffset, iptvid, "
2497 "GROUP_CONCAT(DISTINCT `groups`.`groupids`), "
2498 "GROUP_CONCAT(DISTINCT capturecard.cardid "
2499 " ORDER BY livetvorder), "
2500 "MIN(livetvorder) livetvorder "
2502 if (!channelGroupID)
2506 " GROUP_CONCAT(grpid ORDER BY grpid) groupids "
2507 " FROM channelgroup ";
2509 sql +=
" WHERE grpid = :CHANGROUPID ";
2510 sql +=
" GROUP BY chanid "
2512 " ON channel.chanid = `groups`.`chanid` ";
2513 if (!ignoreUntunable && !liveTVOnly)
2515 sql +=
"JOIN capturecard "
2516 " ON capturecard.sourceid = channel.sourceid "
2517 " AND capturecard.parentid = 0 ";
2519 sql +=
" AND capturecard.livetvorder > 0 ";
2521 sql +=
"WHERE channel.deleted IS NULL ";
2523 sql +=
"AND channel.visible > 0 ";
2526 sql +=
"AND channel.sourceid = :SOURCEID ";
2529 sql +=
"GROUP BY channel.callsign ";
2531 sql +=
"GROUP BY channel.callsign, channel.channum ";
2533 sql +=
"GROUP BY channel.chanid ";
2536 sql +=
"ORDER BY channel.name ";
2540 sql +=
"ORDER BY LPAD(CAST(channel.channum AS UNSIGNED), 10, 0), "
2541 " LPAD(channel.channum, 10, 0) ";
2545 sql +=
"ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM DESC, "
2546 " callsign = :CALLSIGN2 DESC, "
2548 " channel.recpriority DESC, "
2553 sql +=
"LIMIT :LIMIT ";
2556 sql +=
"OFFSET :STARTINDEX ";
2559 if (startIndex > 0 || count > 0)
2560 sql = sql.arg(
"SQL_CALC_FOUND_ROWS");
2566 if (channelGroupID > 0)
2567 query.
bindValue(
":CHANGROUPID", channelGroupID);
2576 query.
bindValue(
":STARTINDEX", startIndex);
2580 query.
bindValue(
":CALLSIGN1", callsign);
2582 query.
bindValue(
":CALLSIGN2", callsign);
2591 QList<uint> groupIdList;
2592 while (query.
next())
2608 channelInfo.
m_hue = query.
value(13).toUInt();
2625 QStringList groupIDs = query.
value(28).toString().split(
",");
2626 groupIdList.clear();
2627 while (!groupIDs.isEmpty())
2628 groupIdList.push_back(groupIDs.takeFirst().toUInt());
2629 std::sort(groupIdList.begin(), groupIdList.end());
2630 for (
auto groupId : groupIdList)
2633 QStringList parentIDs = query.
value(29).toString().split(
",");
2634 while (!parentIDs.isEmpty())
2636 auto parentId = parentIDs.takeFirst().toUInt();
2638 auto childIdList = childIdLists[parentId];
2639 for (
auto childId : childIdList)
2643 channelList.push_back(channelInfo);
2646 if ((startIndex > 0 || count > 0) &&
2647 query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
2648 totalAvailable = query.
value(0).toUInt();
2650 totalAvailable = query.
size();