21#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
22#include <QStringConverter>
36#include "libmythbase/mythversion.h"
62 qRegisterMetaType<Preformat*>(
"Preformat");
63 qRegisterMetaType<V2MachineInfo*>(
"V2MachineInfo");
64 qRegisterMetaType<V2BackendStatus*>(
"V2BackendStatus");
65 qRegisterMetaType<V2Encoder*>(
"V2Encoder");
66 qRegisterMetaType<V2Program*>(
"V2Program");
67 qRegisterMetaType<V2Frontend*>(
"V2Frontend");
68 qRegisterMetaType<V2StorageGroup*>(
"V2StorageGroup");
69 qRegisterMetaType<V2Job*>(
"V2Job");
70 qRegisterMetaType<V2ChannelInfo*>(
"V2ChannelInfo");
71 qRegisterMetaType<V2RecordingInfo*>(
"V2RecordingInfo");
72 qRegisterMetaType<V2ArtworkInfoList*>(
"V2ArtworkInfoList");
73 qRegisterMetaType<V2ArtworkInfo*>(
"V2ArtworkInfo");
74 qRegisterMetaType<V2CastMemberList*>(
"V2CastMemberList");
75 qRegisterMetaType<V2CastMember*>(
"V2CastMember");
76 qRegisterMetaType<V2Input*>(
"V2Input");
77 qRegisterMetaType<V2Backend*>(
"V2Backend");
78 qRegisterMetaType<V2ShowStats*>(
"V2ShowStats");
79 qRegisterMetaType<V2RecStats*>(
"V2RecStats");
107 QDomDocument doc(
"Status" );
109 QDomProcessingInstruction encoding =
110 doc.createProcessingInstruction(
"xml",
111 R
"(version="1.0" encoding="UTF-8")");
112 doc.appendChild(encoding);
115 pResult->setmimetype(
"application/xml");
116 pResult->setbuffer(doc.toString());
123 QDomDocument doc(
"Status" );
126 QTextStream stream( &html );
129 pResult->setmimetype(
"text/html");
130 pResult->setbuffer(html);
153 pStatus->setVersion ( MYTH_BINARY_VERSION );
154 pStatus->setProtoVer ( MYTH_PROTO_VERSION );
177 backend = pStatus->AddNewBackend();
179 backend->setName(thisHost);
184 backend->setType(
"Master");
185 QStringList backends;
187 for (
const QString&
hostname : std::as_const(backends))
192 backend = pStatus->AddNewBackend();
194 backend->setType(
"Slave");
204 backend->setType(
"Slave");
207 backend = pStatus->AddNewBackend();
208 backend->setName(masterhost);
209 backend->setIP(masterip);
210 backend->setType(
"Master");
214 QMap<int, JobQueueEntry> jobs;
215 QMap<int, JobQueueEntry>::Iterator it;
221 for (it = jobs.begin(); it != jobs.end(); ++it)
223 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
227 V2Job * pJob = pStatus->AddNewJob();
229 pJob->setId( (*it).id );
230 pJob->setChanId((*it).chanid );
231 pJob->setStartTime( (*it).recstartts);
232 pJob->setStartTs( (*it).startts );
233 pJob->setInsertTime((*it).inserttime);
234 pJob->setType( (*it).type );
236 pJob->setCmds( (*it).cmds );
237 pJob->setFlags( (*it).flags );
238 pJob->setStatus( (*it).status );
240 pJob->setStatusTime( (*it).statustime);
241 pJob->setSchedRunTime( (*it).schedruntime);
242 pJob->setArgs( (*it).args );
243 if ((*it).hostname.isEmpty())
244 pJob->setHostName( QObject::tr(
"master"));
246 pJob->setHostName((*it).hostname);
247 pJob->setComment((*it).comment);
257 if (rgdAverages[0] != -1)
259 pMachineInfo->setLoadAvg1(rgdAverages[0]);
260 pMachineInfo->setLoadAvg2(rgdAverages[1]);
261 pMachineInfo->setLoadAvg3(rgdAverages[2]);
265 QDateTime GuideDataThrough;
267 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
272 pMachineInfo->setGuideStart
274 pMachineInfo->setGuideEnd(
276 pMachineInfo->setGuideStatus(
280 pMachineInfo->setGuideNext(
284 if (!GuideDataThrough.isNull())
287 pMachineInfo->setGuideThru(GuideDataThrough);
288 pMachineInfo->setGuideDays(qdtNow.daysTo(GuideDataThrough));
293 if ((!info_script.isEmpty()) && (info_script !=
"none"))
300 LOG(VB_GENERAL, LOG_ERR,
301 QString(
"Error running miscellaneous "
302 "status information script: %1").arg(info_script));
305 QByteArray input = ms.
ReadAll();
306 pStatus->setMiscellaneous(QString(input));
321 query.
prepare(
"select count(distinct title) from oldrecorded "
322 "where recstatus = -3 and future = 0;");
324 pStatus->setShowCount(query.
value(0).toInt());
326 query.
prepare(
"select count(title) from oldrecorded "
327 "where recstatus = -3 and future = 0;");
329 pStatus->setEpisodeCount(query.
value(0).toInt());
331 query.
prepare(
"select starttime from oldrecorded "
332 "where recstatus = -3 and future = 0 "
333 "order by starttime asc limit 1;");
335 pStatus->setFirstRecDate(query.
value(0).toDateTime());
336 query.
prepare(
"select endtime from oldrecorded "
337 "where recstatus = -3 and future = 0 "
338 "order by starttime desc limit 1;");
340 pStatus->setLastRecDate(query.
value(0).toDateTime());
341 query.
prepare(
"select SUM( TIMESTAMPDIFF(SECOND, starttime, endtime) ) "
343 "where recstatus = -3 and future = 0;");
345 pStatus->setRecTimeSecs(query.
value(0).toLongLong());
346 pStatus->setRunTimeSecs(pStatus->GetFirstRecDate().secsTo(pStatus->GetLastRecDate()));
348 query.
prepare(
"select title, COUNT(*) as recorded, MAX(starttime) as last_recorded "
350 "where recstatus = -3 and future = 0 "
352 "order by recorded desc, last_recorded desc, title asc "
357 auto*
show = pStatus->AddNewShow();
358 show->setTitle(query.
value(0).toString());
360 show->setLastRecDate(query.
value(2).toDateTime());
364 query.
prepare(
"select c.name, COUNT(*) as recorded, MAX(r.starttime) as last_recorded "
365 "from oldrecorded r "
366 "join channel c on r.chanid = c.chanid "
367 "where r.recstatus = -3 and r.future = 0 "
368 "group by c.callsign "
369 "order by recorded desc, last_recorded desc, c.name asc "
372 while (query.
next()) {
373 auto* channel = pStatus->AddNewChannel();
374 channel->setTitle(query.
value(0).toString());
375 channel->setCount(query.
value(1).toInt());
376 channel->setLastRecDate(query.
value(2).toDateTime());
393 QStringList::const_iterator sit = strlist.cbegin();
394 while (sit != strlist.cend())
397 directory = *(sit++);
398 isLocalstr = *(sit++);
402 long long iTotal = (*(sit++)).toLongLong();
403 long long iUsed = (*(sit++)).toLongLong();;
404 long long iAvail = iTotal - iUsed;
410 group->setId(QString(fsID));
411 group->setTotal((
int)(iTotal>>10));
412 group->setUsed((
int)(iUsed>>10));
413 group->setFree((
int)(iAvail>>10));
414 group->setDirectory(directory);
418 long long iLiveTV = -1;
419 long long iDeleted = -1;
420 long long iExpirable = -1;
422 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
423 " WHERE recgroup = :RECGROUP;");
428 iLiveTV = query.
value(0).toLongLong();
433 iDeleted = query.
value(0).toLongLong();
435 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
436 " WHERE autoexpire = 1 "
437 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
440 iExpirable = query.
value(0).toLongLong();
442 group->setLiveTV( (
int)(iLiveTV>>20) );
443 group->setDeleted( (
int)(iDeleted>>20) );
444 group->setExpirable ( (
int)(iExpirable>>20) );
456 QDomElement root = pDoc->createElement(
"Status");
457 pDoc->appendChild(root);
461 root.setAttribute(
"time" ,
463 root.setAttribute(
"ISODate" , qdtNow.toString(
Qt::ISODate) );
464 root.setAttribute(
"version" , MYTH_BINARY_VERSION );
465 root.setAttribute(
"protoVer", MYTH_PROTO_VERSION );
469 QDomElement encoders = pDoc->createElement(
"Encoders");
470 root.appendChild(encoders);
479 if (elink !=
nullptr)
481 TVState state = elink->GetState();
482 isLocal = elink->IsLocal();
484 QDomElement encoder = pDoc->createElement(
"Encoder");
485 encoders.appendChild(encoder);
487 encoder.setAttribute(
"id" , elink->GetInputID() );
488 encoder.setAttribute(
"local" ,
static_cast<int>(isLocal));
489 encoder.setAttribute(
"connected" ,
static_cast<int>(elink->IsConnected()));
490 encoder.setAttribute(
"state" , state );
491 encoder.setAttribute(
"sleepstatus" , elink->GetSleepStatus() );
497 encoder.setAttribute(
"hostname", elink->GetHostName());
499 encoder.setAttribute(
"devlabel",
502 if (elink->IsConnected())
530 encoders.setAttribute(
"count", numencoders);
534 QDomElement scheduled = pDoc->createElement(
"Scheduled");
535 root.appendChild(scheduled);
542 unsigned int iNum = 10;
543 unsigned int iNumRecordings = 0;
545 auto itProg = recordingList.begin();
546 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
549 ((*itProg)->GetRecordingStartTime() >=
557 while (!recordingList.empty())
561 recordingList.pop_back();
564 scheduled.setAttribute(
"count", iNumRecordings);
568 QDomElement frontends = pDoc->createElement(
"Frontends");
569 root.appendChild(frontends);
572 "urn:schemas-mythtv-org:service:MythFrontend:1");
580 frontends.setAttribute(
"count", map.size() );
581 for (
const auto & entry : std::as_const(map))
583 QDomElement fe = pDoc->createElement(
"Frontend");
584 frontends.appendChild(fe);
585 QUrl url(entry->m_sLocation);
586 fe.setAttribute(
"name", url.host());
587 fe.setAttribute(
"url", url.toString(QUrl::RemovePath));
594 QDomElement backends = pDoc->createElement(
"Backends");
595 root.appendChild(backends);
605 QDomElement mbe = pDoc->createElement(
"Backend");
606 backends.appendChild(mbe);
607 mbe.setAttribute(
"type",
"Master");
608 mbe.setAttribute(
"name", masterhost);
609 mbe.setAttribute(
"url" , masterip +
":" + QString::number(masterport));
613 "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
617 QString ipaddress = QString();
626 for (
const auto & entry : std::as_const(map))
628 QUrl url(entry->m_sLocation);
629 if (url.host() != ipaddress)
632 QDomElement mbe = pDoc->createElement(
"Backend");
633 backends.appendChild(mbe);
634 mbe.setAttribute(
"type",
"Slave");
635 mbe.setAttribute(
"name", url.host());
636 mbe.setAttribute(
"url" , url.toString(QUrl::RemovePath));
642 backends.setAttribute(
"count", numbes);
646 QDomElement queue = pDoc->createElement(
"JobQueue");
647 root.appendChild(queue);
649 QMap<int, JobQueueEntry> jobs;
650 QMap<int, JobQueueEntry>::Iterator it;
656 for (it = jobs.begin(); it != jobs.end(); ++it)
658 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
662 QDomElement job = pDoc->createElement(
"Job");
663 queue.appendChild(job);
665 job.setAttribute(
"id" , (*it).id );
666 job.setAttribute(
"chanId" , (*it).chanid );
667 job.setAttribute(
"startTime" ,
669 job.setAttribute(
"startTs" , (*it).startts );
670 job.setAttribute(
"insertTime",
672 job.setAttribute(
"type" , (*it).type );
673 job.setAttribute(
"cmds" , (*it).cmds );
674 job.setAttribute(
"flags" , (*it).flags );
675 job.setAttribute(
"status" , (*it).status );
676 job.setAttribute(
"statusTime",
678 job.setAttribute(
"schedTime" ,
680 job.setAttribute(
"args" , (*it).args );
682 if ((*it).hostname.isEmpty())
683 job.setAttribute(
"hostname", QObject::tr(
"master"));
685 job.setAttribute(
"hostname",(*it).hostname);
687 QDomText textNode = pDoc->createTextNode((*it).comment);
688 job.appendChild(textNode);
693 queue.setAttribute(
"count", jobs.size() );
697 QDomElement mInfo = pDoc->createElement(
"MachineInfo");
698 QDomElement storage = pDoc->createElement(
"Storage" );
699 QDomElement load = pDoc->createElement(
"Load" );
700 QDomElement guide = pDoc->createElement(
"Guide" );
702 root.appendChild (mInfo );
703 mInfo.appendChild(storage);
704 mInfo.appendChild(load );
705 mInfo.appendChild(guide );
722 QList<QDomElement> fsXML;
723 QStringList::const_iterator sit = strlist.cbegin();
724 while (sit != strlist.cend())
727 directory = *(sit++);
728 isLocalstr = *(sit++);
732 long long iTotal = (*(sit++)).toLongLong();
733 long long iUsed = (*(sit++)).toLongLong();;
734 long long iAvail = iTotal - iUsed;
739 QDomElement group = pDoc->createElement(
"Group");
741 group.setAttribute(
"id" , fsID );
742 group.setAttribute(
"total", (
int)(iTotal>>10) );
743 group.setAttribute(
"used" , (
int)(iUsed>>10) );
744 group.setAttribute(
"free" , (
int)(iAvail>>10) );
745 group.setAttribute(
"dir" , directory );
749 long long iLiveTV = -1;
750 long long iDeleted = -1;
751 long long iExpirable = -1;
753 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
754 " WHERE recgroup = :RECGROUP;");
759 iLiveTV = query.
value(0).toLongLong();
764 iDeleted = query.
value(0).toLongLong();
766 query.
prepare(
"SELECT SUM(filesize) FROM recorded "
767 " WHERE autoexpire = 1 "
768 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
771 iExpirable = query.
value(0).toLongLong();
773 group.setAttribute(
"livetv", (
int)(iLiveTV>>20) );
774 group.setAttribute(
"deleted", (
int)(iDeleted>>20) );
775 group.setAttribute(
"expirable", (
int)(iExpirable>>20) );
784 storage.appendChild(total);
785 int num_elements = fsXML.size();
786 for (
int fs_index = 0; fs_index < num_elements; fs_index++)
788 storage.appendChild(fsXML[fs_index]);
794 load.setAttribute(
"avg1", 0);
795 load.setAttribute(
"avg2", 1);
796 load.setAttribute(
"avg3", 2);
799 if (rgdAverages[0] != -1)
801 load.setAttribute(
"avg1", rgdAverages[0]);
802 load.setAttribute(
"avg2", rgdAverages[1]);
803 load.setAttribute(
"avg3", rgdAverages[2]);
809 QDateTime GuideDataThrough;
812 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
819 guide.setAttribute(
"start",
821 guide.setAttribute(
"end",
823 guide.setAttribute(
"status",
827 guide.setAttribute(
"next",
831 if (!GuideDataThrough.isNull())
833 guide.setAttribute(
"guideThru",
835 guide.setAttribute(
"guideDays", qdtNow.daysTo(GuideDataThrough));
841 if ((!info_script.isEmpty()) && (info_script !=
"none"))
843 QDomElement misc = pDoc->createElement(
"Miscellaneous");
844 root.appendChild(misc);
851 LOG(VB_GENERAL, LOG_ERR,
852 QString(
"Error running miscellaneous "
853 "status information script: %1").arg(info_script));
857 QByteArray input = ms.
ReadAll();
859 QStringList
output = QString(input).split(
'\n',
861 for (
const auto & line : std::as_const(
output))
863 QDomElement
info = pDoc->createElement(
"Information");
865 QStringList list = line.split(
"[]:[]");
866 unsigned int size = list.size();
867 unsigned int hasAttributes = 0;
869 if ((size > 0) && (!list[0].isEmpty()))
871 info.setAttribute(
"display", list[0]);
874 if ((size > 1) && (!list[1].isEmpty()))
876 info.setAttribute(
"name", list[1]);
879 if ((size > 2) && (!list[2].isEmpty()))
881 info.setAttribute(
"value", list[2]);
885 if (hasAttributes > 0)
886 misc.appendChild(
info);
897#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
898 os.setCodec(
"UTF-8");
900 os.setEncoding(QStringConverter::Utf8);
905 QDomElement docElem = pDoc->documentElement();
907 os <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
908 <<
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
909 <<
"<html xmlns=\"http://www.w3.org/1999/xhtml\""
910 <<
" xml:lang=\"en\" lang=\"en\">\r\n"
912 <<
" <meta http-equiv=\"Content-Type\""
913 <<
"content=\"text/html; charset=UTF-8\" />\r\n"
914 <<
" <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
915 <<
" <title>MythTV Status - "
919 << docElem.attribute(
"version", MYTH_BINARY_VERSION ) <<
"</title>\r\n"
921 <<
"<body bgcolor=\"#fff\">\r\n"
922 <<
"<div class=\"status\">\r\n"
923 <<
" <h1 class=\"status\">MythTV Status</h1>\r\n";
927 QDomNode node = docElem.namedItem(
"Encoders" );
934 node = docElem.namedItem(
"Scheduled" );
941 node = docElem.namedItem(
"Frontends" );
948 node = docElem.namedItem(
"Backends" );
955 node = docElem.namedItem(
"JobQueue" );
962 node = docElem.namedItem(
"MachineInfo" );
969 node = docElem.namedItem(
"Miscellaneous" );
974 os <<
"\r\n</div>\r\n</body>\r\n</html>\r\n";
984 int nNumEncoders = 0;
986 if (encoders.isNull())
989 os <<
" <div class=\"content\">\r\n"
990 <<
" <h2 class=\"status\">Encoder Status</h2>\r\n";
992 QDomNode node = encoders.firstChild();
994 while (!node.isNull())
996 QDomElement e = node.toElement();
1000 if (e.tagName() ==
"Encoder")
1002 QString sIsLocal = (e.attribute(
"local" ,
"remote" )==
"1")
1003 ?
"local" :
"remote";
1004 QString sCardId = e.attribute(
"id" ,
"0" );
1005 QString sHostName = e.attribute(
"hostname" ,
"Unknown");
1006 bool bConnected=
static_cast<bool>(e.attribute(
"connected",
"0" ).toInt());
1008 bool bIsLowOnFreeSpace=
static_cast<bool>(e.attribute(
"lowOnFreeSpace",
"0").toInt());
1010 QString sDevlabel = e.attribute(
"devlabel",
"[ UNKNOWN ]");
1012 os <<
" Encoder " << sCardId <<
" " << sDevlabel
1013 <<
" is " << sIsLocal <<
" on " << sHostName;
1015 if ((sIsLocal ==
"remote") && !bConnected)
1022 os <<
" (currently asleep).<br />";
1024 os <<
" (currently not connected).<br />";
1026 node = node.nextSibling();
1037 os <<
" and is watching Live TV";
1042 os <<
" and is recording";
1046 os <<
" and is not recording.";
1052 QDomNode tmpNode = e.namedItem(
"Program" );
1054 if (!tmpNode.isNull())
1056 QDomElement program = tmpNode.toElement();
1058 if (!program.isNull())
1060 os <<
" '" << program.attribute(
"title",
"Unknown" ) <<
"'";
1064 tmpNode = program.namedItem(
"Channel" );
1066 if (!tmpNode.isNull())
1068 QDomElement channel = tmpNode.toElement();
1070 if (!channel.isNull())
1072 << channel.attribute(
"callSign",
"unknown" );
1077 tmpNode = program.namedItem(
"Recording" );
1079 if (!tmpNode.isNull())
1081 QDomElement recording = tmpNode.toElement();
1083 if (!recording.isNull())
1086 recording.attribute(
"recEndTs",
"" ));
1088 os <<
". This recording ";
1094 os <<
"scheduled to end at "
1104 if (bIsLowOnFreeSpace)
1106 os <<
" <strong>WARNING</strong>:"
1107 <<
" This backend is low on free disk space!";
1114 node = node.nextSibling();
1117 os <<
" </div>\r\n\r\n";
1119 return nNumEncoders;
1130 if (scheduled.isNull())
1133 int nNumRecordings= scheduled.attribute(
"count",
"0" ).toInt();
1135 os <<
" <div class=\"content\">\r\n"
1136 <<
" <h2 class=\"status\">Schedule</h2>\r\n";
1138 if (nNumRecordings == 0)
1140 os <<
" There are no shows scheduled for recording.\r\n"
1145 os <<
" The next " << nNumRecordings <<
" show" << (nNumRecordings == 1 ?
"" :
"s" )
1146 <<
" that " << (nNumRecordings == 1 ?
"is" :
"are")
1147 <<
" scheduled for recording:\r\n";
1149 os <<
" <div class=\"schedule\">\r\n";
1153 QDomNode node = scheduled.firstChild();
1155 while (!node.isNull())
1157 QDomElement e = node.toElement();
1161 QDomNode recNode = e.namedItem(
"Recording" );
1162 QDomNode chanNode = e.namedItem(
"Channel" );
1164 if ((e.tagName() ==
"Program") && !recNode.isNull() &&
1167 QDomElement r = recNode.toElement();
1168 QDomElement c = chanNode.toElement();
1170 QString sTitle = e.attribute(
"title" ,
"" );
1171 QString sSubTitle = e.attribute(
"subTitle",
"" );
1177 int nPreRollSecs = r.attribute(
"preRollSeconds",
"0" ).toInt();
1178 int nEncoderId = r.attribute(
"encoderId" ,
"0" ).toInt();
1179 QString sProfile = r.attribute(
"recProfile" ,
"" );
1180 QString sChanName = c.attribute(
"channelName" ,
"" );
1183 QDomText text = e.firstChild().toText();
1185 sDesc = text.nodeValue();
1189 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
1195 int nTotalDays = nTotalSecs / 86400;
1196 int nTotalHours = (nTotalSecs / 3600)
1197 - (nTotalDays * 24);
1198 int nTotalMins = (nTotalSecs / 60) % 60;
1200 QString sTimeToStart =
"in";
1202 sTimeToStart += QObject::tr(
" %n day(s),",
"", nTotalDays );
1203 sTimeToStart += QObject::tr(
" %n hour(s) and",
"", nTotalHours);
1204 sTimeToStart += QObject::tr(
" %n minute(s)",
"", nTotalMins);
1206 if ( nTotalHours == 0 && nTotalMins == 0)
1207 sTimeToStart = QObject::tr(
"within one minute",
"Recording starting");
1209 if ( nTotalSecs < 0)
1210 sTimeToStart = QObject::tr(
"soon",
"Recording starting");
1214 os <<
" <a href=\"#\">";
1222 os <<
"Encoder " << nEncoderId <<
" - ";
1224 os << sChanName <<
" - " << sTitle <<
"<br />"
1225 <<
"<span><strong>" << sTitle <<
"</strong> ("
1229 if ( !sSubTitle.isEmpty())
1230 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1232 if ( airDate.isValid())
1234 os <<
"Orig. Airdate: "
1240 os << sDesc <<
"<br /><br />"
1241 <<
"This recording will start " << sTimeToStart
1242 <<
" using encoder " << nEncoderId <<
" with the '"
1243 << sProfile <<
"' profile.</span></a><hr />\r\n";
1247 node = node.nextSibling();
1249 os <<
" </div>\r\n";
1250 os <<
" </div>\r\n\r\n";
1252 return nNumRecordings;
1261 if (frontends.isNull())
1264 int nNumFES= frontends.attribute(
"count",
"0" ).toInt();
1270 os <<
" <div class=\"content\">\r\n"
1271 <<
" <h2 class=\"status\">Frontends</h2>\r\n";
1273 QDomNode node = frontends.firstChild();
1274 while (!node.isNull())
1276 QDomElement e = node.toElement();
1280 QString name = e.attribute(
"name" ,
"" );
1281 QString url = e.attribute(
"url" ,
"" );
1282 os << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1285 node = node.nextSibling();
1288 os <<
" </div>\r\n\r\n";
1299 if (backends.isNull())
1302 int nNumBES= backends.attribute(
"count",
"0" ).toInt();
1308 os <<
" <div class=\"content\">\r\n"
1309 <<
" <h2 class=\"status\">Other Backends</h2>\r\n";
1311 QDomNode node = backends.firstChild();
1312 while (!node.isNull())
1314 QDomElement e = node.toElement();
1318 QString
type = e.attribute(
"type",
"" );
1319 QString name = e.attribute(
"name" ,
"" );
1320 QString url = e.attribute(
"url" ,
"" );
1321 os <<
type <<
": " << name <<
" (<a href=\"" << url <<
"\">Status page</a>)<br />";
1324 node = node.nextSibling();
1327 os <<
" </div>\r\n\r\n";
1341 int nNumJobs= jobs.attribute(
"count",
"0" ).toInt();
1343 os <<
" <div class=\"content\">\r\n"
1344 <<
" <h2 class=\"status\">Job Queue</h2>\r\n";
1348 QString statusColor;
1351 os <<
" Jobs currently in Queue or recently ended:\r\n<br />"
1352 <<
" <div class=\"schedule\">\r\n";
1355 QDomNode node = jobs.firstChild();
1357 while (!node.isNull())
1359 QDomElement e = node.toElement();
1363 QDomNode progNode = e.namedItem(
"Program" );
1365 if ((e.tagName() ==
"Job") && !progNode.isNull() )
1367 QDomElement
p = progNode.toElement();
1369 QDomNode recNode =
p.namedItem(
"Recording" );
1370 QDomNode chanNode =
p.namedItem(
"Channel" );
1372 QDomElement r = recNode.toElement();
1373 QDomElement c = chanNode.toElement();
1375 int nType = e.attribute(
"type" ,
"0" ).toInt();
1376 int nStatus = e.attribute(
"status",
"0" ).toInt();
1381 statusColor =
" class=\"jobaborted\"";
1386 statusColor =
" class=\"joberrored\"";
1387 jobColor =
" class=\"joberrored\"";
1391 statusColor =
" class=\"jobfinished\"";
1392 jobColor =
" class=\"jobfinished\"";
1396 statusColor =
" class=\"jobrunning\"";
1397 jobColor =
" class=\"jobrunning\"";
1401 statusColor =
" class=\"jobqueued\"";
1402 jobColor =
" class=\"jobqueued\"";
1406 QString sTitle =
p.attribute(
"title" ,
"" );
1407 QString sSubTitle =
p.attribute(
"subTitle",
"" );
1413 QString sHostname = e.attribute(
"hostname",
"master" );
1414 QString sComment =
"";
1416 QDomText text = e.firstChild().toText();
1418 sComment = text.nodeValue();
1420 os <<
"<a href=\"javascript:void(0)\">"
1424 << sTitle <<
" - <font" << jobColor <<
">"
1426 <<
"<span><strong>" << sTitle <<
"</strong> ("
1430 if (!sSubTitle.isEmpty())
1431 os <<
"<em>" << sSubTitle <<
"</em><br /><br />";
1437 os <<
"Scheduled Run Time: "
1444 os <<
"Status: <font" << statusColor <<
">"
1452 if ( nStatus != JOB_QUEUED)
1453 os <<
"Host: " << sHostname <<
"<br />";
1455 if (!sComment.isEmpty())
1456 os <<
"<br />Comments:<br />" << sComment <<
"<br />";
1458 os <<
"</span></a><hr />\r\n";
1462 node = node.nextSibling();
1464 os <<
" </div>\r\n";
1468 os <<
" Job Queue is currently empty.\r\n\r\n";
1471 os <<
" </div>\r\n\r\n ";
1488 os <<
"<div class=\"content\">\r\n"
1489 <<
" <h2 class=\"status\">Machine Information</h2>\r\n";
1493 QDomNode node =
info.namedItem(
"Load" );
1497 QDomElement e = node.toElement();
1501 double dAvg1 = e.attribute(
"avg1" ,
"0" ).toDouble();
1502 double dAvg2 = e.attribute(
"avg2" ,
"0" ).toDouble();
1503 double dAvg3 = e.attribute(
"avg3" ,
"0" ).toDouble();
1505 os <<
" <div class=\"loadstatus\">\r\n"
1506 <<
" This machine's load average:"
1507 <<
"\r\n <ul>\r\n <li>"
1508 <<
"1 Minute: " << dAvg1 <<
"</li>\r\n"
1509 <<
" <li>5 Minutes: " << dAvg2 <<
"</li>\r\n"
1510 <<
" <li>15 Minutes: " << dAvg3
1511 <<
"</li>\r\n </ul>\r\n"
1517 node =
info.namedItem(
"Storage" );
1518 QDomElement storage = node.toElement();
1519 node = storage.firstChild();
1524 while (!node.isNull())
1526 QDomElement g = node.toElement();
1528 if (!g.isNull() && g.tagName() ==
"Group")
1530 QString
id = g.attribute(
"id",
"" );
1534 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1535 int nTotal = g.attribute(
"total",
"0" ).toInt();
1536 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1537 int nLiveTV = g.attribute(
"livetv" ,
"0" ).toInt();
1538 int nDeleted = g.attribute(
"deleted",
"0" ).toInt();
1539 int nExpirable = g.attribute(
"expirable" ,
"0" ).toInt();
1540 QString nDir = g.attribute(
"dir" ,
"" );
1542 nDir.replace(
",",
", ");
1544 os <<
" Disk Usage Summary:<br />\r\n";
1547 os <<
" <li>Total Disk Space:\r\n"
1550 os <<
" <li>Total Space: ";
1551 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1552 os << sRep <<
"</li>\r\n";
1554 os <<
" <li>Space Used: ";
1555 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1556 os << sRep <<
"</li>\r\n";
1558 os <<
" <li>Space Free: ";
1559 sRep = QString(
"%L1").arg(nFree) +
" MB";
1560 os << sRep <<
"</li>\r\n";
1562 if ((nLiveTV + nDeleted + nExpirable) > 0)
1564 os <<
" <li>Space Available "
1565 "After Auto-expire: ";
1566 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1567 sRep = QString(
"%L1").arg(nFree + nLiveTV +
1568 nDeleted + nExpirable) +
" MB";
1569 os << sRep <<
"\r\n";
1571 os <<
" <li>Space Used by LiveTV: ";
1572 sRep = QString(
"%L1").arg(nLiveTV) +
" MB";
1573 os << sRep <<
"</li>\r\n";
1574 os <<
" <li>Space Used by "
1575 "Deleted Recordings: ";
1576 sRep = QString(
"%L1").arg(nDeleted) +
" MB";
1577 os << sRep <<
"</li>\r\n";
1578 os <<
" <li>Space Used by "
1579 "Auto-expirable Recordings: ";
1580 sRep = QString(
"%L1").arg(nExpirable) +
" MB";
1581 os << sRep <<
"</li>\r\n";
1594 node = node.nextSibling();
1598 node = storage.firstChild();
1600 os <<
" Disk Usage Details:<br />\r\n";
1604 while (!node.isNull())
1606 QDomElement g = node.toElement();
1608 if (!g.isNull() && g.tagName() ==
"Group")
1610 int nFree = g.attribute(
"free" ,
"0" ).toInt();
1611 int nTotal = g.attribute(
"total",
"0" ).toInt();
1612 int nUsed = g.attribute(
"used" ,
"0" ).toInt();
1613 QString nDir = g.attribute(
"dir" ,
"" );
1614 QString
id = g.attribute(
"id" ,
"" );
1616 nDir.replace(
",",
", ");
1622 os <<
" <li>MythTV Drive #" <<
id <<
":"
1626 if (nDir.contains(
','))
1627 os <<
" <li>Directories: ";
1629 os <<
" <li>Directory: ";
1631 os << nDir <<
"</li>\r\n";
1633 os <<
" <li>Total Space: ";
1634 sRep = QString(
"%L1").arg(nTotal) +
" MB";
1635 os << sRep <<
"</li>\r\n";
1637 os <<
" <li>Space Used: ";
1638 sRep = QString(
"%L1").arg(nUsed) +
" MB";
1639 os << sRep <<
"</li>\r\n";
1641 os <<
" <li>Space Free: ";
1642 sRep = QString(
"%L1").arg(nFree) +
" MB";
1643 os << sRep <<
"</li>\r\n";
1651 node = node.nextSibling();
1658 node =
info.namedItem(
"Guide" );
1662 QDomElement e = node.toElement();
1666 int nDays = e.attribute(
"guideDays",
"0" ).toInt();
1667 QString sStart = e.attribute(
"start" ,
"" );
1668 QString sEnd = e.attribute(
"end" ,
"" );
1669 QString sStatus = e.attribute(
"status" ,
"" );
1671 QString sNext = next.isNull() ?
"" :
1677 QDomText text = e.firstChild().toText();
1684 sMsg = text.nodeValue();
1686 os <<
" Last mythfilldatabase run started on " << sStart
1692 os <<
"ended on " << sEnd <<
". ";
1694 os << sStatus <<
"<br />\r\n";
1696 if (!next.isNull() && next >= lastrunstart)
1698 os <<
" Suggested next mythfilldatabase run: "
1699 << sNext <<
".<br />\r\n";
1704 os <<
" There's guide data until "
1708 os <<
" " << QObject::tr(
"(%n day(s))",
"", nDays);
1713 os <<
" <strong>WARNING</strong>: is mythfilldatabase running?";
1717 os <<
" There's <strong>no guide data</strong> available! "
1718 <<
"Have you run mythfilldatabase?";
1722 os <<
"\r\n </div>\r\n";
1734 QDomNodeList nodes =
info.elementsByTagName(
"Information");
1735 uint count = nodes.count();
1741 os <<
"<div class=\"content\">\r\n"
1742 <<
" <h2 class=\"status\">Miscellaneous</h2>\r\n";
1743 for (
unsigned int i = 0; i < count; i++)
1745 QDomNode node = nodes.item(i);
1749 QDomElement e = node.toElement();
1753 display = e.attribute(
"display",
"");
1757 if (display.isEmpty())
1762 if (display.contains(
"<p>", Qt::CaseInsensitive) ||
1763 display.contains(
"<br", Qt::CaseInsensitive))
1770 linebreak =
"<br />\r\n";
1773 os <<
" " << display << linebreak;
1787 if ((pDoc ==
nullptr) || (pInfo ==
nullptr))
1792 QDomElement program = pDoc->createElement(
"Program" );
1793 node.appendChild( program );
1795 program.setAttribute(
"startTime" ,
1798 program.setAttribute(
"title" , pInfo->
GetTitle() );
1799 program.setAttribute(
"subTitle" , pInfo->
GetSubtitle());
1800 program.setAttribute(
"category" , pInfo->
GetCategory());
1802 program.setAttribute(
"repeat" ,
static_cast<int>(pInfo->
IsRepeat()));
1807 program.setAttribute(
"seriesId" , pInfo->
GetSeriesID() );
1808 program.setAttribute(
"programId" , pInfo->
GetProgramID() );
1809 program.setAttribute(
"stars" , pInfo->
GetStars() );
1810 program.setAttribute(
"fileSize" ,
1812 program.setAttribute(
"lastModified",
1815 program.setAttribute(
"hostname" , pInfo->
GetHostname() );
1818 program.setAttribute(
1821 QDomText textNode = pDoc->createTextNode( pInfo->
GetDescription() );
1822 program.appendChild( textNode );
1830 QDomElement channel = pDoc->createElement(
"Channel" );
1831 program.appendChild( channel );
1840 QDomElement recording = pDoc->createElement(
"Recording" );
1841 program.appendChild( recording );
1843 recording.setAttribute(
"recStatus" ,
1845 recording.setAttribute(
"recPriority" ,
1847 recording.setAttribute(
"recStartTs" ,
1849 recording.setAttribute(
"recEndTs" ,
1854 recording.setAttribute(
"recordId" ,
1856 recording.setAttribute(
"recGroup" ,
1858 recording.setAttribute(
"playGroup" ,
1860 recording.setAttribute(
"recType" ,
1862 recording.setAttribute(
"dupInType" ,
1864 recording.setAttribute(
"dupMethod" ,
1866 recording.setAttribute(
"encoderId" ,
1869 recording.setAttribute(
"recProfile" ,
1896 channel.setAttribute(
"chanId" , pInfo->
GetChanID() );
1897 channel.setAttribute(
"chanNum" , pInfo->
GetChanNum());
1904 channel.setAttribute(
"chanFilters",
1906 channel.setAttribute(
"sourceId" , pInfo->
GetSourceID() );
1907 channel.setAttribute(
"inputId" , pInfo->
GetInputID() );
1908 channel.setAttribute(
"commFree" ,
1916 static QRegularExpression re(
".*\\.sql\\.gz$");
1920 QStringList result = fileList.filter(re);
1923 result.append(fileList.filter(re));
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
QStringList GetFileList(const QString &Path, bool recursive=false)
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)
static V2RecStats * GetRecStats()
void FillStatusXML(QDomDocument *pDoc)
static QStringList GetBackupsList()
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.
static void show(uint8_t *buf, int length)
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)