7 #include <QDomDocument>
16 #define LOC QString("VBox: ")
19 {
"http://{URL}/cgi-bin/HttpControl/HttpControlApp?OPTION=1&Method=QueryBoardInfo" };
21 {
"http://{URL}/cgi-bin/HttpControl/HttpControlApp?OPTION=1&Method=GetXmltvChannelsList" \
22 "&FromChIndex=FirstChannel&ToChIndex=LastChannel&FilterBy=All" };
24 static constexpr std::chrono::milliseconds
SEARCH_TIME { 3s };
25 static constexpr
const char*
VBOX_URI {
"urn:schemas-upnp-org:device:MediaServer:1" };
26 static constexpr
const char*
VBOX_UDN {
"uuid:b7531642-0123-3210" };
31 const std::chrono::milliseconds milliSeconds {
SEARCH_TIME };
32 auto seconds = duration_cast<std::chrono::seconds>(milliSeconds);
37 if (!result.isEmpty())
41 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using UPNP to search for Vboxes (%1 secs)")
42 .arg(seconds.count()));
50 while (totalTime.
elapsed() < milliSeconds)
52 std::this_thread::sleep_for(25ms);
53 auto ttl = duration_cast<std::chrono::seconds>(milliSeconds - totalTime.
elapsed());
54 if ((searchTime.
elapsed() > 249ms) && (ttl > 1s))
56 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UPNP Search %1 secs")
74 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"No UPnP VBoxes found");
78 int count = vboxes->
Count();
81 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
82 QString(
"Found %1 possible VBoxes").arg(count));
86 LOG(VB_GENERAL, LOG_ERR,
LOC +
87 "No UPnP VBoxes found, but SSDP::Find() not NULL");
93 for (
auto *BE : qAsConst(map))
95 if (!BE->GetDeviceDesc())
97 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"GetDeviceDesc() failed for %1").arg(BE->GetFriendlyName()));
101 QString friendlyName = BE->GetDeviceDesc()->m_rootDevice.m_sFriendlyName;
102 QString ip = BE->GetDeviceDesc()->m_hostUrl.host();
103 QString udn = BE->GetDeviceDesc()->m_rootDevice.m_sUDN;
104 int port = BE->GetDeviceDesc()->m_hostUrl.port();
106 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Found possible VBox at %1 (%2:%3)")
107 .arg(friendlyName, ip, QString::number(port)));
113 int startPos = friendlyName.indexOf(
'(');
114 int endPos = friendlyName.indexOf(
')');
116 if (startPos != -1 && endPos != -1)
117 id = friendlyName.mid(startPos + 1, endPos - startPos - 1);
128 for (
int x = 0; x < tuners.count(); x++)
132 const QString& tuner = tuners.at(x);
133 QString device = QString(
"%1 %2 %3").arg(
id, ip, tuner);
135 LOG(VB_GENERAL, LOG_INFO, QString(
"Found VBox - %1").arg(device));
154 QStringList devItems = dev.split(
"-");
156 if (devItems.size() != 3)
158 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Got malformed videodev %1").arg(dev));
162 QString
id = devItems.at(0).trimmed();
165 static const QRegularExpression ipRE { R
"(^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$)" };
166 auto match = ipRE.match(
id);
167 if (match.hasMatch())
173 for (
int x = 0; x < vboxes.count(); x++)
175 QStringList vboxItems = vboxes.at(x).split(
" ");
176 if (vboxItems.size() != 4)
178 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Got malformed probed device %1").arg(vboxes.at(x)));
182 const QString& vboxID = vboxItems.at(0);
183 QString vboxIP = vboxItems.at(1);
195 auto *xmlDoc =
new QDomDocument();
198 query.replace(
"{URL}",
m_url);
218 QStringList sList = requiredVersion.split(
'.');
221 if (sList.count() < 3 || !requiredVersion.startsWith(
"V"))
223 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Failed to parse required version from %1").arg(requiredVersion));
228 int requiredMajor = sList[1].toInt();
229 int requiredMinor = sList[2].toInt();
235 QDomElement elem = xmlDoc->documentElement();
244 if (sList.count() < 3 || !(
version.startsWith(
"VB.") ||
version.startsWith(
"VJ.")
247 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Failed to parse version from %1").arg(
version));
252 major = sList[1].toInt();
253 minor = sList[2].toInt();
258 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"CheckVersion - required: %1, actual: %2")
261 if (major < requiredMajor)
264 if (major == requiredMajor &&
minor < requiredMinor)
276 QDomElement elem = xmlDoc->documentElement();
282 for (
int x = 1; x <= noTuners; x++)
284 QString tuner =
getStrValue(elem, QString(
"Tuner%1").arg(x));
285 QString s = QString(
"%1 %2").arg(x).arg(tuner);
299 auto *xmlDoc =
new QDomDocument();
302 query.replace(
"{URL}",
m_url);
311 QDomNodeList chanNodes = xmlDoc->elementsByTagName(
"channel");
313 for (
int x = 0; x < chanNodes.count(); x++)
315 QDomElement chanElem = chanNodes.at(x).toElement();
316 QString xmltvid = chanElem.attribute(
"id",
"UNKNOWN_ID");
317 QString name =
getStrValue(chanElem,
"display-name", 0);
318 QString chanType =
getStrValue(chanElem,
"display-name", 1);
319 QString triplet =
getStrValue(chanElem,
"display-name", 2);
320 bool fta = (
getStrValue(chanElem,
"display-name", 3) ==
"Free");
321 QString lcn =
getStrValue(chanElem,
"display-name", 4);
322 uint serviceID = triplet.right(4).toUInt(
nullptr, 16);
324 QString transType =
"UNKNOWN";
325 QStringList slist = triplet.split(
'-');
326 uint networkID = slist[2].left(4).toUInt(
nullptr, 16);
327 uint transportID = slist[2].mid(4, 4).toUInt(
nullptr, 16);
328 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"NIT/TID/SID %1 %2 %3)").arg(networkID).arg(transportID).arg(serviceID));
332 if (slist.count() == 3)
333 transType = slist[0];
336 QDomNodeList iconNodes = chanElem.elementsByTagName(
"icon");
337 if (iconNodes.count())
339 QDomElement iconElem = iconNodes.at(0).toElement();
340 icon = iconElem.attribute(
"src",
"");
344 QDomNodeList urlNodes = chanElem.elementsByTagName(
"url");
345 if (urlNodes.count())
347 QDomElement urlElem = urlNodes.at(0).toElement();
348 url = urlElem.attribute(
"src",
"");
351 VBoxChannelInfo chanInfo(name, xmltvid, url, fta, chanType, transType, serviceID, networkID, transportID);
352 result->insert(lcn, chanInfo);
369 if (!xmlDoc->setContent(result,
false, &errorMsg, &errorLine, &errorColumn))
371 LOG(VB_GENERAL, LOG_ERR,
LOC +
372 QString(
"Error parsing: %1\nat line: %2 column: %3 msg: %4").
373 arg(query).arg(errorLine).arg(errorColumn).arg(errorMsg));
378 QDomNodeList statusNodes = xmlDoc->elementsByTagName(
"Status");
380 if (!statusNodes.count())
381 statusNodes = xmlDoc->elementsByTagName(
"Error");
383 if (statusNodes.count())
385 QDomElement elem = statusNodes.at(0).toElement();
389 QString errorDesc =
getStrValue(elem,
"ErrorDescription");
394 LOG(VB_GENERAL, LOG_ERR,
LOC +
395 QString(
"API Error: %1 - %2, Query was: %3").arg(errorCode).arg(errorDesc, query));
407 QDomNodeList nodes = element.elementsByTagName(name);
408 if (!nodes.isEmpty())
410 if (index >= nodes.count())
412 QDomElement e = nodes.at(index).toElement();
423 return value.toInt();
428 for (QDomNode dname = element.firstChild(); !dname.isNull();
429 dname = dname.nextSibling())
431 QDomText
t = dname.toText();