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 );
174 backend = pStatus->AddNewBackend();
176 backend->setName(thisHost);
181 backend->setType(
"Master");
182 QStringList backends;
184 for (
const QString&
hostname : std::as_const(backends))
189 backend = pStatus->AddNewBackend();
191 backend->setType(
"Slave");
201 backend->setType(
"Slave");
204 backend = pStatus->AddNewBackend();
205 backend->setName(masterhost);
206 backend->setIP(masterip);
207 backend->setType(
"Master");
211 QMap<int, JobQueueEntry> jobs;
212 QMap<int, JobQueueEntry>::Iterator it;
218 for (it = jobs.begin(); it != jobs.end(); ++it)
220 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
224 V2Job * pJob = pStatus->AddNewJob();
226 pJob->setId( (*it).id );
227 pJob->setChanId((*it).chanid );
228 pJob->setStartTime( (*it).recstartts);
229 pJob->setStartTs( (*it).startts );
230 pJob->setInsertTime((*it).inserttime);
231 pJob->setType( (*it).type );
233 pJob->setCmds( (*it).cmds );
234 pJob->setFlags( (*it).flags );
235 pJob->setStatus( (*it).status );
237 pJob->setStatusTime( (*it).statustime);
238 pJob->setSchedRunTime( (*it).schedruntime);
239 pJob->setArgs( (*it).args );
240 if ((*it).hostname.isEmpty())
241 pJob->setHostName( QObject::tr(
"master"));
243 pJob->setHostName((*it).hostname);
244 pJob->setComment((*it).comment);
254 if (rgdAverages[0] != -1)
256 pMachineInfo->setLoadAvg1(rgdAverages[0]);
257 pMachineInfo->setLoadAvg2(rgdAverages[1]);
258 pMachineInfo->setLoadAvg3(rgdAverages[2]);
262 QDateTime GuideDataThrough;
264 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
269 pMachineInfo->setGuideStart
271 pMachineInfo->setGuideEnd(
273 pMachineInfo->setGuideStatus(
277 pMachineInfo->setGuideNext(
281 if (!GuideDataThrough.isNull())
284 pMachineInfo->setGuideThru(GuideDataThrough);
285 pMachineInfo->setGuideDays(qdtNow.daysTo(GuideDataThrough));
290 if ((!info_script.isEmpty()) && (info_script !=
"none"))
297 LOG(VB_GENERAL, LOG_ERR,
298 QString(
"Error running miscellaneous "
299 "status information script: %1").arg(info_script));
302 QByteArray input = ms.
ReadAll();
303 pStatus->setMiscellaneous(QString(input));
319 QStringList::const_iterator sit = strlist.cbegin();
320 while (sit != strlist.cend())
323 directory = *(sit++);
324 isLocalstr = *(sit++);
328 long long iTotal = (*(sit++)).toLongLong();
329 long long iUsed = (*(sit++)).toLongLong();;
330 long long iAvail = iTotal - iUsed;
336 group->setId(QString(fsID));
337 group->setTotal((
int)(iTotal>>10));
338 group->setUsed((
int)(iUsed>>10));
339 group->setFree((
int)(iAvail>>10));
340 group->setDirectory(directory);
344 long long iLiveTV = -1;
345 long long iDeleted = -1;
346 long long iExpirable = -1;
348 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
349 " WHERE recgroup = :RECGROUP;");
354 iLiveTV = query.
value(0).toLongLong();
359 iDeleted = query.
value(0).toLongLong();
361 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
362 " WHERE autoexpire = 1 "
363 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
366 iExpirable = query.
value(0).toLongLong();
368 group->setLiveTV( (
int)(iLiveTV>>20) );
369 group->setDeleted( (
int)(iDeleted>>20) );
370 group->setExpirable ( (
int)(iExpirable>>20) );
382 QDomElement root = pDoc->createElement(
"Status");
383 pDoc->appendChild(root);
387 root.setAttribute(
"time" ,
389 root.setAttribute(
"ISODate" , qdtNow.toString(
Qt::ISODate) );
390 root.setAttribute(
"version" , MYTH_BINARY_VERSION );
391 root.setAttribute(
"protoVer", MYTH_PROTO_VERSION );
395 QDomElement encoders = pDoc->createElement(
"Encoders");
396 root.appendChild(encoders);
405 if (elink !=
nullptr)
407 TVState state = elink->GetState();
408 isLocal = elink->IsLocal();
410 QDomElement encoder = pDoc->createElement(
"Encoder");
411 encoders.appendChild(encoder);
413 encoder.setAttribute(
"id" , elink->GetInputID() );
414 encoder.setAttribute(
"local" ,
static_cast<int>(isLocal));
415 encoder.setAttribute(
"connected" ,
static_cast<int>(elink->IsConnected()));
416 encoder.setAttribute(
"state" , state );
417 encoder.setAttribute(
"sleepstatus" , elink->GetSleepStatus() );
423 encoder.setAttribute(
"hostname", elink->GetHostName());
425 encoder.setAttribute(
"devlabel",
428 if (elink->IsConnected())
456 encoders.setAttribute(
"count", numencoders);
460 QDomElement scheduled = pDoc->createElement(
"Scheduled");
461 root.appendChild(scheduled);
468 unsigned int iNum = 10;
469 unsigned int iNumRecordings = 0;
471 auto itProg = recordingList.begin();
472 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
475 ((*itProg)->GetRecordingStartTime() >=
483 while (!recordingList.empty())
487 recordingList.pop_back();
490 scheduled.setAttribute(
"count", iNumRecordings);
494 QDomElement frontends = pDoc->createElement(
"Frontends");
495 root.appendChild(frontends);
498 "urn:schemas-mythtv-org:service:MythFrontend:1");
506 frontends.setAttribute(
"count", map.size() );
507 for (
const auto & entry : std::as_const(map))
509 QDomElement fe = pDoc->createElement(
"Frontend");
510 frontends.appendChild(fe);
511 QUrl url(entry->m_sLocation);
512 fe.setAttribute(
"name", url.host());
513 fe.setAttribute(
"url", url.toString(QUrl::RemovePath));
520 QDomElement backends = pDoc->createElement(
"Backends");
521 root.appendChild(backends);
531 QDomElement mbe = pDoc->createElement(
"Backend");
532 backends.appendChild(mbe);
533 mbe.setAttribute(
"type",
"Master");
534 mbe.setAttribute(
"name", masterhost);
535 mbe.setAttribute(
"url" , masterip +
":" + QString::number(masterport));
539 "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
543 QString ipaddress = QString();
552 for (
const auto & entry : std::as_const(map))
554 QUrl url(entry->m_sLocation);
555 if (url.host() != ipaddress)
558 QDomElement mbe = pDoc->createElement(
"Backend");
559 backends.appendChild(mbe);
560 mbe.setAttribute(
"type",
"Slave");
561 mbe.setAttribute(
"name", url.host());
562 mbe.setAttribute(
"url" , url.toString(QUrl::RemovePath));
568 backends.setAttribute(
"count", numbes);
572 QDomElement queue = pDoc->createElement(
"JobQueue");
573 root.appendChild(queue);
575 QMap<int, JobQueueEntry> jobs;
576 QMap<int, JobQueueEntry>::Iterator it;
582 for (it = jobs.begin(); it != jobs.end(); ++it)
584 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
588 QDomElement job = pDoc->createElement(
"Job");
589 queue.appendChild(job);
591 job.setAttribute(
"id" , (*it).id );
592 job.setAttribute(
"chanId" , (*it).chanid );
593 job.setAttribute(
"startTime" ,
595 job.setAttribute(
"startTs" , (*it).startts );
596 job.setAttribute(
"insertTime",
598 job.setAttribute(
"type" , (*it).type );
599 job.setAttribute(
"cmds" , (*it).cmds );
600 job.setAttribute(
"flags" , (*it).flags );
601 job.setAttribute(
"status" , (*it).status );
602 job.setAttribute(
"statusTime",
604 job.setAttribute(
"schedTime" ,
606 job.setAttribute(
"args" , (*it).args );
608 if ((*it).hostname.isEmpty())
609 job.setAttribute(
"hostname", QObject::tr(
"master"));
611 job.setAttribute(
"hostname",(*it).hostname);
613 QDomText textNode = pDoc->createTextNode((*it).comment);
614 job.appendChild(textNode);
619 queue.setAttribute(
"count", jobs.size() );
623 QDomElement mInfo = pDoc->createElement(
"MachineInfo");
624 QDomElement storage = pDoc->createElement(
"Storage" );
625 QDomElement load = pDoc->createElement(
"Load" );
626 QDomElement guide = pDoc->createElement(
"Guide" );
628 root.appendChild (mInfo );
629 mInfo.appendChild(storage);
630 mInfo.appendChild(load );
631 mInfo.appendChild(guide );
648 QList<QDomElement> fsXML;
649 QStringList::const_iterator sit = strlist.cbegin();
650 while (sit != strlist.cend())
653 directory = *(sit++);
654 isLocalstr = *(sit++);
658 long long iTotal = (*(sit++)).toLongLong();
659 long long iUsed = (*(sit++)).toLongLong();;
660 long long iAvail = iTotal - iUsed;
665 QDomElement group = pDoc->createElement(
"Group");
667 group.setAttribute(
"id" , fsID );
668 group.setAttribute(
"total", (
int)(iTotal>>10) );
669 group.setAttribute(
"used" , (
int)(iUsed>>10) );
670 group.setAttribute(
"free" , (
int)(iAvail>>10) );
671 group.setAttribute(
"dir" , directory );
675 long long iLiveTV = -1;
676 long long iDeleted = -1;
677 long long iExpirable = -1;
679 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
680 " WHERE recgroup = :RECGROUP;");
685 iLiveTV = query.
value(0).toLongLong();
690 iDeleted = query.
value(0).toLongLong();
692 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
693 " WHERE autoexpire = 1 "
694 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
697 iExpirable = query.
value(0).toLongLong();
699 group.setAttribute(
"livetv", (
int)(iLiveTV>>20) );
700 group.setAttribute(
"deleted", (
int)(iDeleted>>20) );
701 group.setAttribute(
"expirable", (
int)(iExpirable>>20) );
710 storage.appendChild(total);
711 int num_elements = fsXML.size();
712 for (
int fs_index = 0; fs_index < num_elements; fs_index++)
714 storage.appendChild(fsXML[fs_index]);
720 load.setAttribute(
"avg1", 0);
721 load.setAttribute(
"avg2", 1);
722 load.setAttribute(
"avg3", 2);
725 if (rgdAverages[0] != -1)
727 load.setAttribute(
"avg1", rgdAverages[0]);
728 load.setAttribute(
"avg2", rgdAverages[1]);
729 load.setAttribute(
"avg3", rgdAverages[2]);
735 QDateTime GuideDataThrough;
738 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
745 guide.setAttribute(
"start",
747 guide.setAttribute(
"end",
749 guide.setAttribute(
"status",
753 guide.setAttribute(
"next",
757 if (!GuideDataThrough.isNull())
759 guide.setAttribute(
"guideThru",
761 guide.setAttribute(
"guideDays", qdtNow.daysTo(GuideDataThrough));
767 if ((!info_script.isEmpty()) && (info_script !=
"none"))
769 QDomElement misc = pDoc->createElement(
"Miscellaneous");
770 root.appendChild(misc);
777 LOG(VB_GENERAL, LOG_ERR,
778 QString(
"Error running miscellaneous "
779 "status information script: %1").arg(info_script));
783 QByteArray input = ms.
ReadAll();
785 QStringList
output = QString(input).split(
'\n',
787 for (
const auto & line : std::as_const(
output))
789 QDomElement
info = pDoc->createElement(
"Information");
791 QStringList list = line.split(
"[]:[]");
792 unsigned int size = list.size();
793 unsigned int hasAttributes = 0;
795 if ((size > 0) && (!list[0].isEmpty()))
797 info.setAttribute(
"display", list[0]);
800 if ((size > 1) && (!list[1].isEmpty()))
802 info.setAttribute(
"name", list[1]);
805 if ((size > 2) && (!list[2].isEmpty()))
807 info.setAttribute(
"value", list[2]);
811 if (hasAttributes > 0)
812 misc.appendChild(
info);
823#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
824 os.setCodec(
"UTF-8");
826 os.setEncoding(QStringConverter::Utf8);
831 QDomElement docElem = pDoc->documentElement();
833 os <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
834 <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
835 <<
"<html xmlns=\"http://www.w3.org/1999/xhtml\""
836 <<
" xml:lang=\"en\" lang=\"en\">\r\n"
838 <<
" <meta http-equiv=\"Content-Type\""
839 <<
"content=\"text/html; charset=UTF-8\" />\r\n"
840 <<
" <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
841 <<
" <title>MythTV Status - "
845 << docElem.attribute(
"version", MYTH_BINARY_VERSION ) <<
"</title>\r\n"
847 <<
"<body bgcolor=\"#fff\">\r\n"
848 <<
"<div class=\"status\">\r\n"
849 <<
" <h1 class=\"status\">MythTV Status</h1>\r\n";
853 QDomNode node = docElem.namedItem(
"Encoders" );
860 node = docElem.namedItem(
"Scheduled" );
867 node = docElem.namedItem(
"Frontends" );
874 node = docElem.namedItem(
"Backends" );
881 node = docElem.namedItem(
"JobQueue" );
888 node = docElem.namedItem(
"MachineInfo" );
895 node = docElem.namedItem(
"Miscellaneous" );
900 os <<
"\r\n</div>\r\n</body>\r\n</html>\r\n";
910 int nNumEncoders = 0;
912 if (encoders.isNull())
915 os <<
" <div class=\"content\">\r\n"
916 <<
" <h2 class=\"status\">Encoder Status</h2>\r\n";
918 QDomNode node = encoders.firstChild();
920 while (!node.isNull())
922 QDomElement e = node.toElement();
926 if (e.tagName() ==
"Encoder")
928 QString sIsLocal = (e.attribute(
"local" ,
"remote" )==
"1")
929 ?
"local" :
"remote";
930 QString sCardId = e.attribute(
"id" ,
"0" );
931 QString sHostName = e.attribute(
"hostname" ,
"Unknown");
932 bool bConnected=
static_cast<bool>(e.attribute(
"connected",
"0" ).toInt());
934 bool bIsLowOnFreeSpace=
static_cast<bool>(e.attribute(
"lowOnFreeSpace",
"0").toInt());
936 QString sDevlabel = e.attribute(
"devlabel",
"[ UNKNOWN ]");
938 os <<
" Encoder " << sCardId <<
" " << sDevlabel
939 <<
" is " << sIsLocal <<
" on " << sHostName;
941 if ((sIsLocal ==
"remote") && !bConnected)
948 os <<
" (currently asleep).<br />";
950 os <<
" (currently not connected).<br />";
952 node = node.nextSibling();
963 os <<
" and is watching Live TV";
968 os <<
" and is recording";
972 os <<
" and is not recording.";
978 QDomNode tmpNode = e.namedItem(
"Program" );
980 if (!tmpNode.isNull())
982 QDomElement program = tmpNode.toElement();
984 if (!program.isNull())
986 os <<
" '" << program.attribute(
"title",
"Unknown" ) <<
"'";
990 tmpNode = program.namedItem(
"Channel" );
992 if (!tmpNode.isNull())
994 QDomElement channel = tmpNode.toElement();
996 if (!channel.isNull())
998 << channel.attribute(
"callSign",
"unknown" );
1003 tmpNode = program.namedItem(
"Recording" );
1005 if (!tmpNode.isNull())
1007 QDomElement recording = tmpNode.toElement();
1009 if (!recording.isNull())
1012 recording.attribute(
"recEndTs",
"" ));
1014 os <<
". This recording ";
1020 os <<
"scheduled to end at "
1030 if (bIsLowOnFreeSpace)
1032 os <<
" <strong>WARNING</strong>:"
1033 <<
" This backend is low on free disk space!";
1040 node = node.nextSibling();
1043 os <<
" </div>\r\n\r\n";
1045 return( nNumEncoders );
1056 if (scheduled.isNull())
1059 int nNumRecordings= scheduled.attribute(
"count",
"0" ).toInt();
1061 os <<
" <div class=\"content\">\r\n"
1062 <<
" <h2 class=\"status\">Schedule</h2>\r\n";
1064 if (nNumRecordings == 0)
1066 os <<
" There are no shows scheduled for recording.\r\n"
1071 os <<
" The next " << nNumRecordings <<
" show" << (nNumRecordings == 1 ?
"" :
"s" )
1072 <<
" that " << (nNumRecordings == 1 ?
"is" :
"are")
1073 <<
" scheduled for recording:\r\n";
1075 os <<
" <div class=\"schedule\">\r\n";
1079 QDomNode node = scheduled.firstChild();
1081 while (!node.isNull())
1083 QDomElement e = node.toElement();
1087 QDomNode recNode = e.namedItem(
"Recording" );
1088 QDomNode chanNode = e.namedItem(
"Channel" );
1090 if ((e.tagName() ==
"Program") && !recNode.isNull() &&
1093 QDomElement r = recNode.toElement();
1094 QDomElement c = chanNode.toElement();
1096 QString sTitle = e.attribute(
"title" ,
"" );
1097 QString sSubTitle = e.attribute(
"subTitle",
"" );
1103 int nPreRollSecs = r.attribute(
"preRollSeconds",
"0" ).toInt();
1104 int nEncoderId = r.attribute(
"encoderId" ,
"0" ).toInt();
1105 QString sProfile = r.attribute(
"recProfile" ,
"" );
1106 QString sChanName = c.attribute(
"channelName" ,
"" );
1109 QDomText text = e.firstChild().toText();
1111 sDesc = text.nodeValue();
1115 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
1121 int nTotalDays = nTotalSecs / 86400;
1122 int nTotalHours = (nTotalSecs / 3600)
1123 - (nTotalDays * 24);
1124 int nTotalMins = (nTotalSecs / 60) % 60;
1126 QString sTimeToStart =
"in";
1128 sTimeToStart += QObject::tr(
" %n day(s),",
"", nTotalDays );
1129 sTimeToStart += QObject::tr(
" %n hour(s) and",
"", nTotalHours);
1130 sTimeToStart += QObject::tr(
" %n minute(s)",
"", nTotalMins);
1132 if ( nTotalHours == 0 && nTotalMins == 0)
1133 sTimeToStart = QObject::tr(
"within one minute",
"Recording starting");
1135 if ( nTotalSecs < 0)
1136 sTimeToStart = QObject::tr(
"soon",
"Recording starting");
1140 os <<
" <a href=\"#\">";
1148 os <<
"Encoder " << nEncoderId <<
" - ";
1150 os << sChanName <<
" - " << sTitle <<
"<br />"
1151 <<
"<span><strong>" << sTitle <<
"</strong> ("
1155 if ( !sSubTitle.isEmpty())
1156 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1158 if ( airDate.isValid())
1160 os <<
"Orig. Airdate: "
1166 os << sDesc <<
"<br /><br />"
1167 <<
"This recording will start " << sTimeToStart
1168 <<
" using encoder " << nEncoderId <<
" with the '"
1169 << sProfile <<
"' profile.</span></a><hr />\r\n";
1173 node = node.nextSibling();
1175 os <<
" </div>\r\n";
1176 os <<
" </div>\r\n\r\n";
1178 return( nNumRecordings );
1187 if (frontends.isNull())
1190 int nNumFES= frontends.attribute(
"count",
"0" ).toInt();
1196 os <<
" <div class=\"content\">\r\n"
1197 <<
" <h2 class=\"status\">Frontends</h2>\r\n";
1199 QDomNode node = frontends.firstChild();
1200 while (!node.isNull())
1202 QDomElement e = node.toElement();
1206 QString name = e.attribute(
"name" ,
"" );
1207 QString url = e.attribute(
"url" ,
"" );
1208 os << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1211 node = node.nextSibling();
1214 os <<
" </div>\r\n\r\n";
1225 if (backends.isNull())
1228 int nNumBES= backends.attribute(
"count",
"0" ).toInt();
1234 os <<
" <div class=\"content\">\r\n"
1235 <<
" <h2 class=\"status\">Other Backends</h2>\r\n";
1237 QDomNode node = backends.firstChild();
1238 while (!node.isNull())
1240 QDomElement e = node.toElement();
1244 QString
type = e.attribute(
"type",
"" );
1245 QString name = e.attribute(
"name" ,
"" );
1246 QString url = e.attribute(
"url" ,
"" );
1247 os <<
type <<
": " << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1250 node = node.nextSibling();
1253 os <<
" </div>\r\n\r\n";
1267 int nNumJobs= jobs.attribute(
"count",
"0" ).toInt();
1269 os <<
" <div class=\"content\">\r\n"
1270 <<
" <h2 class=\"status\">Job Queue</h2>\r\n";
1274 QString statusColor;
1277 os <<
" Jobs currently in Queue or recently ended:\r\n<br />"
1278 <<
" <div class=\"schedule\">\r\n";
1281 QDomNode node = jobs.firstChild();
1283 while (!node.isNull())
1285 QDomElement e = node.toElement();
1289 QDomNode progNode = e.namedItem(
"Program" );
1291 if ((e.tagName() ==
"Job") && !progNode.isNull() )
1293 QDomElement
p = progNode.toElement();
1295 QDomNode recNode =
p.namedItem(
"Recording" );
1296 QDomNode chanNode =
p.namedItem(
"Channel" );
1298 QDomElement r = recNode.toElement();
1299 QDomElement c = chanNode.toElement();
1301 int nType = e.attribute(
"type" ,
"0" ).toInt();
1302 int nStatus = e.attribute(
"status",
"0" ).toInt();
1307 statusColor =
" class=\"jobaborted\"";
1312 statusColor =
" class=\"joberrored\"";
1313 jobColor =
" class=\"joberrored\"";
1317 statusColor =
" class=\"jobfinished\"";
1318 jobColor =
" class=\"jobfinished\"";
1322 statusColor =
" class=\"jobrunning\"";
1323 jobColor =
" class=\"jobrunning\"";
1327 statusColor =
" class=\"jobqueued\"";
1328 jobColor =
" class=\"jobqueued\"";
1332 QString sTitle =
p.attribute(
"title" ,
"" );
1333 QString sSubTitle =
p.attribute(
"subTitle",
"" );
1339 QString sHostname = e.attribute(
"hostname",
"master" );
1340 QString sComment =
"";
1342 QDomText text = e.firstChild().toText();
1344 sComment = text.nodeValue();
1346 os <<
"<a href=\"javascript:void(0)\">"
1350 << sTitle <<
" - <font" << jobColor <<
">"
1352 <<
"<span><strong>" << sTitle <<
"</strong> ("
1356 if (!sSubTitle.isEmpty())
1357 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1363 os <<
"Scheduled Run Time: "
1370 os <<
"Status: <font" << statusColor <<
">"
1378 if ( nStatus != JOB_QUEUED)
1379 os <<
"Host: " << sHostname <<
"<br />";
1381 if (!sComment.isEmpty())
1382 os <<
"<br />Comments:<br />" << sComment <<
"<br />";
1384 os <<
"</span></a><hr />\r\n";
1388 node = node.nextSibling();
1390 os <<
" </div>\r\n";
1394 os <<
" Job Queue is currently empty.\r\n\r\n";
1397 os <<
" </div>\r\n\r\n ";
1414 os <<
"<div class=\"content\">\r\n"
1415 <<
" <h2 class=\"status\">Machine Information</h2>\r\n";
1419 QDomNode node =
info.namedItem(
"Load" );
1423 QDomElement e = node.toElement();
1427 double dAvg1 = e.attribute(
"avg1" ,
"0" ).toDouble();
1428 double dAvg2 = e.attribute(
"avg2" ,
"0" ).toDouble();
1429 double dAvg3 = e.attribute(
"avg3" ,
"0" ).toDouble();
1431 os <<
" <div class=\"loadstatus\">\r\n"
1432 <<
" This machine's load average:"
1433 <<
"\r\n <ul>\r\n <li>"
1434 <<
"1 Minute: " << dAvg1 <<
"</li>\r\n"
1435 <<
" <li>5 Minutes: " << dAvg2 <<
"</li>\r\n"
1436 <<
" <li>15 Minutes: " << dAvg3
1437 <<
"</li>\r\n </ul>\r\n"
1443 node =
info.namedItem(
"Storage" );
1444 QDomElement storage = node.toElement();
1445 node = storage.firstChild();
1450 while (!node.isNull())
1452 QDomElement g = node.toElement();
1454 if (!g.isNull() && g.tagName() ==
"Group")
1456 QString
id = g.attribute(
"id",
"" );
1460 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1461 int nTotal = g.attribute(
"total",
"0" ).toInt();
1462 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1463 int nLiveTV = g.attribute(
"livetv" ,
"0" ).toInt();
1464 int nDeleted = g.attribute(
"deleted",
"0" ).toInt();
1465 int nExpirable = g.attribute(
"expirable" ,
"0" ).toInt();
1466 QString nDir = g.attribute(
"dir" ,
"" );
1468 nDir.replace(
",",
", ");
1470 os <<
" Disk Usage Summary:<br />\r\n";
1473 os <<
" <li>Total Disk Space:\r\n"
1476 os <<
" <li>Total Space: ";
1477 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1478 os << sRep <<
"</li>\r\n";
1480 os <<
" <li>Space Used: ";
1481 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1482 os << sRep <<
"</li>\r\n";
1484 os <<
" <li>Space Free: ";
1485 sRep = QString(
"%L1").arg(nFree) +
" MB";
1486 os << sRep <<
"</li>\r\n";
1488 if ((nLiveTV + nDeleted + nExpirable) > 0)
1490 os <<
" <li>Space Available "
1491 "After Auto-expire: ";
1492 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1493 sRep = QString(
"%L1").arg(nFree + nLiveTV +
1494 nDeleted + nExpirable) +
" MB";
1495 os << sRep <<
"\r\n";
1497 os <<
" <li>Space Used by LiveTV: ";
1498 sRep = QString(
"%L1").arg(nLiveTV) +
" MB";
1499 os << sRep <<
"</li>\r\n";
1500 os <<
" <li>Space Used by "
1501 "Deleted Recordings: ";
1502 sRep = QString(
"%L1").arg(nDeleted) +
" MB";
1503 os << sRep <<
"</li>\r\n";
1504 os <<
" <li>Space Used by "
1505 "Auto-expirable Recordings: ";
1506 sRep = QString(
"%L1").arg(nExpirable) +
" MB";
1507 os << sRep <<
"</li>\r\n";
1520 node = node.nextSibling();
1524 node = storage.firstChild();
1526 os <<
" Disk Usage Details:<br />\r\n";
1530 while (!node.isNull())
1532 QDomElement g = node.toElement();
1534 if (!g.isNull() && g.tagName() ==
"Group")
1536 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1537 int nTotal = g.attribute(
"total",
"0" ).toInt();
1538 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1539 QString nDir = g.attribute(
"dir" ,
"" );
1540 QString
id = g.attribute(
"id" ,
"" );
1542 nDir.replace(
",",
", ");
1548 os <<
" <li>MythTV Drive #" <<
id <<
":"
1552 if (nDir.contains(
','))
1553 os <<
" <li>Directories: ";
1555 os <<
" <li>Directory: ";
1557 os << nDir <<
"</li>\r\n";
1559 os <<
" <li>Total Space: ";
1560 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1561 os << sRep <<
"</li>\r\n";
1563 os <<
" <li>Space Used: ";
1564 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1565 os << sRep <<
"</li>\r\n";
1567 os <<
" <li>Space Free: ";
1568 sRep = QString(
"%L1").arg(nFree) +
" MB";
1569 os << sRep <<
"</li>\r\n";
1577 node = node.nextSibling();
1584 node =
info.namedItem(
"Guide" );
1588 QDomElement e = node.toElement();
1592 int nDays = e.attribute(
"guideDays",
"0" ).toInt();
1593 QString sStart = e.attribute(
"start" ,
"" );
1594 QString sEnd = e.attribute(
"end" ,
"" );
1595 QString sStatus = e.attribute(
"status" ,
"" );
1597 QString sNext = next.isNull() ?
"" :
1603 QDomText text = e.firstChild().toText();
1610 sMsg = text.nodeValue();
1612 os <<
" Last mythfilldatabase run started on " << sStart
1618 os <<
"ended on " << sEnd <<
". ";
1620 os << sStatus <<
"<br />\r\n";
1622 if (!next.isNull() && next >= lastrunstart)
1624 os <<
" Suggested next mythfilldatabase run: "
1625 << sNext <<
".<br />\r\n";
1630 os <<
" There's guide data until "
1634 os <<
" " << QObject::tr(
"(%n day(s))",
"", nDays);
1639 os <<
" <strong>WARNING</strong>: is mythfilldatabase running?";
1643 os <<
" There's <strong>no guide data</strong> available! "
1644 <<
"Have you run mythfilldatabase?";
1648 os <<
"\r\n </div>\r\n";
1660 QDomNodeList nodes =
info.elementsByTagName(
"Information");
1661 uint count = nodes.count();
1667 os <<
"<div class=\"content\">\r\n"
1668 <<
" <h2 class=\"status\">Miscellaneous</h2>\r\n";
1669 for (
unsigned int i = 0; i < count; i++)
1671 QDomNode node = nodes.item(i);
1675 QDomElement e = node.toElement();
1679 display = e.attribute(
"display",
"");
1683 if (display.isEmpty())
1688 if (display.contains(
"<p>", Qt::CaseInsensitive) ||
1689 display.contains(
"<br", Qt::CaseInsensitive))
1696 linebreak =
"<br />\r\n";
1699 os <<
" " << display << linebreak;
1713 if ((pDoc ==
nullptr) || (pInfo ==
nullptr))
1718 QDomElement program = pDoc->createElement(
"Program" );
1719 node.appendChild( program );
1721 program.setAttribute(
"startTime" ,
1724 program.setAttribute(
"title" , pInfo->
GetTitle() );
1725 program.setAttribute(
"subTitle" , pInfo->
GetSubtitle());
1726 program.setAttribute(
"category" , pInfo->
GetCategory());
1728 program.setAttribute(
"repeat" ,
static_cast<int>(pInfo->
IsRepeat()));
1733 program.setAttribute(
"seriesId" , pInfo->
GetSeriesID() );
1734 program.setAttribute(
"programId" , pInfo->
GetProgramID() );
1735 program.setAttribute(
"stars" , pInfo->
GetStars() );
1736 program.setAttribute(
"fileSize" ,
1738 program.setAttribute(
"lastModified",
1741 program.setAttribute(
"hostname" , pInfo->
GetHostname() );
1744 program.setAttribute(
1747 QDomText textNode = pDoc->createTextNode( pInfo->
GetDescription() );
1748 program.appendChild( textNode );
1756 QDomElement channel = pDoc->createElement(
"Channel" );
1757 program.appendChild( channel );
1766 QDomElement recording = pDoc->createElement(
"Recording" );
1767 program.appendChild( recording );
1769 recording.setAttribute(
"recStatus" ,
1771 recording.setAttribute(
"recPriority" ,
1773 recording.setAttribute(
"recStartTs" ,
1775 recording.setAttribute(
"recEndTs" ,
1780 recording.setAttribute(
"recordId" ,
1782 recording.setAttribute(
"recGroup" ,
1784 recording.setAttribute(
"playGroup" ,
1786 recording.setAttribute(
"recType" ,
1788 recording.setAttribute(
"dupInType" ,
1790 recording.setAttribute(
"dupMethod" ,
1792 recording.setAttribute(
"encoderId" ,
1795 recording.setAttribute(
"recProfile" ,
1822 channel.setAttribute(
"chanId" , pInfo->
GetChanID() );
1823 channel.setAttribute(
"chanNum" , pInfo->
GetChanNum());
1830 channel.setAttribute(
"chanFilters",
1832 channel.setAttribute(
"sourceId" , pInfo->
GetSourceID() );
1833 channel.setAttribute(
"inputId" , pInfo->
GetInputID() );
1834 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
const char * GetMythSourceVersion()
const char * GetMythSourcePath()
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)