16#include <QElapsedTimer>
28#define LOC QString("ChanImport: ")
58 "WHERE videosource.sourceid = :SOURCEID");
64 else if (query.
next())
66 lcnOffset = query.
value(0).toUInt();
69 LOG(VB_CHANSCAN, LOG_INFO,
LOC +
70 QString(
"Logical Channel Number offset:%1")
77 bool _delete,
bool insert,
bool save,
78 bool fta_only,
bool lcn_only,
bool complete_only,
79 bool full_channel_search,
80 bool remove_duplicates,
84 m_isInteractive(interactive),
90 m_completeOnly(complete_only),
91 m_fullChannelSearch(full_channel_search),
92 m_removeDuplicates(remove_duplicates),
94 m_serviceRequirements(service_requirements)
108 if (_transports.empty())
114 LOG(VB_GENERAL, LOG_INFO,
LOC + (channels ?
116 QString(
"Found %1 channels")
118 "No new channels to process") :
119 "No channels to process.."));
123 msg = tr(
"Failed to find any channels.");
125 msg = tr(
"Found %n channel(s)",
"", channels);
127 msg = tr(
"Failed to find any new channels!");
138 "No new channels to process" :
139 "No channels to process..");
153 QTextStream ssMsg(&msg);
159 const char *desired {
"all" };
163 desired =
"tv+radio";
164 ssMsg << Qt::endl << Qt::endl;
165 ssMsg <<
"Scan parameters:" << Qt::endl;
166 ssMsg <<
"Desired Services : " << desired << Qt::endl;
167 ssMsg <<
"Unencrypted Only : " << (
m_ftaOnly ?
"yes" :
"no") << Qt::endl;
168 ssMsg <<
"Logical Channel Numbers only: " << (
m_lcnOnly ?
"yes" :
"no") << Qt::endl;
169 ssMsg <<
"Complete scan data required : " << (
m_completeOnly ?
"yes" :
"no") << Qt::endl;
170 ssMsg <<
"Full search for old channels: " << (
m_fullChannelSearch ?
"yes" :
"no") << Qt::endl;
175 if (!transports.empty())
178 ssMsg <<
"Transport list before processing (" << transports.size() <<
"):" << Qt::endl;
183 ssMsg <<
"Channel list before processing (";
187 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
201 if (!duplicates.empty())
205 ssMsg <<
"Discarded duplicate transports (" << duplicates.size() <<
"):" << Qt::endl;
207 ssMsg <<
"Discarded duplicate channels (" <<
SimpleCountChannels(duplicates) <<
"):" << Qt::endl;
208 ssMsg <<
FormatChannels(duplicates).toLatin1().constData() << Qt::endl;
209 LOG(VB_CHANSCAN, LOG_INFO,
LOC + msg);
233 if (!db_trans.empty())
236 ssMsg <<
"Transports with channels in DB but not in scan (";
237 ssMsg << db_trans.size() <<
"):" << Qt::endl;
248 ssMsg <<
"Channel list after compare with database (";
280 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
317 std::vector<uint> off_air_list;
318 QMap<uint,bool> deleted;
321 for (
size_t i = 0; i < transports.size(); ++i)
324 for (
size_t j = 0; j < transports[i].m_channels.size(); ++j)
333 off_air_list.push_back(i<<16|j);
338 off_air_transports.push_back(transport_copy);
341 if (off_air_list.empty())
347 std::cout <<
FormatChannels(off_air_transports, &infoA).toLatin1().constData() <<
'\n';
352 QString msg = tr(
"Found %n off-air channel(s).",
"", off_air_list.size());
361 for (
uint item : off_air_list)
364 int j = item & 0xFFFF;
366 transports[i].m_channels[j].m_channelId);
367 deleted[item] =
true;
372 for (
uint item : off_air_list)
375 int j = item & 0xFFFF;
376 int chanid = transports[i].m_channels[j].m_channelId;
395 newlist.reserve(transports.size());
396 for (
size_t i = 0; i < transports.size(); ++i)
398 newlist.push_back(transports[i]);
399 newlist.back().m_channels.clear();
400 for (
size_t j = 0; j < transports[i].m_channels.size(); ++j)
402 if (!deleted.contains(i<<16|j))
404 newlist.back().m_channels.push_back(
405 transports[i].m_channels[j]);
410 transports = newlist;
411 return deleted.size();
418 "SELECT mplexid FROM dtv_multiplex "
419 "WHERE sourceid = :SOURCEID1 AND "
423 " WHERE sourceid = :SOURCEID2)");
432 QString msg = tr(
"Found %n unused transport(s).",
"", query.
size());
433 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
437 if (query.
size() == 0)
447 "DELETE FROM dtv_multiplex "
448 "WHERE sourceid = :SOURCEID1 AND "
452 " WHERE sourceid = :SOURCEID2)");
464 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Manual delete of transport not implemented");
495 QString msg = tr(
"Found %n old %1 channel(s).",
"", old_chan)
504 QString msg = tr(
"Found %n new %1 channel(s).",
"", new_chan)
532 QString msg = tr(
"Found %n conflicting old %1 channel(s).",
541 QString msg = tr(
"Found %n new conflicting %1 channel(s).",
550 QTextStream ssMsg(&msg);
552 if (!updated.empty())
554 ssMsg << Qt::endl << Qt::endl;
555 ssMsg <<
"Updated old transports (" << updated.size() <<
"):" << Qt::endl;
562 if (!skipped_updates.empty())
565 ssMsg <<
"Skipped old channels (" <<
SimpleCountChannels(skipped_updates) <<
"):" << Qt::endl;
568 if (!inserted.empty())
574 if (!skipped_inserts.empty())
577 ssMsg <<
"Skipped new channels (" <<
SimpleCountChannels(skipped_inserts) <<
"):" << Qt::endl;
589 ssMsg <<
GetSummary(ninfo, nstats).toLatin1().constData();
591 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
615 bool cancel_all =
false;
619 inserted_list.reserve(transports.size());
620 skipped_list.reserve(transports.size());
621 next_list.reserve(transports.size());
625 for (
const auto & transport : transports)
631 for (
size_t j = 0; j < transport.m_channels.size(); ++j)
673 bool conflicting =
false;
682 bool ok_done =
false;
722 bool inserted =
false;
764 if (!transport.m_iptvTuning.GetDataURL().isEmpty())
766 transport.m_iptvTuning);
789 next_list.push_back(new_transport);
792 skipped_list.push_back(skipped_transport);
795 inserted_list.push_back(inserted_transport);
823 updated_list.reserve(transports.size());
824 skipped_list.reserve(transports.size());
825 next_list.reserve(transports.size());
829 for (
const auto & transport : transports)
835 for (
size_t j = 0; j < transport.m_channels.size(); ++j)
853 bool conflicting =
false;
872 bool updated =
false;
934 next_list.push_back(new_transport);
937 skipped_list.push_back(skipped_transport);
940 updated_list.push_back(updated_transport);
963 transport_copy = transport;
979 if (!transports.empty())
980 tuner_type = transports[0].m_tunerType;
985 uint freq_mult = is_dvbs ? 1 : 1000;
987 std::vector<bool> ignore;
988 ignore.resize(transports.size());
989 for (
size_t i = 0; i < transports.size(); ++i)
994 for (
size_t j = i+1; j < transports.size(); ++j)
996 if (!transports[i].IsEqual(
997 tuner_type, transports[j], 500 * freq_mult))
1002 for (
size_t k = 0; k < transports[j].m_channels.size(); ++k)
1004 bool found_same =
false;
1005 for (
size_t l = 0; l < transports[i].m_channels.size(); ++l)
1007 if (transports[j].m_channels[k].IsSameChannel(
1008 transports[i].m_channels[l]))
1011 transports[i].m_channels[l].ImportExtraInfo(
1012 transports[j].m_channels[k]);
1016 transports[i].m_channels.push_back(transports[j].m_channels[k]);
1018 LOG(VB_CHANSCAN, LOG_INFO,
LOC +
1019 QString(
"Transport on same frequency:") +
FormatTransport(transports[j]));
1022 no_dups.push_back(transports[i]);
1024 transports = no_dups;
1039 LOG(VB_CHANSCAN, LOG_INFO,
LOC +
1040 QString(
"Number of transports:%1").arg(transports.size()));
1043 std::vector<bool> ignore;
1044 no_dups.reserve(transports.size());
1045 ignore.resize(transports.size());
1046 for (
size_t i = 0; i < transports.size(); ++i)
1049 LOG(VB_CHANSCAN, LOG_INFO,
LOC +
"Transport " +
1054 for (
size_t j = i+1; j < transports.size(); ++j)
1057 bool found_same =
true;
1058 bool found_diff =
true;
1061 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC +
"Comparing transport A " +
1063 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC +
"Comparing transport B " +
1066 for (
size_t k = 0; found_same && k < tb.
m_channels.size(); ++k)
1080 if (found_same && !found_diff)
1082 size_t lowss = transports[i].m_signalStrength < transports[j].m_signalStrength ? i : j;
1083 ignore[lowss] =
true;
1084 duplicates.push_back(transports[lowss]);
1086 LOG(VB_CHANSCAN, LOG_INFO,
LOC +
"Duplicate transports found:");
1095 no_dups.push_back(transports[i]);
1099 transports = no_dups;
1107 for (
auto & transport : transports)
1110 for (
auto & channel : transport.m_channels)
1112 if (
m_ftaOnly && channel.m_isEncrypted &&
1116 if (require_a && channel.m_isDataService)
1119 if (require_av && channel.m_isAudioService)
1123 if (
m_lcnOnly && channel.m_chanNum.isEmpty())
1126 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"No LCN: %1").arg(msg));
1132 !(channel.m_inPat &&
1136 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Not in PAT/PMT: %1").arg(msg));
1142 channel.m_atscMajorChannel == 0 &&
1143 channel.m_atscMinorChannel == 0 &&
1144 (!channel.m_inPat ||
1147 (channel.m_patTsId !=
1148 channel.m_sdtTsId)))
1151 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Not in PAT/PMT/SDT: %1").arg(msg));
1159 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"No name: %1").arg(msg));
1164 if (channel.m_inChannelsConf &&
1165 !(channel.m_inPat ||
1172 filtered.push_back(channel);
1174 transport.m_channels = filtered;
1180 QMap<uint64_t, bool> rs;
1183 for (
auto & transport : transports)
1185 for (
auto & channel : transport.m_channels)
1187 if (channel.m_oldOrigNetId > 0)
1189 uint64_t key = ((uint64_t)channel.m_oldOrigNetId << 32) | (channel.m_oldTsId << 16) | channel.m_oldServiceId;
1196 for (
auto & transport : transports)
1199 for (
auto & channel : transport.m_channels)
1201 uint64_t key = ((uint64_t)channel.m_origNetId << 32) | (channel.m_sdtTsId << 16) | channel.m_serviceId;
1202 if (rs.value(key,
false))
1205 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Relocated: %1").arg(msg));
1208 filtered.push_back(channel);
1210 transport.m_channels = filtered;
1217 QMap<qlonglong, uint> map_sid_scn;
1218 QMap<qlonglong, uint> map_sid_lcn;
1219 QMap<uint, qlonglong> map_lcn_sid;
1221 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Process DVB Channel Numbers"));
1222 for (
auto & transport : transports)
1224 for (
auto & channel : transport.m_channels)
1226 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC + QString(
"Channel onid:%1 sid:%2 lcn:%3 scn:%4")
1227 .arg(channel.m_origNetId).arg(channel.m_serviceId).arg(channel.m_logicalChannel)
1228 .arg(channel.m_simulcastChannel));
1229 qlonglong key = ((qlonglong)channel.m_origNetId<<32) | channel.m_serviceId;
1230 if (channel.m_logicalChannel > 0)
1232 map_sid_lcn[key] = channel.m_logicalChannel;
1233 map_lcn_sid[channel.m_logicalChannel] = key;
1235 if (channel.m_simulcastChannel > 0)
1237 map_sid_scn[key] = channel.m_simulcastChannel;
1255 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Process Simulcast Channel Numbers"));
1257 QMap<qlonglong, uint>::iterator it;
1258 for (it = map_sid_scn.begin(); it != map_sid_scn.end(); ++it)
1261 qlonglong key_hd = it.key();
1263 uint lcn_sd = scn_hd;
1264 uint lcn_hd = map_sid_lcn[key_hd];
1266 qlonglong key_sd = map_lcn_sid[lcn_sd];
1268 map_sid_lcn[key_sd] = lcn_hd;
1269 map_sid_lcn[key_hd] = lcn_sd;
1270 map_lcn_sid[lcn_hd] = key_sd;
1271 map_lcn_sid[lcn_sd] = key_hd;
1276 LOG(VB_CHANSCAN, LOG_INFO,
LOC + QString(
"Process Logical Channel Numbers"));
1277 for (
auto & transport : transports)
1279 for (
auto & channel : transport.m_channels)
1281 if (channel.m_chanNum.isEmpty())
1283 qlonglong key = ((qlonglong)channel.m_origNetId<<32) | channel.m_serviceId;
1284 QMap<qlonglong, uint>::const_iterator it = map_sid_lcn.constFind(key);
1285 if (it != map_sid_lcn.cend())
1287 channel.m_chanNum = QString::number(*it +
m_lcnOffset);
1288 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC +
1289 QString(
"Final channel sid:%1 channel %2")
1290 .arg(channel.m_serviceId).arg(channel.m_chanNum));
1294 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC +
1295 QString(
"Final channel sid:%1 NO channel number")
1296 .arg(channel.m_serviceId));
1301 LOG(VB_CHANSCAN, LOG_DEBUG,
LOC +
1302 QString(
"Final channel sid:%1 has already channel number %2")
1303 .arg(channel.m_serviceId).arg(channel.m_chanNum));
1320 int found_in_same_transport = 0;
1321 int found_in_other_transport = 0;
1322 int found_nowhere = 0;
1325 if (!transports.empty())
1326 tuner_type = transports[0].m_tunerType;
1332 uint freq_mult = is_dvbs ? 1 : 1000;
1337 "FROM dtv_multiplex "
1338 "WHERE sourceid = :SOURCEID "
1340 "ORDER BY mplexid");
1349 QMap<uint,bool> found_in_scan;
1350 while (query.
next())
1354 if (db_transport.
FillFromDB(tuner_type, mplexid))
1362 bool found_transport =
false;
1363 QMap<uint,bool> found_in_database;
1366 for (
size_t ist = 0; ist < transports.size(); ++ist)
1369 if (scan_transport.
IsEqual(tuner_type, db_transport, 500 * freq_mult,
true))
1371 found_transport =
true;
1373 for (
size_t jdc = 0; jdc < db_transport.
m_channels.size(); ++jdc)
1375 if (!found_in_database[jdc])
1378 for (
size_t ksc = 0; ksc < scan_transport.
m_channels.size(); ++ksc)
1380 if (!found_in_scan[(ist<<16)+ksc])
1385 found_in_same_transport++;
1386 found_in_database[jdc] =
true;
1387 found_in_scan[(ist<<16)+ksc] =
true;
1404 for (
size_t ist = 0; ist < transports.size(); ++ist)
1407 for (
size_t jdc = 0; jdc < db_transport.
m_channels.size(); ++jdc)
1409 if (!found_in_database[jdc])
1412 for (
size_t ksc = 0; ksc < scan_transport.
m_channels.size(); ++ksc)
1414 if (!found_in_scan[(ist<<16)+ksc])
1419 found_in_other_transport++;
1420 found_in_database[jdc] =
true;
1421 found_in_scan[(ist<<16)+ksc] =
true;
1435 if (found_transport)
1440 for (
size_t idc = 0; idc < db_transport.
m_channels.size(); ++idc)
1442 if (!found_in_database[idc])
1450 not_in_scan.push_back(tmp);
1453 LOG(VB_GENERAL, LOG_INFO,
LOC +
1454 QString(
"Old channels found in same transport: %1")
1455 .arg(found_in_same_transport));
1456 LOG(VB_GENERAL, LOG_INFO,
LOC +
1457 QString(
"Old channels found in other transport: %1")
1458 .arg(found_in_other_transport));
1459 LOG(VB_GENERAL, LOG_INFO,
LOC +
1460 QString(
"Old channels not found (off-air): %1")
1461 .arg(found_nowhere));
1469 for (
auto & transport : transports)
1471 for (
auto & chan : transport.m_channels)
1473 if (((chan.m_couldBeOpencable && (chan.m_siStandard ==
"mpeg")) ||
1474 chan.m_isOpencable) && !chan.m_inVct)
1476 chan.m_siStandard =
"opencable";
1486 for (
const auto & transport : transports)
1488 for (
const auto & chan : transport.m_channels)
1491 if (chan.m_isEncrypted)
1493 if (chan.m_siStandard ==
"atsc")
info.m_atscChannels[enc] += 1;
1494 if (chan.m_siStandard ==
"dvb")
info.m_dvbChannels[enc] += 1;
1495 if (chan.m_siStandard ==
"mpeg")
info.m_mpegChannels[enc] += 1;
1496 if (chan.m_siStandard ==
"opencable")
info.m_scteChannels[enc] += 1;
1497 if (chan.m_siStandard ==
"ntsc")
info.m_ntscChannels[enc] += 1;
1498 if (chan.m_siStandard !=
"ntsc")
1500 ++
info.m_progNumCnt[chan.m_serviceId];
1503 if (chan.m_siStandard ==
"atsc")
1505 ++
info.m_atscNumCnt[(chan.m_atscMajorChannel << 16) |
1506 (chan.m_atscMinorChannel)];
1507 ++
info.m_atscMinCnt[chan.m_atscMinorChannel];
1508 ++
info.m_atscMajCnt[chan.m_atscMajorChannel];
1510 if (chan.m_siStandard ==
"ntsc")
1512 ++
info.m_atscNumCnt[(chan.m_atscMajorChannel << 16) |
1513 (chan.m_atscMinorChannel)];
1527 for (
const auto & transport : transports)
1529 for (
const auto & chan : transport.m_channels)
1532 (
info.m_progNumCnt[chan.m_serviceId] == 1) ? 1 : 0;
1534 (
info.m_chanNumCnt[
map_str(chan.m_chanNum)] == 1) ? 1 : 0;
1536 if (chan.m_siStandard ==
"atsc")
1539 (
info.m_atscNumCnt[(chan.m_atscMajorChannel << 16) |
1540 (chan.m_atscMinorChannel)] == 1) ? 1 : 0;
1542 (
info.m_atscMinCnt[(chan.m_atscMinorChannel)] == 1) ? 1 : 0;
1545 info.m_atscMajCnt[chan.m_atscMajorChannel]);
1563 QTextStream ssMsg(&msg);
1567 QString si_standard = (chan.
m_siStandard==
"opencable") ?
1570 if (si_standard ==
"atsc" || si_standard ==
"scte")
1572 ssMsg << (QString(
"%1:%2:%3-%4:%5:%6=%7=%8:%9")
1580 .arg(si_standard)).toLatin1().constData();
1582 else if (si_standard ==
"dvb")
1584 ssMsg << (QString(
"%1:%2:%3:%4:%5:%6=%7:%8")
1590 .arg(si_standard)).toLatin1().constData();
1594 ssMsg << (QString(
"%1:%2:%3:%4:%5")
1598 .arg(si_standard)).toLatin1().constData();
1604 msg = msg.leftJustified(72);
1609 << (QString(
"cnt(pnum:%1,channum:%2)")
1612 ).toLatin1().constData();
1617 (QString(
":atsc_cnt(tot:%1,minor:%2)")
1618 .arg(
info->m_atscNumCnt[
1622 ).toLatin1().constData();
1645 QTextStream ssMsg(&msg);
1647 QString si_standard = (chan.
m_siStandard==
"opencable") ?
1650 if (si_standard ==
"atsc" || si_standard ==
"scte")
1652 if (si_standard ==
"atsc")
1660 ssMsg << (QString(
"%1-%2")
1666 ssMsg << (QString(
"%1-%2")
1672 ssMsg << (QString(
" (%1)")
1673 .arg(chan.
m_callSign)).toLatin1().constData();
1675 else if (si_standard ==
"dvb")
1677 ssMsg << (QString(
"%1 (%2 %3)")
1679 .arg(chan.
m_netId)).toLatin1().constData();
1683 ssMsg << (QString(
"%1-%2")
1685 .toLatin1().constData();
1689 ssMsg << (QString(
"%1-%2")
1691 .toLatin1().constData();
1702 struct less_than_key
1710 std::ranges::sort(transports, less_than_key());
1714 for (
auto & transport : transports)
1716 auto fmt_chan = [transport,
info](
const QString & m,
const auto & chan)
1718 msg = std::accumulate(transport.m_channels.cbegin(), transport.m_channels.cend(),
1729 QTextStream ssMsg(&msg);
1731 ssMsg << QString(
" onid:%1").arg(transport.
m_networkID);
1741 struct less_than_key
1749 std::ranges::sort(transports, less_than_key());
1751 auto fmt_trans = [](
const QString& msg,
const auto & transport)
1753 return std::accumulate(transports.cbegin(), transports.cend(),
1754 QString(), fmt_trans);
1761 QString msg = tr(
"Channels: FTA Enc Dec\n") +
1762 QString(
"ATSC %1 %2 %3\n")
1763 .arg(
info.m_atscChannels[0],3)
1764 .arg(
info.m_atscChannels[1],3)
1765 .arg(
info.m_atscChannels[2],3) +
1766 QString(
"DVB %1 %2 %3\n")
1767 .arg(
info.m_dvbChannels [0],3)
1768 .arg(
info.m_dvbChannels [1],3)
1769 .arg(
info.m_dvbChannels [2],3) +
1770 QString(
"SCTE %1 %2 %3\n")
1771 .arg(
info.m_scteChannels[0],3)
1772 .arg(
info.m_scteChannels[1],3)
1773 .arg(
info.m_scteChannels[2],3) +
1774 QString(
"MPEG %1 %2 %3\n")
1775 .arg(
info.m_mpegChannels[0],3)
1776 .arg(
info.m_mpegChannels[1],3)
1777 .arg(
info.m_mpegChannels[2],3) +
1778 QString(
"NTSC %1\n")
1779 .arg(
info.m_ntscChannels[0],3) +
1780 tr(
"Unique: prog %1 atsc %2 atsc minor %3 channum %4\n")
1783 tr(
"Max atsc major count: %1")
1849 new_chan = old_chan = 0;
1850 for (
const auto & transport : transports)
1852 for (
const auto& chan : transport.m_channels)
1856 if (chan.m_channelId)
1868 auto add_count = [](
int count,
const auto & transport)
1869 {
return count + transport.m_channels.size(); };
1870 return std::accumulate(transports.cbegin(), transports.cend(),
1891 static QMutex s_lastFreeLock;
1892 static QMap<uint,uint> s_lastFreeChanNumMap;
1900 for (
char suffix =
'A'; suffix <=
'Z'; ++suffix)
1908 QMutexLocker locker(&s_lastFreeLock);
1910 for (last_free_chan_num++; ; ++last_free_chan_num)
1912 chanNum = QString::number(last_free_chan_num);
1916 s_lastFreeChanNumMap[chan.
m_sourceId] = last_free_chan_num;
1944 auto *deleteDialog =
1947 if (deleteDialog->Create())
1949 deleteDialog->AddButton(tr(
"Delete All"));
1950 deleteDialog->AddButton(tr(
"Set all invisible"));
1952 deleteDialog->AddButton(tr(
"Ignore All"));
1954 [
this](
const QString & ,
int result)
1974 std::cout << msg.toLatin1().constData()
1976 << tr(
"Do you want to:").toLatin1().constData()
1978 << tr(
"1. Delete All").toLatin1().constData()
1980 << tr(
"2. Set all invisible").toLatin1().constData()
1983 << tr(
"4. Ignore All").toLatin1().constData()
1990 uint val = QString(ret.c_str()).toUInt(&ok);
1991 if (ok && (val == 1 || val == 2 || val == 4))
2001 std::cout << tr(
"Please enter either 1, 2 or 4:")
2002 .toLatin1().constData() <<
'\n';
2032 auto *insertDialog =
2035 if (insertDialog->Create())
2037 insertDialog->AddButton(tr(
"Insert All"));
2038 insertDialog->AddButton(tr(
"Insert Manually"));
2039 insertDialog->AddButton(tr(
"Ignore All"));
2041 [
this](
const QString & ,
int result)
2061 std::cout << msg.toLatin1().constData()
2063 << tr(
"Do you want to:").toLatin1().constData()
2065 << tr(
"1. Insert All").toLatin1().constData()
2067 << tr(
"2. Insert Manually").toLatin1().constData()
2069 << tr(
"3. Ignore All").toLatin1().constData()
2076 uint val = QString(ret.c_str()).toUInt(&ok);
2077 if (ok && (1 <= val) && (val <= 3))
2085 std::cout << tr(
"Please enter either 1, 2, or 3:")
2086 .toLatin1().constData() <<
'\n';
2117 auto *updateDialog =
2120 if (updateDialog->Create())
2122 updateDialog->AddButton(tr(
"Update All"));
2123 updateDialog->AddButton(tr(
"Ignore All"));
2125 [
this](
const QString& ,
int result)
2144 std::cout << msg.toLatin1().constData()
2146 << tr(
"Do you want to:").toLatin1().constData()
2148 << tr(
"1. Update All").toLatin1().constData()
2150 << tr(
"2. Update Manually").toLatin1().constData()
2152 << tr(
"3. Ignore All").toLatin1().constData()
2159 uint val = QString(ret.c_str()).toUInt(&ok);
2160 if (ok && (1 <= val) && (val <= 3))
2168 std::cout << tr(
"Please enter either 1, 2, or 3:")
2169 .toLatin1().constData() <<
'\n';
2177 const QString& title,
2178 const QString& message, QString &text)
2198 popupStack = parent->
GetStack(
"popup stack");
2200 "manualchannelpopup");
2202 if (popup->Create())
2204 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"OK"), 0 == dmc);
2205 popup->AddButtonD(tr(
"Edit"), 1 == dmc);
2206 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"Cancel"), 2 == dmc);
2207 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"Cancel All"), 3 == dmc);
2209 [
this](
const QString & ,
int result)
2240 tr(
"Please enter a unique channel number."),
2242 if (textEdit->Create())
2245 [
this,&text](QString result)
2248 text = std::move(result);
2267 case 0: rval =
kOCTOk;
break;
2277 const QString& title,
2278 const QString& message, QString &text)
2299 popupStack = parent->
GetStack(
"popup stack");
2301 "resolvechannelpopup");
2303 if (popup->Create())
2305 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"OK"), 0 == dmc);
2306 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"OK All"), 1 == dmc);
2307 popup->AddButtonD(tr(
"Edit"), 2 == dmc);
2308 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"Cancel"), 3 == dmc);
2309 popup->AddButtonD(QCoreApplication::translate(
"(Common)",
"Cancel All"), 4 == dmc);
2311 [
this](
const QString & ,
int result)
2341 tr(
"Please enter a unique channel number."),
2343 if (textEdit->Create())
2346 [
this,&text](QString result)
2349 text = std::move(result);
2369 case 0: rval =
kOCTOk;
break;
2383 QString msg = tr(
"Channel %1 has channel number %2 but that is already in use.")
2395 msg2 += tr(
"Please enter a unique channel number.");
2399 msg2 += tr(
"Default value is %1.").arg(val);
2401 tr(
"Channel Importer"),
2417 std::cout << msg.toLatin1().constData() <<
'\n';
2419 QString cancelStr = QCoreApplication::translate(
"(Common)",
2420 "Cancel").toLower();
2421 QString cancelAllStr = QCoreApplication::translate(
"(Common)",
2422 "Cancel All").toLower();
2423 QString msg2 = tr(
"Please enter a non-conflicting channel number "
2424 "(or type '%1' to skip, '%2' to skip all):")
2425 .arg(cancelStr, cancelAllStr);
2429 std::cout << msg2.toLatin1().constData() <<
'\n';
2432 QString val = QString(sret.c_str());
2433 if (val.toLower() == cancelStr)
2438 if (val.toLower() == cancelAllStr)
2461 QString msg = tr(
"You chose to manually insert channel %1.")
2472 msg2 += tr(
"Please enter a unique channel number.");
2476 msg2 += tr(
"Default value is %1").arg(val);
2478 tr(
"Channel Importer"),
2495 std::cout << msg.toLatin1().constData() <<
'\n';
2497 QString cancelStr = QCoreApplication::translate(
"(Common)",
"Cancel").toLower();
2498 QString cancelAllStr = QCoreApplication::translate(
"(Common)",
"Cancel All").toLower();
2501 QString msg2 = tr(
"Please enter a non-conflicting channel number "
2502 "(or type '%1' to skip, '%2' to skip all): ")
2503 .arg(cancelStr, cancelAllStr);
2507 std::cout << msg2.toLatin1().constData() <<
'\n';
2510 QString val = QString(sret.c_str());
2511 if (val.toLower() == cancelStr)
2516 if (val.toLower() == cancelAllStr)
2545 bool ok = (num.length() >= 1);
2546 ok = ok && ((num[0] >=
'0') && (num[0] <=
'9'));
2552#include "moc_channelimporter.cpp"
static QString map_str(QString str)
static void channum_not_empty(ChannelInsertInfo &chan)
static const QString kATSCChannelFormat
static uint getLcnOffset(int sourceid)
std::vector< ChannelInsertInfo > ChannelInsertInfoList
static QString ComputeSuggestedChannelNum(const ChannelInsertInfo &chan)
Compute a suggested channel number that is unique in the video source.
static ChannelImporterBasicStats CollectStats(const ScanDTVTransportList &transports)
static QString FormatTransports(const ScanDTVTransportList &transports_in)
UpdateAction QueryUserUpdate(const QString &msg)
For multiple channels.
ChannelScannerWeb * m_pWeb
static QString toString(ChannelType type)
static QString FormatTransport(const ScanDTVTransport &transport)
void ChannelNumbers(ScanDTVTransportList &transports) const
static bool IsType(const ChannelImporterBasicStats &info, const ChannelInsertInfo &chan, ChannelType type)
OkCancelType ShowManualChannelPopup(const QString &title, const QString &message, QString &text)
void Process(const ScanDTVTransportList &_transports, int sourceid=-1)
static bool CheckChannelNumber(const QString &num, const ChannelInsertInfo &chan)
static void CountChannels(const ScanDTVTransportList &transports, const ChannelImporterBasicStats &info, ChannelType type, uint &new_chan, uint &old_chan)
static void RemoveDuplicates(ScanDTVTransportList &transports, ScanDTVTransportList &duplicates)
@ kChannelTypeNonConflictingLast
@ kChannelTypeConflictingLast
@ kChannelTypeNonConflictingFirst
@ kChannelTypeConflictingFirst
static void AddChanToCopy(ScanDTVTransport &transport_copy, const ScanDTVTransport &transport, const ChannelInsertInfo &chan)
static QString SimpleFormatChannel(const ScanDTVTransport &transport, const ChannelInsertInfo &chan)
Format channel information into a simple string.
uint DeleteChannels(ScanDTVTransportList &transports)
uint DeleteUnusedTransports(uint sourceid)
bool m_keepChannelNumbers
static void MergeSameFrequency(ScanDTVTransportList &transports)
void InsertChannels(const ScanDTVTransportList &transports, const ChannelImporterBasicStats &info)
static ChannelImporterUniquenessStats CollectUniquenessStats(const ScanDTVTransportList &transports, const ChannelImporterBasicStats &info)
static void FilterRelocatedServices(ScanDTVTransportList &transports)
OkCancelType QueryUserResolve(const ScanDTVTransport &transport, ChannelInsertInfo &chan)
For a single channel.
ScanDTVTransportList UpdateChannels(const ScanDTVTransportList &transports, const ChannelImporterBasicStats &info, UpdateAction action, ChannelType type, ScanDTVTransportList &updated, ScanDTVTransportList &skipped) const
ServiceRequirements m_serviceRequirements
DeleteAction QueryUserDelete(const QString &msg)
For multiple channels.
ScanDTVTransportList GetDBTransports(uint sourceid, ScanDTVTransportList &transports) const
Adds found channel info to transports list, returns channels in DB which were not found in scan in an...
InsertAction QueryUserInsert(const QString &msg)
For multiple channels.
static QString FormatChannels(const ScanDTVTransportList &transports, const ChannelImporterBasicStats *info=nullptr)
static QString FormatChannel(const ScanDTVTransport &transport, const ChannelInsertInfo &chan, const ChannelImporterBasicStats *info=nullptr)
ChannelImporter(bool gui, bool interactive, bool _delete, bool insert, bool save, bool fta_only, bool lcn_only, bool complete_only, bool full_channel_search, bool remove_duplicates, ServiceRequirements service_requirements, bool success=false)
static void FixUpOpenCable(ScanDTVTransportList &transports)
static int SimpleCountChannels(const ScanDTVTransportList &transports)
static QString GetSummary(const ChannelImporterBasicStats &info, const ChannelImporterUniquenessStats &stats)
OkCancelType ShowResolveChannelPopup(const QString &title, const QString &message, QString &text)
void FilterServices(ScanDTVTransportList &transports) const
bool IsSameChannel(const ChannelInsertInfo &other, int relaxed=0) const
ChannelVisibleType m_visible
QString m_defaultAuthority
QWaitCondition m_waitCondition
void log(const QString &msg)
static ChannelScannerWeb * getInstance()
static bool CreateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
static bool DeleteChannel(uint channel_id)
static bool UpdateChannel(uint db_mplexid, uint source_id, uint channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid=QString(), const QString &icon=QString(), QString format=QString(), const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=INT_MIN, int tmOffset=INT_MIN, int commMethod=INT_MIN)
static uint CreateMultiplex(int sourceid, const QString &sistandard, uint64_t frequency, const QString &modulation, int transport_id=-1, int network_id=-1)
static bool SetVisible(uint channel_id, ChannelVisibleType visible)
static bool SetChannelValue(const QString &field_name, const QString &value, uint sourceid, const QString &channum)
static uint GetChannelCount(int sourceid=-1)
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
static bool CreateChannel(uint db_mplexid, uint db_sourceid, uint new_channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=0, int tmOffset=0, int commMethod=-1)
static void UpdateChannelNumberFromDB(ChannelInsertInfo &chan)
static void UpdateInsertInfoFromDB(ChannelInsertInfo &chan)
static bool IsConflicting(const QString &channum, uint sourceid=0, uint excluded_chanid=0)
bool IsEqual(DTVTunerType type, const DTVMultiplex &other, uint freq_range=0, bool fuzzy=false) const
static const int kTunerTypeDVBS2
static const int kTunerTypeDVBS1
static const int kTunerTypeATSC
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool isActive(void) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
bool IsBackend(void) const
is this process a backend process
static void DBError(const QString &where, const MSqlQuery &query)
Basic menu dialog, message and a list of options.
void Closed(QString, int)
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Dialog prompting the user to enter a text string.
bool FillFromDB(DTVTunerType type, uint mplexid) override
ChannelInsertInfoList m_channels
static bool MarkProcessed(uint scanid)
std::vector< ScanDTVTransport > ScanDTVTransportList
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
uint SaveScan(const ScanDTVTransportList &scan)