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