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