MythTV  master
httpstatus.cpp
Go to the documentation of this file.
1 // Program Name: httpstatus.cpp
3 //
4 // Purpose - Html & XML status HttpServerExtension
5 //
6 // Created By : David Blain Created On : Oct. 24, 2005
7 // Modified By : Modified On:
8 //
10 
11 // POSIX headers
12 #include <unistd.h>
13 
14 // ANSI C headers
15 #include <cmath>
16 #include <cstdio>
17 #include <cstdlib>
18 
19 // Qt headers
20 #include <QtGlobal>
21 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
22 #include <QStringConverter>
23 #endif
24 #include <QTextStream>
25 
26 // MythTV headers
27 #include "libmythbase/compat.h"
28 #include "libmythbase/exitcodes.h"
29 #include "libmythbase/mythconfig.h"
31 #include "libmythbase/mythdate.h"
32 #include "libmythbase/mythdbcon.h"
35 #include "libmythbase/mythversion.h"
36 #include "libmythtv/cardutil.h"
37 #include "libmythtv/jobqueue.h"
38 #include "libmythtv/tv.h"
39 #include "libmythtv/tv_rec.h"
40 #include "libmythupnp/upnp.h"
41 
42 // MythBackend
43 #include "autoexpire.h"
44 #include "encoderlink.h"
45 #include "httpstatus.h"
46 #include "mainserver.h"
47 #include "scheduler.h"
48 
50 //
52 
53 HttpStatus::HttpStatus( QMap<int, EncoderLink *> *tvList, Scheduler *sched,
54  AutoExpire *expirer, bool bIsMaster )
55  : HttpServerExtension( "HttpStatus" , QString())
56 {
57  m_pEncoders = tvList;
58  m_pSched = sched;
60  m_bIsMaster = bIsMaster;
61 
62  m_nPreRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll", 0);
63 
64  m_pMainServer = nullptr;
65 }
66 
68 //
70 
72 {
73  if (sURI == "Status" ) return( HSM_GetStatusHTML );
74  if (sURI == "GetStatusHTML" ) return( HSM_GetStatusHTML );
75  if (sURI == "GetStatus" ) return( HSM_GetStatusXML );
76  if (sURI == "xml" ) return( HSM_GetStatusXML );
77 
78  return( HSM_Unknown );
79 }
80 
82 //
84 
86 {
87  return QStringList( "/Status" );
88 }
89 
91 //
93 
95 {
96  try
97  {
98  if (pRequest)
99  {
100  if ((pRequest->m_sBaseUrl != "/Status" ) &&
101  (pRequest->m_sResourceUrl != "/Status" ))
102  {
103  return( false );
104  }
105 
106  switch( GetMethod( pRequest->m_sMethod ))
107  {
108  case HSM_GetStatusXML : GetStatusXML ( pRequest ); return true;
109  case HSM_GetStatusHTML : GetStatusHTML ( pRequest ); return true;
110 
111  default:
112  {
113  pRequest->m_eResponseType = ResponseTypeHTML;
114  pRequest->m_nResponseStatus = 200;
115 
116  break;
117  }
118  }
119  }
120  }
121  catch( ... )
122  {
123  LOG(VB_GENERAL, LOG_ERR,
124  "HttpStatus::ProcessRequest() - Unexpected Exception");
125  }
126 
127  return( false );
128 }
129 
131 //
133 
135 {
136  QDomDocument doc( "Status" );
137 
138  // UTF-8 is the default, but good practice to specify it anyway
139  QDomProcessingInstruction encoding =
140  doc.createProcessingInstruction("xml",
141  R"(version="1.0" encoding="UTF-8")");
142  doc.appendChild(encoding);
143 
144  FillStatusXML( &doc );
145 
146  pRequest->m_eResponseType = ResponseTypeXML;
147  pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
148 
149  QTextStream stream( &pRequest->m_response );
150 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
151  stream.setCodec("UTF-8"); // Otherwise locale default is used.
152 #else
153  stream.setEncoding(QStringConverter::Utf8);
154 #endif
155  stream << doc.toString();
156 }
157 
159 //
161 
163 {
164  pRequest->m_eResponseType = ResponseTypeHTML;
165  pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
166 
167  QDomDocument doc( "Status" );
168 
169  FillStatusXML( &doc );
170 
171  QTextStream stream( &pRequest->m_response );
172  PrintStatus( stream, &doc );
173 }
174 
175 static QString setting_to_localtime(const char *setting)
176 {
177  QString origDateString = gCoreContext->GetSetting(setting);
178  QDateTime origDate = MythDate::fromString(origDateString);
180 }
181 
182 void HttpStatus::FillStatusXML( QDomDocument *pDoc )
183 {
184  QDateTime qdtNow = MythDate::current();
185 
186  // Add Root Node.
187 
188  QDomElement root = pDoc->createElement("Status");
189  pDoc->appendChild(root);
190 
191  root.setAttribute("date" , MythDate::toString(
193  root.setAttribute("time" ,
195  root.setAttribute("ISODate" , qdtNow.toString(Qt::ISODate) );
196  root.setAttribute("version" , MYTH_BINARY_VERSION );
197  root.setAttribute("protoVer", MYTH_PROTO_VERSION );
198 
199  // Add all encoders, if any
200 
201  QDomElement encoders = pDoc->createElement("Encoders");
202  root.appendChild(encoders);
203 
204  int numencoders = 0;
205  bool isLocal = true;
206 
207  TVRec::s_inputsLock.lockForRead();
208 
209  for (auto * elink : qAsConst(*m_pEncoders))
210  {
211  if (elink != nullptr)
212  {
213  TVState state = elink->GetState();
214  isLocal = elink->IsLocal();
215 
216  QDomElement encoder = pDoc->createElement("Encoder");
217  encoders.appendChild(encoder);
218 
219  encoder.setAttribute("id" , elink->GetInputID() );
220  encoder.setAttribute("local" , static_cast<int>(isLocal));
221  encoder.setAttribute("connected" , static_cast<int>(elink->IsConnected()));
222  encoder.setAttribute("state" , state );
223  encoder.setAttribute("sleepstatus" , elink->GetSleepStatus() );
224  //encoder.setAttribute("lowOnFreeSpace", elink->isLowOnFreeSpace());
225 
226  if (isLocal)
227  encoder.setAttribute("hostname", gCoreContext->GetHostName());
228  else
229  encoder.setAttribute("hostname", elink->GetHostName());
230 
231  encoder.setAttribute("devlabel",
232  CardUtil::GetDeviceLabel(elink->GetInputID()) );
233 
234  if (elink->IsConnected())
235  numencoders++;
236 
237  switch (state)
238  {
242  {
243  ProgramInfo *pInfo = elink->GetRecording();
244 
245  if (pInfo)
246  {
247  FillProgramInfo(pDoc, encoder, pInfo);
248  delete pInfo;
249  }
250 
251  break;
252  }
253 
254  default:
255  break;
256  }
257  }
258  }
259 
260  TVRec::s_inputsLock.unlock();
261 
262  encoders.setAttribute("count", numencoders);
263 
264  // Add upcoming shows
265 
266  QDomElement scheduled = pDoc->createElement("Scheduled");
267  root.appendChild(scheduled);
268 
269  RecList recordingList;
270 
271  if (m_pSched)
272  m_pSched->GetAllPending(recordingList);
273 
274  unsigned int iNum = 10;
275  unsigned int iNumRecordings = 0;
276 
277  auto itProg = recordingList.begin();
278  for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
279  {
280  if (((*itProg)->GetRecordingStatus() <= RecStatus::WillRecord) &&
281  ((*itProg)->GetRecordingStartTime() >=
283  {
284  iNumRecordings++;
285  FillProgramInfo(pDoc, scheduled, *itProg);
286  }
287  }
288 
289  while (!recordingList.empty())
290  {
291  ProgramInfo *pginfo = recordingList.back();
292  delete pginfo;
293  recordingList.pop_back();
294  }
295 
296  scheduled.setAttribute("count", iNumRecordings);
297 
298  // Add known frontends
299 
300  QDomElement frontends = pDoc->createElement("Frontends");
301  root.appendChild(frontends);
302 
304  "urn:schemas-mythtv-org:service:MythFrontend:1");
305  if (fes)
306  {
307  EntryMap map;
308  fes->GetEntryMap(map);
309  fes->DecrRef();
310  fes = nullptr;
311 
312  frontends.setAttribute( "count", map.size() );
313  for (const auto & entry : qAsConst(map))
314  {
315  QDomElement fe = pDoc->createElement("Frontend");
316  frontends.appendChild(fe);
317  QUrl url(entry->m_sLocation);
318  fe.setAttribute("name", url.host());
319  fe.setAttribute("url", url.toString(QUrl::RemovePath));
320  entry->DecrRef();
321  }
322  }
323 
324  // Other backends
325 
326  QDomElement backends = pDoc->createElement("Backends");
327  root.appendChild(backends);
328 
329  int numbes = 0;
331  {
332  numbes++;
333  QString masterhost = gCoreContext->GetMasterHostName();
334  QString masterip = gCoreContext->GetMasterServerIP();
335  int masterport = gCoreContext->GetMasterServerStatusPort();
336 
337  QDomElement mbe = pDoc->createElement("Backend");
338  backends.appendChild(mbe);
339  mbe.setAttribute("type", "Master");
340  mbe.setAttribute("name", masterhost);
341  mbe.setAttribute("url" , masterip + ":" + QString::number(masterport));
342  }
343 
345  "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
346  if (sbes)
347  {
348 
349  QString ipaddress = QString();
350  if (!UPnp::g_IPAddrList.isEmpty())
351  ipaddress = UPnp::g_IPAddrList.at(0).toString();
352 
353  EntryMap map;
354  sbes->GetEntryMap(map);
355  sbes->DecrRef();
356  sbes = nullptr;
357 
358  for (const auto & entry : qAsConst(map))
359  {
360  QUrl url(entry->m_sLocation);
361  if (url.host() != ipaddress)
362  {
363  numbes++;
364  QDomElement mbe = pDoc->createElement("Backend");
365  backends.appendChild(mbe);
366  mbe.setAttribute("type", "Slave");
367  mbe.setAttribute("name", url.host());
368  mbe.setAttribute("url" , url.toString(QUrl::RemovePath));
369  }
370  entry->DecrRef();
371  }
372  }
373 
374  backends.setAttribute("count", numbes);
375 
376  // Add Job Queue Entries
377 
378  QDomElement jobqueue = pDoc->createElement("JobQueue");
379  root.appendChild(jobqueue);
380 
381  QMap<int, JobQueueEntry> jobs;
382  QMap<int, JobQueueEntry>::Iterator it;
383 
387 
388  for (it = jobs.begin(); it != jobs.end(); ++it)
389  {
390  ProgramInfo pginfo((*it).chanid, (*it).recstartts);
391  if (!pginfo.GetChanID())
392  continue;
393 
394  QDomElement job = pDoc->createElement("Job");
395  jobqueue.appendChild(job);
396 
397  job.setAttribute("id" , (*it).id );
398  job.setAttribute("chanId" , (*it).chanid );
399  job.setAttribute("startTime" ,
400  (*it).recstartts.toString(Qt::ISODate));
401  job.setAttribute("startTs" , (*it).startts );
402  job.setAttribute("insertTime",
403  (*it).inserttime.toString(Qt::ISODate));
404  job.setAttribute("type" , (*it).type );
405  job.setAttribute("cmds" , (*it).cmds );
406  job.setAttribute("flags" , (*it).flags );
407  job.setAttribute("status" , (*it).status );
408  job.setAttribute("statusTime",
409  (*it).statustime.toString(Qt::ISODate));
410  job.setAttribute("schedTime" ,
411  (*it).schedruntime.toString(Qt::ISODate));
412  job.setAttribute("args" , (*it).args );
413 
414  if ((*it).hostname.isEmpty())
415  job.setAttribute("hostname", QObject::tr("master"));
416  else
417  job.setAttribute("hostname",(*it).hostname);
418 
419  QDomText textNode = pDoc->createTextNode((*it).comment);
420  job.appendChild(textNode);
421 
422  FillProgramInfo(pDoc, job, &pginfo);
423  }
424 
425  jobqueue.setAttribute( "count", jobs.size() );
426 
427  // Add Machine information
428 
429  QDomElement mInfo = pDoc->createElement("MachineInfo");
430  QDomElement storage = pDoc->createElement("Storage" );
431  QDomElement load = pDoc->createElement("Load" );
432  QDomElement guide = pDoc->createElement("Guide" );
433 
434  root.appendChild (mInfo );
435  mInfo.appendChild(storage);
436  mInfo.appendChild(load );
437  mInfo.appendChild(guide );
438 
439  // drive space ---------------------
440 
441  QStringList strlist;
442  QString hostname;
443  QString directory;
444  QString isLocalstr;
445  QString fsID;
446 
447  if (m_pMainServer)
449 
450  QDomElement total;
451 
452  // Make a temporary list to hold the per-filesystem elements so that the
453  // total is always the first element.
454  QList<QDomElement> fsXML;
455  QStringList::const_iterator sit = strlist.cbegin();
456  while (sit != strlist.cend())
457  {
458  hostname = *(sit++);
459  directory = *(sit++);
460  isLocalstr = *(sit++);
461  fsID = *(sit++);
462  ++sit; // ignore dirID
463  ++sit; // ignore blocksize
464  long long iTotal = (*(sit++)).toLongLong();
465  long long iUsed = (*(sit++)).toLongLong();;
466  long long iAvail = iTotal - iUsed;
467 
468  if (fsID == "-2")
469  fsID = "total";
470 
471  QDomElement group = pDoc->createElement("Group");
472 
473  group.setAttribute("id" , fsID );
474  group.setAttribute("total", (int)(iTotal>>10) );
475  group.setAttribute("used" , (int)(iUsed>>10) );
476  group.setAttribute("free" , (int)(iAvail>>10) );
477  group.setAttribute("dir" , directory );
478 
479  if (fsID == "total")
480  {
481  long long iLiveTV = -1;
482  long long iDeleted = -1;
483  long long iExpirable = -1;
484  MSqlQuery query(MSqlQuery::InitCon());
485  query.prepare("SELECT SUM(filesize) FROM recorded "
486  " WHERE recgroup = :RECGROUP;");
487 
488  query.bindValue(":RECGROUP", "LiveTV");
489  if (query.exec() && query.next())
490  {
491  iLiveTV = query.value(0).toLongLong();
492  }
493  query.bindValue(":RECGROUP", "Deleted");
494  if (query.exec() && query.next())
495  {
496  iDeleted = query.value(0).toLongLong();
497  }
498  query.prepare("SELECT SUM(filesize) FROM recorded "
499  " WHERE autoexpire = 1 "
500  " AND recgroup NOT IN ('LiveTV', 'Deleted');");
501  if (query.exec() && query.next())
502  {
503  iExpirable = query.value(0).toLongLong();
504  }
505  group.setAttribute("livetv", (int)(iLiveTV>>20) );
506  group.setAttribute("deleted", (int)(iDeleted>>20) );
507  group.setAttribute("expirable", (int)(iExpirable>>20) );
508  total = group;
509  }
510  else
511  fsXML << group;
512  }
513 
514  storage.appendChild(total);
515  int num_elements = fsXML.size();
516  for (int fs_index = 0; fs_index < num_elements; fs_index++)
517  {
518  storage.appendChild(fsXML[fs_index]);
519  }
520 
521  // load average ---------------------
522 
523 #ifdef Q_OS_ANDROID
524  load.setAttribute("avg1", 0);
525  load.setAttribute("avg2", 1);
526  load.setAttribute("avg3", 2);
527 #else
528  loadArray rgdAverages = getLoadAvgs();
529  if (rgdAverages[0] != -1)
530  {
531  load.setAttribute("avg1", rgdAverages[0]);
532  load.setAttribute("avg2", rgdAverages[1]);
533  load.setAttribute("avg3", rgdAverages[2]);
534  }
535 #endif
536 
537  // Guide Data ---------------------
538 
539  QDateTime GuideDataThrough;
540 
541  MSqlQuery query(MSqlQuery::InitCon());
542  query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
543 
544  if (query.exec() && query.next())
545  {
546  GuideDataThrough = MythDate::fromString(query.value(0).toString());
547  }
548 
549  guide.setAttribute("start",
550  setting_to_localtime("mythfilldatabaseLastRunStart"));
551  guide.setAttribute("end",
552  setting_to_localtime("mythfilldatabaseLastRunEnd"));
553  guide.setAttribute("status",
554  gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
555  if (gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", false))
556  {
557  guide.setAttribute("next",
558  gCoreContext->GetSetting("MythFillSuggestedRunTime"));
559  }
560 
561  if (!GuideDataThrough.isNull())
562  {
563  guide.setAttribute("guideThru",
564  GuideDataThrough.toString(Qt::ISODate));
565  guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
566  }
567 
568  // Add Miscellaneous information
569 
570  QString info_script = gCoreContext->GetSetting("MiscStatusScript");
571  if ((!info_script.isEmpty()) && (info_script != "none"))
572  {
573  QDomElement misc = pDoc->createElement("Miscellaneous");
574  root.appendChild(misc);
575 
576  uint flags = kMSRunShell | kMSStdOut;
577  MythSystemLegacy ms(info_script, flags);
578  ms.Run(10s);
579  if (ms.Wait() != GENERIC_EXIT_OK)
580  {
581  LOG(VB_GENERAL, LOG_ERR,
582  QString("Error running miscellaneous "
583  "status information script: %1").arg(info_script));
584  return;
585  }
586 
587  QByteArray input = ms.ReadAll();
588 
589 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
590  QStringList output = QString(input).split('\n',
591  QString::SkipEmptyParts);
592 #else
593  QStringList output = QString(input).split('\n',
594  Qt::SkipEmptyParts);
595 #endif
596 
597  for (const auto & line : qAsConst(output))
598  {
599  QDomElement info = pDoc->createElement("Information");
600 
601  QStringList list = line.split("[]:[]");
602  unsigned int size = list.size();
603  unsigned int hasAttributes = 0;
604 
605  if ((size > 0) && (!list[0].isEmpty()))
606  {
607  info.setAttribute("display", list[0]);
608  hasAttributes++;
609  }
610  if ((size > 1) && (!list[1].isEmpty()))
611  {
612  info.setAttribute("name", list[1]);
613  hasAttributes++;
614  }
615  if ((size > 2) && (!list[2].isEmpty()))
616  {
617  info.setAttribute("value", list[2]);
618  hasAttributes++;
619  }
620 
621  if (hasAttributes > 0)
622  misc.appendChild(info);
623  }
624  }
625 }
626 
628 //
630 
631 void HttpStatus::PrintStatus( QTextStream &os, QDomDocument *pDoc )
632 {
633 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
634  os.setCodec("UTF-8");
635 #else
636  os.setEncoding(QStringConverter::Utf8);
637 #endif
638 
639  QDateTime qdtNow = MythDate::current();
640 
641  QDomElement docElem = pDoc->documentElement();
642 
643  os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
644  << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
645  << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
646  << " xml:lang=\"en\" lang=\"en\">\r\n"
647  << "<head>\r\n"
648  << " <meta http-equiv=\"Content-Type\""
649  << "content=\"text/html; charset=UTF-8\" />\r\n"
650  << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
651  << " <title>MythTV Status - "
652  << docElem.attribute( "date", MythDate::toString(qdtNow, MythDate::kDateShort) )
653  << " "
654  << docElem.attribute( "time", MythDate::toString(qdtNow, MythDate::kTime) ) << " - "
655  << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
656  << "</head>\r\n"
657  << "<body bgcolor=\"#fff\">\r\n"
658  << "<div class=\"status\">\r\n"
659  << " <h1 class=\"status\">MythTV Status</h1>\r\n";
660 
661  // encoder information ---------------------
662 
663  QDomNode node = docElem.namedItem( "Encoders" );
664 
665  if (!node.isNull())
666  PrintEncoderStatus( os, node.toElement() );
667 
668  // upcoming shows --------------------------
669 
670  node = docElem.namedItem( "Scheduled" );
671 
672  if (!node.isNull())
673  PrintScheduled( os, node.toElement());
674 
675  // Frontends
676 
677  node = docElem.namedItem( "Frontends" );
678 
679  if (!node.isNull())
680  PrintFrontends (os, node.toElement());
681 
682  // Backends
683 
684  node = docElem.namedItem( "Backends" );
685 
686  if (!node.isNull())
687  PrintBackends (os, node.toElement());
688 
689  // Job Queue Entries -----------------------
690 
691  node = docElem.namedItem( "JobQueue" );
692 
693  if (!node.isNull())
694  PrintJobQueue( os, node.toElement());
695 
696  // Machine information ---------------------
697 
698  node = docElem.namedItem( "MachineInfo" );
699 
700  if (!node.isNull())
701  PrintMachineInfo( os, node.toElement());
702 
703  // Miscellaneous information ---------------
704 
705  node = docElem.namedItem( "Miscellaneous" );
706 
707  if (!node.isNull())
708  PrintMiscellaneousInfo( os, node.toElement());
709 
710  os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
711 
712 }
713 
715 //
717 
718 int HttpStatus::PrintEncoderStatus( QTextStream &os, const QDomElement& encoders )
719 {
720  int nNumEncoders = 0;
721 
722  if (encoders.isNull())
723  return 0;
724 
725  os << " <div class=\"content\">\r\n"
726  << " <h2 class=\"status\">Encoder Status</h2>\r\n";
727 
728  QDomNode node = encoders.firstChild();
729 
730  while (!node.isNull())
731  {
732  QDomElement e = node.toElement();
733 
734  if (!e.isNull())
735  {
736  if (e.tagName() == "Encoder")
737  {
738  QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
739  ? "local" : "remote";
740  QString sCardId = e.attribute( "id" , "0" );
741  QString sHostName = e.attribute( "hostname" , "Unknown");
742  bool bConnected= static_cast<bool>(e.attribute( "connected", "0" ).toInt());
743 
744  bool bIsLowOnFreeSpace=static_cast<bool>(e.attribute( "lowOnFreeSpace", "0").toInt());
745 
746  QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
747 
748  os << " Encoder " << sCardId << " " << sDevlabel
749  << " is " << sIsLocal << " on " << sHostName;
750 
751  if ((sIsLocal == "remote") && !bConnected)
752  {
753  SleepStatus sleepStatus =
754  (SleepStatus) e.attribute("sleepstatus",
755  QString::number(sStatus_Undefined)).toInt();
756 
757  if (sleepStatus == sStatus_Asleep)
758  os << " (currently asleep).<br />";
759  else
760  os << " (currently not connected).<br />";
761 
762  node = node.nextSibling();
763  continue;
764  }
765 
766  nNumEncoders++;
767 
768  TVState encState = (TVState) e.attribute( "state", "0").toInt();
769 
770  switch( encState )
771  {
773  os << " and is watching Live TV";
774  break;
775 
778  os << " and is recording";
779  break;
780 
781  default:
782  os << " and is not recording.";
783  break;
784  }
785 
786  // Display first Program Element listed under the encoder
787 
788  QDomNode tmpNode = e.namedItem( "Program" );
789 
790  if (!tmpNode.isNull())
791  {
792  QDomElement program = tmpNode.toElement();
793 
794  if (!program.isNull())
795  {
796  os << " '" << program.attribute( "title", "Unknown" ) << "'";
797 
798  // Get Channel information
799 
800  tmpNode = program.namedItem( "Channel" );
801 
802  if (!tmpNode.isNull())
803  {
804  QDomElement channel = tmpNode.toElement();
805 
806  if (!channel.isNull())
807  os << " on "
808  << channel.attribute( "callSign", "unknown" );
809  }
810 
811  // Get Recording Information (if any)
812 
813  tmpNode = program.namedItem( "Recording" );
814 
815  if (!tmpNode.isNull())
816  {
817  QDomElement recording = tmpNode.toElement();
818 
819  if (!recording.isNull())
820  {
821  QDateTime endTs = MythDate::fromString(
822  recording.attribute( "recEndTs", "" ));
823 
824  os << ". This recording ";
825  if (endTs < MythDate::current())
826  os << "was ";
827  else
828  os << "is ";
829 
830  os << "scheduled to end at "
831  << MythDate::toString(endTs,
833  }
834  }
835  }
836 
837  os << ".";
838  }
839 
840  if (bIsLowOnFreeSpace)
841  {
842  os << " <strong>WARNING</strong>:"
843  << " This backend is low on free disk space!";
844  }
845 
846  os << "<br />\r\n";
847  }
848  }
849 
850  node = node.nextSibling();
851  }
852 
853  os << " </div>\r\n\r\n";
854 
855  return( nNumEncoders );
856 }
857 
859 //
861 
862 int HttpStatus::PrintScheduled( QTextStream &os, const QDomElement& scheduled )
863 {
864  QDateTime qdtNow = MythDate::current();
865 
866  if (scheduled.isNull())
867  return( 0 );
868 
869  int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
870 
871  os << " <div class=\"content\">\r\n"
872  << " <h2 class=\"status\">Schedule</h2>\r\n";
873 
874  if (nNumRecordings == 0)
875  {
876  os << " There are no shows scheduled for recording.\r\n"
877  << " </div>\r\n";
878  return( 0 );
879  }
880 
881  os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
882  << " that " << (nNumRecordings == 1 ? "is" : "are")
883  << " scheduled for recording:\r\n";
884 
885  os << " <div class=\"schedule\">\r\n";
886 
887  // Iterate through all scheduled programs
888 
889  QDomNode node = scheduled.firstChild();
890 
891  while (!node.isNull())
892  {
893  QDomElement e = node.toElement();
894 
895  if (!e.isNull())
896  {
897  QDomNode recNode = e.namedItem( "Recording" );
898  QDomNode chanNode = e.namedItem( "Channel" );
899 
900  if ((e.tagName() == "Program") && !recNode.isNull() &&
901  !chanNode.isNull())
902  {
903  QDomElement r = recNode.toElement();
904  QDomElement c = chanNode.toElement();
905 
906  QString sTitle = e.attribute( "title" , "" );
907  QString sSubTitle = e.attribute( "subTitle", "" );
908  QDateTime airDate = MythDate::fromString( e.attribute( "airdate" ,"" ));
909  QDateTime startTs = MythDate::fromString( e.attribute( "startTime" ,"" ));
910  QDateTime endTs = MythDate::fromString( e.attribute( "endTime" ,"" ));
911  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
912 // QDateTime recEndTs = MythDate::fromString( r.attribute( "recEndTs" ,"" ));
913  int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
914  int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
915  QString sProfile = r.attribute( "recProfile" , "" );
916  QString sChanName = c.attribute( "channelName" , "" );
917  QString sDesc = "";
918 
919  QDomText text = e.firstChild().toText();
920  if (!text.isNull())
921  sDesc = text.nodeValue();
922 
923  // Build Time to recording start.
924 
925  int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
926 
927  //since we're not displaying seconds
928 
929  nTotalSecs -= 60;
930 
931  int nTotalDays = nTotalSecs / 86400;
932  int nTotalHours = (nTotalSecs / 3600)
933  - (nTotalDays * 24);
934  int nTotalMins = (nTotalSecs / 60) % 60;
935 
936  QString sTimeToStart = "in";
937 
938  sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
939  sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
940  sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
941 
942  if ( nTotalHours == 0 && nTotalMins == 0)
943  sTimeToStart = QObject::tr("within one minute", "Recording starting");
944 
945  if ( nTotalSecs < 0)
946  sTimeToStart = QObject::tr("soon", "Recording starting");
947 
948  // Output HTML
949 
950  os << " <a href=\"#\">";
951  os << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
953  MythDate::kSimplify) << " "
954  << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
955  MythDate::kTime) << " - ";
956 
957  if (nEncoderId > 0)
958  os << "Encoder " << nEncoderId << " - ";
959 
960  os << sChanName << " - " << sTitle << "<br />"
961  << "<span><strong>" << sTitle << "</strong> ("
962  << MythDate::toString(startTs, MythDate::kTime) << "-"
963  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
964 
965  if ( !sSubTitle.isEmpty())
966  os << "<em>" << sSubTitle << "</em><br /><br />";
967 
968  if ( airDate.isValid())
969  {
970  os << "Orig. Airdate: "
973  << "<br /><br />";
974  }
975 
976  os << sDesc << "<br /><br />"
977  << "This recording will start " << sTimeToStart
978  << " using encoder " << nEncoderId << " with the '"
979  << sProfile << "' profile.</span></a><hr />\r\n";
980  }
981  }
982 
983  node = node.nextSibling();
984  }
985  os << " </div>\r\n";
986  os << " </div>\r\n\r\n";
987 
988  return( nNumRecordings );
989 }
990 
992 //
994 
995 int HttpStatus::PrintFrontends( QTextStream &os, const QDomElement& frontends )
996 {
997  if (frontends.isNull())
998  return( 0 );
999 
1000  int nNumFES= frontends.attribute( "count", "0" ).toInt();
1001 
1002  if (nNumFES < 1)
1003  return( 0 );
1004 
1005 
1006  os << " <div class=\"content\">\r\n"
1007  << " <h2 class=\"status\">Frontends</h2>\r\n";
1008 
1009  QDomNode node = frontends.firstChild();
1010  while (!node.isNull())
1011  {
1012  QDomElement e = node.toElement();
1013 
1014  if (!e.isNull())
1015  {
1016  QString name = e.attribute( "name" , "" );
1017  QString url = e.attribute( "url" , "" );
1018  os << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1019  }
1020 
1021  node = node.nextSibling();
1022  }
1023 
1024  os << " </div>\r\n\r\n";
1025 
1026  return nNumFES;
1027 }
1028 
1030 //
1032 
1033 int HttpStatus::PrintBackends( QTextStream &os, const QDomElement& backends )
1034 {
1035  if (backends.isNull())
1036  return( 0 );
1037 
1038  int nNumBES= backends.attribute( "count", "0" ).toInt();
1039 
1040  if (nNumBES < 1)
1041  return( 0 );
1042 
1043 
1044  os << " <div class=\"content\">\r\n"
1045  << " <h2 class=\"status\">Other Backends</h2>\r\n";
1046 
1047  QDomNode node = backends.firstChild();
1048  while (!node.isNull())
1049  {
1050  QDomElement e = node.toElement();
1051 
1052  if (!e.isNull())
1053  {
1054  QString type = e.attribute( "type", "" );
1055  QString name = e.attribute( "name" , "" );
1056  QString url = e.attribute( "url" , "" );
1057  os << type << ": " << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1058  }
1059 
1060  node = node.nextSibling();
1061  }
1062 
1063  os << " </div>\r\n\r\n";
1064 
1065  return nNumBES;
1066 }
1067 
1069 //
1071 
1072 int HttpStatus::PrintJobQueue( QTextStream &os, const QDomElement& jobs )
1073 {
1074  if (jobs.isNull())
1075  return( 0 );
1076 
1077  int nNumJobs= jobs.attribute( "count", "0" ).toInt();
1078 
1079  os << " <div class=\"content\">\r\n"
1080  << " <h2 class=\"status\">Job Queue</h2>\r\n";
1081 
1082  if (nNumJobs != 0)
1083  {
1084  QString statusColor;
1085  QString jobColor;
1086 
1087  os << " Jobs currently in Queue or recently ended:\r\n<br />"
1088  << " <div class=\"schedule\">\r\n";
1089 
1090 
1091  QDomNode node = jobs.firstChild();
1092 
1093  while (!node.isNull())
1094  {
1095  QDomElement e = node.toElement();
1096 
1097  if (!e.isNull())
1098  {
1099  QDomNode progNode = e.namedItem( "Program" );
1100 
1101  if ((e.tagName() == "Job") && !progNode.isNull() )
1102  {
1103  QDomElement p = progNode.toElement();
1104 
1105  QDomNode recNode = p.namedItem( "Recording" );
1106  QDomNode chanNode = p.namedItem( "Channel" );
1107 
1108  QDomElement r = recNode.toElement();
1109  QDomElement c = chanNode.toElement();
1110 
1111  int nType = e.attribute( "type" , "0" ).toInt();
1112  int nStatus = e.attribute( "status", "0" ).toInt();
1113 
1114  switch( nStatus )
1115  {
1116  case JOB_ABORTED:
1117  statusColor = " class=\"jobaborted\"";
1118  jobColor = "";
1119  break;
1120 
1121  case JOB_ERRORED:
1122  statusColor = " class=\"joberrored\"";
1123  jobColor = " class=\"joberrored\"";
1124  break;
1125 
1126  case JOB_FINISHED:
1127  statusColor = " class=\"jobfinished\"";
1128  jobColor = " class=\"jobfinished\"";
1129  break;
1130 
1131  case JOB_RUNNING:
1132  statusColor = " class=\"jobrunning\"";
1133  jobColor = " class=\"jobrunning\"";
1134  break;
1135 
1136  default:
1137  statusColor = " class=\"jobqueued\"";
1138  jobColor = " class=\"jobqueued\"";
1139  break;
1140  }
1141 
1142  QString sTitle = p.attribute( "title" , "" ); //.replace("\"", "&quot;");
1143  QString sSubTitle = p.attribute( "subTitle", "" );
1144  QDateTime startTs = MythDate::fromString( p.attribute( "startTime" ,"" ));
1145  QDateTime endTs = MythDate::fromString( p.attribute( "endTime" ,"" ));
1146  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1147  QDateTime statusTime = MythDate::fromString( e.attribute( "statusTime","" ));
1148  QDateTime schedRunTime = MythDate::fromString( e.attribute( "schedTime","" ));
1149  QString sHostname = e.attribute( "hostname", "master" );
1150  QString sComment = "";
1151 
1152  QDomText text = e.firstChild().toText();
1153  if (!text.isNull())
1154  sComment = text.nodeValue();
1155 
1156  os << "<a href=\"javascript:void(0)\">"
1157  << MythDate::toString(recStartTs, MythDate::kDateFull |
1159  << " - "
1160  << sTitle << " - <font" << jobColor << ">"
1161  << JobQueue::JobText( nType ) << "</font><br />"
1162  << "<span><strong>" << sTitle << "</strong> ("
1163  << MythDate::toString(startTs, MythDate::kTime) << "-"
1164  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1165 
1166  if (!sSubTitle.isEmpty())
1167  os << "<em>" << sSubTitle << "</em><br /><br />";
1168 
1169  os << "Job: " << JobQueue::JobText( nType ) << "<br />";
1170 
1171  if (schedRunTime > MythDate::current())
1172  {
1173  os << "Scheduled Run Time: "
1174  << MythDate::toString(schedRunTime,
1177  << "<br />";
1178  }
1179 
1180  os << "Status: <font" << statusColor << ">"
1181  << JobQueue::StatusText( nStatus )
1182  << "</font><br />"
1183  << "Status Time: "
1184  << MythDate::toString(statusTime, MythDate::kDateFull |
1186  << "<br />";
1187 
1188  if ( nStatus != JOB_QUEUED)
1189  os << "Host: " << sHostname << "<br />";
1190 
1191  if (!sComment.isEmpty())
1192  os << "<br />Comments:<br />" << sComment << "<br />";
1193 
1194  os << "</span></a><hr />\r\n";
1195  }
1196  }
1197 
1198  node = node.nextSibling();
1199  }
1200  os << " </div>\r\n";
1201  }
1202  else
1203  os << " Job Queue is currently empty.\r\n\r\n";
1204 
1205  os << " </div>\r\n\r\n ";
1206 
1207  return( nNumJobs );
1208 
1209 }
1210 
1212 //
1214 
1215 int HttpStatus::PrintMachineInfo( QTextStream &os, const QDomElement& info )
1216 {
1217  QString sRep;
1218 
1219  if (info.isNull())
1220  return( 0 );
1221 
1222  os << "<div class=\"content\">\r\n"
1223  << " <h2 class=\"status\">Machine Information</h2>\r\n";
1224 
1225  // load average ---------------------
1226 
1227  QDomNode node = info.namedItem( "Load" );
1228 
1229  if (!node.isNull())
1230  {
1231  QDomElement e = node.toElement();
1232 
1233  if (!e.isNull())
1234  {
1235  double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
1236  double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
1237  double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
1238 
1239  os << " <div class=\"loadstatus\">\r\n"
1240  << " This machine's load average:"
1241  << "\r\n <ul>\r\n <li>"
1242  << "1 Minute: " << dAvg1 << "</li>\r\n"
1243  << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
1244  << " <li>15 Minutes: " << dAvg3
1245  << "</li>\r\n </ul>\r\n"
1246  << " </div>\r\n";
1247  }
1248  }
1249 
1250  // local drive space ---------------------
1251  node = info.namedItem( "Storage" );
1252  QDomElement storage = node.toElement();
1253  node = storage.firstChild();
1254 
1255  // Loop once until we find id == "total". This should be first, but a loop
1256  // separate from the per-filesystem details loop ensures total is first,
1257  // regardless.
1258  while (!node.isNull())
1259  {
1260  QDomElement g = node.toElement();
1261 
1262  if (!g.isNull() && g.tagName() == "Group")
1263  {
1264  QString id = g.attribute("id", "" );
1265 
1266  if (id == "total")
1267  {
1268  int nFree = g.attribute("free" , "0" ).toInt();
1269  int nTotal = g.attribute("total", "0" ).toInt();
1270  int nUsed = g.attribute("used" , "0" ).toInt();
1271  int nLiveTV = g.attribute("livetv" , "0" ).toInt();
1272  int nDeleted = g.attribute("deleted", "0" ).toInt();
1273  int nExpirable = g.attribute("expirable" , "0" ).toInt();
1274  QString nDir = g.attribute("dir" , "" );
1275 
1276  nDir.replace(",", ", ");
1277 
1278  os << " Disk Usage Summary:<br />\r\n";
1279  os << " <ul>\r\n";
1280 
1281  os << " <li>Total Disk Space:\r\n"
1282  << " <ul>\r\n";
1283 
1284  os << " <li>Total Space: ";
1285  sRep = QString("%L1").arg(nTotal) + " MB";
1286  os << sRep << "</li>\r\n";
1287 
1288  os << " <li>Space Used: ";
1289  sRep = QString("%L1").arg(nUsed) + " MB";
1290  os << sRep << "</li>\r\n";
1291 
1292  os << " <li>Space Free: ";
1293  sRep = QString("%L1").arg(nFree) + " MB";
1294  os << sRep << "</li>\r\n";
1295 
1296  if ((nLiveTV + nDeleted + nExpirable) > 0)
1297  {
1298  os << " <li>Space Available "
1299  "After Auto-expire: ";
1300  sRep = QString("%L1").arg(nUsed) + " MB";
1301  sRep = QString("%L1").arg(nFree + nLiveTV +
1302  nDeleted + nExpirable) + " MB";
1303  os << sRep << "\r\n";
1304  os << " <ul>\r\n";
1305  os << " <li>Space Used by LiveTV: ";
1306  sRep = QString("%L1").arg(nLiveTV) + " MB";
1307  os << sRep << "</li>\r\n";
1308  os << " <li>Space Used by "
1309  "Deleted Recordings: ";
1310  sRep = QString("%L1").arg(nDeleted) + " MB";
1311  os << sRep << "</li>\r\n";
1312  os << " <li>Space Used by "
1313  "Auto-expirable Recordings: ";
1314  sRep = QString("%L1").arg(nExpirable) + " MB";
1315  os << sRep << "</li>\r\n";
1316  os << " </ul>\r\n";
1317  os << " </li>\r\n";
1318  }
1319 
1320  os << " </ul>\r\n"
1321  << " </li>\r\n";
1322 
1323  os << " </ul>\r\n";
1324  break;
1325  }
1326  }
1327 
1328  node = node.nextSibling();
1329  }
1330 
1331  // Loop again to handle per-filesystem details.
1332  node = storage.firstChild();
1333 
1334  os << " Disk Usage Details:<br />\r\n";
1335  os << " <ul>\r\n";
1336 
1337 
1338  while (!node.isNull())
1339  {
1340  QDomElement g = node.toElement();
1341 
1342  if (!g.isNull() && g.tagName() == "Group")
1343  {
1344  int nFree = g.attribute("free" , "0" ).toInt();
1345  int nTotal = g.attribute("total", "0" ).toInt();
1346  int nUsed = g.attribute("used" , "0" ).toInt();
1347  QString nDir = g.attribute("dir" , "" );
1348  QString id = g.attribute("id" , "" );
1349 
1350  nDir.replace(",", ", ");
1351 
1352 
1353  if (id != "total")
1354  {
1355 
1356  os << " <li>MythTV Drive #" << id << ":"
1357  << "\r\n"
1358  << " <ul>\r\n";
1359 
1360  if (nDir.contains(','))
1361  os << " <li>Directories: ";
1362  else
1363  os << " <li>Directory: ";
1364 
1365  os << nDir << "</li>\r\n";
1366 
1367  os << " <li>Total Space: ";
1368  sRep = QString("%L1").arg(nTotal) + " MB";
1369  os << sRep << "</li>\r\n";
1370 
1371  os << " <li>Space Used: ";
1372  sRep = QString("%L1").arg(nUsed) + " MB";
1373  os << sRep << "</li>\r\n";
1374 
1375  os << " <li>Space Free: ";
1376  sRep = QString("%L1").arg(nFree) + " MB";
1377  os << sRep << "</li>\r\n";
1378 
1379  os << " </ul>\r\n"
1380  << " </li>\r\n";
1381  }
1382 
1383  }
1384 
1385  node = node.nextSibling();
1386  }
1387 
1388  os << " </ul>\r\n";
1389 
1390  // Guide Info ---------------------
1391 
1392  node = info.namedItem( "Guide" );
1393 
1394  if (!node.isNull())
1395  {
1396  QDomElement e = node.toElement();
1397 
1398  if (!e.isNull())
1399  {
1400  int nDays = e.attribute( "guideDays", "0" ).toInt();
1401  QString sStart = e.attribute( "start" , "" );
1402  QString sEnd = e.attribute( "end" , "" );
1403  QString sStatus = e.attribute( "status" , "" );
1404  QDateTime next = MythDate::fromString( e.attribute( "next" , "" ));
1405  QString sNext = next.isNull() ? "" :
1407  QString sMsg = "";
1408 
1409  QDateTime thru = MythDate::fromString( e.attribute( "guideThru", "" ));
1410 
1411  QDomText text = e.firstChild().toText();
1412 
1413  QString mfdblrs =
1414  gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
1415  QDateTime lastrunstart = MythDate::fromString(mfdblrs);
1416 
1417  if (!text.isNull())
1418  sMsg = text.nodeValue();
1419 
1420  os << " Last mythfilldatabase run started on " << sStart
1421  << " and ";
1422 
1423  if (sEnd < sStart)
1424  os << "is ";
1425  else
1426  os << "ended on " << sEnd << ". ";
1427 
1428  os << sStatus << "<br />\r\n";
1429 
1430  if (!next.isNull() && next >= lastrunstart)
1431  {
1432  os << " Suggested next mythfilldatabase run: "
1433  << sNext << ".<br />\r\n";
1434  }
1435 
1436  if (!thru.isNull())
1437  {
1438  os << " There's guide data until "
1440 
1441  if (nDays > 0)
1442  os << " " << QObject::tr("(%n day(s))", "", nDays);
1443 
1444  os << ".";
1445 
1446  if (nDays <= 3)
1447  os << " <strong>WARNING</strong>: is mythfilldatabase running?";
1448  }
1449  else
1450  os << " There's <strong>no guide data</strong> available! "
1451  << "Have you run mythfilldatabase?";
1452  }
1453  }
1454  os << "\r\n </div>\r\n";
1455 
1456  return( 1 );
1457 }
1458 
1459 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, const QDomElement& info )
1460 {
1461  if (info.isNull())
1462  return( 0 );
1463 
1464  // Miscellaneous information
1465 
1466  QDomNodeList nodes = info.elementsByTagName("Information");
1467  uint count = nodes.count();
1468  if (count > 0)
1469  {
1470  QString display;
1471  QString linebreak;
1472  //QString name, value;
1473  os << "<div class=\"content\">\r\n"
1474  << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
1475  for (unsigned int i = 0; i < count; i++)
1476  {
1477  QDomNode node = nodes.item(i);
1478  if (node.isNull())
1479  continue;
1480 
1481  QDomElement e = node.toElement();
1482  if (e.isNull())
1483  continue;
1484 
1485  display = e.attribute("display", "");
1486  //name = e.attribute("name", "");
1487  //value = e.attribute("value", "");
1488 
1489  if (display.isEmpty())
1490  continue;
1491 
1492  // Only include HTML line break if display value doesn't already
1493  // contain breaks.
1494  if (display.contains("<p>", Qt::CaseInsensitive) ||
1495  display.contains("<br", Qt::CaseInsensitive))
1496  {
1497  // matches <BR> or <br /
1498  linebreak = "\r\n";
1499  }
1500  else
1501  linebreak = "<br />\r\n";
1502 
1503  os << " " << display << linebreak;
1504  }
1505  os << "</div>\r\n";
1506  }
1507 
1508  return( 1 );
1509 }
1510 
1511 void HttpStatus::FillProgramInfo(QDomDocument *pDoc,
1512  QDomNode &node,
1513  ProgramInfo *pInfo,
1514  bool bIncChannel /* = true */,
1515  bool bDetails /* = true */)
1516 {
1517  if ((pDoc == nullptr) || (pInfo == nullptr))
1518  return;
1519 
1520  // Build Program Element
1521 
1522  QDomElement program = pDoc->createElement( "Program" );
1523  node.appendChild( program );
1524 
1525  program.setAttribute( "startTime" ,
1527  program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(MythDate::ISODate));
1528  program.setAttribute( "title" , pInfo->GetTitle() );
1529  program.setAttribute( "subTitle" , pInfo->GetSubtitle());
1530  program.setAttribute( "category" , pInfo->GetCategory());
1531  program.setAttribute( "catType" , pInfo->GetCategoryTypeString());
1532  program.setAttribute( "repeat" , static_cast<int>(pInfo->IsRepeat()));
1533 
1534  if (bDetails)
1535  {
1536 
1537  program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
1538  program.setAttribute( "programId" , pInfo->GetProgramID() );
1539  program.setAttribute( "stars" , pInfo->GetStars() );
1540  program.setAttribute( "fileSize" ,
1541  QString::number( pInfo->GetFilesize() ));
1542  program.setAttribute( "lastModified",
1544  program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
1545  program.setAttribute( "hostname" , pInfo->GetHostname() );
1546 
1547  if (pInfo->GetOriginalAirDate().isValid())
1548  program.setAttribute(
1549  "airdate", pInfo->GetOriginalAirDate().toString());
1550 
1551  QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
1552  program.appendChild( textNode );
1553 
1554  }
1555 
1556  if ( bIncChannel )
1557  {
1558  // Build Channel Child Element
1559 
1560  QDomElement channel = pDoc->createElement( "Channel" );
1561  program.appendChild( channel );
1562 
1563  FillChannelInfo( channel, pInfo, bDetails );
1564  }
1565 
1566  // Build Recording Child Element
1567 
1568  if ( pInfo->GetRecordingStatus() != RecStatus::Unknown )
1569  {
1570  QDomElement recording = pDoc->createElement( "Recording" );
1571  program.appendChild( recording );
1572 
1573  recording.setAttribute( "recStatus" ,
1574  pInfo->GetRecordingStatus() );
1575  recording.setAttribute( "recPriority" ,
1576  pInfo->GetRecordingPriority() );
1577  recording.setAttribute( "recStartTs" ,
1579  recording.setAttribute( "recEndTs" ,
1581 
1582  if (bDetails)
1583  {
1584  recording.setAttribute( "recordId" ,
1585  pInfo->GetRecordingRuleID() );
1586  recording.setAttribute( "recGroup" ,
1587  pInfo->GetRecordingGroup() );
1588  recording.setAttribute( "playGroup" ,
1589  pInfo->GetPlaybackGroup() );
1590  recording.setAttribute( "recType" ,
1591  pInfo->GetRecordingRuleType() );
1592  recording.setAttribute( "dupInType" ,
1593  pInfo->GetDuplicateCheckSource() );
1594  recording.setAttribute( "dupMethod" ,
1595  pInfo->GetDuplicateCheckMethod() );
1596  recording.setAttribute( "encoderId" ,
1597  pInfo->GetInputID() );
1598  const RecordingInfo ri(*pInfo);
1599  recording.setAttribute( "recProfile" ,
1601  //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
1602  }
1603  }
1604 }
1605 
1607 //
1609 
1610 void HttpStatus::FillChannelInfo( QDomElement &channel,
1611  ProgramInfo *pInfo,
1612  bool bDetails /* = true */ )
1613 {
1614  if (pInfo)
1615  {
1616 /*
1617  QString sHostName = gCoreContext->GetHostName();
1618  QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort",
1619  sHostName);
1620  QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
1621  .arg( sHostName )
1622  .arg( sPort )
1623  .arg( pInfo->chanid );
1624 */
1625 
1626  channel.setAttribute( "chanId" , pInfo->GetChanID() );
1627  channel.setAttribute( "chanNum" , pInfo->GetChanNum());
1628  channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
1629  //channel.setAttribute( "iconURL" , sIconURL );
1630  channel.setAttribute( "channelName", pInfo->GetChannelName());
1631 
1632  if (bDetails)
1633  {
1634  channel.setAttribute( "chanFilters",
1635  pInfo->GetChannelPlaybackFilters() );
1636  channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
1637  channel.setAttribute( "inputId" , pInfo->GetInputID() );
1638  channel.setAttribute( "commFree" ,
1639  (pInfo->IsCommercialFree()) ? 1 : 0 );
1640  }
1641  }
1642 }
1643 
1644 
1645 
1646 
1647 // vim:set shiftwidth=4 tabstop=4 expandtab:
HttpStatus::PrintStatus
static void PrintStatus(QTextStream &os, QDomDocument *pDoc)
Definition: httpstatus.cpp:631
HttpStatus::GetMethod
static HttpStatusMethod GetMethod(const QString &sURI)
Definition: httpstatus.cpp:71
Scheduler
Definition: scheduler.h:45
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:811
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
HTTPRequest::m_sBaseUrl
QString m_sBaseUrl
Definition: httprequest.h:127
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
tv.h
HTTPRequest
Definition: httprequest.h:109
HttpStatus::m_pEncoders
QMap< int, EncoderLink * > * m_pEncoders
Definition: httpstatus.h:47
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:806
ProgramInfo::GetFilesize
virtual uint64_t GetFilesize(void) const
Definition: programinfo.cpp:6345
HSM_GetStatusXML
@ HSM_GetStatusXML
Definition: httpstatus.h:25
CardUtil::GetDeviceLabel
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
Definition: cardutil.cpp:2625
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ProgramInfo::GetHostname
QString GetHostname(void) const
Definition: programinfo.h:421
HttpStatusMethod
HttpStatusMethod
Definition: httpstatus.h:21
MythSystemLegacy
Definition: mythsystemlegacy.h:67
HttpStatus::GetStatusHTML
void GetStatusHTML(HTTPRequest *pRequest)
Definition: httpstatus.cpp:162
SleepStatus
SleepStatus
SleepStatus is an enumeration of the awake/sleep status of a slave.
Definition: tv.h:97
HttpStatus::PrintScheduled
static int PrintScheduled(QTextStream &os, const QDomElement &scheduled)
Definition: httpstatus.cpp:862
HttpStatus::m_pSched
Scheduler * m_pSched
Definition: httpstatus.h:46
HTTPRequest::m_sMethod
QString m_sMethod
Definition: httprequest.h:129
HttpStatus::m_bIsMaster
bool m_bIsMaster
Definition: httpstatus.h:50
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
HTTPRequest::m_sResourceUrl
QString m_sResourceUrl
Definition: httprequest.h:128
ProgramInfo::GetChannelName
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:386
ProgramInfo::GetChanNum
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:376
MainServer::BackendQueryDiskSpace
void BackendQueryDiskSpace(QStringList &strlist, bool consolidated, bool allHosts)
Definition: mainserver.cpp:5169
httpstatus.h
getLoadAvgs
loadArray getLoadAvgs(void)
Returns the system load averages.
Definition: mythmiscutil.cpp:175
sched
Scheduler * sched
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
mythdbcon.h
SSDP::Find
static SSDPCacheEntries * Find(const QString &sURI)
Definition: ssdp.h:132
ProgramInfo::GetChannelSchedulingID
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:383
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:369
AutoExpire
Used to expire recordings to make space for new recordings.
Definition: autoexpire.h:60
RecStatus::Unknown
@ Unknown
Definition: recordingstatus.h:32
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:617
JOB_LIST_NOT_DONE
@ JOB_LIST_NOT_DONE
Definition: jobqueue.h:71
HttpStatus::FillProgramInfo
static void FillProgramInfo(QDomDocument *pDoc, QDomNode &node, ProgramInfo *pInfo, bool bIncChannel=true, bool bDetails=true)
Definition: httpstatus.cpp:1511
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:397
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:402
SSDPCacheEntries::GetEntryMap
void GetEntryMap(EntryMap &map)
Returns a copy of the EntryMap.
Definition: ssdpcache.cpp:93
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:412
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
HttpStatus::ProcessRequest
bool ProcessRequest(HTTPRequest *pRequest) override
Definition: httpstatus.cpp:94
ProgramInfo::GetProgramFlags
uint32_t GetProgramFlags(void) const
Definition: programinfo.h:470
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
ProgramInfo::GetRecordingPriority
int GetRecordingPriority(void) const
Definition: programinfo.h:440
HttpStatus::GetBasePaths
QStringList GetBasePaths() override
Definition: httpstatus.cpp:85
scheduler.h
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythCoreContext::GetMasterServerStatusPort
int GetMasterServerStatusPort(void)
Returns the Master Backend status port If no master server status port has been defined in the databa...
Definition: mythcorecontext.cpp:992
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
mythsystemlegacy.h
kState_WatchingRecording
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:80
JobQueue::JobText
static QString JobText(int jobType)
Definition: jobqueue.cpp:1111
HTTPRequest::m_mapRespHeaders
QStringMap m_mapRespHeaders
Definition: httprequest.h:153
ProgramInfo::IsRepeat
bool IsRepeat(void) const
Definition: programinfo.h:487
RecStatus::WillRecord
@ WillRecord
Definition: recordingstatus.h:31
RecordingInfo::GetProgramRecordingProfile
QString GetProgramRecordingProfile(void) const
Returns recording profile name that will be, or was used, for this program, creating "record" field i...
Definition: recordinginfo.cpp:492
MythCoreContext::IsMasterBackend
bool IsMasterBackend(void)
is this the actual MBE process
Definition: mythcorecontext.cpp:694
HttpStatus::PrintBackends
static int PrintBackends(QTextStream &os, const QDomElement &backends)
Definition: httpstatus.cpp:1033
JobQueue::GetJobsInQueue
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
Definition: jobqueue.cpp:1275
mythdate.h
autoexpire.h
upnp.h
HTTPRequest::m_nResponseStatus
long m_nResponseStatus
Definition: httprequest.h:152
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:447
hardwareprofile.config.p
p
Definition: config.py:33
MythCoreContext::GetMasterServerIP
QString GetMasterServerIP(void)
Returns the Master Backend IP address If the address is an IPv6 address, the scope Id is removed.
Definition: mythcorecontext.cpp:965
HttpStatus::m_pMainServer
MainServer * m_pMainServer
Definition: httpstatus.h:49
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:549
ProgramInfo::GetDescription
QString GetDescription(void) const
Definition: programinfo.h:365
compat.h
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:462
EntryMap
QMap< QString, DeviceLocation * > EntryMap
Key == Unique Service Name (USN)
Definition: ssdpcache.h:29
MythSystemLegacy::Wait
uint Wait(std::chrono::seconds timeout=0s)
Definition: mythsystemlegacy.cpp:243
MythDate::kDateShort
@ kDateShort
Default local time.
Definition: mythdate.h:20
sStatus_Asleep
@ sStatus_Asleep
A slave is considered asleep when it is not awake and not undefined.
Definition: tv.h:104
HSM_Unknown
@ HSM_Unknown
Definition: httpstatus.h:23
HttpStatus::PrintMachineInfo
static int PrintMachineInfo(QTextStream &os, const QDomElement &info)
Definition: httpstatus.cpp:1215
setting_to_localtime
static QString setting_to_localtime(const char *setting)
Definition: httpstatus.cpp:175
loadArray
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:22
ProgramInfo::GetPlaybackGroup
QString GetPlaybackGroup(void) const
Definition: programinfo.h:420
jobqueue.h
HttpStatus::FillStatusXML
void FillStatusXML(QDomDocument *pDoc)
Definition: httpstatus.cpp:182
ProgramInfo::GetChannelPlaybackFilters
QString GetChannelPlaybackFilters(void) const
Definition: programinfo.h:387
ResponseTypeXML
@ ResponseTypeXML
Definition: httprequest.h:78
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:433
SSDPCacheEntries
Definition: ssdpcache.h:35
uint
unsigned int uint
Definition: compat.h:81
HttpStatus::PrintJobQueue
static int PrintJobQueue(QTextStream &os, const QDomElement &jobs)
Definition: httpstatus.cpp:1072
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
ProgramInfo::GetSeriesID
QString GetSeriesID(void) const
Definition: programinfo.h:435
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:911
ProgramInfo::GetOriginalAirDate
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:428
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
ResponseTypeHTML
@ ResponseTypeHTML
Definition: httprequest.h:79
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
HSM_GetStatusHTML
@ HSM_GetStatusHTML
Definition: httpstatus.h:24
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:26
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:905
ProgramInfo::GetDuplicateCheckMethod
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
Definition: programinfo.h:459
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:463
sStatus_Undefined
@ sStatus_Undefined
A slave's sleep status is undefined when it has never connected to the master backend or is not able ...
Definition: tv.h:117
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:451
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
mythmiscutil.h
HttpStatus::PrintMiscellaneousInfo
static int PrintMiscellaneousInfo(QTextStream &os, const QDomElement &info)
Definition: httpstatus.cpp:1459
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:25
ProgramInfo::GetLastModifiedTime
QDateTime GetLastModifiedTime(void) const
Definition: programinfo.h:429
mythcorecontext.h
HttpStatus::m_pExpirer
AutoExpire * m_pExpirer
Definition: httpstatus.h:48
cardutil.h
ProgramInfo::GetCategoryTypeString
QString GetCategoryTypeString(void) const
Returns catType as a string.
Definition: programinfo.cpp:1887
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:887
jobqueue
JobQueue * jobqueue
Definition: mythjobqueue.cpp:43
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
HTTPRequest::m_eResponseType
HttpResponseType m_eResponseType
Definition: httprequest.h:149
HttpStatus::PrintEncoderStatus
static int PrintEncoderStatus(QTextStream &os, const QDomElement &encoders)
Definition: httpstatus.cpp:718
RecList
std::deque< RecordingInfo * > RecList
Definition: mythscheduler.h:12
tv_rec.h
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
ProgramInfo::GetDuplicateCheckSource
RecordingDupInType GetDuplicateCheckSource(void) const
Where should we check for duplicates?
Definition: programinfo.h:455
mainserver.h
MythDate::kDatabase
@ kDatabase
Default UTC, database format.
Definition: mythdate.h:27
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:19
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:837
Scheduler::GetAllPending
bool GetAllPending(RecList &retList, int recRuleId=0) const
Definition: scheduler.cpp:1741
JOB_LIST_RECENT
@ JOB_LIST_RECENT
Definition: jobqueue.h:73
HttpStatus::m_nPreRollSeconds
int m_nPreRollSeconds
Definition: httpstatus.h:51
ProgramInfo::GetProgramID
QString GetProgramID(void) const
Definition: programinfo.h:436
MythSystemLegacy::Run
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:213
expirer
AutoExpire * expirer
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:23
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:449
exitcodes.h
HttpStatus::PrintFrontends
static int PrintFrontends(QTextStream &os, const QDomElement &frontends)
Definition: httpstatus.cpp:995
JOB_LIST_ERROR
@ JOB_LIST_ERROR
Definition: jobqueue.h:72
HttpServerExtension
Definition: httpserver.h:71
UPnp::g_IPAddrList
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:110
HttpStatus::FillChannelInfo
static void FillChannelInfo(QDomElement &channel, ProgramInfo *pInfo, bool bDetails=true)
Definition: httpstatus.cpp:1610
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
HttpStatus::HttpStatus
HttpStatus(QMap< int, EncoderLink * > *tvList, Scheduler *sched, AutoExpire *expirer, bool bIsMaster)
Definition: httpstatus.cpp:53
output
#define output
Definition: synaesthesia.cpp:220
kState_RecordingOnly
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:84
ProgramInfo::IsCommercialFree
bool IsCommercialFree(void) const
Definition: programinfo.h:477
HTTPRequest::m_response
QBuffer m_response
Definition: httprequest.h:157
JobQueue::StatusText
static QString StatusText(int status)
Definition: jobqueue.cpp:1134
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:897
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:836
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:363
ProgramInfo::GetStars
float GetStars(void) const
Definition: programinfo.h:442
HttpStatus::GetStatusXML
void GetStatusXML(HTTPRequest *pRequest)
Definition: httpstatus.cpp:134