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