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