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