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