11 #include <QReadWriteLock>
12 #include <QRegularExpression>
22 #define LOC QString("ChanUtil: ")
39 "WHERE sourceid = :SOURCEID "
40 " AND sistandard = :SISTANDARD ";
42 if (sistandard.toLower() !=
"dvb")
43 qstr +=
"AND frequency = :FREQUENCY ";
46 qstr +=
"AND transportid = :TRANSPORTID ";
47 qstr +=
"AND networkid = :NETWORKID ";
48 qstr +=
"AND polarity = :POLARITY ";
55 query.
bindValue(
":SOURCEID", db_source_id);
56 query.
bindValue(
":SISTANDARD", sistandard);
58 if (sistandard.toLower() !=
"dvb")
59 query.
bindValue(
":FREQUENCY", QString::number(frequency));
62 query.
bindValue(
":TRANSPORTID", transport_id);
63 query.
bindValue(
":NETWORKID", network_id);
64 query.
bindValue(
":POLARITY", QChar(polarity));
74 return query.
value(0).toUInt();
80 int db_source_id,
const QString& sistandard,
81 uint64_t frequency,
const QString& modulation,
83 int transport_id,
int network_id,
84 int symbol_rate,
signed char bandwidth,
85 signed char polarity,
signed char inversion,
86 signed char trans_mode,
87 const QString& inner_FEC,
const QString& constellation,
88 signed char hierarchy,
const QString& hp_code_rate,
89 const QString& lp_code_rate,
const QString& guard_interval,
90 const QString& mod_sys,
const QString& rolloff)
96 db_source_id, sistandard, frequency,
98 transport_id, network_id, polarity);
100 LOG(VB_CHANSCAN, LOG_INFO,
"insert_dtv_multiplex(" +
101 QString(
"dbid:%1 std:'%2' ").arg(db_source_id).arg(sistandard) +
102 QString(
"freq:%1 mod:%2 ").arg(frequency).arg(modulation) +
103 QString(
"tid:%1 nid:%2 ").arg(transport_id).arg(network_id) +
104 QString(
"pol:%1 msys:%2 ...)").arg(QChar(polarity)).arg(mod_sys) +
105 QString(
"mplexid:%1").arg(mplex));
107 bool isDVB = (sistandard.toLower() ==
"dvb");
110 "UPDATE dtv_multiplex "
111 "SET frequency = :FREQUENCY1, ";
113 updateStr += (!modulation.isNull()) ?
114 "modulation = :MODULATION, " :
"";
115 updateStr += (symbol_rate >= 0) ?
116 "symbolrate = :SYMBOLRATE, " :
"";
117 updateStr += (bandwidth >= 0) ?
118 "bandwidth = :BANDWIDTH, " :
"";
119 updateStr += (polarity >= 0) ?
120 "polarity = :POLARITY, " :
"";
121 updateStr += (inversion >= 0) ?
122 "inversion = :INVERSION, " :
"";
123 updateStr += (trans_mode >= 0) ?
124 "transmission_mode= :TRANS_MODE, " :
"";
125 updateStr += (!inner_FEC.isNull()) ?
126 "fec = :INNER_FEC, " :
"";
127 updateStr += (!constellation.isNull()) ?
128 "constellation = :CONSTELLATION, " :
"";
129 updateStr += (hierarchy >= 0) ?
130 "hierarchy = :HIERARCHY, " :
"";
131 updateStr += (!hp_code_rate.isNull()) ?
132 "hp_code_rate = :HP_CODE_RATE, " :
"";
133 updateStr += (!lp_code_rate.isNull()) ?
134 "lp_code_rate = :LP_CODE_RATE, " :
"";
135 updateStr += (!guard_interval.isNull()) ?
136 "guard_interval = :GUARD_INTERVAL, " :
"";
137 updateStr += (!mod_sys.isNull()) ?
138 "mod_sys = :MOD_SYS, " :
"";
139 updateStr += (symbol_rate >= 0) ?
140 "rolloff = :ROLLOFF, " :
"";
141 updateStr += (transport_id && !isDVB) ?
142 "transportid = :TRANSPORTID, " :
"";
144 updateStr = updateStr.left(updateStr.length()-2) +
" ";
147 "WHERE sourceid = :SOURCEID AND "
148 " sistandard = :SISTANDARD AND ";
150 updateStr += (isDVB) ?
151 " polarity = :WHEREPOLARITY AND "
152 " transportid = :TRANSPORTID AND networkid = :NETWORKID " :
153 " frequency = :FREQUENCY2 ";
156 "INSERT INTO dtv_multiplex "
157 " (sourceid, sistandard, frequency, ";
159 insertStr += (!modulation.isNull()) ?
"modulation, " :
"";
160 insertStr += (transport_id || isDVB) ?
"transportid, " :
"";
161 insertStr += (isDVB) ?
"networkid, " :
"";
162 insertStr += (symbol_rate >= 0) ?
"symbolrate, " :
"";
163 insertStr += (bandwidth >= 0) ?
"bandwidth, " :
"";
164 insertStr += (polarity >= 0) ?
"polarity, " :
"";
165 insertStr += (inversion >= 0) ?
"inversion, " :
"";
166 insertStr += (trans_mode >= 0) ?
"transmission_mode, " :
"";
167 insertStr += (!inner_FEC.isNull()) ?
"fec, " :
"";
168 insertStr += (!constellation.isNull()) ?
"constellation, " :
"";
169 insertStr += (hierarchy >= 0) ?
"hierarchy, " :
"";
170 insertStr += (!hp_code_rate.isNull()) ?
"hp_code_rate, " :
"";
171 insertStr += (!lp_code_rate.isNull()) ?
"lp_code_rate, " :
"";
172 insertStr += (!guard_interval.isNull()) ?
"guard_interval, " :
"";
173 insertStr += (!mod_sys.isNull()) ?
"mod_sys, " :
"";
174 insertStr += (!rolloff.isNull()) ?
"rolloff, " :
"";
175 insertStr = insertStr.left(insertStr.length()-2) +
") ";
179 " (:SOURCEID, :SISTANDARD, :FREQUENCY1, ";
180 insertStr += (!modulation.isNull()) ?
":MODULATION, " :
"";
181 insertStr += (transport_id || isDVB) ?
":TRANSPORTID, " :
"";
182 insertStr += (isDVB) ?
":NETWORKID, " :
"";
183 insertStr += (symbol_rate >= 0) ?
":SYMBOLRATE, " :
"";
184 insertStr += (bandwidth >= 0) ?
":BANDWIDTH, " :
"";
185 insertStr += (polarity >= 0) ?
":POLARITY, " :
"";
186 insertStr += (inversion >= 0) ?
":INVERSION, " :
"";
187 insertStr += (trans_mode >= 0) ?
":TRANS_MODE, " :
"";
188 insertStr += (!inner_FEC.isNull()) ?
":INNER_FEC, " :
"";
189 insertStr += (!constellation.isNull()) ?
":CONSTELLATION, " :
"";
190 insertStr += (hierarchy >= 0) ?
":HIERARCHY, " :
"";
191 insertStr += (!hp_code_rate.isNull()) ?
":HP_CODE_RATE, " :
"";
192 insertStr += (!lp_code_rate.isNull()) ?
":LP_CODE_RATE, " :
"";
193 insertStr += (!guard_interval.isNull()) ?
":GUARD_INTERVAL, " :
"";
194 insertStr += (!mod_sys.isNull()) ?
":MOD_SYS, " :
"";
195 insertStr += (!rolloff.isNull()) ?
":ROLLOFF, " :
"";
196 insertStr = insertStr.left(insertStr.length()-2) +
");";
198 query.
prepare((mplex) ? updateStr : insertStr);
200 query.
bindValue(
":SOURCEID", db_source_id);
201 query.
bindValue(
":SISTANDARD", sistandard);
202 query.
bindValue(
":FREQUENCY1", QString::number(frequency));
208 query.
bindValue(
":TRANSPORTID", transport_id);
209 query.
bindValue(
":NETWORKID", network_id);
210 query.
bindValue(
":WHEREPOLARITY", QChar(polarity));
214 query.
bindValue(
":FREQUENCY2", QString::number(frequency));
216 query.
bindValue(
":TRANSPORTID", transport_id);
221 if (transport_id || isDVB)
222 query.
bindValue(
":TRANSPORTID", transport_id);
224 query.
bindValue(
":NETWORKID", network_id);
227 if (!modulation.isNull())
228 query.
bindValue(
":MODULATION", modulation);
230 if (symbol_rate >= 0)
231 query.
bindValue(
":SYMBOLRATE", symbol_rate);
233 query.
bindValue(
":BANDWIDTH", QString(
"%1").arg((
char)bandwidth));
235 query.
bindValue(
":POLARITY", QString(
"%1").arg((
char)polarity));
237 query.
bindValue(
":INVERSION", QString(
"%1").arg((
char)inversion));
239 query.
bindValue(
":TRANS_MODE", QString(
"%1").arg((
char)trans_mode));
241 if (!inner_FEC.isNull())
242 query.
bindValue(
":INNER_FEC", inner_FEC);
243 if (!constellation.isNull())
244 query.
bindValue(
":CONSTELLATION", constellation);
246 query.
bindValue(
":HIERARCHY", QString(
"%1").arg((
char)hierarchy));
247 if (!hp_code_rate.isNull())
248 query.
bindValue(
":HP_CODE_RATE", hp_code_rate);
249 if (!lp_code_rate.isNull())
250 query.
bindValue(
":LP_CODE_RATE", lp_code_rate);
251 if (!guard_interval.isNull())
252 query.
bindValue(
":GUARD_INTERVAL",guard_interval);
253 if (!mod_sys.isNull())
255 if (!rolloff.isNull())
268 db_source_id, sistandard, frequency,
270 transport_id, network_id, polarity);
272 LOG(VB_CHANSCAN, LOG_INFO, QString(
"insert_dtv_multiplex -- ") +
273 QString(
"inserted mplexid %1").arg(mplex));
297 uint dummy_netid = 0;
299 dummy_tsid, dummy_netid, dummy_sistd);
303 (
int)sourceid,
"dvb",
306 (
int)tsid, (
int)netid,
313 QString(), QString());
316 muxes.push_back(mux);
340 QString(), QString(),
344 muxes.push_back(mux);
364 QString(), QString(),
365 QString(), QString());
368 muxes.push_back(mux);
373 uint64_t frequency,
const QString& modulation,
374 int transport_id,
int network_id)
377 sourceid, sistandard,
378 frequency, modulation,
379 transport_id, network_id,
383 QString(), QString(),
385 QString(), QString(),
386 QString(), QString());
390 int sourceid,
const QString& sistandard,
391 uint64_t
freq,
const QString& modulation,
393 int transport_id,
int network_id,
394 int symbol_rate,
signed char bandwidth,
395 signed char polarity,
signed char inversion,
396 signed char trans_mode,
397 const QString& inner_FEC,
const QString& constellation,
398 signed char hierarchy,
const QString& hp_code_rate,
399 const QString& lp_code_rate,
const QString& guard_interval,
400 const QString& mod_sys,
const QString& rolloff)
403 sourceid, sistandard,
406 transport_id, network_id,
407 symbol_rate, bandwidth,
410 inner_FEC, constellation,
411 hierarchy, hp_code_rate,
412 lp_code_rate, guard_interval,
417 int transport_id,
int network_id)
423 transport_id, network_id,
440 std::vector<uint> muxes;
453 for (
const auto *j : list)
469 "WHERE deleted IS NULL AND "
470 " sourceid = :SOURCEID AND "
471 " channum = :CHANNUM");
478 else if (query.
next())
479 return query.
value(0).toInt();
490 "FROM dtv_multiplex "
491 "WHERE sourceid = :SOURCEID AND "
492 " frequency = :FREQUENCY");
495 query.
bindValue(
":FREQUENCY", QString::number(frequency));
504 return query.
value(0).toInt();
516 "FROM dtv_multiplex "
517 "WHERE networkid = :NETWORKID AND "
518 " transportid = :TRANSPORTID AND "
519 " frequency = :FREQUENCY AND "
520 " sourceid = :SOURCEID");
523 query.
bindValue(
":NETWORKID", network_id);
524 query.
bindValue(
":TRANSPORTID", transport_id);
525 query.
bindValue(
":FREQUENCY", QString::number(frequency));
534 return query.
value(0).toInt();
546 "FROM dtv_multiplex "
547 "WHERE networkid = :NETWORKID AND "
548 " transportid = :TRANSPORTID AND "
549 " sourceid = :SOURCEID");
552 query.
bindValue(
":NETWORKID", network_id);
553 query.
bindValue(
":TRANSPORTID", transport_id);
562 return query.
value(0).toInt();
574 "WHERE chanid = :CHANID");
580 else if (query.
next())
581 return query.
value(0).toInt();
614 LOG(VB_CHANSCAN, LOG_INFO,
615 QString(
"GetBetterMplexID(mplexId %1, tId %2, netId %3)")
616 .arg(current_mplexid).arg(transport_id).arg(network_id));
619 int q_transportid = 0;
622 query.
prepare(
"SELECT networkid, transportid "
623 "FROM dtv_multiplex "
624 "WHERE mplexid = :MPLEX_ID");
626 query.
bindValue(
":MPLEX_ID", current_mplexid);
630 else if (query.
next())
632 q_networkid = query.
value(0).toInt();
633 q_transportid = query.
value(1).toInt();
637 if ((q_networkid == network_id) && (q_transportid == transport_id))
639 LOG(VB_CHANSCAN, LOG_INFO,
640 QString(
"GetBetterMplexID(): Returning perfect match %1")
641 .arg(current_mplexid));
642 return current_mplexid;
646 if (!q_networkid && !q_transportid)
648 int qsize = query.
size();
649 query.
prepare(
"UPDATE dtv_multiplex "
650 "SET networkid = :NETWORK_ID, "
651 " transportid = :TRANSPORT_ID "
652 "WHERE mplexid = :MPLEX_ID");
654 query.
bindValue(
":NETWORK_ID", network_id);
655 query.
bindValue(
":TRANSPORT_ID", transport_id);
656 query.
bindValue(
":MPLEX_ID", current_mplexid);
661 LOG(VB_CHANSCAN, LOG_INFO,
662 QString(
"GetBetterMplexID(): net id and transport id "
663 "are null, qsize(%1), Returning %2")
664 .arg(qsize).arg(current_mplexid));
665 return current_mplexid;
669 std::array<QString,2> theQueries
671 QString(
"SELECT a.mplexid "
672 "FROM dtv_multiplex a, dtv_multiplex b "
673 "WHERE a.networkid = :NETWORK_ID AND "
674 " a.transportid = :TRANSPORT_ID AND "
675 " a.sourceid = b.sourceid AND "
676 " b.mplexid = :MPLEX_ID"),
678 QString(
"SELECT mplexid "
679 "FROM dtv_multiplex "
680 "WHERE networkid = :NETWORK_ID AND "
681 " transportid = :TRANSPORT_ID"),
684 for (
uint i=0; i<2; i++)
688 query.
bindValue(
":NETWORK_ID", network_id);
689 query.
bindValue(
":TRANSPORT_ID", transport_id);
691 query.
bindValue(
":MPLEX_ID", current_mplexid);
696 if (query.
size() == 1 && query.
next())
698 LOG(VB_CHANSCAN, LOG_INFO,
699 QString(
"GetBetterMplexID(): query#%1 qsize(%2) "
701 .arg(i).arg(query.
size()).arg(current_mplexid));
702 return query.
value(0).toInt();
707 int ret = (i==0) ? current_mplexid : query.
value(0).toInt();
708 LOG(VB_CHANSCAN, LOG_INFO,
709 QString(
"GetBetterMplexID(): query#%1 qsize(%2) "
711 .arg(i).arg(query.
size()).arg(ret));
717 LOG(VB_CHANSCAN, LOG_INFO,
"GetBetterMplexID(): Returning -1");
724 uint &dvb_transportid,
728 if (!mplexid || (mplexid == 32767))
733 "SELECT transportid, networkid, frequency, modulation, sistandard "
734 "FROM dtv_multiplex "
735 "WHERE mplexid = :MPLEXID");
747 dvb_transportid = query.
value(0).toUInt();
748 dvb_networkid = query.
value(1).toUInt();
749 frequency = query.
value(2).toULongLong();
750 modulation = query.
value(3).toString();
751 si_std = query.
value(4).toString();
762 query.
prepare(QString(
"SELECT %1 FROM channel "
763 "WHERE chanid = :CHANID").arg(field));
774 return query.
value(0).toString();
791 query.
prepare(
"SELECT sourceid "
792 "FROM dtv_multiplex "
793 "WHERE mplexid = :MPLEXID");
802 return query.
value(0).toInt();
814 "WHERE chanid = :CHANID");
819 else if (query.
next())
820 return query.
value(0).toUInt();
828 query.
prepare(
"SELECT cardtype "
829 "FROM capturecard, channel "
830 "WHERE channel.chanid = :CHANID AND "
831 " channel.sourceid = capturecard.sourceid "
832 "GROUP BY cardtype");
842 list.push_back(query.
value(0).toString());
862 query.
prepare(
"SELECT pid, tableid FROM pidcache "
863 "WHERE chanid = :CHANID");
875 int pid = query.
value(0).toInt();
876 int tid = query.
value(1).toInt();
877 if ((pid >= 0) && (tid >= 0))
878 pid_cache.emplace_back(pid, tid);
880 stable_sort(pid_cache.begin(), pid_cache.end(),
lt_pidcache);
899 query.
prepare(
"DELETE FROM pidcache WHERE chanid = :CHANID");
903 "DELETE FROM pidcache "
904 "WHERE chanid = :CHANID AND tableid < 65536");
918 stable_sort(pid_cache.begin(), pid_cache.end(),
lt_pidcache);
922 "INSERT INTO pidcache "
923 "SET chanid = :CHANID, pid = :PID, tableid = :TABLEID");
927 auto ito = old_cache.begin();
928 for (
const auto& itn : pid_cache)
931 for (; ito != old_cache.end() && ito->GetPID() < itn.GetPID(); ++ito);
934 if (ito != old_cache.end() && ito->GetPID() == itn.GetPID())
938 query.
bindValue(
":TABLEID", itn.GetComposite());
952 const QString &channum)
962 "WHERE deleted IS NULL AND "
963 " channum = :CHANNUM AND "
964 " sourceid = :SOURCEID")
965 .arg(channel_field));
972 else if (query.
next())
973 retval = query.
value(0).toString();
980 const QString &channum)
986 retval = val.toInt();
988 return (retval) ? retval : -1;
992 const QString &new_channum,
993 const QString &old_channum)
995 if (new_channum.isEmpty() || old_channum.isEmpty())
998 if (new_channum == old_channum)
1009 LOG(VB_CHANNEL, LOG_INFO, QString(
"IsOnSameMultiplex? %1==%2 -> %3")
1010 .arg(old_mplexid).arg(new_mplexid)
1011 .arg(old_mplexid == new_mplexid));
1013 return old_mplexid == new_mplexid;
1023 QStringList reclist;
1030 "SELECT capturecard.cardid "
1032 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1033 "WHERE channel.chanid = :CHANID AND "
1034 " capturecard.livetvorder > 0 "
1035 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1044 while (query.
next())
1045 reclist << query.
value(0).toString();
1057 QStringList reclist;
1064 "SELECT capturecard.cardid "
1066 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1067 "WHERE channel.deleted IS NULL AND "
1068 " channel.channum = :CHANNUM AND "
1069 " capturecard.livetvorder > 0 "
1070 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1079 while (query.
next())
1080 reclist << query.
value(0).toString();
1093 uint chanid,
const QString &channum)
1097 if (!channum.isEmpty())
1106 std::vector<uint> conflicting;
1111 "SELECT chanid from channel "
1112 "WHERE deleted IS NULL AND "
1113 " sourceid = :SOURCEID AND "
1114 " channum = :CHANNUM");
1120 "SELECT chanid from channel "
1121 "WHERE deleted IS NULL AND "
1122 " channum = :CHANNUM");
1129 conflicting.push_back(0);
1133 while (query.
next())
1134 conflicting.push_back(query.
value(0).toUInt());
1140 const QString& value,
1142 const QString &channum)
1147 QString(
"UPDATE channel SET channel.%1=:VALUE "
1148 "WHERE channel.channum = :CHANNUM AND "
1149 " channel.sourceid = :SOURCEID").arg(field_name));
1155 return query.
exec();
1159 const QString& value,
1165 QString(
"UPDATE channel SET channel.%1=:VALUE "
1166 "WHERE channel.chanid = :CHANID").arg(field_name));
1171 return query.
exec();
1192 "SELECT chanid, m.default_authority "
1194 "LEFT JOIN dtv_multiplex m "
1195 "ON (c.mplexid = m.mplexid) "
1196 "WHERE deleted IS NULL");
1199 while (query.
next())
1201 if (!query.
value(1).toString().isEmpty())
1204 query.
value(1).toString();
1215 "SELECT chanid, default_authority "
1217 "WHERE deleted IS NULL");
1220 while (query.
next())
1222 if (!query.
value(1).toString().isEmpty())
1225 query.
value(1).toString();
1249 static QReadWriteLock s_channelIconMapLock;
1250 static QHash<uint,QString> s_channelIconMap;
1251 static bool s_runInit =
true;
1253 s_channelIconMapLock.lockForRead();
1255 QString ret(s_channelIconMap.value(chanid,
"_cold_"));
1257 s_channelIconMapLock.unlock();
1259 if (ret !=
"_cold_")
1262 s_channelIconMapLock.lockForWrite();
1265 QString iconquery =
"SELECT chanid, icon FROM channel";
1268 iconquery +=
" WHERE visible > 0";
1270 iconquery +=
" WHERE chanid = :CHANID";
1281 s_channelIconMap.reserve(query.
size());
1282 while (query.
next())
1284 s_channelIconMap[query.
value(0).toUInt()] =
1285 query.
value(1).toString();
1291 s_channelIconMap[chanid] = (query.
next()) ?
1292 query.
value(1).toString() :
"";
1300 ret = s_channelIconMap.value(chanid,
"");
1302 s_channelIconMapLock.unlock();
1309 return tr(
"UNKNOWN",
"Synthesized callsign");
1313 int major_channel,
int minor_channel,
1319 query.
prepare(
"SELECT sourceid "
1320 "FROM dtv_multiplex "
1321 "WHERE mplexid = :MPLEXID");
1331 int source_id = query.
value(0).toInt();
1334 query.
prepare(
"SELECT chanid FROM channel,dtv_multiplex "
1335 "WHERE channel.deleted IS NULL AND "
1336 " channel.sourceid = :SOURCEID AND "
1337 " atsc_major_chan = :MAJORCHAN AND "
1338 " atsc_minor_chan = :MINORCHAN AND "
1339 " dtv_multiplex.transportid = :TRANSPORTID AND "
1340 " dtv_multiplex.mplexid = :MPLEXID AND "
1341 " dtv_multiplex.sourceid = channel.sourceid AND "
1342 " dtv_multiplex.mplexid = channel.mplexid");
1344 query.
bindValue(
":SOURCEID", source_id);
1345 query.
bindValue(
":MAJORCHAN", major_channel);
1346 query.
bindValue(
":MINORCHAN", minor_channel);
1347 query.
bindValue(
":TRANSPORTID", service_transport_id);
1351 return query.
value(0).toInt();
1355 query.
prepare(
"SELECT chanid FROM channel "
1356 "WHERE deleted IS NULL AND "
1357 "sourceid = :SOURCEID AND "
1358 "atsc_major_chan = :MAJORCHAN AND "
1359 "atsc_minor_chan = :MINORCHAN");
1361 query.
bindValue(
":SOURCEID", source_id);
1362 query.
bindValue(
":MAJORCHAN", major_channel);
1363 query.
bindValue(
":MINORCHAN", minor_channel);
1366 return query.
value(0).toInt();
1369 query.
prepare(
"SELECT chanid FROM channel "
1370 "WHERE deleted IS NULL AND "
1371 "sourceid = :SOURCEID AND "
1372 "serviceID = :SERVICEID AND "
1373 "mplexid = :MPLEXID");
1375 query.
bindValue(
":SOURCEID", source_id);
1376 query.
bindValue(
":SERVICEID", program_number);
1380 return query.
value(0).toInt();
1388 query.
prepare(
"SELECT chanid "
1390 "WHERE deleted IS NULL AND "
1391 " sourceid = :SOURCEID AND "
1392 " freqid = :FREQID");
1399 else if (query.
next())
1400 return query.
value(0).toUInt();
1408 QString qstr =
"SELECT MAX(chanid) FROM channel ";
1409 qstr += (sourceid) ?
"WHERE sourceid = :SOURCEID" :
"";
1419 else if (!query.
next())
1420 LOG(VB_GENERAL, LOG_ERR,
"Error getting chanid for new channel.");
1422 return query.
value(0).toUInt();
1433 "WHERE chanid = :CHANID");
1438 else if (query.
size() == 0)
1451 static const QRegularExpression kNonDigitRE { R
"(\D)" };
1453 int chansep = chan_num.indexOf(kNonDigitRE);
1458 chan_num.left(chansep).toInt() * 100 +
1459 chan_num.right(chan_num.length() - chansep - 1).toInt();
1463 chanid = sourceid * 10000 + chan_num.toInt();
1470 chanid = std::max(
get_max_chanid(sourceid) + 1, sourceid * 10000);
1487 uint new_channel_id,
1488 const QString &callsign,
1489 const QString &service_name,
1490 const QString &chan_num,
1492 uint atsc_major_channel,
1493 uint atsc_minor_channel,
1494 bool use_on_air_guide,
1496 const QString &freqid,
1497 const QString& icon,
1499 const QString& xmltvid,
1500 const QString& default_authority,
1508 QString chanNum = (chan_num ==
"-1") ?
1509 QString::number(service_id) : chan_num;
1512 "INSERT INTO channel "
1513 " (chanid, channum, sourceid, "
1514 " callsign, name, serviceid, ";
1515 qstr += (db_mplexid > 0) ?
"mplexid, " :
"";
1516 qstr += (!freqid.isEmpty()) ?
"freqid, " :
"";
1518 " atsc_major_chan, atsc_minor_chan, "
1519 " useonairguide, visible, tvformat, "
1520 " icon, xmltvid, default_authority, "
1521 " service_type, recpriority, tmoffset, "
1524 " (:CHANID, :CHANNUM, :SOURCEID, "
1525 " :CALLSIGN, :NAME, :SERVICEID, ";
1526 qstr += (db_mplexid > 0) ?
":MPLEXID, " :
"";
1527 qstr += (!freqid.isEmpty()) ?
":FREQID, " :
"";
1529 " :MAJORCHAN, :MINORCHAN, "
1530 " :USEOAG, :VISIBLE, :TVFORMAT, "
1531 " :ICON, :XMLTVID, :AUTHORITY, "
1532 " :SERVICETYPE, :RECPRIORITY, :TMOFFSET, "
1537 query.
bindValue (
":CHANID", new_channel_id);
1539 query.
bindValue (
":SOURCEID", db_sourceid);
1544 query.
bindValue(
":MPLEXID", db_mplexid);
1546 query.
bindValue(
":SERVICEID", service_id);
1547 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1548 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1549 query.
bindValue(
":USEOAG", use_on_air_guide);
1552 if (!freqid.isEmpty())
1555 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1560 query.
bindValue (
":SERVICETYPE", service_type);
1561 query.
bindValue (
":RECPRIORITY", recpriority);
1562 query.
bindValue (
":TMOFFSET", tmOffset);
1563 query.
bindValue (
":COMMMETHOD", commMethod);
1576 const QString &callsign,
1577 const QString &service_name,
1578 const QString &chan_num,
1580 uint atsc_major_channel,
1581 uint atsc_minor_channel,
1582 bool use_on_air_guide,
1584 const QString& freqid,
1585 const QString& icon,
1587 const QString& xmltvid,
1588 const QString& default_authority,
1597 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1598 bool set_channum = !chan_num.isEmpty() && chan_num !=
"-1";
1599 QString qstr = QString(
1601 "SET %1 %2 %3 %4 %5 %6 %7 %8 %9 "
1602 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
1603 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
1604 " callsign = :CALLSIGN, name = :NAME, "
1605 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
1606 " visible = :VISIBLE, service_type = :SERVICETYPE "
1607 "WHERE chanid=:CHANID")
1608 .arg((!set_channum) ?
"" :
"channum = :CHANNUM, ",
1609 (freqid.isNull()) ?
"" :
"freqid = :FREQID, ",
1610 (icon.isNull()) ?
"" :
"icon = :ICON, ",
1611 (tvformat.isNull()) ?
"" :
"tvformat = :TVFORMAT, ",
1612 (xmltvid.isNull()) ?
"" :
"xmltvid = :XMLTVID, ",
1613 (default_authority.isNull()) ?
1614 "" :
"default_authority = :AUTHORITY,",
1615 (recpriority == INT_MIN) ?
"" :
"recpriority = :RECPRIORITY, ",
1616 (tmOffset == INT_MIN) ?
"" :
"tmOffset = :TMOFFSET, ",
1617 (commMethod == INT_MIN) ?
"" :
"commmethod = :COMMMETHOD, ");
1627 query.
bindValue (
":SOURCEID", source_id);
1631 query.
bindValue(
":MPLEXID", db_mplexid);
1632 query.
bindValue(
":SERVICEID", service_id);
1633 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1634 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1635 query.
bindValue(
":USEOAG", use_on_air_guide);
1637 query.
bindValue(
":SERVICETYPE", service_type);
1639 if (!freqid.isNull())
1641 if (!tvformat.isNull())
1645 if (!xmltvid.isNull())
1647 if (!default_authority.isNull())
1648 query.
bindValue(
":AUTHORITY", default_authority);
1649 if (recpriority != INT_MIN)
1650 query.
bindValue(
":RECPRIORITY", recpriority);
1651 if (tmOffset != INT_MIN)
1653 if (commMethod != INT_MIN)
1654 query.
bindValue(
":COMMMETHOD", commMethod);
1670 "WHERE chanid = :ID");
1681 QString channum = query.
value(0).toString();
1683 if (!channum.isEmpty())
1694 "SELECT xmltvid, useonairguide, visible "
1696 "WHERE chanid = :ID");
1707 QString xmltvid = query.
value(0).toString();
1708 bool useeit = query.
value(1).toBool();
1712 if (!xmltvid.isEmpty())
1716 LOG(VB_GENERAL, LOG_ERR,
1717 "Using EIT and xmltv for the same channel "
1718 "is an unsupported configuration.");
1735 "DELETE FROM iptv_channel "
1736 "WHERE chanid=:CHANID");
1746 "INSERT INTO iptv_channel (chanid, url, type, bitrate) "
1747 "VALUES (:CHANID, :URL, :TYPE, :BITRATE)");
1792 "SET deleted = NOW() "
1793 "WHERE chanid = :ID");
1803 "DELETE FROM iptv_channel "
1804 "WHERE chanid = :ID");
1821 "SET visible = :VISIBLE "
1822 "WHERE chanid = :ID");
1839 query.
prepare(
"UPDATE dtv_multiplex "
1840 "SET serviceversion = :VERSION "
1841 "WHERE mplexid = :MPLEXID");
1858 query.
prepare(
"SELECT serviceversion "
1859 "FROM dtv_multiplex "
1860 "WHERE mplexid = :MPLEXID");
1871 return query.
value(0).toInt();
1883 "SELECT atsc_major_chan, atsc_minor_chan "
1885 "WHERE deleted IS NULL AND "
1886 " channum = :CHANNUM AND "
1887 " sourceid = :SOURCEID");
1894 else if (query.
next())
1896 major = query.
value(0).toUInt();
1906 uint &chanid,
const QString &channum,
1907 QString &tvformat, QString &modulation,
1908 QString &freqtable, QString &freqid,
1909 int &finetune, uint64_t &frequency,
1910 QString &dtv_si_std,
int &mpeg_prog_num,
1911 uint &atsc_major,
uint &atsc_minor,
1912 uint &dvb_transportid,
uint &dvb_networkid,
1925 atsc_major = atsc_minor = mplexid = 0;
1926 dvb_networkid = dvb_transportid = 0;
1932 "SELECT finetune, freqid, tvformat, freqtable, "
1933 " commmethod, mplexid, "
1934 " atsc_major_chan, atsc_minor_chan, serviceid, "
1936 "FROM channel, videosource "
1937 "WHERE channel.deleted IS NULL AND "
1938 " videosource.sourceid = channel.sourceid AND "
1939 " channum = :CHANNUM AND "
1940 " channel.sourceid = :SOURCEID "
1941 "ORDER BY channel.visible > 0 DESC, channel.chanid ");
1953 finetune = query.
value(0).toInt();
1954 freqid = query.
value(1).toString();
1955 tvformat = query.
value(2).toString();
1956 freqtable = query.
value(3).toString();
1957 commfree = (query.
value(4).toInt() == -2);
1958 mplexid = query.
value(5).toUInt();
1959 atsc_major = query.
value(6).toUInt();
1960 atsc_minor = query.
value(7).toUInt();
1961 mpeg_prog_num = (query.
value(8).isNull()) ? -1
1962 : query.
value(8).toInt();
1963 chanid = query.
value(9).toUInt();
1969 while (query.
next())
1973 if (found == 0 && chanid)
1975 LOG(VB_GENERAL, LOG_WARNING,
1976 QString(
"No visible channels for %1, using invisble chanid %2")
1977 .arg(channum).arg(chanid));
1982 LOG(VB_GENERAL, LOG_WARNING,
1983 QString(
"Found multiple visible channels for %1, using chanid %2")
1984 .arg(channum).arg(chanid));
1989 LOG(VB_GENERAL, LOG_ERR,
1990 QString(
"Could not find channel '%1' in DB for source %2 '%3'.")
1995 if (!mplexid || (mplexid == 32767))
1999 dvb_transportid, dvb_networkid, dtv_si_std);
2006 "SELECT type+0, url, bitrate "
2007 "FROM iptv_channel "
2008 "WHERE chanid = :CHANID "
2022 std::array<uint,3> bitrate { 0, 0, 0, };
2023 while (query.
next())
2026 query.
value(0).toUInt();
2030 data_url = query.
value(1).toString();
2031 bitrate[0] = query.
value(2).toUInt();
2036 fec_url0 = query.
value(1).toString();
2037 bitrate[1] = query.
value(2).toUInt();
2042 fec_url1 = query.
value(1).toString();
2043 bitrate[2] = query.
value(2).toUInt();
2067 fec_url0, bitrate[1], fec_url1, bitrate[2]);
2068 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %1 for %2")
2079 uint sourceid,
bool visible_only,
bool include_disconnected,
2080 const QString &group_by,
uint channel_groupid)
2086 QString qstr = QString(
2087 "SELECT videosource.sourceid, GROUP_CONCAT(capturecard.cardid) "
2089 "%1 JOIN capturecard ON capturecard.sourceid = videosource.sourceid "
2090 "GROUP BY videosource.sourceid")
2091 .arg((include_disconnected) ?
"LEFT" :
"");
2100 QMap<uint, QList<uint>> inputIdLists;
2101 while (query.
next())
2103 uint qSourceId = query.
value(0).toUInt();
2104 QList<uint> &inputIdList = inputIdLists[qSourceId];
2105 QStringList inputIds = query.
value(1).toString().split(
",");
2106 while (!inputIds.isEmpty())
2107 inputIdList.append(inputIds.takeFirst().toUInt());
2111 "SELECT channum, callsign, channel.chanid, "
2112 " atsc_major_chan, atsc_minor_chan, "
2113 " name, icon, mplexid, visible, "
2114 " channel.sourceid, "
2115 " GROUP_CONCAT(DISTINCT channelgroup.grpid), "
2118 "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid ");
2120 qstr +=
"WHERE deleted IS NULL ";
2123 qstr += QString(
"AND channel.sourceid='%1' ").arg(sourceid);
2126 if (channel_groupid > 0)
2127 qstr += QString(
"AND channelgroup.grpid = '%1' ").arg(channel_groupid);
2130 qstr += QString(
"AND visible > 0 ");
2132 qstr +=
" GROUP BY chanid";
2134 if (!group_by.isEmpty())
2135 qstr += QString(
", %1").arg(group_by);
2144 while (query.
next())
2146 if (query.
value(0).toString().isEmpty() || !query.
value(2).toBool())
2149 uint qSourceID = query.
value(9).toUInt();
2151 query.
value(0).toString(),
2152 query.
value(1).toString(),
2153 query.
value(2).toUInt(),
2154 query.
value(3).toUInt(),
2155 query.
value(4).toUInt(),
2156 query.
value(7).toUInt(),
2159 query.
value(5).toString(),
2160 query.
value(6).toString(),
2165 for (
auto inputId : std::as_const(inputIdLists[qSourceID]))
2168 QStringList groupIDs = query.
value(10).toString().split(
",");
2169 while (!groupIDs.isEmpty())
2170 chan.
AddGroupId(groupIDs.takeFirst().toUInt());
2172 list.push_back(chan);
2183 QString select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2185 if (onlyVisible || sourceid > 0)
2188 select +=
"AND visible > 0 ";
2190 select +=
"AND sourceid=" + QString::number(sourceid);
2193 std::vector<uint> list;
2201 while (query.
next())
2202 list.push_back(query.
value(0).toUInt());
2214 static QMutex s_sepExprLock;
2217 bool isIntA =
false;
2218 bool isIntB =
false;
2219 int a_int = a.
m_chanNum.toUInt(&isIntA);
2220 int b_int = b.
m_chanNum.toUInt(&isIntB);
2230 QMutexLocker locker(&s_sepExprLock);
2238 int major = a.
m_chanNum.left(idxA).toUInt(&tmp1);
2241 (a_major = major), (a_minor =
minor), (isIntA =
false);
2248 int major = b.
m_chanNum.left(idxB).toUInt(&tmp1);
2251 (b_major = major), (b_minor =
minor), (isIntB =
false);
2255 if ((a_minor > 0) && isIntA)
2257 int atsc_int = (QString(
"%1%2").arg(a_major).arg(a_minor)).toInt();
2258 a_minor = (atsc_int == a_int) ? a_minor : 0;
2261 if ((b_minor > 0) && isIntB)
2263 int atsc_int = (QString(
"%1%2").arg(b_major).arg(b_minor)).toInt();
2264 b_minor = (atsc_int == b_int) ? b_minor : 0;
2269 if ((a_minor || b_minor) &&
2270 (a_minor || isIntA) && (b_minor || isIntB))
2272 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
2273 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
2274 int cmp = a_maj - b_maj;
2278 cmp = a_minor - b_minor;
2283 if (isIntA && isIntB)
2286 int cmp = a_int - b_int;
2290 else if (isIntA ^ isIntB)
2312 select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2314 select +=
"AND sourceid=" + QString::number(sourceid);
2322 return query.
size();
2326 bool eliminate_duplicates)
2328 bool cs = order.toLower() ==
"callsign";
2330 stable_sort(list.begin(), list.end(),
lt_callsign);
2332 stable_sort(list.begin(), list.end(),
lt_smart);
2334 if (eliminate_duplicates && !list.empty())
2337 tmp.push_back(list[0]);
2338 for (
size_t i = 1; i < list.size(); i++)
2343 tmp.push_back(list[i]);
2359 const QString &channum)
2364 for (
int i = 0; i < (int)list.size(); ++i)
2385 uint mplexid_restriction,
2386 uint chanid_restriction,
2388 bool skip_non_visible,
2389 bool skip_same_channum_and_callsign,
2390 bool skip_other_sources)
2392 auto it =
find(sorted.cbegin(), sorted.cend(), old_chanid);
2394 if (it == sorted.end())
2395 it = sorted.begin();
2397 if (it == sorted.end())
2406 if (it == sorted.begin())
2408 it =
find(sorted.begin(), sorted.end(),
2409 sorted.rbegin()->m_chanId);
2410 if (it == sorted.end())
2420 while ((it != start) &&
2422 (skip_other_sources &&
2423 it->m_sourceId != start->m_sourceId) ||
2424 (skip_same_channum_and_callsign &&
2425 it->m_chanNum == start->m_chanNum &&
2426 it->m_callSign == start->m_callSign) ||
2427 ((mplexid_restriction != 0U) &&
2428 (mplexid_restriction != it->m_mplexId)) ||
2429 ((chanid_restriction != 0U) &&
2430 (chanid_restriction != it->m_chanId))));
2438 if (it == sorted.end())
2439 it = sorted.begin();
2441 while ((it != start) &&
2443 (skip_other_sources &&
2444 it->m_sourceId != start->m_sourceId) ||
2445 (skip_same_channum_and_callsign &&
2446 it->m_chanNum == start->m_chanNum &&
2447 it->m_callSign == start->m_callSign) ||
2448 ((mplexid_restriction != 0U) &&
2449 (mplexid_restriction != it->m_mplexId)) ||
2450 ((chanid_restriction != 0U) &&
2451 (chanid_restriction != it->m_chanId))));
2454 return it->m_chanId;
2458 uint &totalAvailable,
2463 uint channelGroupID,
2465 const QString& callsign,
2466 const QString& channum,
2467 bool ignoreUntunable)
2473 QString sql = QString(
2474 "SELECT parentid, GROUP_CONCAT(cardid ORDER BY cardid) "
2476 "WHERE parentid <> 0 "
2477 "GROUP BY parentid ");
2486 QMap<uint, QList<uint>> childIdLists;
2487 while (query.
next())
2489 auto parentId = query.
value(0).toUInt();
2490 auto &childIdList = childIdLists[parentId];
2491 auto childIds = query.
value(1).toString().split(
",");
2492 while (!childIds.isEmpty())
2493 childIdList.append(childIds.takeFirst().toUInt());
2496 sql =
"SELECT %1 channum, freqid, channel.sourceid, "
2497 "callsign, name, icon, finetune, videofilters, xmltvid, "
2498 "channel.recpriority, channel.contrast, channel.brightness, "
2499 "channel.colour, channel.hue, tvformat, "
2500 "visible, outputfilters, useonairguide, mplexid, "
2501 "serviceid, atsc_major_chan, atsc_minor_chan, last_record, "
2502 "default_authority, commmethod, tmoffset, iptvid, "
2504 "GROUP_CONCAT(DISTINCT `groups`.`groupids`), "
2505 "GROUP_CONCAT(DISTINCT capturecard.cardid "
2506 " ORDER BY livetvorder), "
2507 "MIN(livetvorder) livetvorder "
2509 if (!channelGroupID)
2513 " GROUP_CONCAT(grpid ORDER BY grpid) groupids "
2514 " FROM channelgroup ";
2516 sql +=
" WHERE grpid = :CHANGROUPID ";
2517 sql +=
" GROUP BY chanid "
2519 " ON channel.chanid = `groups`.`chanid` ";
2520 if (!ignoreUntunable && !liveTVOnly)
2522 sql +=
"JOIN capturecard "
2523 " ON capturecard.sourceid = channel.sourceid "
2524 " AND capturecard.parentid = 0 ";
2526 sql +=
" AND capturecard.livetvorder > 0 ";
2528 sql +=
"WHERE channel.deleted IS NULL ";
2530 sql +=
"AND channel.visible > 0 ";
2533 sql +=
"AND channel.sourceid = :SOURCEID ";
2536 sql +=
"GROUP BY channel.callsign ";
2538 sql +=
"GROUP BY channel.callsign, channel.channum ";
2540 sql +=
"GROUP BY channel.chanid ";
2543 sql +=
"ORDER BY channel.name ";
2547 sql +=
"ORDER BY LPAD(CAST(channel.channum AS UNSIGNED), 10, 0), "
2548 " LPAD(channel.channum, 10, 0) ";
2552 sql +=
"ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM DESC, "
2553 " callsign = :CALLSIGN2 DESC, "
2555 " channel.recpriority DESC, "
2560 sql +=
"LIMIT :LIMIT ";
2563 sql +=
"OFFSET :STARTINDEX ";
2566 if (startIndex > 0 || count > 0)
2567 sql = sql.arg(
"SQL_CALC_FOUND_ROWS");
2573 if (channelGroupID > 0)
2574 query.
bindValue(
":CHANGROUPID", channelGroupID);
2583 query.
bindValue(
":STARTINDEX", startIndex);
2587 query.
bindValue(
":CALLSIGN1", callsign);
2589 query.
bindValue(
":CALLSIGN2", callsign);
2598 QList<uint> groupIdList;
2599 while (query.
next())
2615 channelInfo.
m_hue = query.
value(13).toUInt();
2632 QStringList groupIDs = query.
value(28).toString().split(
",");
2633 groupIdList.clear();
2634 while (!groupIDs.isEmpty())
2635 groupIdList.push_back(groupIDs.takeFirst().toUInt());
2636 std::sort(groupIdList.begin(), groupIdList.end());
2637 for (
auto groupId : groupIdList)
2640 QStringList parentIDs = query.
value(29).toString().split(
",");
2641 while (!parentIDs.isEmpty())
2643 auto parentId = parentIDs.takeFirst().toUInt();
2645 auto childIdList = childIdLists[parentId];
2646 for (
auto childId : childIdList)
2650 channelList.push_back(channelInfo);
2653 if ((startIndex > 0 || count > 0) &&
2654 query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
2655 totalAvailable = query.
value(0).toUInt();
2657 totalAvailable = query.
size();