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;
993 if (channel_name.isEmpty())
997 query.
prepare(
"SELECT channum FROM channel WHERE sourceid = :SOURCEID "
999 "AND deleted IS NULL;" );
1001 query.
bindValue(
":NAME", channel_name.left(64));
1011 return query.
value(0).toString();
1015 const QString &new_channum,
1016 const QString &old_channum)
1018 if (new_channum.isEmpty() || old_channum.isEmpty())
1021 if (new_channum == old_channum)
1032 LOG(VB_CHANNEL, LOG_INFO, QString(
"IsOnSameMultiplex? %1==%2 -> %3")
1033 .arg(old_mplexid).arg(new_mplexid)
1034 .arg(old_mplexid == new_mplexid));
1036 return old_mplexid == new_mplexid;
1046 QStringList reclist;
1053 "SELECT capturecard.cardid "
1055 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1056 "WHERE channel.chanid = :CHANID AND "
1057 " capturecard.livetvorder > 0 "
1058 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1067 while (query.
next())
1068 reclist << query.
value(0).toString();
1080 QStringList reclist;
1087 "SELECT capturecard.cardid "
1089 "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1090 "WHERE channel.deleted IS NULL AND "
1091 " channel.channum = :CHANNUM AND "
1092 " capturecard.livetvorder > 0 "
1093 "ORDER BY capturecard.livetvorder, capturecard.cardid");
1102 while (query.
next())
1103 reclist << query.
value(0).toString();
1116 uint chanid,
const QString &channum)
1120 if (!channum.isEmpty())
1129 std::vector<uint> conflicting;
1134 "SELECT chanid from channel "
1135 "WHERE deleted IS NULL AND "
1136 " sourceid = :SOURCEID AND "
1137 " channum = :CHANNUM");
1143 "SELECT chanid from channel "
1144 "WHERE deleted IS NULL AND "
1145 " channum = :CHANNUM");
1152 conflicting.push_back(0);
1156 while (query.
next())
1157 conflicting.push_back(query.
value(0).toUInt());
1163 const QString& value,
1165 const QString &channum)
1170 QString(
"UPDATE channel SET channel.%1=:VALUE "
1171 "WHERE channel.channum = :CHANNUM AND "
1172 " channel.sourceid = :SOURCEID").arg(field_name));
1178 return query.
exec();
1182 const QString& value,
1188 QString(
"UPDATE channel SET channel.%1=:VALUE "
1189 "WHERE channel.chanid = :CHANID").arg(field_name));
1194 return query.
exec();
1215 "SELECT chanid, m.default_authority "
1217 "LEFT JOIN dtv_multiplex m "
1218 "ON (c.mplexid = m.mplexid) "
1219 "WHERE deleted IS NULL");
1222 while (query.
next())
1224 if (!query.
value(1).toString().isEmpty())
1227 query.
value(1).toString();
1238 "SELECT chanid, default_authority "
1240 "WHERE deleted IS NULL");
1243 while (query.
next())
1245 if (!query.
value(1).toString().isEmpty())
1248 query.
value(1).toString();
1272 static QReadWriteLock s_channelIconMapLock;
1273 static QHash<uint,QString> s_channelIconMap;
1274 static bool s_runInit =
true;
1276 s_channelIconMapLock.lockForRead();
1278 QString ret(s_channelIconMap.value(chanid,
"_cold_"));
1280 s_channelIconMapLock.unlock();
1282 if (ret !=
"_cold_")
1285 s_channelIconMapLock.lockForWrite();
1288 QString iconquery =
"SELECT chanid, icon FROM channel";
1291 iconquery +=
" WHERE visible > 0";
1293 iconquery +=
" WHERE chanid = :CHANID";
1304 s_channelIconMap.reserve(query.
size());
1305 while (query.
next())
1307 s_channelIconMap[query.
value(0).toUInt()] =
1308 query.
value(1).toString();
1314 s_channelIconMap[chanid] = (query.
next()) ?
1315 query.
value(1).toString() :
"";
1323 ret = s_channelIconMap.value(chanid,
"");
1325 s_channelIconMapLock.unlock();
1332 return tr(
"UNKNOWN",
"Synthesized callsign");
1336 int major_channel,
int minor_channel,
1342 query.
prepare(
"SELECT sourceid "
1343 "FROM dtv_multiplex "
1344 "WHERE mplexid = :MPLEXID");
1354 int source_id = query.
value(0).toInt();
1357 query.
prepare(
"SELECT chanid FROM channel,dtv_multiplex "
1358 "WHERE channel.deleted IS NULL AND "
1359 " channel.sourceid = :SOURCEID AND "
1360 " atsc_major_chan = :MAJORCHAN AND "
1361 " atsc_minor_chan = :MINORCHAN AND "
1362 " dtv_multiplex.transportid = :TRANSPORTID AND "
1363 " dtv_multiplex.mplexid = :MPLEXID AND "
1364 " dtv_multiplex.sourceid = channel.sourceid AND "
1365 " dtv_multiplex.mplexid = channel.mplexid");
1367 query.
bindValue(
":SOURCEID", source_id);
1368 query.
bindValue(
":MAJORCHAN", major_channel);
1369 query.
bindValue(
":MINORCHAN", minor_channel);
1370 query.
bindValue(
":TRANSPORTID", service_transport_id);
1374 return query.
value(0).toInt();
1378 query.
prepare(
"SELECT chanid FROM channel "
1379 "WHERE deleted IS NULL AND "
1380 "sourceid = :SOURCEID AND "
1381 "atsc_major_chan = :MAJORCHAN AND "
1382 "atsc_minor_chan = :MINORCHAN");
1384 query.
bindValue(
":SOURCEID", source_id);
1385 query.
bindValue(
":MAJORCHAN", major_channel);
1386 query.
bindValue(
":MINORCHAN", minor_channel);
1389 return query.
value(0).toInt();
1392 query.
prepare(
"SELECT chanid FROM channel "
1393 "WHERE deleted IS NULL AND "
1394 "sourceid = :SOURCEID AND "
1395 "serviceID = :SERVICEID AND "
1396 "mplexid = :MPLEXID");
1398 query.
bindValue(
":SOURCEID", source_id);
1399 query.
bindValue(
":SERVICEID", program_number);
1403 return query.
value(0).toInt();
1411 query.
prepare(
"SELECT chanid "
1413 "WHERE deleted IS NULL AND "
1414 " sourceid = :SOURCEID AND "
1415 " freqid = :FREQID");
1422 else if (query.
next())
1423 return query.
value(0).toUInt();
1431 QString qstr =
"SELECT MAX(chanid) FROM channel ";
1432 qstr += (sourceid) ?
"WHERE sourceid = :SOURCEID" :
"";
1442 else if (!query.
next())
1443 LOG(VB_GENERAL, LOG_ERR,
"Error getting chanid for new channel.");
1445 return query.
value(0).toUInt();
1456 "WHERE chanid = :CHANID");
1461 else if (query.
size() == 0)
1474 static const QRegularExpression kNonDigitRE { R
"(\D)" };
1476 int chansep = chan_num.indexOf(kNonDigitRE);
1481 chan_num.left(chansep).toInt() * 100 +
1482 chan_num.right(chan_num.length() - chansep - 1).toInt();
1486 chanid = sourceid * 10000 + chan_num.toInt();
1493 chanid = std::max(
get_max_chanid(sourceid) + 1, sourceid * 10000);
1510 uint new_channel_id,
1511 const QString &callsign,
1512 const QString &service_name,
1513 const QString &chan_num,
1515 uint atsc_major_channel,
1516 uint atsc_minor_channel,
1517 bool use_on_air_guide,
1519 const QString &freqid,
1520 const QString& icon,
1522 const QString& xmltvid,
1523 const QString& default_authority,
1531 QString chanNum = (chan_num ==
"-1") ?
1532 QString::number(service_id) : chan_num;
1535 "INSERT INTO channel "
1536 " (chanid, channum, sourceid, "
1537 " callsign, name, serviceid, ";
1538 qstr += (db_mplexid > 0) ?
"mplexid, " :
"";
1539 qstr += (!freqid.isEmpty()) ?
"freqid, " :
"";
1541 " atsc_major_chan, atsc_minor_chan, "
1542 " useonairguide, visible, tvformat, "
1543 " icon, xmltvid, default_authority, "
1544 " service_type, recpriority, tmoffset, "
1547 " (:CHANID, :CHANNUM, :SOURCEID, "
1548 " :CALLSIGN, :NAME, :SERVICEID, ";
1549 qstr += (db_mplexid > 0) ?
":MPLEXID, " :
"";
1550 qstr += (!freqid.isEmpty()) ?
":FREQID, " :
"";
1552 " :MAJORCHAN, :MINORCHAN, "
1553 " :USEOAG, :VISIBLE, :TVFORMAT, "
1554 " :ICON, :XMLTVID, :AUTHORITY, "
1555 " :SERVICETYPE, :RECPRIORITY, :TMOFFSET, "
1560 query.
bindValue (
":CHANID", new_channel_id);
1562 query.
bindValue (
":SOURCEID", db_sourceid);
1567 query.
bindValue(
":MPLEXID", db_mplexid);
1569 query.
bindValue(
":SERVICEID", service_id);
1570 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1571 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1572 query.
bindValue(
":USEOAG", use_on_air_guide);
1575 if (!freqid.isEmpty())
1578 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1583 query.
bindValue (
":SERVICETYPE", service_type);
1584 query.
bindValue (
":RECPRIORITY", recpriority);
1585 query.
bindValue (
":TMOFFSET", tmOffset);
1586 query.
bindValue (
":COMMMETHOD", commMethod);
1599 const QString &callsign,
1600 const QString &service_name,
1601 const QString &chan_num,
1603 uint atsc_major_channel,
1604 uint atsc_minor_channel,
1605 bool use_on_air_guide,
1607 const QString& freqid,
1608 const QString& icon,
1610 const QString& xmltvid,
1611 const QString& default_authority,
1620 QString tvformat = (atsc_minor_channel > 0) ?
"ATSC" : std::move(format);
1621 bool set_channum = !chan_num.isEmpty() && chan_num !=
"-1";
1622 QString qstr = QString(
1624 "SET %1 %2 %3 %4 %5 %6 %7 %8 %9 "
1625 " mplexid = :MPLEXID, serviceid = :SERVICEID, "
1626 " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
1627 " callsign = :CALLSIGN, name = :NAME, "
1628 " sourceid = :SOURCEID, useonairguide = :USEOAG, "
1629 " visible = :VISIBLE, service_type = :SERVICETYPE "
1630 "WHERE chanid=:CHANID")
1631 .arg((!set_channum) ?
"" :
"channum = :CHANNUM, ",
1632 (freqid.isEmpty()) ?
"" :
"freqid = :FREQID, ",
1633 (icon.isEmpty()) ?
"" :
"icon = :ICON, ",
1634 (tvformat.isEmpty()) ?
"" :
"tvformat = :TVFORMAT, ",
1635 (xmltvid.isEmpty()) ?
"" :
"xmltvid = :XMLTVID, ",
1636 (default_authority.isEmpty()) ?
1637 "" :
"default_authority = :AUTHORITY,",
1638 (recpriority == INT_MIN) ?
"" :
"recpriority = :RECPRIORITY, ",
1639 (tmOffset == INT_MIN) ?
"" :
"tmOffset = :TMOFFSET, ",
1640 (commMethod == INT_MIN) ?
"" :
"commmethod = :COMMMETHOD, ");
1650 query.
bindValue (
":SOURCEID", source_id);
1654 query.
bindValue(
":MPLEXID", db_mplexid);
1655 query.
bindValue(
":SERVICEID", service_id);
1656 query.
bindValue(
":MAJORCHAN", atsc_major_channel);
1657 query.
bindValue(
":MINORCHAN", atsc_minor_channel);
1658 query.
bindValue(
":USEOAG", use_on_air_guide);
1660 query.
bindValue(
":SERVICETYPE", service_type);
1662 if (!freqid.isNull())
1664 if (!tvformat.isNull())
1668 if (!xmltvid.isNull())
1670 if (!default_authority.isNull())
1671 query.
bindValue(
":AUTHORITY", default_authority);
1672 if (recpriority != INT_MIN)
1673 query.
bindValue(
":RECPRIORITY", recpriority);
1674 if (tmOffset != INT_MIN)
1676 if (commMethod != INT_MIN)
1677 query.
bindValue(
":COMMMETHOD", commMethod);
1693 "WHERE chanid = :ID");
1704 QString channum = query.
value(0).toString();
1706 if (!channum.isEmpty())
1717 "SELECT xmltvid, useonairguide, visible "
1719 "WHERE chanid = :ID");
1730 QString xmltvid = query.
value(0).toString();
1731 bool useeit = query.
value(1).toBool();
1735 if (!xmltvid.isEmpty())
1739 LOG(VB_GENERAL, LOG_ERR,
1740 "Using EIT and xmltv for the same channel "
1741 "is an unsupported configuration.");
1758 "DELETE FROM iptv_channel "
1759 "WHERE chanid=:CHANID");
1769 "INSERT INTO iptv_channel (chanid, url, type, bitrate) "
1770 "VALUES (:CHANID, :URL, :TYPE, :BITRATE)");
1815 "SET deleted = NOW() "
1816 "WHERE chanid = :ID");
1833 "SET visible = :VISIBLE "
1834 "WHERE chanid = :ID");
1851 query.
prepare(
"UPDATE dtv_multiplex "
1852 "SET serviceversion = :VERSION "
1853 "WHERE mplexid = :MPLEXID");
1870 query.
prepare(
"SELECT serviceversion "
1871 "FROM dtv_multiplex "
1872 "WHERE mplexid = :MPLEXID");
1883 return query.
value(0).toInt();
1895 "SELECT atsc_major_chan, atsc_minor_chan "
1897 "WHERE deleted IS NULL AND "
1898 " channum = :CHANNUM AND "
1899 " sourceid = :SOURCEID");
1906 else if (query.
next())
1908 major = query.
value(0).toUInt();
1918 uint &chanid,
const QString &channum,
1919 QString &tvformat, QString &modulation,
1920 QString &freqtable, QString &freqid,
1921 int &finetune, uint64_t &frequency,
1922 QString &dtv_si_std,
int &mpeg_prog_num,
1923 uint &atsc_major,
uint &atsc_minor,
1924 uint &dvb_transportid,
uint &dvb_networkid,
1937 atsc_major = atsc_minor = mplexid = 0;
1938 dvb_networkid = dvb_transportid = 0;
1944 "SELECT finetune, freqid, tvformat, freqtable, "
1945 " commmethod, mplexid, "
1946 " atsc_major_chan, atsc_minor_chan, serviceid, "
1948 "FROM channel, videosource "
1949 "WHERE channel.deleted IS NULL AND "
1950 " videosource.sourceid = channel.sourceid AND "
1951 " channum = :CHANNUM AND "
1952 " channel.sourceid = :SOURCEID "
1953 "ORDER BY channel.visible > 0 DESC, channel.chanid ");
1965 finetune = query.
value(0).toInt();
1966 freqid = query.
value(1).toString();
1967 tvformat = query.
value(2).toString();
1968 freqtable = query.
value(3).toString();
1969 commfree = (query.
value(4).toInt() == -2);
1970 mplexid = query.
value(5).toUInt();
1971 atsc_major = query.
value(6).toUInt();
1972 atsc_minor = query.
value(7).toUInt();
1973 mpeg_prog_num = (query.
value(8).isNull()) ? -1
1974 : query.
value(8).toInt();
1975 chanid = query.
value(9).toUInt();
1981 while (query.
next())
1985 if (found == 0 && chanid)
1987 LOG(VB_GENERAL, LOG_WARNING,
1988 QString(
"No visible channels for %1, using invisble chanid %2")
1989 .arg(channum).arg(chanid));
1994 LOG(VB_GENERAL, LOG_WARNING,
1995 QString(
"Found multiple visible channels for %1, using chanid %2")
1996 .arg(channum).arg(chanid));
2001 LOG(VB_GENERAL, LOG_ERR,
2002 QString(
"Could not find channel '%1' in DB for source %2 '%3'.")
2007 if (!mplexid || (mplexid == 32767))
2011 dvb_transportid, dvb_networkid, dtv_si_std);
2018 "SELECT type+0, url, bitrate "
2019 "FROM iptv_channel "
2020 "WHERE chanid = :CHANID "
2034 std::array<uint,3> bitrate { 0, 0, 0, };
2035 while (query.
next())
2038 query.
value(0).toUInt();
2042 data_url = query.
value(1).toString();
2043 bitrate[0] = query.
value(2).toUInt();
2048 fec_url0 = query.
value(1).toString();
2049 bitrate[1] = query.
value(2).toUInt();
2054 fec_url1 = query.
value(1).toString();
2055 bitrate[2] = query.
value(2).toUInt();
2079 fec_url0, bitrate[1], fec_url1, bitrate[2]);
2080 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %1 for %2")
2091 uint sourceid,
bool visible_only,
bool include_disconnected,
2092 const QString &group_by,
uint channel_groupid)
2098 QString qstr = QString(
2099 "SELECT videosource.sourceid, GROUP_CONCAT(capturecard.cardid) "
2101 "%1 JOIN capturecard ON capturecard.sourceid = videosource.sourceid "
2102 "GROUP BY videosource.sourceid")
2103 .arg((include_disconnected) ?
"LEFT" :
"");
2112 QMap<uint, QList<uint>> inputIdLists;
2113 while (query.
next())
2115 uint qSourceId = query.
value(0).toUInt();
2116 QList<uint> &inputIdList = inputIdLists[qSourceId];
2117 QStringList inputIds = query.
value(1).toString().split(
",");
2118 while (!inputIds.isEmpty())
2119 inputIdList.append(inputIds.takeFirst().toUInt());
2123 "SELECT channum, callsign, channel.chanid, "
2124 " atsc_major_chan, atsc_minor_chan, "
2125 " name, icon, mplexid, visible, "
2126 " channel.sourceid, "
2127 " GROUP_CONCAT(DISTINCT channelgroup.grpid), "
2130 "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid ");
2132 qstr +=
"WHERE deleted IS NULL ";
2135 qstr += QString(
"AND channel.sourceid='%1' ").arg(sourceid);
2138 if (channel_groupid > 0)
2139 qstr += QString(
"AND channelgroup.grpid = '%1' ").arg(channel_groupid);
2142 qstr += QString(
"AND visible > 0 ");
2144 qstr +=
" GROUP BY chanid";
2146 if (!group_by.isEmpty())
2147 qstr += QString(
", %1").arg(group_by);
2156 while (query.
next())
2158 if (query.
value(0).toString().isEmpty() || !query.
value(2).toBool())
2161 uint qSourceID = query.
value(9).toUInt();
2163 query.
value(0).toString(),
2164 query.
value(1).toString(),
2165 query.
value(2).toUInt(),
2166 query.
value(3).toUInt(),
2167 query.
value(4).toUInt(),
2168 query.
value(7).toUInt(),
2171 query.
value(5).toString(),
2172 query.
value(6).toString(),
2177 for (
auto inputId : std::as_const(inputIdLists[qSourceID]))
2180 QStringList groupIDs = query.
value(10).toString().split(
",");
2181 while (!groupIDs.isEmpty())
2182 chan.
AddGroupId(groupIDs.takeFirst().toUInt());
2184 list.push_back(chan);
2195 QString select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2197 if (onlyVisible || sourceid > 0)
2200 select +=
"AND visible > 0 ";
2202 select +=
"AND sourceid=" + QString::number(sourceid);
2205 std::vector<uint> list;
2213 while (query.
next())
2214 list.push_back(query.
value(0).toUInt());
2226 static QMutex s_sepExprLock;
2229 bool isIntA =
false;
2230 bool isIntB =
false;
2231 int a_int = a.
m_chanNum.toUInt(&isIntA);
2232 int b_int = b.
m_chanNum.toUInt(&isIntB);
2242 QMutexLocker locker(&s_sepExprLock);
2250 int major = a.
m_chanNum.left(idxA).toUInt(&tmp1);
2253 (a_major = major), (a_minor =
minor), (isIntA =
false);
2260 int major = b.
m_chanNum.left(idxB).toUInt(&tmp1);
2263 (b_major = major), (b_minor =
minor), (isIntB =
false);
2267 if ((a_minor > 0) && isIntA)
2269 int atsc_int = (QString(
"%1%2").arg(a_major).arg(a_minor)).toInt();
2270 a_minor = (atsc_int == a_int) ? a_minor : 0;
2273 if ((b_minor > 0) && isIntB)
2275 int atsc_int = (QString(
"%1%2").arg(b_major).arg(b_minor)).toInt();
2276 b_minor = (atsc_int == b_int) ? b_minor : 0;
2281 if ((a_minor || b_minor) &&
2282 (a_minor || isIntA) && (b_minor || isIntB))
2284 int a_maj = (!a_minor && isIntA) ? a_int : a_major;
2285 int b_maj = (!b_minor && isIntB) ? b_int : b_major;
2286 int cmp = a_maj - b_maj;
2290 cmp = a_minor - b_minor;
2295 if (isIntA && isIntB)
2298 int cmp = a_int - b_int;
2302 else if (isIntA ^ isIntB)
2324 select =
"SELECT chanid FROM channel WHERE deleted IS NULL ";
2326 select +=
"AND sourceid=" + QString::number(sourceid);
2334 return query.
size();
2338 bool eliminate_duplicates)
2340 bool cs = order.toLower() ==
"callsign";
2342 stable_sort(list.begin(), list.end(),
lt_callsign);
2344 stable_sort(list.begin(), list.end(),
lt_smart);
2346 if (eliminate_duplicates && !list.empty())
2349 tmp.push_back(list[0]);
2350 for (
size_t i = 1; i < list.size(); i++)
2355 tmp.push_back(list[i]);
2371 const QString &channum)
2376 for (
int i = 0; i < (int)list.size(); ++i)
2397 uint mplexid_restriction,
2398 uint chanid_restriction,
2400 bool skip_non_visible,
2401 bool skip_same_channum_and_callsign,
2402 bool skip_other_sources)
2404 auto it =
find(sorted.cbegin(), sorted.cend(), old_chanid);
2406 if (it == sorted.end())
2407 it = sorted.begin();
2409 if (it == sorted.end())
2418 if (it == sorted.begin())
2420 it =
find(sorted.begin(), sorted.end(),
2421 sorted.rbegin()->m_chanId);
2422 if (it == sorted.end())
2432 while ((it != start) &&
2434 (skip_other_sources &&
2435 it->m_sourceId != start->m_sourceId) ||
2436 (skip_same_channum_and_callsign &&
2437 it->m_chanNum == start->m_chanNum &&
2438 it->m_callSign == start->m_callSign) ||
2439 ((mplexid_restriction != 0U) &&
2440 (mplexid_restriction != it->m_mplexId)) ||
2441 ((chanid_restriction != 0U) &&
2442 (chanid_restriction != it->m_chanId))));
2450 if (it == sorted.end())
2451 it = sorted.begin();
2453 while ((it != start) &&
2455 (skip_other_sources &&
2456 it->m_sourceId != start->m_sourceId) ||
2457 (skip_same_channum_and_callsign &&
2458 it->m_chanNum == start->m_chanNum &&
2459 it->m_callSign == start->m_callSign) ||
2460 ((mplexid_restriction != 0U) &&
2461 (mplexid_restriction != it->m_mplexId)) ||
2462 ((chanid_restriction != 0U) &&
2463 (chanid_restriction != it->m_chanId))));
2466 return it->m_chanId;
2470 uint &totalAvailable,
2475 uint channelGroupID,
2477 const QString& callsign,
2478 const QString& channum,
2479 bool ignoreUntunable)
2485 QString sql = QString(
2486 "SELECT parentid, GROUP_CONCAT(cardid ORDER BY cardid) "
2488 "WHERE parentid <> 0 "
2489 "GROUP BY parentid ");
2498 QMap<uint, QList<uint>> childIdLists;
2499 while (query.
next())
2501 auto parentId = query.
value(0).toUInt();
2502 auto &childIdList = childIdLists[parentId];
2503 auto childIds = query.
value(1).toString().split(
",");
2504 while (!childIds.isEmpty())
2505 childIdList.append(childIds.takeFirst().toUInt());
2508 sql =
"SELECT %1 channum, freqid, channel.sourceid, "
2509 "callsign, name, icon, finetune, videofilters, xmltvid, "
2510 "channel.recpriority, channel.contrast, channel.brightness, "
2511 "channel.colour, channel.hue, tvformat, "
2512 "visible, outputfilters, useonairguide, mplexid, "
2513 "serviceid, atsc_major_chan, atsc_minor_chan, last_record, "
2514 "default_authority, commmethod, tmoffset, iptvid, "
2516 "GROUP_CONCAT(DISTINCT `groups`.`groupids`), "
2517 "GROUP_CONCAT(DISTINCT capturecard.cardid "
2518 " ORDER BY livetvorder), "
2519 "MIN(livetvorder) livetvorder "
2521 if (!channelGroupID)
2525 " GROUP_CONCAT(grpid ORDER BY grpid) groupids "
2526 " FROM channelgroup ";
2528 sql +=
" WHERE grpid = :CHANGROUPID ";
2529 sql +=
" GROUP BY chanid "
2531 " ON channel.chanid = `groups`.`chanid` ";
2532 if (!ignoreUntunable && !liveTVOnly)
2534 sql +=
"JOIN capturecard "
2535 " ON capturecard.sourceid = channel.sourceid "
2536 " AND capturecard.parentid = 0 ";
2538 sql +=
" AND capturecard.livetvorder > 0 ";
2540 sql +=
"WHERE channel.deleted IS NULL ";
2542 sql +=
"AND channel.visible > 0 ";
2545 sql +=
"AND channel.sourceid = :SOURCEID ";
2548 sql +=
"GROUP BY channel.callsign ";
2550 sql +=
"GROUP BY channel.callsign, channel.channum ";
2552 sql +=
"GROUP BY channel.chanid ";
2555 sql +=
"ORDER BY channel.name ";
2559 sql +=
"ORDER BY LPAD(CAST(channel.channum AS UNSIGNED), 10, 0), "
2560 " LPAD(channel.channum, 10, 0) ";
2564 sql +=
"ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM DESC, "
2565 " callsign = :CALLSIGN2 DESC, "
2567 " channel.recpriority DESC, "
2572 sql +=
"LIMIT :LIMIT ";
2575 sql +=
"OFFSET :STARTINDEX ";
2578 if (startIndex > 0 || count > 0)
2579 sql = sql.arg(
"SQL_CALC_FOUND_ROWS");
2585 if (channelGroupID > 0)
2586 query.
bindValue(
":CHANGROUPID", channelGroupID);
2595 query.
bindValue(
":STARTINDEX", startIndex);
2599 query.
bindValue(
":CALLSIGN1", callsign);
2601 query.
bindValue(
":CALLSIGN2", callsign);
2610 QList<uint> groupIdList;
2611 while (query.
next())
2627 channelInfo.
m_hue = query.
value(13).toUInt();
2644 QStringList groupIDs = query.
value(28).toString().split(
",");
2645 groupIdList.clear();
2646 while (!groupIDs.isEmpty())
2647 groupIdList.push_back(groupIDs.takeFirst().toUInt());
2648 std::sort(groupIdList.begin(), groupIdList.end());
2649 for (
auto groupId : groupIdList)
2652 QStringList parentIDs = query.
value(29).toString().split(
",");
2653 while (!parentIDs.isEmpty())
2655 auto parentId = parentIDs.takeFirst().toUInt();
2657 auto childIdList = childIdLists[parentId];
2658 for (
auto childId : childIdList)
2662 channelList.push_back(channelInfo);
2665 if ((startIndex > 0 || count > 0) &&
2666 query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
2667 totalAvailable = query.
value(0).toUInt();
2669 totalAvailable = query.
size();