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  hostname = *(sit++);
451  directory = *(sit++);
452  isLocalstr = *(sit++);
453  fsID = *(sit++);
454  ++sit; // ignore dirID
455  ++sit; // ignore blocksize
456  long long iTotal = (*(sit++)).toLongLong();
457  long long iUsed = (*(sit++)).toLongLong();;
458  long long iAvail = iTotal - iUsed;
459 
460  if (fsID == "-2")
461  fsID = "total";
462 
463  QDomElement group = pDoc->createElement("Group");
464 
465  group.setAttribute("id" , fsID );
466  group.setAttribute("total", (int)(iTotal>>10) );
467  group.setAttribute("used" , (int)(iUsed>>10) );
468  group.setAttribute("free" , (int)(iAvail>>10) );
469  group.setAttribute("dir" , directory );
470 
471  if (fsID == "total")
472  {
473  long long iLiveTV = -1;
474  long long iDeleted = -1;
475  long long iExpirable = -1;
477  query.prepare("SELECT SUM(filesize) FROM recorded "
478  " WHERE recgroup = :RECGROUP;");
479 
480  query.bindValue(":RECGROUP", "LiveTV");
481  if (query.exec() && query.next())
482  {
483  iLiveTV = query.value(0).toLongLong();
484  }
485  query.bindValue(":RECGROUP", "Deleted");
486  if (query.exec() && query.next())
487  {
488  iDeleted = query.value(0).toLongLong();
489  }
490  query.prepare("SELECT SUM(filesize) FROM recorded "
491  " WHERE autoexpire = 1 "
492  " AND recgroup NOT IN ('LiveTV', 'Deleted');");
493  if (query.exec() && query.next())
494  {
495  iExpirable = query.value(0).toLongLong();
496  }
497  group.setAttribute("livetv", (int)(iLiveTV>>20) );
498  group.setAttribute("deleted", (int)(iDeleted>>20) );
499  group.setAttribute("expirable", (int)(iExpirable>>20) );
500  total = group;
501  }
502  else
503  fsXML << group;
504  }
505 
506  storage.appendChild(total);
507  int num_elements = fsXML.size();
508  for (int fs_index = 0; fs_index < num_elements; fs_index++)
509  {
510  storage.appendChild(fsXML[fs_index]);
511  }
512 
513  // load average ---------------------
514 
515 #ifdef Q_OS_ANDROID
516  load.setAttribute("avg1", 0);
517  load.setAttribute("avg2", 1);
518  load.setAttribute("avg3", 2);
519 #else
520  loadArray rgdAverages = getLoadAvgs();
521  if (rgdAverages[0] != -1)
522  {
523  load.setAttribute("avg1", rgdAverages[0]);
524  load.setAttribute("avg2", rgdAverages[1]);
525  load.setAttribute("avg3", rgdAverages[2]);
526  }
527 #endif
528 
529  // Guide Data ---------------------
530 
531  QDateTime GuideDataThrough;
532 
534  query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
535 
536  if (query.exec() && query.next())
537  {
538  GuideDataThrough = MythDate::fromString(query.value(0).toString());
539  }
540 
541  guide.setAttribute("start",
542  setting_to_localtime("mythfilldatabaseLastRunStart"));
543  guide.setAttribute("end",
544  setting_to_localtime("mythfilldatabaseLastRunEnd"));
545  guide.setAttribute("status",
546  gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
547  if (gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", false))
548  {
549  guide.setAttribute("next",
550  gCoreContext->GetSetting("MythFillSuggestedRunTime"));
551  }
552 
553  if (!GuideDataThrough.isNull())
554  {
555  guide.setAttribute("guideThru",
556  GuideDataThrough.toString(Qt::ISODate));
557  guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
558  }
559 
560  // Add Miscellaneous information
561 
562  QString info_script = gCoreContext->GetSetting("MiscStatusScript");
563  if ((!info_script.isEmpty()) && (info_script != "none"))
564  {
565  QDomElement misc = pDoc->createElement("Miscellaneous");
566  root.appendChild(misc);
567 
568  uint flags = kMSRunShell | kMSStdOut;
569  MythSystemLegacy ms(info_script, flags);
570  ms.Run(10);
571  if (ms.Wait() != GENERIC_EXIT_OK)
572  {
573  LOG(VB_GENERAL, LOG_ERR,
574  QString("Error running miscellaneous "
575  "status information script: %1").arg(info_script));
576  return;
577  }
578 
579  QByteArray input = ms.ReadAll();
580 
581 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
582  QStringList output = QString(input).split('\n',
583  QString::SkipEmptyParts);
584 #else
585  QStringList output = QString(input).split('\n',
586  Qt::SkipEmptyParts);
587 #endif
588 
589  for (const auto & line : qAsConst(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  os.setCodec("UTF-8");
626 
627  QDateTime qdtNow = MythDate::current();
628 
629  QDomElement docElem = pDoc->documentElement();
630 
631  os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
632  << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
633  << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
634  << " xml:lang=\"en\" lang=\"en\">\r\n"
635  << "<head>\r\n"
636  << " <meta http-equiv=\"Content-Type\""
637  << "content=\"text/html; charset=UTF-8\" />\r\n"
638  << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
639  << " <title>MythTV Status - "
640  << docElem.attribute( "date", MythDate::toString(qdtNow, MythDate::kDateShort) )
641  << " "
642  << docElem.attribute( "time", MythDate::toString(qdtNow, MythDate::kTime) ) << " - "
643  << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
644  << "</head>\r\n"
645  << "<body bgcolor=\"#fff\">\r\n"
646  << "<div class=\"status\">\r\n"
647  << " <h1 class=\"status\">MythTV Status</h1>\r\n";
648 
649  // encoder information ---------------------
650 
651  QDomNode node = docElem.namedItem( "Encoders" );
652 
653  if (!node.isNull())
654  PrintEncoderStatus( os, node.toElement() );
655 
656  // upcoming shows --------------------------
657 
658  node = docElem.namedItem( "Scheduled" );
659 
660  if (!node.isNull())
661  PrintScheduled( os, node.toElement());
662 
663  // Frontends
664 
665  node = docElem.namedItem( "Frontends" );
666 
667  if (!node.isNull())
668  PrintFrontends (os, node.toElement());
669 
670  // Backends
671 
672  node = docElem.namedItem( "Backends" );
673 
674  if (!node.isNull())
675  PrintBackends (os, node.toElement());
676 
677  // Job Queue Entries -----------------------
678 
679  node = docElem.namedItem( "JobQueue" );
680 
681  if (!node.isNull())
682  PrintJobQueue( os, node.toElement());
683 
684  // Machine information ---------------------
685 
686  node = docElem.namedItem( "MachineInfo" );
687 
688  if (!node.isNull())
689  PrintMachineInfo( os, node.toElement());
690 
691  // Miscellaneous information ---------------
692 
693  node = docElem.namedItem( "Miscellaneous" );
694 
695  if (!node.isNull())
696  PrintMiscellaneousInfo( os, node.toElement());
697 
698  os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
699 
700 }
701 
703 //
705 
706 int HttpStatus::PrintEncoderStatus( QTextStream &os, const QDomElement& encoders )
707 {
708  int nNumEncoders = 0;
709 
710  if (encoders.isNull())
711  return 0;
712 
713  os << " <div class=\"content\">\r\n"
714  << " <h2 class=\"status\">Encoder Status</h2>\r\n";
715 
716  QDomNode node = encoders.firstChild();
717 
718  while (!node.isNull())
719  {
720  QDomElement e = node.toElement();
721 
722  if (!e.isNull())
723  {
724  if (e.tagName() == "Encoder")
725  {
726  QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
727  ? "local" : "remote";
728  QString sCardId = e.attribute( "id" , "0" );
729  QString sHostName = e.attribute( "hostname" , "Unknown");
730  bool bConnected= static_cast<bool>(e.attribute( "connected", "0" ).toInt());
731 
732  bool bIsLowOnFreeSpace=static_cast<bool>(e.attribute( "lowOnFreeSpace", "0").toInt());
733 
734  QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
735 
736  os << " Encoder " << sCardId << " " << sDevlabel
737  << " is " << sIsLocal << " on " << sHostName;
738 
739  if ((sIsLocal == "remote") && !bConnected)
740  {
741  SleepStatus sleepStatus =
742  (SleepStatus) e.attribute("sleepstatus",
743  QString((int)sStatus_Undefined)).toInt();
744 
745  if (sleepStatus == sStatus_Asleep)
746  os << " (currently asleep).<br />";
747  else
748  os << " (currently not connected).<br />";
749 
750  node = node.nextSibling();
751  continue;
752  }
753 
754  nNumEncoders++;
755 
756  TVState encState = (TVState) e.attribute( "state", "0").toInt();
757 
758  switch( encState )
759  {
761  os << " and is watching Live TV";
762  break;
763 
766  os << " and is recording";
767  break;
768 
769  default:
770  os << " and is not recording.";
771  break;
772  }
773 
774  // Display first Program Element listed under the encoder
775 
776  QDomNode tmpNode = e.namedItem( "Program" );
777 
778  if (!tmpNode.isNull())
779  {
780  QDomElement program = tmpNode.toElement();
781 
782  if (!program.isNull())
783  {
784  os << " '" << program.attribute( "title", "Unknown" ) << "'";
785 
786  // Get Channel information
787 
788  tmpNode = program.namedItem( "Channel" );
789 
790  if (!tmpNode.isNull())
791  {
792  QDomElement channel = tmpNode.toElement();
793 
794  if (!channel.isNull())
795  os << " on "
796  << channel.attribute( "callSign", "unknown" );
797  }
798 
799  // Get Recording Information (if any)
800 
801  tmpNode = program.namedItem( "Recording" );
802 
803  if (!tmpNode.isNull())
804  {
805  QDomElement recording = tmpNode.toElement();
806 
807  if (!recording.isNull())
808  {
809  QDateTime endTs = MythDate::fromString(
810  recording.attribute( "recEndTs", "" ));
811 
812  os << ". This recording ";
813  if (endTs < MythDate::current())
814  os << "was ";
815  else
816  os << "is ";
817 
818  os << "scheduled to end at "
819  << MythDate::toString(endTs,
821  }
822  }
823  }
824 
825  os << ".";
826  }
827 
828  if (bIsLowOnFreeSpace)
829  {
830  os << " <strong>WARNING</strong>:"
831  << " This backend is low on free disk space!";
832  }
833 
834  os << "<br />\r\n";
835  }
836  }
837 
838  node = node.nextSibling();
839  }
840 
841  os << " </div>\r\n\r\n";
842 
843  return( nNumEncoders );
844 }
845 
847 //
849 
850 int HttpStatus::PrintScheduled( QTextStream &os, const QDomElement& scheduled )
851 {
852  QDateTime qdtNow = MythDate::current();
853 
854  if (scheduled.isNull())
855  return( 0 );
856 
857  int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
858 
859  os << " <div class=\"content\">\r\n"
860  << " <h2 class=\"status\">Schedule</h2>\r\n";
861 
862  if (nNumRecordings == 0)
863  {
864  os << " There are no shows scheduled for recording.\r\n"
865  << " </div>\r\n";
866  return( 0 );
867  }
868 
869  os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
870  << " that " << (nNumRecordings == 1 ? "is" : "are")
871  << " scheduled for recording:\r\n";
872 
873  os << " <div class=\"schedule\">\r\n";
874 
875  // Iterate through all scheduled programs
876 
877  QDomNode node = scheduled.firstChild();
878 
879  while (!node.isNull())
880  {
881  QDomElement e = node.toElement();
882 
883  if (!e.isNull())
884  {
885  QDomNode recNode = e.namedItem( "Recording" );
886  QDomNode chanNode = e.namedItem( "Channel" );
887 
888  if ((e.tagName() == "Program") && !recNode.isNull() &&
889  !chanNode.isNull())
890  {
891  QDomElement r = recNode.toElement();
892  QDomElement c = chanNode.toElement();
893 
894  QString sTitle = e.attribute( "title" , "" );
895  QString sSubTitle = e.attribute( "subTitle", "" );
896  QDateTime airDate = MythDate::fromString( e.attribute( "airdate" ,"" ));
897  QDateTime startTs = MythDate::fromString( e.attribute( "startTime" ,"" ));
898  QDateTime endTs = MythDate::fromString( e.attribute( "endTime" ,"" ));
899  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
900 // QDateTime recEndTs = MythDate::fromString( r.attribute( "recEndTs" ,"" ));
901  int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
902  int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
903  QString sProfile = r.attribute( "recProfile" , "" );
904  QString sChanName = c.attribute( "channelName" , "" );
905  QString sDesc = "";
906 
907  QDomText text = e.firstChild().toText();
908  if (!text.isNull())
909  sDesc = text.nodeValue();
910 
911  // Build Time to recording start.
912 
913  int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
914 
915  //since we're not displaying seconds
916 
917  nTotalSecs -= 60;
918 
919  int nTotalDays = nTotalSecs / 86400;
920  int nTotalHours = (nTotalSecs / 3600)
921  - (nTotalDays * 24);
922  int nTotalMins = (nTotalSecs / 60) % 60;
923 
924  QString sTimeToStart = "in";
925 
926  sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
927  sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
928  sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
929 
930  if ( nTotalHours == 0 && nTotalMins == 0)
931  sTimeToStart = QObject::tr("within one minute", "Recording starting");
932 
933  if ( nTotalSecs < 0)
934  sTimeToStart = QObject::tr("soon", "Recording starting");
935 
936  // Output HTML
937 
938  os << " <a href=\"#\">";
939  os << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
941  MythDate::kSimplify) << " "
942  << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
943  MythDate::kTime) << " - ";
944 
945  if (nEncoderId > 0)
946  os << "Encoder " << nEncoderId << " - ";
947 
948  os << sChanName << " - " << sTitle << "<br />"
949  << "<span><strong>" << sTitle << "</strong> ("
950  << MythDate::toString(startTs, MythDate::kTime) << "-"
951  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
952 
953  if ( !sSubTitle.isEmpty())
954  os << "<em>" << sSubTitle << "</em><br /><br />";
955 
956  if ( airDate.isValid())
957  {
958  os << "Orig. Airdate: "
961  << "<br /><br />";
962  }
963 
964  os << sDesc << "<br /><br />"
965  << "This recording will start " << sTimeToStart
966  << " using encoder " << nEncoderId << " with the '"
967  << sProfile << "' profile.</span></a><hr />\r\n";
968  }
969  }
970 
971  node = node.nextSibling();
972  }
973  os << " </div>\r\n";
974  os << " </div>\r\n\r\n";
975 
976  return( nNumRecordings );
977 }
978 
980 //
982 
983 int HttpStatus::PrintFrontends( QTextStream &os, const QDomElement& frontends )
984 {
985  if (frontends.isNull())
986  return( 0 );
987 
988  int nNumFES= frontends.attribute( "count", "0" ).toInt();
989 
990  if (nNumFES < 1)
991  return( 0 );
992 
993 
994  os << " <div class=\"content\">\r\n"
995  << " <h2 class=\"status\">Frontends</h2>\r\n";
996 
997  QDomNode node = frontends.firstChild();
998  while (!node.isNull())
999  {
1000  QDomElement e = node.toElement();
1001 
1002  if (!e.isNull())
1003  {
1004  QString name = e.attribute( "name" , "" );
1005  QString url = e.attribute( "url" , "" );
1006  os << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1007  }
1008 
1009  node = node.nextSibling();
1010  }
1011 
1012  os << " </div>\r\n\r\n";
1013 
1014  return nNumFES;
1015 }
1016 
1018 //
1020 
1021 int HttpStatus::PrintBackends( QTextStream &os, const QDomElement& backends )
1022 {
1023  if (backends.isNull())
1024  return( 0 );
1025 
1026  int nNumBES= backends.attribute( "count", "0" ).toInt();
1027 
1028  if (nNumBES < 1)
1029  return( 0 );
1030 
1031 
1032  os << " <div class=\"content\">\r\n"
1033  << " <h2 class=\"status\">Other Backends</h2>\r\n";
1034 
1035  QDomNode node = backends.firstChild();
1036  while (!node.isNull())
1037  {
1038  QDomElement e = node.toElement();
1039 
1040  if (!e.isNull())
1041  {
1042  QString type = e.attribute( "type", "" );
1043  QString name = e.attribute( "name" , "" );
1044  QString url = e.attribute( "url" , "" );
1045  os << type << ": " << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1046  }
1047 
1048  node = node.nextSibling();
1049  }
1050 
1051  os << " </div>\r\n\r\n";
1052 
1053  return nNumBES;
1054 }
1055 
1057 //
1059 
1060 int HttpStatus::PrintJobQueue( QTextStream &os, const QDomElement& jobs )
1061 {
1062  if (jobs.isNull())
1063  return( 0 );
1064 
1065  int nNumJobs= jobs.attribute( "count", "0" ).toInt();
1066 
1067  os << " <div class=\"content\">\r\n"
1068  << " <h2 class=\"status\">Job Queue</h2>\r\n";
1069 
1070  if (nNumJobs != 0)
1071  {
1072  QString statusColor;
1073  QString jobColor;
1074 
1075  os << " Jobs currently in Queue or recently ended:\r\n<br />"
1076  << " <div class=\"schedule\">\r\n";
1077 
1078 
1079  QDomNode node = jobs.firstChild();
1080 
1081  while (!node.isNull())
1082  {
1083  QDomElement e = node.toElement();
1084 
1085  if (!e.isNull())
1086  {
1087  QDomNode progNode = e.namedItem( "Program" );
1088 
1089  if ((e.tagName() == "Job") && !progNode.isNull() )
1090  {
1091  QDomElement p = progNode.toElement();
1092 
1093  QDomNode recNode = p.namedItem( "Recording" );
1094  QDomNode chanNode = p.namedItem( "Channel" );
1095 
1096  QDomElement r = recNode.toElement();
1097  QDomElement c = chanNode.toElement();
1098 
1099  int nType = e.attribute( "type" , "0" ).toInt();
1100  int nStatus = e.attribute( "status", "0" ).toInt();
1101 
1102  switch( nStatus )
1103  {
1104  case JOB_ABORTED:
1105  statusColor = " class=\"jobaborted\"";
1106  jobColor = "";
1107  break;
1108 
1109  case JOB_ERRORED:
1110  statusColor = " class=\"joberrored\"";
1111  jobColor = " class=\"joberrored\"";
1112  break;
1113 
1114  case JOB_FINISHED:
1115  statusColor = " class=\"jobfinished\"";
1116  jobColor = " class=\"jobfinished\"";
1117  break;
1118 
1119  case JOB_RUNNING:
1120  statusColor = " class=\"jobrunning\"";
1121  jobColor = " class=\"jobrunning\"";
1122  break;
1123 
1124  default:
1125  statusColor = " class=\"jobqueued\"";
1126  jobColor = " class=\"jobqueued\"";
1127  break;
1128  }
1129 
1130  QString sTitle = p.attribute( "title" , "" ); //.replace(QRegExp("\""), "&quot;");
1131  QString sSubTitle = p.attribute( "subTitle", "" );
1132  QDateTime startTs = MythDate::fromString( p.attribute( "startTime" ,"" ));
1133  QDateTime endTs = MythDate::fromString( p.attribute( "endTime" ,"" ));
1134  QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1135  QDateTime statusTime = MythDate::fromString( e.attribute( "statusTime","" ));
1136  QDateTime schedRunTime = MythDate::fromString( e.attribute( "schedTime","" ));
1137  QString sHostname = e.attribute( "hostname", "master" );
1138  QString sComment = "";
1139 
1140  QDomText text = e.firstChild().toText();
1141  if (!text.isNull())
1142  sComment = text.nodeValue();
1143 
1144  os << "<a href=\"javascript:void(0)\">"
1145  << MythDate::toString(recStartTs, MythDate::kDateFull |
1147  << " - "
1148  << sTitle << " - <font" << jobColor << ">"
1149  << JobQueue::JobText( nType ) << "</font><br />"
1150  << "<span><strong>" << sTitle << "</strong> ("
1151  << MythDate::toString(startTs, MythDate::kTime) << "-"
1152  << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1153 
1154  if (!sSubTitle.isEmpty())
1155  os << "<em>" << sSubTitle << "</em><br /><br />";
1156 
1157  os << "Job: " << JobQueue::JobText( nType ) << "<br />";
1158 
1159  if (schedRunTime > MythDate::current())
1160  {
1161  os << "Scheduled Run Time: "
1162  << MythDate::toString(schedRunTime,
1165  << "<br />";
1166  }
1167 
1168  os << "Status: <font" << statusColor << ">"
1169  << JobQueue::StatusText( nStatus )
1170  << "</font><br />"
1171  << "Status Time: "
1172  << MythDate::toString(statusTime, MythDate::kDateFull |
1174  << "<br />";
1175 
1176  if ( nStatus != JOB_QUEUED)
1177  os << "Host: " << sHostname << "<br />";
1178 
1179  if (!sComment.isEmpty())
1180  os << "<br />Comments:<br />" << sComment << "<br />";
1181 
1182  os << "</span></a><hr />\r\n";
1183  }
1184  }
1185 
1186  node = node.nextSibling();
1187  }
1188  os << " </div>\r\n";
1189  }
1190  else
1191  os << " Job Queue is currently empty.\r\n\r\n";
1192 
1193  os << " </div>\r\n\r\n ";
1194 
1195  return( nNumJobs );
1196 
1197 }
1198 
1200 //
1202 
1203 int HttpStatus::PrintMachineInfo( QTextStream &os, const QDomElement& info )
1204 {
1205  QString sRep;
1206 
1207  if (info.isNull())
1208  return( 0 );
1209 
1210  os << "<div class=\"content\">\r\n"
1211  << " <h2 class=\"status\">Machine Information</h2>\r\n";
1212 
1213  // load average ---------------------
1214 
1215  QDomNode node = info.namedItem( "Load" );
1216 
1217  if (!node.isNull())
1218  {
1219  QDomElement e = node.toElement();
1220 
1221  if (!e.isNull())
1222  {
1223  double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
1224  double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
1225  double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
1226 
1227  os << " <div class=\"loadstatus\">\r\n"
1228  << " This machine's load average:"
1229  << "\r\n <ul>\r\n <li>"
1230  << "1 Minute: " << dAvg1 << "</li>\r\n"
1231  << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
1232  << " <li>15 Minutes: " << dAvg3
1233  << "</li>\r\n </ul>\r\n"
1234  << " </div>\r\n";
1235  }
1236  }
1237 
1238  // local drive space ---------------------
1239  node = info.namedItem( "Storage" );
1240  QDomElement storage = node.toElement();
1241  node = storage.firstChild();
1242 
1243  // Loop once until we find id == "total". This should be first, but a loop
1244  // separate from the per-filesystem details loop ensures total is first,
1245  // regardless.
1246  while (!node.isNull())
1247  {
1248  QDomElement g = node.toElement();
1249 
1250  if (!g.isNull() && g.tagName() == "Group")
1251  {
1252  QString id = g.attribute("id", "" );
1253 
1254  if (id == "total")
1255  {
1256  int nFree = g.attribute("free" , "0" ).toInt();
1257  int nTotal = g.attribute("total", "0" ).toInt();
1258  int nUsed = g.attribute("used" , "0" ).toInt();
1259  int nLiveTV = g.attribute("livetv" , "0" ).toInt();
1260  int nDeleted = g.attribute("deleted", "0" ).toInt();
1261  int nExpirable = g.attribute("expirable" , "0" ).toInt();
1262  QString nDir = g.attribute("dir" , "" );
1263 
1264  nDir.replace(QRegExp(","), ", ");
1265 
1266  os << " Disk Usage Summary:<br />\r\n";
1267  os << " <ul>\r\n";
1268 
1269  os << " <li>Total Disk Space:\r\n"
1270  << " <ul>\r\n";
1271 
1272  os << " <li>Total Space: ";
1273  sRep = QString("%L1").arg(nTotal) + " MB";
1274  os << sRep << "</li>\r\n";
1275 
1276  os << " <li>Space Used: ";
1277  sRep = QString("%L1").arg(nUsed) + " MB";
1278  os << sRep << "</li>\r\n";
1279 
1280  os << " <li>Space Free: ";
1281  sRep = QString("%L1").arg(nFree) + " MB";
1282  os << sRep << "</li>\r\n";
1283 
1284  if ((nLiveTV + nDeleted + nExpirable) > 0)
1285  {
1286  os << " <li>Space Available "
1287  "After Auto-expire: ";
1288  sRep = QString("%L1").arg(nUsed) + " MB";
1289  sRep = QString("%L1").arg(nFree + nLiveTV +
1290  nDeleted + nExpirable) + " MB";
1291  os << sRep << "\r\n";
1292  os << " <ul>\r\n";
1293  os << " <li>Space Used by LiveTV: ";
1294  sRep = QString("%L1").arg(nLiveTV) + " MB";
1295  os << sRep << "</li>\r\n";
1296  os << " <li>Space Used by "
1297  "Deleted Recordings: ";
1298  sRep = QString("%L1").arg(nDeleted) + " MB";
1299  os << sRep << "</li>\r\n";
1300  os << " <li>Space Used by "
1301  "Auto-expirable Recordings: ";
1302  sRep = QString("%L1").arg(nExpirable) + " MB";
1303  os << sRep << "</li>\r\n";
1304  os << " </ul>\r\n";
1305  os << " </li>\r\n";
1306  }
1307 
1308  os << " </ul>\r\n"
1309  << " </li>\r\n";
1310 
1311  os << " </ul>\r\n";
1312  break;
1313  }
1314  }
1315 
1316  node = node.nextSibling();
1317  }
1318 
1319  // Loop again to handle per-filesystem details.
1320  node = storage.firstChild();
1321 
1322  os << " Disk Usage Details:<br />\r\n";
1323  os << " <ul>\r\n";
1324 
1325 
1326  while (!node.isNull())
1327  {
1328  QDomElement g = node.toElement();
1329 
1330  if (!g.isNull() && g.tagName() == "Group")
1331  {
1332  int nFree = g.attribute("free" , "0" ).toInt();
1333  int nTotal = g.attribute("total", "0" ).toInt();
1334  int nUsed = g.attribute("used" , "0" ).toInt();
1335  QString nDir = g.attribute("dir" , "" );
1336  QString id = g.attribute("id" , "" );
1337 
1338  nDir.replace(QRegExp(","), ", ");
1339 
1340 
1341  if (id != "total")
1342  {
1343 
1344  os << " <li>MythTV Drive #" << id << ":"
1345  << "\r\n"
1346  << " <ul>\r\n";
1347 
1348  if (nDir.contains(','))
1349  os << " <li>Directories: ";
1350  else
1351  os << " <li>Directory: ";
1352 
1353  os << nDir << "</li>\r\n";
1354 
1355  os << " <li>Total Space: ";
1356  sRep = QString("%L1").arg(nTotal) + " MB";
1357  os << sRep << "</li>\r\n";
1358 
1359  os << " <li>Space Used: ";
1360  sRep = QString("%L1").arg(nUsed) + " MB";
1361  os << sRep << "</li>\r\n";
1362 
1363  os << " <li>Space Free: ";
1364  sRep = QString("%L1").arg(nFree) + " MB";
1365  os << sRep << "</li>\r\n";
1366 
1367  os << " </ul>\r\n"
1368  << " </li>\r\n";
1369  }
1370 
1371  }
1372 
1373  node = node.nextSibling();
1374  }
1375 
1376  os << " </ul>\r\n";
1377 
1378  // Guide Info ---------------------
1379 
1380  node = info.namedItem( "Guide" );
1381 
1382  if (!node.isNull())
1383  {
1384  QDomElement e = node.toElement();
1385 
1386  if (!e.isNull())
1387  {
1388  int nDays = e.attribute( "guideDays", "0" ).toInt();
1389  QString sStart = e.attribute( "start" , "" );
1390  QString sEnd = e.attribute( "end" , "" );
1391  QString sStatus = e.attribute( "status" , "" );
1392  QDateTime next = MythDate::fromString( e.attribute( "next" , "" ));
1393  QString sNext = next.isNull() ? "" :
1395  QString sMsg = "";
1396 
1397  QDateTime thru = MythDate::fromString( e.attribute( "guideThru", "" ));
1398 
1399  QDomText text = e.firstChild().toText();
1400 
1401  QString mfdblrs =
1402  gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
1403  QDateTime lastrunstart = MythDate::fromString(mfdblrs);
1404 
1405  if (!text.isNull())
1406  sMsg = text.nodeValue();
1407 
1408  os << " Last mythfilldatabase run started on " << sStart
1409  << " and ";
1410 
1411  if (sEnd < sStart)
1412  os << "is ";
1413  else
1414  os << "ended on " << sEnd << ". ";
1415 
1416  os << sStatus << "<br />\r\n";
1417 
1418  if (!next.isNull() && next >= lastrunstart)
1419  {
1420  os << " Suggested next mythfilldatabase run: "
1421  << sNext << ".<br />\r\n";
1422  }
1423 
1424  if (!thru.isNull())
1425  {
1426  os << " There's guide data until "
1428 
1429  if (nDays > 0)
1430  os << " " << QObject::tr("(%n day(s))", "", nDays);
1431 
1432  os << ".";
1433 
1434  if (nDays <= 3)
1435  os << " <strong>WARNING</strong>: is mythfilldatabase running?";
1436  }
1437  else
1438  os << " There's <strong>no guide data</strong> available! "
1439  << "Have you run mythfilldatabase?";
1440  }
1441  }
1442  os << "\r\n </div>\r\n";
1443 
1444  return( 1 );
1445 }
1446 
1447 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, const QDomElement& info )
1448 {
1449  if (info.isNull())
1450  return( 0 );
1451 
1452  // Miscellaneous information
1453 
1454  QDomNodeList nodes = info.elementsByTagName("Information");
1455  uint count = nodes.count();
1456  if (count > 0)
1457  {
1458  QString display;
1459  QString linebreak;
1460  //QString name, value;
1461  os << "<div class=\"content\">\r\n"
1462  << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
1463  for (unsigned int i = 0; i < count; i++)
1464  {
1465  QDomNode node = nodes.item(i);
1466  if (node.isNull())
1467  continue;
1468 
1469  QDomElement e = node.toElement();
1470  if (e.isNull())
1471  continue;
1472 
1473  display = e.attribute("display", "");
1474  //name = e.attribute("name", "");
1475  //value = e.attribute("value", "");
1476 
1477  if (display.isEmpty())
1478  continue;
1479 
1480  // Only include HTML line break if display value doesn't already
1481  // contain breaks.
1482  if (display.contains("<p>", Qt::CaseInsensitive) ||
1483  display.contains("<br", Qt::CaseInsensitive))
1484  {
1485  // matches <BR> or <br /
1486  linebreak = "\r\n";
1487  }
1488  else
1489  linebreak = "<br />\r\n";
1490 
1491  os << " " << display << linebreak;
1492  }
1493  os << "</div>\r\n";
1494  }
1495 
1496  return( 1 );
1497 }
1498 
1499 void HttpStatus::FillProgramInfo(QDomDocument *pDoc,
1500  QDomNode &node,
1501  ProgramInfo *pInfo,
1502  bool bIncChannel /* = true */,
1503  bool bDetails /* = true */)
1504 {
1505  if ((pDoc == nullptr) || (pInfo == nullptr))
1506  return;
1507 
1508  // Build Program Element
1509 
1510  QDomElement program = pDoc->createElement( "Program" );
1511  node.appendChild( program );
1512 
1513  program.setAttribute( "startTime" ,
1515  program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(MythDate::ISODate));
1516  program.setAttribute( "title" , pInfo->GetTitle() );
1517  program.setAttribute( "subTitle" , pInfo->GetSubtitle());
1518  program.setAttribute( "category" , pInfo->GetCategory());
1519  program.setAttribute( "catType" , pInfo->GetCategoryTypeString());
1520  program.setAttribute( "repeat" , static_cast<int>(pInfo->IsRepeat()));
1521 
1522  if (bDetails)
1523  {
1524 
1525  program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
1526  program.setAttribute( "programId" , pInfo->GetProgramID() );
1527  program.setAttribute( "stars" , pInfo->GetStars() );
1528  program.setAttribute( "fileSize" ,
1529  QString::number( pInfo->GetFilesize() ));
1530  program.setAttribute( "lastModified",
1532  program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
1533  program.setAttribute( "hostname" , pInfo->GetHostname() );
1534 
1535  if (pInfo->GetOriginalAirDate().isValid())
1536  program.setAttribute(
1537  "airdate", pInfo->GetOriginalAirDate().toString());
1538 
1539  QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
1540  program.appendChild( textNode );
1541 
1542  }
1543 
1544  if ( bIncChannel )
1545  {
1546  // Build Channel Child Element
1547 
1548  QDomElement channel = pDoc->createElement( "Channel" );
1549  program.appendChild( channel );
1550 
1551  FillChannelInfo( channel, pInfo, bDetails );
1552  }
1553 
1554  // Build Recording Child Element
1555 
1556  if ( pInfo->GetRecordingStatus() != RecStatus::Unknown )
1557  {
1558  QDomElement recording = pDoc->createElement( "Recording" );
1559  program.appendChild( recording );
1560 
1561  recording.setAttribute( "recStatus" ,
1562  pInfo->GetRecordingStatus() );
1563  recording.setAttribute( "recPriority" ,
1564  pInfo->GetRecordingPriority() );
1565  recording.setAttribute( "recStartTs" ,
1567  recording.setAttribute( "recEndTs" ,
1569 
1570  if (bDetails)
1571  {
1572  recording.setAttribute( "recordId" ,
1573  pInfo->GetRecordingRuleID() );
1574  recording.setAttribute( "recGroup" ,
1575  pInfo->GetRecordingGroup() );
1576  recording.setAttribute( "playGroup" ,
1577  pInfo->GetPlaybackGroup() );
1578  recording.setAttribute( "recType" ,
1579  pInfo->GetRecordingRuleType() );
1580  recording.setAttribute( "dupInType" ,
1581  pInfo->GetDuplicateCheckSource() );
1582  recording.setAttribute( "dupMethod" ,
1583  pInfo->GetDuplicateCheckMethod() );
1584  recording.setAttribute( "encoderId" ,
1585  pInfo->GetInputID() );
1586  const RecordingInfo ri(*pInfo);
1587  recording.setAttribute( "recProfile" ,
1589  //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
1590  }
1591  }
1592 }
1593 
1595 //
1597 
1599  ProgramInfo *pInfo,
1600  bool bDetails /* = true */ )
1601 {
1602  if (pInfo)
1603  {
1604 /*
1605  QString sHostName = gCoreContext->GetHostName();
1606  QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort",
1607  sHostName);
1608  QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
1609  .arg( sHostName )
1610  .arg( sPort )
1611  .arg( pInfo->chanid );
1612 */
1613 
1614  channel.setAttribute( "chanId" , pInfo->GetChanID() );
1615  channel.setAttribute( "chanNum" , pInfo->GetChanNum());
1616  channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
1617  //channel.setAttribute( "iconURL" , sIconURL );
1618  channel.setAttribute( "channelName", pInfo->GetChannelName());
1619 
1620  if (bDetails)
1621  {
1622  channel.setAttribute( "chanFilters",
1623  pInfo->GetChannelPlaybackFilters() );
1624  channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
1625  channel.setAttribute( "inputId" , pInfo->GetInputID() );
1626  channel.setAttribute( "commFree" ,
1627  (pInfo->IsCommercialFree()) ? 1 : 0 );
1628  }
1629  }
1630 }
1631 
1632 
1633 
1634 
1635 // 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:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
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:107
HttpStatus::m_pEncoders
QMap< int, EncoderLink * > * m_pEncoders
Definition: httpstatus.h:47
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:828
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:6162
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:2494
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:21
MythSystemLegacy
Definition: mythsystemlegacy.h:67
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:850
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:34
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:5143
httpstatus.h
getLoadAvgs
loadArray getLoadAvgs(void)
Returns the system load averages.
Definition: mythmiscutil.cpp:178
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:60
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:1499
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:1014
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:1121
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:716
HttpStatus::PrintBackends
static int PrintBackends(QTextStream &os, const QDomElement &backends)
Definition: httpstatus.cpp:1021
JobQueue::GetJobsInQueue
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
Definition: jobqueue.cpp:1282
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:987
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:1203
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:34
uint
unsigned int uint
Definition: compat.h:141
HttpStatus::PrintJobQueue
static int PrintJobQueue(QTextStream &os, const QDomElement &jobs)
Definition: httpstatus.cpp:1060
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
ProgramInfo::GetSeriesID
QString GetSeriesID(void) const
Definition: programinfo.h:433
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:933
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:927
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:67
mythmiscutil.h
HttpStatus::PrintMiscellaneousInfo
static int PrintMiscellaneousInfo(QTextStream &os, const QDomElement &info)
Definition: httpstatus.cpp:1447
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h: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:1797
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:706
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:859
Scheduler::GetAllPending
bool GetAllPending(RecList &retList, int recRuleId=0) const
Definition: scheduler.cpp:1732
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:983
JOB_LIST_ERROR
@ JOB_LIST_ERROR
Definition: jobqueue.h:64
HttpServerExtension
Definition: httpserver.h:71
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:1598
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:1140
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919
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