21#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
22#include <QStringConverter>
30#include "libmythbase/mythconfig.h"
37#include "libmythbase/mythversion.h"
61 qRegisterMetaType<Preformat*>(
"Preformat");
62 qRegisterMetaType<V2MachineInfo*>(
"V2MachineInfo");
63 qRegisterMetaType<V2BackendStatus*>(
"V2BackendStatus");
64 qRegisterMetaType<V2Encoder*>(
"V2Encoder");
65 qRegisterMetaType<V2Program*>(
"V2Program");
66 qRegisterMetaType<V2Frontend*>(
"V2Frontend");
67 qRegisterMetaType<V2StorageGroup*>(
"V2StorageGroup");
68 qRegisterMetaType<V2Job*>(
"V2Job");
69 qRegisterMetaType<V2ChannelInfo*>(
"V2ChannelInfo");
70 qRegisterMetaType<V2RecordingInfo*>(
"V2RecordingInfo");
71 qRegisterMetaType<V2ArtworkInfoList*>(
"V2ArtworkInfoList");
72 qRegisterMetaType<V2ArtworkInfo*>(
"V2ArtworkInfo");
73 qRegisterMetaType<V2CastMemberList*>(
"V2CastMemberList");
74 qRegisterMetaType<V2CastMember*>(
"V2CastMember");
75 qRegisterMetaType<V2Input*>(
"V2Input");
76 qRegisterMetaType<V2Backend*>(
"V2Backend");
104 QDomDocument doc(
"Status" );
106 QDomProcessingInstruction encoding =
107 doc.createProcessingInstruction(
"xml",
108 R
"(version="1.0" encoding="UTF-8")");
109 doc.appendChild(encoding);
112 pResult->setmimetype(
"application/xml");
113 pResult->setbuffer(doc.toString());
120 QDomDocument doc(
"Status" );
123 QTextStream stream( &html );
126 pResult->setmimetype(
"text/html");
127 pResult->setbuffer(html);
150 pStatus->setVersion ( MYTH_BINARY_VERSION );
151 pStatus->setProtoVer ( MYTH_PROTO_VERSION );
171 backend = pStatus->AddNewBackend();
173 backend->setName(thisHost);
178 backend->setType(
"Master");
179 QStringList backends;
181 for (
const QString&
hostname : std::as_const(backends))
186 backend = pStatus->AddNewBackend();
188 backend->setType(
"Slave");
198 backend->setType(
"Slave");
201 backend = pStatus->AddNewBackend();
202 backend->setName(masterhost);
203 backend->setIP(masterip);
204 backend->setType(
"Master");
208 QMap<int, JobQueueEntry> jobs;
209 QMap<int, JobQueueEntry>::Iterator it;
215 for (it = jobs.begin(); it != jobs.end(); ++it)
217 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
221 V2Job * pJob = pStatus->AddNewJob();
223 pJob->setId( (*it).id );
224 pJob->setChanId((*it).chanid );
225 pJob->setStartTime( (*it).recstartts);
226 pJob->setStartTs( (*it).startts );
227 pJob->setInsertTime((*it).inserttime);
228 pJob->setType( (*it).type );
230 pJob->setCmds( (*it).cmds );
231 pJob->setFlags( (*it).flags );
232 pJob->setStatus( (*it).status );
234 pJob->setStatusTime( (*it).statustime);
235 pJob->setSchedRunTime( (*it).schedruntime);
236 pJob->setArgs( (*it).args );
237 if ((*it).hostname.isEmpty())
238 pJob->setHostName( QObject::tr(
"master"));
240 pJob->setHostName((*it).hostname);
241 pJob->setComment((*it).comment);
251 if (rgdAverages[0] != -1)
253 pMachineInfo->setLoadAvg1(rgdAverages[0]);
254 pMachineInfo->setLoadAvg2(rgdAverages[1]);
255 pMachineInfo->setLoadAvg3(rgdAverages[2]);
259 QDateTime GuideDataThrough;
261 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
266 pMachineInfo->setGuideStart
268 pMachineInfo->setGuideEnd(
270 pMachineInfo->setGuideStatus(
274 pMachineInfo->setGuideNext(
278 if (!GuideDataThrough.isNull())
281 pMachineInfo->setGuideThru(GuideDataThrough);
282 pMachineInfo->setGuideDays(qdtNow.daysTo(GuideDataThrough));
287 if ((!info_script.isEmpty()) && (info_script !=
"none"))
294 LOG(VB_GENERAL, LOG_ERR,
295 QString(
"Error running miscellaneous "
296 "status information script: %1").arg(info_script));
299 QByteArray input = ms.
ReadAll();
300 pStatus->setMiscellaneous(QString(input));
316 QStringList::const_iterator sit = strlist.cbegin();
317 while (sit != strlist.cend())
320 directory = *(sit++);
321 isLocalstr = *(sit++);
325 long long iTotal = (*(sit++)).toLongLong();
326 long long iUsed = (*(sit++)).toLongLong();;
327 long long iAvail = iTotal - iUsed;
333 group->setId(QString(fsID));
334 group->setTotal((
int)(iTotal>>10));
335 group->setUsed((
int)(iUsed>>10));
336 group->setFree((
int)(iAvail>>10));
337 group->setDirectory(directory);
341 long long iLiveTV = -1;
342 long long iDeleted = -1;
343 long long iExpirable = -1;
345 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
346 " WHERE recgroup = :RECGROUP;");
351 iLiveTV = query.
value(0).toLongLong();
356 iDeleted = query.
value(0).toLongLong();
358 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
359 " WHERE autoexpire = 1 "
360 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
363 iExpirable = query.
value(0).toLongLong();
365 group->setLiveTV( (
int)(iLiveTV>>20) );
366 group->setDeleted( (
int)(iDeleted>>20) );
367 group->setExpirable ( (
int)(iExpirable>>20) );
379 QDomElement root = pDoc->createElement(
"Status");
380 pDoc->appendChild(root);
384 root.setAttribute(
"time" ,
386 root.setAttribute(
"ISODate" , qdtNow.toString(
Qt::ISODate) );
387 root.setAttribute(
"version" , MYTH_BINARY_VERSION );
388 root.setAttribute(
"protoVer", MYTH_PROTO_VERSION );
392 QDomElement encoders = pDoc->createElement(
"Encoders");
393 root.appendChild(encoders);
402 if (elink !=
nullptr)
404 TVState state = elink->GetState();
405 isLocal = elink->IsLocal();
407 QDomElement encoder = pDoc->createElement(
"Encoder");
408 encoders.appendChild(encoder);
410 encoder.setAttribute(
"id" , elink->GetInputID() );
411 encoder.setAttribute(
"local" ,
static_cast<int>(isLocal));
412 encoder.setAttribute(
"connected" ,
static_cast<int>(elink->IsConnected()));
413 encoder.setAttribute(
"state" , state );
414 encoder.setAttribute(
"sleepstatus" , elink->GetSleepStatus() );
420 encoder.setAttribute(
"hostname", elink->GetHostName());
422 encoder.setAttribute(
"devlabel",
425 if (elink->IsConnected())
453 encoders.setAttribute(
"count", numencoders);
457 QDomElement scheduled = pDoc->createElement(
"Scheduled");
458 root.appendChild(scheduled);
465 unsigned int iNum = 10;
466 unsigned int iNumRecordings = 0;
468 auto itProg = recordingList.begin();
469 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
472 ((*itProg)->GetRecordingStartTime() >=
480 while (!recordingList.empty())
484 recordingList.pop_back();
487 scheduled.setAttribute(
"count", iNumRecordings);
491 QDomElement frontends = pDoc->createElement(
"Frontends");
492 root.appendChild(frontends);
495 "urn:schemas-mythtv-org:service:MythFrontend:1");
503 frontends.setAttribute(
"count", map.size() );
504 for (
const auto & entry : std::as_const(map))
506 QDomElement fe = pDoc->createElement(
"Frontend");
507 frontends.appendChild(fe);
508 QUrl url(entry->m_sLocation);
509 fe.setAttribute(
"name", url.host());
510 fe.setAttribute(
"url", url.toString(QUrl::RemovePath));
517 QDomElement backends = pDoc->createElement(
"Backends");
518 root.appendChild(backends);
528 QDomElement mbe = pDoc->createElement(
"Backend");
529 backends.appendChild(mbe);
530 mbe.setAttribute(
"type",
"Master");
531 mbe.setAttribute(
"name", masterhost);
532 mbe.setAttribute(
"url" , masterip +
":" + QString::number(masterport));
536 "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
540 QString ipaddress = QString();
549 for (
const auto & entry : std::as_const(map))
551 QUrl url(entry->m_sLocation);
552 if (url.host() != ipaddress)
555 QDomElement mbe = pDoc->createElement(
"Backend");
556 backends.appendChild(mbe);
557 mbe.setAttribute(
"type",
"Slave");
558 mbe.setAttribute(
"name", url.host());
559 mbe.setAttribute(
"url" , url.toString(QUrl::RemovePath));
565 backends.setAttribute(
"count", numbes);
569 QDomElement queue = pDoc->createElement(
"JobQueue");
570 root.appendChild(queue);
572 QMap<int, JobQueueEntry> jobs;
573 QMap<int, JobQueueEntry>::Iterator it;
579 for (it = jobs.begin(); it != jobs.end(); ++it)
581 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
585 QDomElement job = pDoc->createElement(
"Job");
586 queue.appendChild(job);
588 job.setAttribute(
"id" , (*it).id );
589 job.setAttribute(
"chanId" , (*it).chanid );
590 job.setAttribute(
"startTime" ,
592 job.setAttribute(
"startTs" , (*it).startts );
593 job.setAttribute(
"insertTime",
595 job.setAttribute(
"type" , (*it).type );
596 job.setAttribute(
"cmds" , (*it).cmds );
597 job.setAttribute(
"flags" , (*it).flags );
598 job.setAttribute(
"status" , (*it).status );
599 job.setAttribute(
"statusTime",
601 job.setAttribute(
"schedTime" ,
603 job.setAttribute(
"args" , (*it).args );
605 if ((*it).hostname.isEmpty())
606 job.setAttribute(
"hostname", QObject::tr(
"master"));
608 job.setAttribute(
"hostname",(*it).hostname);
610 QDomText textNode = pDoc->createTextNode((*it).comment);
611 job.appendChild(textNode);
616 queue.setAttribute(
"count", jobs.size() );
620 QDomElement mInfo = pDoc->createElement(
"MachineInfo");
621 QDomElement storage = pDoc->createElement(
"Storage" );
622 QDomElement load = pDoc->createElement(
"Load" );
623 QDomElement guide = pDoc->createElement(
"Guide" );
625 root.appendChild (mInfo );
626 mInfo.appendChild(storage);
627 mInfo.appendChild(load );
628 mInfo.appendChild(guide );
645 QList<QDomElement> fsXML;
646 QStringList::const_iterator sit = strlist.cbegin();
647 while (sit != strlist.cend())
650 directory = *(sit++);
651 isLocalstr = *(sit++);
655 long long iTotal = (*(sit++)).toLongLong();
656 long long iUsed = (*(sit++)).toLongLong();;
657 long long iAvail = iTotal - iUsed;
662 QDomElement group = pDoc->createElement(
"Group");
664 group.setAttribute(
"id" , fsID );
665 group.setAttribute(
"total", (
int)(iTotal>>10) );
666 group.setAttribute(
"used" , (
int)(iUsed>>10) );
667 group.setAttribute(
"free" , (
int)(iAvail>>10) );
668 group.setAttribute(
"dir" , directory );
672 long long iLiveTV = -1;
673 long long iDeleted = -1;
674 long long iExpirable = -1;
676 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
677 " WHERE recgroup = :RECGROUP;");
682 iLiveTV = query.
value(0).toLongLong();
687 iDeleted = query.
value(0).toLongLong();
689 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
690 " WHERE autoexpire = 1 "
691 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
694 iExpirable = query.
value(0).toLongLong();
696 group.setAttribute(
"livetv", (
int)(iLiveTV>>20) );
697 group.setAttribute(
"deleted", (
int)(iDeleted>>20) );
698 group.setAttribute(
"expirable", (
int)(iExpirable>>20) );
707 storage.appendChild(total);
708 int num_elements = fsXML.size();
709 for (
int fs_index = 0; fs_index < num_elements; fs_index++)
711 storage.appendChild(fsXML[fs_index]);
717 load.setAttribute(
"avg1", 0);
718 load.setAttribute(
"avg2", 1);
719 load.setAttribute(
"avg3", 2);
722 if (rgdAverages[0] != -1)
724 load.setAttribute(
"avg1", rgdAverages[0]);
725 load.setAttribute(
"avg2", rgdAverages[1]);
726 load.setAttribute(
"avg3", rgdAverages[2]);
732 QDateTime GuideDataThrough;
735 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
742 guide.setAttribute(
"start",
744 guide.setAttribute(
"end",
746 guide.setAttribute(
"status",
750 guide.setAttribute(
"next",
754 if (!GuideDataThrough.isNull())
756 guide.setAttribute(
"guideThru",
758 guide.setAttribute(
"guideDays", qdtNow.daysTo(GuideDataThrough));
764 if ((!info_script.isEmpty()) && (info_script !=
"none"))
766 QDomElement misc = pDoc->createElement(
"Miscellaneous");
767 root.appendChild(misc);
774 LOG(VB_GENERAL, LOG_ERR,
775 QString(
"Error running miscellaneous "
776 "status information script: %1").arg(info_script));
780 QByteArray input = ms.
ReadAll();
782 QStringList
output = QString(input).split(
'\n',
784 for (
const auto & line : std::as_const(
output))
786 QDomElement
info = pDoc->createElement(
"Information");
788 QStringList list = line.split(
"[]:[]");
789 unsigned int size = list.size();
790 unsigned int hasAttributes = 0;
792 if ((size > 0) && (!list[0].isEmpty()))
794 info.setAttribute(
"display", list[0]);
797 if ((size > 1) && (!list[1].isEmpty()))
799 info.setAttribute(
"name", list[1]);
802 if ((size > 2) && (!list[2].isEmpty()))
804 info.setAttribute(
"value", list[2]);
808 if (hasAttributes > 0)
809 misc.appendChild(
info);
820#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
821 os.setCodec(
"UTF-8");
823 os.setEncoding(QStringConverter::Utf8);
828 QDomElement docElem = pDoc->documentElement();
830 os <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
831 <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
832 <<
"<html xmlns=\"http://www.w3.org/1999/xhtml\""
833 <<
" xml:lang=\"en\" lang=\"en\">\r\n"
835 <<
" <meta http-equiv=\"Content-Type\""
836 <<
"content=\"text/html; charset=UTF-8\" />\r\n"
837 <<
" <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
838 <<
" <title>MythTV Status - "
842 << docElem.attribute(
"version", MYTH_BINARY_VERSION ) <<
"</title>\r\n"
844 <<
"<body bgcolor=\"#fff\">\r\n"
845 <<
"<div class=\"status\">\r\n"
846 <<
" <h1 class=\"status\">MythTV Status</h1>\r\n";
850 QDomNode node = docElem.namedItem(
"Encoders" );
857 node = docElem.namedItem(
"Scheduled" );
864 node = docElem.namedItem(
"Frontends" );
871 node = docElem.namedItem(
"Backends" );
878 node = docElem.namedItem(
"JobQueue" );
885 node = docElem.namedItem(
"MachineInfo" );
892 node = docElem.namedItem(
"Miscellaneous" );
897 os <<
"\r\n</div>\r\n</body>\r\n</html>\r\n";
907 int nNumEncoders = 0;
909 if (encoders.isNull())
912 os <<
" <div class=\"content\">\r\n"
913 <<
" <h2 class=\"status\">Encoder Status</h2>\r\n";
915 QDomNode node = encoders.firstChild();
917 while (!node.isNull())
919 QDomElement e = node.toElement();
923 if (e.tagName() ==
"Encoder")
925 QString sIsLocal = (e.attribute(
"local" ,
"remote" )==
"1")
926 ?
"local" :
"remote";
927 QString sCardId = e.attribute(
"id" ,
"0" );
928 QString sHostName = e.attribute(
"hostname" ,
"Unknown");
929 bool bConnected=
static_cast<bool>(e.attribute(
"connected",
"0" ).toInt());
931 bool bIsLowOnFreeSpace=
static_cast<bool>(e.attribute(
"lowOnFreeSpace",
"0").toInt());
933 QString sDevlabel = e.attribute(
"devlabel",
"[ UNKNOWN ]");
935 os <<
" Encoder " << sCardId <<
" " << sDevlabel
936 <<
" is " << sIsLocal <<
" on " << sHostName;
938 if ((sIsLocal ==
"remote") && !bConnected)
945 os <<
" (currently asleep).<br />";
947 os <<
" (currently not connected).<br />";
949 node = node.nextSibling();
960 os <<
" and is watching Live TV";
965 os <<
" and is recording";
969 os <<
" and is not recording.";
975 QDomNode tmpNode = e.namedItem(
"Program" );
977 if (!tmpNode.isNull())
979 QDomElement program = tmpNode.toElement();
981 if (!program.isNull())
983 os <<
" '" << program.attribute(
"title",
"Unknown" ) <<
"'";
987 tmpNode = program.namedItem(
"Channel" );
989 if (!tmpNode.isNull())
991 QDomElement channel = tmpNode.toElement();
993 if (!channel.isNull())
995 << channel.attribute(
"callSign",
"unknown" );
1000 tmpNode = program.namedItem(
"Recording" );
1002 if (!tmpNode.isNull())
1004 QDomElement recording = tmpNode.toElement();
1006 if (!recording.isNull())
1009 recording.attribute(
"recEndTs",
"" ));
1011 os <<
". This recording ";
1017 os <<
"scheduled to end at "
1027 if (bIsLowOnFreeSpace)
1029 os <<
" <strong>WARNING</strong>:"
1030 <<
" This backend is low on free disk space!";
1037 node = node.nextSibling();
1040 os <<
" </div>\r\n\r\n";
1042 return( nNumEncoders );
1053 if (scheduled.isNull())
1056 int nNumRecordings= scheduled.attribute(
"count",
"0" ).toInt();
1058 os <<
" <div class=\"content\">\r\n"
1059 <<
" <h2 class=\"status\">Schedule</h2>\r\n";
1061 if (nNumRecordings == 0)
1063 os <<
" There are no shows scheduled for recording.\r\n"
1068 os <<
" The next " << nNumRecordings <<
" show" << (nNumRecordings == 1 ?
"" :
"s" )
1069 <<
" that " << (nNumRecordings == 1 ?
"is" :
"are")
1070 <<
" scheduled for recording:\r\n";
1072 os <<
" <div class=\"schedule\">\r\n";
1076 QDomNode node = scheduled.firstChild();
1078 while (!node.isNull())
1080 QDomElement e = node.toElement();
1084 QDomNode recNode = e.namedItem(
"Recording" );
1085 QDomNode chanNode = e.namedItem(
"Channel" );
1087 if ((e.tagName() ==
"Program") && !recNode.isNull() &&
1090 QDomElement r = recNode.toElement();
1091 QDomElement c = chanNode.toElement();
1093 QString sTitle = e.attribute(
"title" ,
"" );
1094 QString sSubTitle = e.attribute(
"subTitle",
"" );
1100 int nPreRollSecs = r.attribute(
"preRollSeconds",
"0" ).toInt();
1101 int nEncoderId = r.attribute(
"encoderId" ,
"0" ).toInt();
1102 QString sProfile = r.attribute(
"recProfile" ,
"" );
1103 QString sChanName = c.attribute(
"channelName" ,
"" );
1106 QDomText text = e.firstChild().toText();
1108 sDesc = text.nodeValue();
1112 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
1118 int nTotalDays = nTotalSecs / 86400;
1119 int nTotalHours = (nTotalSecs / 3600)
1120 - (nTotalDays * 24);
1121 int nTotalMins = (nTotalSecs / 60) % 60;
1123 QString sTimeToStart =
"in";
1125 sTimeToStart += QObject::tr(
" %n day(s),",
"", nTotalDays );
1126 sTimeToStart += QObject::tr(
" %n hour(s) and",
"", nTotalHours);
1127 sTimeToStart += QObject::tr(
" %n minute(s)",
"", nTotalMins);
1129 if ( nTotalHours == 0 && nTotalMins == 0)
1130 sTimeToStart = QObject::tr(
"within one minute",
"Recording starting");
1132 if ( nTotalSecs < 0)
1133 sTimeToStart = QObject::tr(
"soon",
"Recording starting");
1137 os <<
" <a href=\"#\">";
1145 os <<
"Encoder " << nEncoderId <<
" - ";
1147 os << sChanName <<
" - " << sTitle <<
"<br />"
1148 <<
"<span><strong>" << sTitle <<
"</strong> ("
1152 if ( !sSubTitle.isEmpty())
1153 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1155 if ( airDate.isValid())
1157 os <<
"Orig. Airdate: "
1163 os << sDesc <<
"<br /><br />"
1164 <<
"This recording will start " << sTimeToStart
1165 <<
" using encoder " << nEncoderId <<
" with the '"
1166 << sProfile <<
"' profile.</span></a><hr />\r\n";
1170 node = node.nextSibling();
1172 os <<
" </div>\r\n";
1173 os <<
" </div>\r\n\r\n";
1175 return( nNumRecordings );
1184 if (frontends.isNull())
1187 int nNumFES= frontends.attribute(
"count",
"0" ).toInt();
1193 os <<
" <div class=\"content\">\r\n"
1194 <<
" <h2 class=\"status\">Frontends</h2>\r\n";
1196 QDomNode node = frontends.firstChild();
1197 while (!node.isNull())
1199 QDomElement e = node.toElement();
1203 QString name = e.attribute(
"name" ,
"" );
1204 QString url = e.attribute(
"url" ,
"" );
1205 os << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1208 node = node.nextSibling();
1211 os <<
" </div>\r\n\r\n";
1222 if (backends.isNull())
1225 int nNumBES= backends.attribute(
"count",
"0" ).toInt();
1231 os <<
" <div class=\"content\">\r\n"
1232 <<
" <h2 class=\"status\">Other Backends</h2>\r\n";
1234 QDomNode node = backends.firstChild();
1235 while (!node.isNull())
1237 QDomElement e = node.toElement();
1241 QString
type = e.attribute(
"type",
"" );
1242 QString name = e.attribute(
"name" ,
"" );
1243 QString url = e.attribute(
"url" ,
"" );
1244 os <<
type <<
": " << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1247 node = node.nextSibling();
1250 os <<
" </div>\r\n\r\n";
1264 int nNumJobs= jobs.attribute(
"count",
"0" ).toInt();
1266 os <<
" <div class=\"content\">\r\n"
1267 <<
" <h2 class=\"status\">Job Queue</h2>\r\n";
1271 QString statusColor;
1274 os <<
" Jobs currently in Queue or recently ended:\r\n<br />"
1275 <<
" <div class=\"schedule\">\r\n";
1278 QDomNode node = jobs.firstChild();
1280 while (!node.isNull())
1282 QDomElement e = node.toElement();
1286 QDomNode progNode = e.namedItem(
"Program" );
1288 if ((e.tagName() ==
"Job") && !progNode.isNull() )
1290 QDomElement
p = progNode.toElement();
1292 QDomNode recNode =
p.namedItem(
"Recording" );
1293 QDomNode chanNode =
p.namedItem(
"Channel" );
1295 QDomElement r = recNode.toElement();
1296 QDomElement c = chanNode.toElement();
1298 int nType = e.attribute(
"type" ,
"0" ).toInt();
1299 int nStatus = e.attribute(
"status",
"0" ).toInt();
1304 statusColor =
" class=\"jobaborted\"";
1309 statusColor =
" class=\"joberrored\"";
1310 jobColor =
" class=\"joberrored\"";
1314 statusColor =
" class=\"jobfinished\"";
1315 jobColor =
" class=\"jobfinished\"";
1319 statusColor =
" class=\"jobrunning\"";
1320 jobColor =
" class=\"jobrunning\"";
1324 statusColor =
" class=\"jobqueued\"";
1325 jobColor =
" class=\"jobqueued\"";
1329 QString sTitle =
p.attribute(
"title" ,
"" );
1330 QString sSubTitle =
p.attribute(
"subTitle",
"" );
1336 QString sHostname = e.attribute(
"hostname",
"master" );
1337 QString sComment =
"";
1339 QDomText text = e.firstChild().toText();
1341 sComment = text.nodeValue();
1343 os <<
"<a href=\"javascript:void(0)\">"
1347 << sTitle <<
" - <font" << jobColor <<
">"
1349 <<
"<span><strong>" << sTitle <<
"</strong> ("
1353 if (!sSubTitle.isEmpty())
1354 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1360 os <<
"Scheduled Run Time: "
1367 os <<
"Status: <font" << statusColor <<
">"
1375 if ( nStatus != JOB_QUEUED)
1376 os <<
"Host: " << sHostname <<
"<br />";
1378 if (!sComment.isEmpty())
1379 os <<
"<br />Comments:<br />" << sComment <<
"<br />";
1381 os <<
"</span></a><hr />\r\n";
1385 node = node.nextSibling();
1387 os <<
" </div>\r\n";
1391 os <<
" Job Queue is currently empty.\r\n\r\n";
1394 os <<
" </div>\r\n\r\n ";
1411 os <<
"<div class=\"content\">\r\n"
1412 <<
" <h2 class=\"status\">Machine Information</h2>\r\n";
1416 QDomNode node =
info.namedItem(
"Load" );
1420 QDomElement e = node.toElement();
1424 double dAvg1 = e.attribute(
"avg1" ,
"0" ).toDouble();
1425 double dAvg2 = e.attribute(
"avg2" ,
"0" ).toDouble();
1426 double dAvg3 = e.attribute(
"avg3" ,
"0" ).toDouble();
1428 os <<
" <div class=\"loadstatus\">\r\n"
1429 <<
" This machine's load average:"
1430 <<
"\r\n <ul>\r\n <li>"
1431 <<
"1 Minute: " << dAvg1 <<
"</li>\r\n"
1432 <<
" <li>5 Minutes: " << dAvg2 <<
"</li>\r\n"
1433 <<
" <li>15 Minutes: " << dAvg3
1434 <<
"</li>\r\n </ul>\r\n"
1440 node =
info.namedItem(
"Storage" );
1441 QDomElement storage = node.toElement();
1442 node = storage.firstChild();
1447 while (!node.isNull())
1449 QDomElement g = node.toElement();
1451 if (!g.isNull() && g.tagName() ==
"Group")
1453 QString
id = g.attribute(
"id",
"" );
1457 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1458 int nTotal = g.attribute(
"total",
"0" ).toInt();
1459 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1460 int nLiveTV = g.attribute(
"livetv" ,
"0" ).toInt();
1461 int nDeleted = g.attribute(
"deleted",
"0" ).toInt();
1462 int nExpirable = g.attribute(
"expirable" ,
"0" ).toInt();
1463 QString nDir = g.attribute(
"dir" ,
"" );
1465 nDir.replace(
",",
", ");
1467 os <<
" Disk Usage Summary:<br />\r\n";
1470 os <<
" <li>Total Disk Space:\r\n"
1473 os <<
" <li>Total Space: ";
1474 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1475 os << sRep <<
"</li>\r\n";
1477 os <<
" <li>Space Used: ";
1478 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1479 os << sRep <<
"</li>\r\n";
1481 os <<
" <li>Space Free: ";
1482 sRep = QString(
"%L1").arg(nFree) +
" MB";
1483 os << sRep <<
"</li>\r\n";
1485 if ((nLiveTV + nDeleted + nExpirable) > 0)
1487 os <<
" <li>Space Available "
1488 "After Auto-expire: ";
1489 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1490 sRep = QString(
"%L1").arg(nFree + nLiveTV +
1491 nDeleted + nExpirable) +
" MB";
1492 os << sRep <<
"\r\n";
1494 os <<
" <li>Space Used by LiveTV: ";
1495 sRep = QString(
"%L1").arg(nLiveTV) +
" MB";
1496 os << sRep <<
"</li>\r\n";
1497 os <<
" <li>Space Used by "
1498 "Deleted Recordings: ";
1499 sRep = QString(
"%L1").arg(nDeleted) +
" MB";
1500 os << sRep <<
"</li>\r\n";
1501 os <<
" <li>Space Used by "
1502 "Auto-expirable Recordings: ";
1503 sRep = QString(
"%L1").arg(nExpirable) +
" MB";
1504 os << sRep <<
"</li>\r\n";
1517 node = node.nextSibling();
1521 node = storage.firstChild();
1523 os <<
" Disk Usage Details:<br />\r\n";
1527 while (!node.isNull())
1529 QDomElement g = node.toElement();
1531 if (!g.isNull() && g.tagName() ==
"Group")
1533 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1534 int nTotal = g.attribute(
"total",
"0" ).toInt();
1535 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1536 QString nDir = g.attribute(
"dir" ,
"" );
1537 QString
id = g.attribute(
"id" ,
"" );
1539 nDir.replace(
",",
", ");
1545 os <<
" <li>MythTV Drive #" <<
id <<
":"
1549 if (nDir.contains(
','))
1550 os <<
" <li>Directories: ";
1552 os <<
" <li>Directory: ";
1554 os << nDir <<
"</li>\r\n";
1556 os <<
" <li>Total Space: ";
1557 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1558 os << sRep <<
"</li>\r\n";
1560 os <<
" <li>Space Used: ";
1561 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1562 os << sRep <<
"</li>\r\n";
1564 os <<
" <li>Space Free: ";
1565 sRep = QString(
"%L1").arg(nFree) +
" MB";
1566 os << sRep <<
"</li>\r\n";
1574 node = node.nextSibling();
1581 node =
info.namedItem(
"Guide" );
1585 QDomElement e = node.toElement();
1589 int nDays = e.attribute(
"guideDays",
"0" ).toInt();
1590 QString sStart = e.attribute(
"start" ,
"" );
1591 QString sEnd = e.attribute(
"end" ,
"" );
1592 QString sStatus = e.attribute(
"status" ,
"" );
1594 QString sNext = next.isNull() ?
"" :
1600 QDomText text = e.firstChild().toText();
1607 sMsg = text.nodeValue();
1609 os <<
" Last mythfilldatabase run started on " << sStart
1615 os <<
"ended on " << sEnd <<
". ";
1617 os << sStatus <<
"<br />\r\n";
1619 if (!next.isNull() && next >= lastrunstart)
1621 os <<
" Suggested next mythfilldatabase run: "
1622 << sNext <<
".<br />\r\n";
1627 os <<
" There's guide data until "
1631 os <<
" " << QObject::tr(
"(%n day(s))",
"", nDays);
1636 os <<
" <strong>WARNING</strong>: is mythfilldatabase running?";
1640 os <<
" There's <strong>no guide data</strong> available! "
1641 <<
"Have you run mythfilldatabase?";
1645 os <<
"\r\n </div>\r\n";
1657 QDomNodeList nodes =
info.elementsByTagName(
"Information");
1658 uint count = nodes.count();
1664 os <<
"<div class=\"content\">\r\n"
1665 <<
" <h2 class=\"status\">Miscellaneous</h2>\r\n";
1666 for (
unsigned int i = 0; i < count; i++)
1668 QDomNode node = nodes.item(i);
1672 QDomElement e = node.toElement();
1676 display = e.attribute(
"display",
"");
1680 if (display.isEmpty())
1685 if (display.contains(
"<p>", Qt::CaseInsensitive) ||
1686 display.contains(
"<br", Qt::CaseInsensitive))
1693 linebreak =
"<br />\r\n";
1696 os <<
" " << display << linebreak;
1710 if ((pDoc ==
nullptr) || (pInfo ==
nullptr))
1715 QDomElement program = pDoc->createElement(
"Program" );
1716 node.appendChild( program );
1718 program.setAttribute(
"startTime" ,
1721 program.setAttribute(
"title" , pInfo->
GetTitle() );
1722 program.setAttribute(
"subTitle" , pInfo->
GetSubtitle());
1723 program.setAttribute(
"category" , pInfo->
GetCategory());
1725 program.setAttribute(
"repeat" ,
static_cast<int>(pInfo->
IsRepeat()));
1730 program.setAttribute(
"seriesId" , pInfo->
GetSeriesID() );
1731 program.setAttribute(
"programId" , pInfo->
GetProgramID() );
1732 program.setAttribute(
"stars" , pInfo->
GetStars() );
1733 program.setAttribute(
"fileSize" ,
1735 program.setAttribute(
"lastModified",
1738 program.setAttribute(
"hostname" , pInfo->
GetHostname() );
1741 program.setAttribute(
1744 QDomText textNode = pDoc->createTextNode( pInfo->
GetDescription() );
1745 program.appendChild( textNode );
1753 QDomElement channel = pDoc->createElement(
"Channel" );
1754 program.appendChild( channel );
1763 QDomElement recording = pDoc->createElement(
"Recording" );
1764 program.appendChild( recording );
1766 recording.setAttribute(
"recStatus" ,
1768 recording.setAttribute(
"recPriority" ,
1770 recording.setAttribute(
"recStartTs" ,
1772 recording.setAttribute(
"recEndTs" ,
1777 recording.setAttribute(
"recordId" ,
1779 recording.setAttribute(
"recGroup" ,
1781 recording.setAttribute(
"playGroup" ,
1783 recording.setAttribute(
"recType" ,
1785 recording.setAttribute(
"dupInType" ,
1787 recording.setAttribute(
"dupMethod" ,
1789 recording.setAttribute(
"encoderId" ,
1792 recording.setAttribute(
"recProfile" ,
1819 channel.setAttribute(
"chanId" , pInfo->
GetChanID() );
1820 channel.setAttribute(
"chanNum" , pInfo->
GetChanNum());
1827 channel.setAttribute(
"chanFilters",
1829 channel.setAttribute(
"sourceId" , pInfo->
GetSourceID() );
1830 channel.setAttribute(
"inputId" , pInfo->
GetInputID() );
1831 channel.setAttribute(
"commFree" ,
QMap< int, EncoderLink * > gTVList
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
static QString JobText(int jobType)
static QString StatusText(int status)
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 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.
void BackendQueryDiskSpace(QStringList &strlist, bool consolidated, bool allHosts)
void GetActiveBackends(QStringList &hosts)
PlaybackSock * GetMediaServerByHostname(const QString &hostname)
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
QString GetHostName(void)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetMasterServerStatusPort(void)
Returns the Master Backend status port If no master server status port has been defined in the databa...
bool IsMasterHost(void)
is this the same host as the master
int GetNumSetting(const QString &key, int defaultval=0)
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
QString GetMasterHostName(void)
bool IsMasterBackend(void)
is this the actual MBE process
bool GetBoolSetting(const QString &key, bool defaultval=false)
uint Wait(std::chrono::seconds timeout=0s)
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
void setIP(const QString &lip)
QString getIP(void) const
Holds information on recordings and videos.
float GetStars(void) const
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
uint GetRecordingRuleID(void) const
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
QString GetSeriesID(void) const
QString GetCategoryTypeString(void) const
Returns catType as a string.
QString GetProgramID(void) const
QString GetRecordingGroup(void) const
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
QString GetChannelPlaybackFilters(void) const
RecordingDupInType GetDuplicateCheckSource(void) const
Where should we check for duplicates?
bool IsRepeat(void) const
QString GetHostname(void) const
uint GetSourceID(void) const
QString GetPlaybackGroup(void) const
QString GetDescription(void) const
QDateTime GetLastModifiedTime(void) const
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
QString GetTitle(void) const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
bool IsCommercialFree(void) const
int GetRecordingPriority(void) const
QDate GetOriginalAirDate(void) const
uint GetInputID(void) const
virtual uint64_t GetFilesize(void) const
uint32_t GetProgramFlags(void) const
RecStatus::Type GetRecordingStatus(void) const
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
QString GetSubtitle(void) const
QString GetCategory(void) const
RecordingType GetRecordingRuleType(void) const
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Holds information on a TV Program one might wish to record.
QString GetProgramRecordingProfile(void) const
Returns recording profile name that will be, or was used, for this program, creating "record" field i...
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
void GetEntryMap(EntryMap &map)
Returns a copy of the EntryMap.
static SSDPCache * Instance()
SSDPCacheEntries * Find(const QString &sURI)
Finds the SSDPCacheEntries in the cache, returns nullptr when absent.
MainServer * GetMainServer()
bool GetAllPending(RecList &retList, int recRuleId=0) const
static QReadWriteLock s_inputsLock
static QList< QHostAddress > g_IPAddrList
V2StorageGroup * AddNewStorageGroup()
static void PrintStatus(QTextStream &os, QDomDocument *pDoc)
static void FillChannelInfo(QDomElement &channel, ProgramInfo *pInfo, bool bDetails=true)
QMap< int, EncoderLink * > * m_pEncoders
static int PrintBackends(QTextStream &os, const QDomElement &backends)
static void FillProgramInfo(QDomDocument *pDoc, QDomNode &node, ProgramInfo *pInfo, bool bIncChannel=true, bool bDetails=true)
static int PrintEncoderStatus(QTextStream &os, const QDomElement &encoders)
MainServer * m_pMainServer
static int PrintMiscellaneousInfo(QTextStream &os, const QDomElement &info)
Preformat * GetStatusHTML()
static int PrintFrontends(QTextStream &os, const QDomElement &frontends)
static int PrintScheduled(QTextStream &os, const QDomElement &scheduled)
static int PrintMachineInfo(QTextStream &os, const QDomElement &info)
void FillStatusXML(QDomDocument *pDoc)
void FillDriveSpace(V2MachineInfo *pMachineInfo)
static int PrintJobQueue(QTextStream &os, const QDomElement &jobs)
static void RegisterCustomTypes()
V2BackendStatus * GetBackendStatus()
@ GENERIC_EXIT_OK
Exited with no error.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
loadArray getLoadAvgs(void)
Returns the system load averages.
std::array< double, 3 > loadArray
std::deque< RecordingInfo * > RecList
@ kMSStdOut
allow access to stdout
@ kMSRunShell
run process through shell
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
@ kDateTimeFull
Default local time.
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
@ kDateFull
Default local time.
@ kTime
Default local time.
@ kAddYear
Add year to string if not included.
@ kDateShort
Default local time.
@ kDatabase
Default UTC, database format.
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
QMap< QString, DeviceLocation * > EntryMap
Key == Unique Service Name (USN)
SleepStatus
SleepStatus is an enumeration of the awake/sleep status of a slave.
@ sStatus_Asleep
A slave is considered asleep when it is not awake and not undefined.
@ sStatus_Undefined
A slave's sleep status is undefined when it has never connected to the master backend or is not able ...
TVState
TVState is an enumeration of the states used by TV and TVRec.
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
void FillEncoderList(QVariantList &list, QObject *parent)
void FillFrontendList(QVariantList &list, QObject *parent, bool OnLine)
void V2FillProgramInfo(V2Program *pProgram, ProgramInfo *pInfo, bool bIncChannel, bool bDetails, bool bIncCast, bool bIncArtwork, bool bIncRecording)
int FillUpcomingList(QVariantList &list, QObject *parent, int &nStartIndex, int &nCount, bool bShowAll, int nRecordId, int nRecStatus, const QString &Sort, const QString &RecGroup)
static QDateTime setting_to_qdatetime(const char *setting)
Q_GLOBAL_STATIC_WITH_ARGS(MythHTTPMetaService, s_service,(STATUS_HANDLE, V2Status::staticMetaObject, &V2Status::RegisterCustomTypes)) void V2Status
static QString setting_to_localtime(const char *setting)