MythTV master
v2status.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"
36#include "libmythbase/mythversion.h"
38#include "libmythtv/cardutil.h"
39#include "libmythtv/jobqueue.h"
40#include "libmythtv/tv.h"
41#include "libmythtv/tv_rec.h"
43#include "libmythupnp/upnp.h"
44
45// MythBackend
46#include "autoexpire.h"
47#include "backendcontext.h"
48#include "encoderlink.h"
49#include "mainserver.h"
50#include "scheduler.h"
51#include "v2backendStatus.h"
52#include "v2serviceUtil.h"
53#include "v2status.h"
54
55
56// This will be initialised in a thread safe manner on first use
58 (STATUS_HANDLE, V2Status::staticMetaObject, &V2Status::RegisterCustomTypes))
59
61{
62 qRegisterMetaType<Preformat*>("Preformat");
63 qRegisterMetaType<V2MachineInfo*>("V2MachineInfo");
64 qRegisterMetaType<V2BackendStatus*>("V2BackendStatus");
65 qRegisterMetaType<V2Encoder*>("V2Encoder");
66 qRegisterMetaType<V2Program*>("V2Program");
67 qRegisterMetaType<V2Frontend*>("V2Frontend");
68 qRegisterMetaType<V2StorageGroup*>("V2StorageGroup");
69 qRegisterMetaType<V2Job*>("V2Job");
70 qRegisterMetaType<V2ChannelInfo*>("V2ChannelInfo");
71 qRegisterMetaType<V2RecordingInfo*>("V2RecordingInfo");
72 qRegisterMetaType<V2ArtworkInfoList*>("V2ArtworkInfoList");
73 qRegisterMetaType<V2ArtworkInfo*>("V2ArtworkInfo");
74 qRegisterMetaType<V2CastMemberList*>("V2CastMemberList");
75 qRegisterMetaType<V2CastMember*>("V2CastMember");
76 qRegisterMetaType<V2Input*>("V2Input");
77 qRegisterMetaType<V2Backend*>("V2Backend");
78 qRegisterMetaType<V2ShowStats*>("V2ShowStats");
79 qRegisterMetaType<V2RecStats*>("V2RecStats");
80}
81
83 m_pSched(dynamic_cast<Scheduler*>(gCoreContext->GetScheduler())),
84 m_pEncoders(&gTVList) // extern
85{
86 if (m_pSched)
89 m_nPreRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll", 0);
90}
91
92// HTML
94{
95 return GetStatusHTML();
96}
97
98// XML
100{
101 return GetStatus();
102}
103
104// XML
106{
107 QDomDocument doc( "Status" );
108 // UTF-8 is the default, but good practice to specify it anyway
109 QDomProcessingInstruction encoding =
110 doc.createProcessingInstruction("xml",
111 R"(version="1.0" encoding="UTF-8")");
112 doc.appendChild(encoding);
113 FillStatusXML( &doc );
114 auto *pResult = new Preformat();
115 pResult->setmimetype("application/xml");
116 pResult->setbuffer(doc.toString());
117 return pResult;
118}
119
120// HTML
122{
123 QDomDocument doc( "Status" );
124 FillStatusXML( &doc );
125 QString html;
126 QTextStream stream( &html );
127 PrintStatus( stream, &doc );
128 auto *pResult = new Preformat();
129 pResult->setmimetype("text/html");
130 pResult->setbuffer(html);
131 return pResult;
132}
133
134static QString setting_to_localtime(const char *setting)
135{
136 QString origDateString = gCoreContext->GetSetting(setting);
137 QDateTime origDate = MythDate::fromString(origDateString);
139}
140
141static QDateTime setting_to_qdatetime(const char *setting)
142{
143 QString origDateString = gCoreContext->GetSetting(setting);
144 QDateTime origDate = MythDate::fromString(origDateString);
145 return origDate;
146}
147
148// Standardized version of GetStatus that supports xml, json, etc.
150{
151 auto* pStatus = new V2BackendStatus();
152 pStatus->setAsOf ( MythDate::current() );
153 pStatus->setVersion ( MYTH_BINARY_VERSION );
154 pStatus->setProtoVer ( MYTH_PROTO_VERSION );
155 pStatus->setSourcePath ( GetMythSourcePath() );
156 pStatus->setSourceVer ( GetMythSourceVersion() );
157 pStatus->setHostName ( gCoreContext->GetHostName() );
158 // Encoders
159 FillEncoderList(pStatus->GetEncoders(), pStatus);
160 // Upcoming recordings
161 int nStartIndex = 0;
162 int nCount = 10;
163 // Scheduled Recordings
164 FillUpcomingList(pStatus->GetScheduled(), pStatus,
165 nStartIndex,
166 nCount,
167 true, // bShowAll,
168 -1, // nRecordId,
169 -999); // nRecStatus )
170 // Frontends
171 FillFrontendList(pStatus->GetFrontends(), pStatus,
172 false); // OnLine)
173 // Backends
174 V2Backend *backend {nullptr};
175
176 // Add this host
177 backend = pStatus->AddNewBackend();
178 QString thisHost = gCoreContext->GetHostName();
179 backend->setName(thisHost);
180 backend->setIP(gCoreContext->GetBackendServerIP());
181
182 if (m_pMainServer)
183 {
184 backend->setType("Master");
185 QStringList backends;
187 for (const QString& hostname : std::as_const(backends))
188 {
189 if (hostname != thisHost)
190 {
192 backend = pStatus->AddNewBackend();
193 backend->setName(hostname);
194 backend->setType("Slave");
195 if (pSock)
196 {
197 backend->setIP(pSock->getIP());
198 }
199 }
200 }
201 }
202 else
203 {
204 backend->setType("Slave");
205 QString masterhost = gCoreContext->GetMasterHostName();
206 QString masterip = gCoreContext->GetMasterServerIP();
207 backend = pStatus->AddNewBackend();
208 backend->setName(masterhost);
209 backend->setIP(masterip);
210 backend->setType("Master");
211 }
212
213 // Add Job Queue Entries
214 QMap<int, JobQueueEntry> jobs;
215 QMap<int, JobQueueEntry>::Iterator it;
216
220
221 for (it = jobs.begin(); it != jobs.end(); ++it)
222 {
223 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
224 if (!pginfo.GetChanID())
225 continue;
226
227 V2Job * pJob = pStatus->AddNewJob();
228
229 pJob->setId( (*it).id );
230 pJob->setChanId((*it).chanid );
231 pJob->setStartTime( (*it).recstartts);
232 pJob->setStartTs( (*it).startts );
233 pJob->setInsertTime((*it).inserttime);
234 pJob->setType( (*it).type );
235 pJob->setLocalizedJobName( JobQueue::JobText((*it).type) );
236 pJob->setCmds( (*it).cmds );
237 pJob->setFlags( (*it).flags );
238 pJob->setStatus( (*it).status );
239 pJob->setLocalizedStatus( JobQueue::StatusText((*it).status) );
240 pJob->setStatusTime( (*it).statustime);
241 pJob->setSchedRunTime( (*it).schedruntime);
242 pJob->setArgs( (*it).args );
243 if ((*it).hostname.isEmpty())
244 pJob->setHostName( QObject::tr("master"));
245 else
246 pJob->setHostName((*it).hostname);
247 pJob->setComment((*it).comment);
248 V2Program *pProgram = pJob->Program();
249 V2FillProgramInfo( pProgram, &pginfo, true, false, false);
250 }
251
252 // Machine Info
253 V2MachineInfo *pMachineInfo = pStatus->MachineInfo();
254 FillDriveSpace(pMachineInfo);
255 // load average
256 loadArray rgdAverages = getLoadAvgs();
257 if (rgdAverages[0] != -1)
258 {
259 pMachineInfo->setLoadAvg1(rgdAverages[0]);
260 pMachineInfo->setLoadAvg2(rgdAverages[1]);
261 pMachineInfo->setLoadAvg3(rgdAverages[2]);
262 }
263
264 // Guide Data
265 QDateTime GuideDataThrough;
267 query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
268 if (query.exec() && query.next())
269 {
270 GuideDataThrough = MythDate::fromString(query.value(0).toString());
271 }
272 pMachineInfo->setGuideStart
273 (setting_to_qdatetime("mythfilldatabaseLastRunStart"));
274 pMachineInfo->setGuideEnd(
275 setting_to_qdatetime("mythfilldatabaseLastRunEnd"));
276 pMachineInfo->setGuideStatus(
277 gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
278 if (gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", false))
279 {
280 pMachineInfo->setGuideNext(
281 gCoreContext->GetSetting("MythFillSuggestedRunTime"));
282 }
283
284 if (!GuideDataThrough.isNull())
285 {
286 QDateTime qdtNow = MythDate::current();
287 pMachineInfo->setGuideThru(GuideDataThrough);
288 pMachineInfo->setGuideDays(qdtNow.daysTo(GuideDataThrough));
289 }
290
291 // Add Miscellaneous information
292 QString info_script = gCoreContext->GetSetting("MiscStatusScript");
293 if ((!info_script.isEmpty()) && (info_script != "none"))
294 {
295 uint flags = kMSRunShell | kMSStdOut;
296 MythSystemLegacy ms(info_script, flags);
297 ms.Run(10s);
298 if (ms.Wait() != GENERIC_EXIT_OK)
299 {
300 LOG(VB_GENERAL, LOG_ERR,
301 QString("Error running miscellaneous "
302 "status information script: %1").arg(info_script));
303 }
304
305 QByteArray input = ms.ReadAll();
306 pStatus->setMiscellaneous(QString(input));
307 }
308 return pStatus;
309}
310
311/*
312 Recording stats, such as number of shows, episodes, total recording time, etc.
313 Note RecStatus of -3 means "recorded". Hard coded -3 is used instead of RecStatus.Recorded
314 for efficiency instead of converting the enum to a string for each SQL query.
315*/
317{
318 auto* pStatus = new V2RecStats();
320 // Numnber of shows
321 query.prepare("select count(distinct title) from oldrecorded "
322 "where recstatus = -3 and future = 0;");
323 if (query.exec() && query.next())
324 pStatus->setShowCount(query.value(0).toInt());
325 // Number of episodes
326 query.prepare("select count(title) from oldrecorded "
327 "where recstatus = -3 and future = 0;");
328 if (query.exec() && query.next())
329 pStatus->setEpisodeCount(query.value(0).toInt());
330 // First and last recording dates, total recording time, etc.
331 query.prepare("select starttime from oldrecorded "
332 "where recstatus = -3 and future = 0 "
333 "order by starttime asc limit 1;");
334 if (query.exec() && query.next())
335 pStatus->setFirstRecDate(query.value(0).toDateTime());
336 query.prepare("select endtime from oldrecorded "
337 "where recstatus = -3 and future = 0 "
338 "order by starttime desc limit 1;");
339 if (query.exec() && query.next())
340 pStatus->setLastRecDate(query.value(0).toDateTime());
341 query.prepare("select SUM( TIMESTAMPDIFF(SECOND, starttime, endtime) ) "
342 "from oldrecorded "
343 "where recstatus = -3 and future = 0;");
344 if (query.exec() && query.next())
345 pStatus->setRecTimeSecs(query.value(0).toLongLong());
346 pStatus->setRunTimeSecs(pStatus->GetFirstRecDate().secsTo(pStatus->GetLastRecDate()));
347 // Top 10 shows
348 query.prepare("select title, COUNT(*) as recorded, MAX(starttime) as last_recorded "
349 "from oldrecorded "
350 "where recstatus = -3 and future = 0 "
351 "group by title "
352 "order by recorded desc, last_recorded desc, title asc "
353 "limit 10;");
354 if (query.exec()) {
355 while (query.next())
356 {
357 auto* show = pStatus->AddNewShow();
358 show->setTitle(query.value(0).toString());
359 show->setCount(query.value(1).toInt());
360 show->setLastRecDate(query.value(2).toDateTime());
361 }
362 }
363 // Top 10 channels
364 query.prepare("select c.name, COUNT(*) as recorded, MAX(r.starttime) as last_recorded "
365 "from oldrecorded r "
366 "join channel c on r.chanid = c.chanid "
367 "where r.recstatus = -3 and r.future = 0 "
368 "group by c.callsign "
369 "order by recorded desc, last_recorded desc, c.name asc "
370 "limit 10;");
371 if (query.exec()) {
372 while (query.next()) {
373 auto* channel = pStatus->AddNewChannel();
374 channel->setTitle(query.value(0).toString());
375 channel->setCount(query.value(1).toInt());
376 channel->setLastRecDate(query.value(2).toDateTime());
377 }
378 }
379 return pStatus;
380}
381
383{
384 QStringList strlist;
385 QString hostname;
386 QString directory;
387 QString isLocalstr;
388 QString fsID;
389
390 if (m_pMainServer)
392
393 QStringList::const_iterator sit = strlist.cbegin();
394 while (sit != strlist.cend())
395 {
396 hostname = *(sit++);
397 directory = *(sit++);
398 isLocalstr = *(sit++);
399 fsID = *(sit++);
400 ++sit; // ignore dirID
401 ++sit; // ignore blocksize
402 long long iTotal = (*(sit++)).toLongLong();
403 long long iUsed = (*(sit++)).toLongLong();;
404 long long iAvail = iTotal - iUsed;
405
406 if (fsID == "-2")
407 fsID = "total";
408
409 V2StorageGroup* group = pMachineInfo->AddNewStorageGroup();
410 group->setId(QString(fsID));
411 group->setTotal((int)(iTotal>>10));
412 group->setUsed((int)(iUsed>>10));
413 group->setFree((int)(iAvail>>10));
414 group->setDirectory(directory);
415
416 if (fsID == "total")
417 {
418 long long iLiveTV = -1;
419 long long iDeleted = -1;
420 long long iExpirable = -1;
422 query.prepare("SELECT SUM(filesize) FROM recorded "
423 " WHERE recgroup = :RECGROUP;");
424
425 query.bindValue(":RECGROUP", "LiveTV");
426 if (query.exec() && query.next())
427 {
428 iLiveTV = query.value(0).toLongLong();
429 }
430 query.bindValue(":RECGROUP", "Deleted");
431 if (query.exec() && query.next())
432 {
433 iDeleted = query.value(0).toLongLong();
434 }
435 query.prepare("SELECT SUM(filesize) FROM recorded "
436 " WHERE autoexpire = 1 "
437 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
438 if (query.exec() && query.next())
439 {
440 iExpirable = query.value(0).toLongLong();
441 }
442 group->setLiveTV( (int)(iLiveTV>>20) );
443 group->setDeleted( (int)(iDeleted>>20) );
444 group->setExpirable ( (int)(iExpirable>>20) );
445 }
446 }
447
448}
449
450void V2Status::FillStatusXML( QDomDocument *pDoc )
451{
452 QDateTime qdtNow = MythDate::current();
453
454 // Add Root Node.
455
456 QDomElement root = pDoc->createElement("Status");
457 pDoc->appendChild(root);
458
459 root.setAttribute("date" , MythDate::toString(
461 root.setAttribute("time" ,
463 root.setAttribute("ISODate" , qdtNow.toString(Qt::ISODate) );
464 root.setAttribute("version" , MYTH_BINARY_VERSION );
465 root.setAttribute("protoVer", MYTH_PROTO_VERSION );
466
467 // Add all encoders, if any
468
469 QDomElement encoders = pDoc->createElement("Encoders");
470 root.appendChild(encoders);
471
472 int numencoders = 0;
473 bool isLocal = true;
474
475 TVRec::s_inputsLock.lockForRead();
476
477 for (auto * elink : std::as_const(*m_pEncoders))
478 {
479 if (elink != nullptr)
480 {
481 TVState state = elink->GetState();
482 isLocal = elink->IsLocal();
483
484 QDomElement encoder = pDoc->createElement("Encoder");
485 encoders.appendChild(encoder);
486
487 encoder.setAttribute("id" , elink->GetInputID() );
488 encoder.setAttribute("local" , static_cast<int>(isLocal));
489 encoder.setAttribute("connected" , static_cast<int>(elink->IsConnected()));
490 encoder.setAttribute("state" , state );
491 encoder.setAttribute("sleepstatus" , elink->GetSleepStatus() );
492 //encoder.setAttribute("lowOnFreeSpace", elink->isLowOnFreeSpace());
493
494 if (isLocal)
495 encoder.setAttribute("hostname", gCoreContext->GetHostName());
496 else
497 encoder.setAttribute("hostname", elink->GetHostName());
498
499 encoder.setAttribute("devlabel",
500 CardUtil::GetDeviceLabel(elink->GetInputID()) );
501
502 if (elink->IsConnected())
503 numencoders++;
504
505 switch (state)
506 {
510 {
511 ProgramInfo *pInfo = elink->GetRecording();
512
513 if (pInfo)
514 {
515 FillProgramInfo(pDoc, encoder, pInfo);
516 delete pInfo;
517 }
518
519 break;
520 }
521
522 default:
523 break;
524 }
525 }
526 }
527
528 TVRec::s_inputsLock.unlock();
529
530 encoders.setAttribute("count", numencoders);
531
532 // Add upcoming shows
533
534 QDomElement scheduled = pDoc->createElement("Scheduled");
535 root.appendChild(scheduled);
536
537 RecList recordingList;
538
539 if (m_pSched)
540 m_pSched->GetAllPending(recordingList);
541
542 unsigned int iNum = 10;
543 unsigned int iNumRecordings = 0;
544
545 auto itProg = recordingList.begin();
546 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg)
547 {
548 if (((*itProg)->GetRecordingStatus() <= RecStatus::WillRecord) &&
549 ((*itProg)->GetRecordingStartTime() >=
551 {
552 iNumRecordings++;
553 FillProgramInfo(pDoc, scheduled, *itProg);
554 }
555 }
556
557 while (!recordingList.empty())
558 {
559 ProgramInfo *pginfo = recordingList.back();
560 delete pginfo;
561 recordingList.pop_back();
562 }
563
564 scheduled.setAttribute("count", iNumRecordings);
565
566 // Add known frontends
567
568 QDomElement frontends = pDoc->createElement("Frontends");
569 root.appendChild(frontends);
570
572 "urn:schemas-mythtv-org:service:MythFrontend:1");
573 if (fes)
574 {
575 EntryMap map;
576 fes->GetEntryMap(map);
577 fes->DecrRef();
578 fes = nullptr;
579
580 frontends.setAttribute( "count", map.size() );
581 for (const auto & entry : std::as_const(map))
582 {
583 QDomElement fe = pDoc->createElement("Frontend");
584 frontends.appendChild(fe);
585 QUrl url(entry->m_sLocation);
586 fe.setAttribute("name", url.host());
587 fe.setAttribute("url", url.toString(QUrl::RemovePath));
588 entry->DecrRef();
589 }
590 }
591
592 // Other backends
593
594 QDomElement backends = pDoc->createElement("Backends");
595 root.appendChild(backends);
596
597 int numbes = 0;
599 {
600 numbes++;
601 QString masterhost = gCoreContext->GetMasterHostName();
602 QString masterip = gCoreContext->GetMasterServerIP();
603 int masterport = gCoreContext->GetMasterServerStatusPort();
604
605 QDomElement mbe = pDoc->createElement("Backend");
606 backends.appendChild(mbe);
607 mbe.setAttribute("type", "Master");
608 mbe.setAttribute("name", masterhost);
609 mbe.setAttribute("url" , masterip + ":" + QString::number(masterport));
610 }
611
613 "urn:schemas-mythtv-org:device:SlaveMediaServer:1");
614 if (sbes)
615 {
616
617 QString ipaddress = QString();
618 if (!UPnp::g_IPAddrList.isEmpty())
619 ipaddress = UPnp::g_IPAddrList.at(0).toString();
620
621 EntryMap map;
622 sbes->GetEntryMap(map);
623 sbes->DecrRef();
624 sbes = nullptr;
625
626 for (const auto & entry : std::as_const(map))
627 {
628 QUrl url(entry->m_sLocation);
629 if (url.host() != ipaddress)
630 {
631 numbes++;
632 QDomElement mbe = pDoc->createElement("Backend");
633 backends.appendChild(mbe);
634 mbe.setAttribute("type", "Slave");
635 mbe.setAttribute("name", url.host());
636 mbe.setAttribute("url" , url.toString(QUrl::RemovePath));
637 }
638 entry->DecrRef();
639 }
640 }
641
642 backends.setAttribute("count", numbes);
643
644 // Add Job Queue Entries
645
646 QDomElement queue = pDoc->createElement("JobQueue");
647 root.appendChild(queue);
648
649 QMap<int, JobQueueEntry> jobs;
650 QMap<int, JobQueueEntry>::Iterator it;
651
655
656 for (it = jobs.begin(); it != jobs.end(); ++it)
657 {
658 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
659 if (!pginfo.GetChanID())
660 continue;
661
662 QDomElement job = pDoc->createElement("Job");
663 queue.appendChild(job);
664
665 job.setAttribute("id" , (*it).id );
666 job.setAttribute("chanId" , (*it).chanid );
667 job.setAttribute("startTime" ,
668 (*it).recstartts.toString(Qt::ISODate));
669 job.setAttribute("startTs" , (*it).startts );
670 job.setAttribute("insertTime",
671 (*it).inserttime.toString(Qt::ISODate));
672 job.setAttribute("type" , (*it).type );
673 job.setAttribute("cmds" , (*it).cmds );
674 job.setAttribute("flags" , (*it).flags );
675 job.setAttribute("status" , (*it).status );
676 job.setAttribute("statusTime",
677 (*it).statustime.toString(Qt::ISODate));
678 job.setAttribute("schedTime" ,
679 (*it).schedruntime.toString(Qt::ISODate));
680 job.setAttribute("args" , (*it).args );
681
682 if ((*it).hostname.isEmpty())
683 job.setAttribute("hostname", QObject::tr("master"));
684 else
685 job.setAttribute("hostname",(*it).hostname);
686
687 QDomText textNode = pDoc->createTextNode((*it).comment);
688 job.appendChild(textNode);
689
690 FillProgramInfo(pDoc, job, &pginfo);
691 }
692
693 queue.setAttribute( "count", jobs.size() );
694
695 // Add Machine information
696
697 QDomElement mInfo = pDoc->createElement("MachineInfo");
698 QDomElement storage = pDoc->createElement("Storage" );
699 QDomElement load = pDoc->createElement("Load" );
700 QDomElement guide = pDoc->createElement("Guide" );
701
702 root.appendChild (mInfo );
703 mInfo.appendChild(storage);
704 mInfo.appendChild(load );
705 mInfo.appendChild(guide );
706
707 // drive space ---------------------
708
709 QStringList strlist;
710 QString hostname;
711 QString directory;
712 QString isLocalstr;
713 QString fsID;
714
715 if (m_pMainServer)
717
718 QDomElement total;
719
720 // Make a temporary list to hold the per-filesystem elements so that the
721 // total is always the first element.
722 QList<QDomElement> fsXML;
723 QStringList::const_iterator sit = strlist.cbegin();
724 while (sit != strlist.cend())
725 {
726 hostname = *(sit++);
727 directory = *(sit++);
728 isLocalstr = *(sit++);
729 fsID = *(sit++);
730 ++sit; // ignore dirID
731 ++sit; // ignore blocksize
732 long long iTotal = (*(sit++)).toLongLong();
733 long long iUsed = (*(sit++)).toLongLong();;
734 long long iAvail = iTotal - iUsed;
735
736 if (fsID == "-2")
737 fsID = "total";
738
739 QDomElement group = pDoc->createElement("Group");
740
741 group.setAttribute("id" , fsID );
742 group.setAttribute("total", (int)(iTotal>>10) );
743 group.setAttribute("used" , (int)(iUsed>>10) );
744 group.setAttribute("free" , (int)(iAvail>>10) );
745 group.setAttribute("dir" , directory );
746
747 if (fsID == "total")
748 {
749 long long iLiveTV = -1;
750 long long iDeleted = -1;
751 long long iExpirable = -1;
753 query.prepare("SELECT SUM(filesize) FROM recorded "
754 " WHERE recgroup = :RECGROUP;");
755
756 query.bindValue(":RECGROUP", "LiveTV");
757 if (query.exec() && query.next())
758 {
759 iLiveTV = query.value(0).toLongLong();
760 }
761 query.bindValue(":RECGROUP", "Deleted");
762 if (query.exec() && query.next())
763 {
764 iDeleted = query.value(0).toLongLong();
765 }
766 query.prepare("SELECT SUM(filesize) FROM recorded "
767 " WHERE autoexpire = 1 "
768 " AND recgroup NOT IN ('LiveTV', 'Deleted');");
769 if (query.exec() && query.next())
770 {
771 iExpirable = query.value(0).toLongLong();
772 }
773 group.setAttribute("livetv", (int)(iLiveTV>>20) );
774 group.setAttribute("deleted", (int)(iDeleted>>20) );
775 group.setAttribute("expirable", (int)(iExpirable>>20) );
776 total = group;
777 }
778 else
779 {
780 fsXML << group;
781 }
782 }
783
784 storage.appendChild(total);
785 int num_elements = fsXML.size();
786 for (int fs_index = 0; fs_index < num_elements; fs_index++)
787 {
788 storage.appendChild(fsXML[fs_index]);
789 }
790
791 // load average ---------------------
792
793#ifdef Q_OS_ANDROID
794 load.setAttribute("avg1", 0);
795 load.setAttribute("avg2", 1);
796 load.setAttribute("avg3", 2);
797#else
798 loadArray rgdAverages = getLoadAvgs();
799 if (rgdAverages[0] != -1)
800 {
801 load.setAttribute("avg1", rgdAverages[0]);
802 load.setAttribute("avg2", rgdAverages[1]);
803 load.setAttribute("avg3", rgdAverages[2]);
804 }
805#endif
806
807 // Guide Data ---------------------
808
809 QDateTime GuideDataThrough;
810
812 query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;");
813
814 if (query.exec() && query.next())
815 {
816 GuideDataThrough = MythDate::fromString(query.value(0).toString());
817 }
818
819 guide.setAttribute("start",
820 setting_to_localtime("mythfilldatabaseLastRunStart"));
821 guide.setAttribute("end",
822 setting_to_localtime("mythfilldatabaseLastRunEnd"));
823 guide.setAttribute("status",
824 gCoreContext->GetSetting("mythfilldatabaseLastRunStatus"));
825 if (gCoreContext->GetBoolSetting("MythFillGrabberSuggestsTime", false))
826 {
827 guide.setAttribute("next",
828 gCoreContext->GetSetting("MythFillSuggestedRunTime"));
829 }
830
831 if (!GuideDataThrough.isNull())
832 {
833 guide.setAttribute("guideThru",
834 GuideDataThrough.toString(Qt::ISODate));
835 guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough));
836 }
837
838 // Add Miscellaneous information
839
840 QString info_script = gCoreContext->GetSetting("MiscStatusScript");
841 if ((!info_script.isEmpty()) && (info_script != "none"))
842 {
843 QDomElement misc = pDoc->createElement("Miscellaneous");
844 root.appendChild(misc);
845
846 uint flags = kMSRunShell | kMSStdOut;
847 MythSystemLegacy ms(info_script, flags);
848 ms.Run(10s);
849 if (ms.Wait() != GENERIC_EXIT_OK)
850 {
851 LOG(VB_GENERAL, LOG_ERR,
852 QString("Error running miscellaneous "
853 "status information script: %1").arg(info_script));
854 return;
855 }
856
857 QByteArray input = ms.ReadAll();
858
859 QStringList output = QString(input).split('\n',
860 Qt::SkipEmptyParts);
861 for (const auto & line : std::as_const(output))
862 {
863 QDomElement info = pDoc->createElement("Information");
864
865 QStringList list = line.split("[]:[]");
866 unsigned int size = list.size();
867 unsigned int hasAttributes = 0;
868
869 if ((size > 0) && (!list[0].isEmpty()))
870 {
871 info.setAttribute("display", list[0]);
872 hasAttributes++;
873 }
874 if ((size > 1) && (!list[1].isEmpty()))
875 {
876 info.setAttribute("name", list[1]);
877 hasAttributes++;
878 }
879 if ((size > 2) && (!list[2].isEmpty()))
880 {
881 info.setAttribute("value", list[2]);
882 hasAttributes++;
883 }
884
885 if (hasAttributes > 0)
886 misc.appendChild(info);
887 }
888 }
889}
890
892//
894
895void V2Status::PrintStatus( QTextStream &os, QDomDocument *pDoc )
896{
897#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
898 os.setCodec("UTF-8");
899#else
900 os.setEncoding(QStringConverter::Utf8);
901#endif
902
903 QDateTime qdtNow = MythDate::current();
904
905 QDomElement docElem = pDoc->documentElement();
906
907 os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
908 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n"
909 << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
910 << " xml:lang=\"en\" lang=\"en\">\r\n"
911 << "<head>\r\n"
912 << " <meta http-equiv=\"Content-Type\""
913 << "content=\"text/html; charset=UTF-8\" />\r\n"
914 << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n"
915 << " <title>MythTV Status - "
916 << docElem.attribute( "date", MythDate::toString(qdtNow, MythDate::kDateShort) )
917 << " "
918 << docElem.attribute( "time", MythDate::toString(qdtNow, MythDate::kTime) ) << " - "
919 << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n"
920 << "</head>\r\n"
921 << "<body bgcolor=\"#fff\">\r\n"
922 << "<div class=\"status\">\r\n"
923 << " <h1 class=\"status\">MythTV Status</h1>\r\n";
924
925 // encoder information ---------------------
926
927 QDomNode node = docElem.namedItem( "Encoders" );
928
929 if (!node.isNull())
930 PrintEncoderStatus( os, node.toElement() );
931
932 // upcoming shows --------------------------
933
934 node = docElem.namedItem( "Scheduled" );
935
936 if (!node.isNull())
937 PrintScheduled( os, node.toElement());
938
939 // Frontends
940
941 node = docElem.namedItem( "Frontends" );
942
943 if (!node.isNull())
944 PrintFrontends (os, node.toElement());
945
946 // Backends
947
948 node = docElem.namedItem( "Backends" );
949
950 if (!node.isNull())
951 PrintBackends (os, node.toElement());
952
953 // Job Queue Entries -----------------------
954
955 node = docElem.namedItem( "JobQueue" );
956
957 if (!node.isNull())
958 PrintJobQueue( os, node.toElement());
959
960 // Machine information ---------------------
961
962 node = docElem.namedItem( "MachineInfo" );
963
964 if (!node.isNull())
965 PrintMachineInfo( os, node.toElement());
966
967 // Miscellaneous information ---------------
968
969 node = docElem.namedItem( "Miscellaneous" );
970
971 if (!node.isNull())
972 PrintMiscellaneousInfo( os, node.toElement());
973
974 os << "\r\n</div>\r\n</body>\r\n</html>\r\n";
975
976}
977
979//
981
982int V2Status::PrintEncoderStatus( QTextStream &os, const QDomElement& encoders )
983{
984 int nNumEncoders = 0;
985
986 if (encoders.isNull())
987 return 0;
988
989 os << " <div class=\"content\">\r\n"
990 << " <h2 class=\"status\">Encoder Status</h2>\r\n";
991
992 QDomNode node = encoders.firstChild();
993
994 while (!node.isNull())
995 {
996 QDomElement e = node.toElement();
997
998 if (!e.isNull())
999 {
1000 if (e.tagName() == "Encoder")
1001 {
1002 QString sIsLocal = (e.attribute( "local" , "remote" )== "1")
1003 ? "local" : "remote";
1004 QString sCardId = e.attribute( "id" , "0" );
1005 QString sHostName = e.attribute( "hostname" , "Unknown");
1006 bool bConnected= static_cast<bool>(e.attribute( "connected", "0" ).toInt());
1007
1008 bool bIsLowOnFreeSpace=static_cast<bool>(e.attribute( "lowOnFreeSpace", "0").toInt());
1009
1010 QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]");
1011
1012 os << " Encoder " << sCardId << " " << sDevlabel
1013 << " is " << sIsLocal << " on " << sHostName;
1014
1015 if ((sIsLocal == "remote") && !bConnected)
1016 {
1017 SleepStatus sleepStatus =
1018 (SleepStatus) e.attribute("sleepstatus",
1019 QString::number(sStatus_Undefined)).toInt();
1020
1021 if (sleepStatus == sStatus_Asleep)
1022 os << " (currently asleep).<br />";
1023 else
1024 os << " (currently not connected).<br />";
1025
1026 node = node.nextSibling();
1027 continue;
1028 }
1029
1030 nNumEncoders++;
1031
1032 TVState encState = (TVState) e.attribute( "state", "0").toInt();
1033
1034 switch( encState )
1035 {
1037 os << " and is watching Live TV";
1038 break;
1039
1042 os << " and is recording";
1043 break;
1044
1045 default:
1046 os << " and is not recording.";
1047 break;
1048 }
1049
1050 // Display first Program Element listed under the encoder
1051
1052 QDomNode tmpNode = e.namedItem( "Program" );
1053
1054 if (!tmpNode.isNull())
1055 {
1056 QDomElement program = tmpNode.toElement();
1057
1058 if (!program.isNull())
1059 {
1060 os << " '" << program.attribute( "title", "Unknown" ) << "'";
1061
1062 // Get Channel information
1063
1064 tmpNode = program.namedItem( "Channel" );
1065
1066 if (!tmpNode.isNull())
1067 {
1068 QDomElement channel = tmpNode.toElement();
1069
1070 if (!channel.isNull())
1071 os << " on "
1072 << channel.attribute( "callSign", "unknown" );
1073 }
1074
1075 // Get Recording Information (if any)
1076
1077 tmpNode = program.namedItem( "Recording" );
1078
1079 if (!tmpNode.isNull())
1080 {
1081 QDomElement recording = tmpNode.toElement();
1082
1083 if (!recording.isNull())
1084 {
1085 QDateTime endTs = MythDate::fromString(
1086 recording.attribute( "recEndTs", "" ));
1087
1088 os << ". This recording ";
1089 if (endTs < MythDate::current())
1090 os << "was ";
1091 else
1092 os << "is ";
1093
1094 os << "scheduled to end at "
1095 << MythDate::toString(endTs,
1097 }
1098 }
1099 }
1100
1101 os << ".";
1102 }
1103
1104 if (bIsLowOnFreeSpace)
1105 {
1106 os << " <strong>WARNING</strong>:"
1107 << " This backend is low on free disk space!";
1108 }
1109
1110 os << "<br />\r\n";
1111 }
1112 }
1113
1114 node = node.nextSibling();
1115 }
1116
1117 os << " </div>\r\n\r\n";
1118
1119 return nNumEncoders;
1120}
1121
1123//
1125
1126int V2Status::PrintScheduled( QTextStream &os, const QDomElement& scheduled )
1127{
1128 QDateTime qdtNow = MythDate::current();
1129
1130 if (scheduled.isNull())
1131 return 0;
1132
1133 int nNumRecordings= scheduled.attribute( "count", "0" ).toInt();
1134
1135 os << " <div class=\"content\">\r\n"
1136 << " <h2 class=\"status\">Schedule</h2>\r\n";
1137
1138 if (nNumRecordings == 0)
1139 {
1140 os << " There are no shows scheduled for recording.\r\n"
1141 << " </div>\r\n";
1142 return 0;
1143 }
1144
1145 os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" )
1146 << " that " << (nNumRecordings == 1 ? "is" : "are")
1147 << " scheduled for recording:\r\n";
1148
1149 os << " <div class=\"schedule\">\r\n";
1150
1151 // Iterate through all scheduled programs
1152
1153 QDomNode node = scheduled.firstChild();
1154
1155 while (!node.isNull())
1156 {
1157 QDomElement e = node.toElement();
1158
1159 if (!e.isNull())
1160 {
1161 QDomNode recNode = e.namedItem( "Recording" );
1162 QDomNode chanNode = e.namedItem( "Channel" );
1163
1164 if ((e.tagName() == "Program") && !recNode.isNull() &&
1165 !chanNode.isNull())
1166 {
1167 QDomElement r = recNode.toElement();
1168 QDomElement c = chanNode.toElement();
1169
1170 QString sTitle = e.attribute( "title" , "" );
1171 QString sSubTitle = e.attribute( "subTitle", "" );
1172 QDateTime airDate = MythDate::fromString( e.attribute( "airdate" ,"" ));
1173 QDateTime startTs = MythDate::fromString( e.attribute( "startTime" ,"" ));
1174 QDateTime endTs = MythDate::fromString( e.attribute( "endTime" ,"" ));
1175 QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1176// QDateTime recEndTs = MythDate::fromString( r.attribute( "recEndTs" ,"" ));
1177 int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt();
1178 int nEncoderId = r.attribute( "encoderId" , "0" ).toInt();
1179 QString sProfile = r.attribute( "recProfile" , "" );
1180 QString sChanName = c.attribute( "channelName" , "" );
1181 QString sDesc = "";
1182
1183 QDomText text = e.firstChild().toText();
1184 if (!text.isNull())
1185 sDesc = text.nodeValue();
1186
1187 // Build Time to recording start.
1188
1189 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs;
1190
1191 //since we're not displaying seconds
1192
1193 nTotalSecs -= 60;
1194
1195 int nTotalDays = nTotalSecs / 86400;
1196 int nTotalHours = (nTotalSecs / 3600)
1197 - (nTotalDays * 24);
1198 int nTotalMins = (nTotalSecs / 60) % 60;
1199
1200 QString sTimeToStart = "in";
1201
1202 sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays );
1203 sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours);
1204 sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins);
1205
1206 if ( nTotalHours == 0 && nTotalMins == 0)
1207 sTimeToStart = QObject::tr("within one minute", "Recording starting");
1208
1209 if ( nTotalSecs < 0)
1210 sTimeToStart = QObject::tr("soon", "Recording starting");
1211
1212 // Output HTML
1213
1214 os << " <a href=\"#\">";
1215 os << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
1217 MythDate::kSimplify) << " "
1218 << MythDate::toString(recStartTs.addSecs(-nPreRollSecs),
1219 MythDate::kTime) << " - ";
1220
1221 if (nEncoderId > 0)
1222 os << "Encoder " << nEncoderId << " - ";
1223
1224 os << sChanName << " - " << sTitle << "<br />"
1225 << "<span><strong>" << sTitle << "</strong> ("
1226 << MythDate::toString(startTs, MythDate::kTime) << "-"
1227 << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1228
1229 if ( !sSubTitle.isEmpty())
1230 os << "<em>" << sSubTitle << "</em><br /><br />";
1231
1232 if ( airDate.isValid())
1233 {
1234 os << "Orig. Airdate: "
1237 << "<br /><br />";
1238 }
1239
1240 os << sDesc << "<br /><br />"
1241 << "This recording will start " << sTimeToStart
1242 << " using encoder " << nEncoderId << " with the '"
1243 << sProfile << "' profile.</span></a><hr />\r\n";
1244 }
1245 }
1246
1247 node = node.nextSibling();
1248 }
1249 os << " </div>\r\n";
1250 os << " </div>\r\n\r\n";
1251
1252 return nNumRecordings;
1253}
1254
1256//
1258
1259int V2Status::PrintFrontends( QTextStream &os, const QDomElement& frontends )
1260{
1261 if (frontends.isNull())
1262 return 0;
1263
1264 int nNumFES= frontends.attribute( "count", "0" ).toInt();
1265
1266 if (nNumFES < 1)
1267 return 0;
1268
1269
1270 os << " <div class=\"content\">\r\n"
1271 << " <h2 class=\"status\">Frontends</h2>\r\n";
1272
1273 QDomNode node = frontends.firstChild();
1274 while (!node.isNull())
1275 {
1276 QDomElement e = node.toElement();
1277
1278 if (!e.isNull())
1279 {
1280 QString name = e.attribute( "name" , "" );
1281 QString url = e.attribute( "url" , "" );
1282 os << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1283 }
1284
1285 node = node.nextSibling();
1286 }
1287
1288 os << " </div>\r\n\r\n";
1289
1290 return nNumFES;
1291}
1292
1294//
1296
1297int V2Status::PrintBackends( QTextStream &os, const QDomElement& backends )
1298{
1299 if (backends.isNull())
1300 return 0;
1301
1302 int nNumBES= backends.attribute( "count", "0" ).toInt();
1303
1304 if (nNumBES < 1)
1305 return 0;
1306
1307
1308 os << " <div class=\"content\">\r\n"
1309 << " <h2 class=\"status\">Other Backends</h2>\r\n";
1310
1311 QDomNode node = backends.firstChild();
1312 while (!node.isNull())
1313 {
1314 QDomElement e = node.toElement();
1315
1316 if (!e.isNull())
1317 {
1318 QString type = e.attribute( "type", "" );
1319 QString name = e.attribute( "name" , "" );
1320 QString url = e.attribute( "url" , "" );
1321 os << type << ": " << name << "&nbsp(<a href=\"" << url << "\">Status page</a>)<br />";
1322 }
1323
1324 node = node.nextSibling();
1325 }
1326
1327 os << " </div>\r\n\r\n";
1328
1329 return nNumBES;
1330}
1331
1333//
1335
1336int V2Status::PrintJobQueue( QTextStream &os, const QDomElement& jobs )
1337{
1338 if (jobs.isNull())
1339 return 0;
1340
1341 int nNumJobs= jobs.attribute( "count", "0" ).toInt();
1342
1343 os << " <div class=\"content\">\r\n"
1344 << " <h2 class=\"status\">Job Queue</h2>\r\n";
1345
1346 if (nNumJobs != 0)
1347 {
1348 QString statusColor;
1349 QString jobColor;
1350
1351 os << " Jobs currently in Queue or recently ended:\r\n<br />"
1352 << " <div class=\"schedule\">\r\n";
1353
1354
1355 QDomNode node = jobs.firstChild();
1356
1357 while (!node.isNull())
1358 {
1359 QDomElement e = node.toElement();
1360
1361 if (!e.isNull())
1362 {
1363 QDomNode progNode = e.namedItem( "Program" );
1364
1365 if ((e.tagName() == "Job") && !progNode.isNull() )
1366 {
1367 QDomElement p = progNode.toElement();
1368
1369 QDomNode recNode = p.namedItem( "Recording" );
1370 QDomNode chanNode = p.namedItem( "Channel" );
1371
1372 QDomElement r = recNode.toElement();
1373 QDomElement c = chanNode.toElement();
1374
1375 int nType = e.attribute( "type" , "0" ).toInt();
1376 int nStatus = e.attribute( "status", "0" ).toInt();
1377
1378 switch( nStatus )
1379 {
1380 case JOB_ABORTED:
1381 statusColor = " class=\"jobaborted\"";
1382 jobColor = "";
1383 break;
1384
1385 case JOB_ERRORED:
1386 statusColor = " class=\"joberrored\"";
1387 jobColor = " class=\"joberrored\"";
1388 break;
1389
1390 case JOB_FINISHED:
1391 statusColor = " class=\"jobfinished\"";
1392 jobColor = " class=\"jobfinished\"";
1393 break;
1394
1395 case JOB_RUNNING:
1396 statusColor = " class=\"jobrunning\"";
1397 jobColor = " class=\"jobrunning\"";
1398 break;
1399
1400 default:
1401 statusColor = " class=\"jobqueued\"";
1402 jobColor = " class=\"jobqueued\"";
1403 break;
1404 }
1405
1406 QString sTitle = p.attribute( "title" , "" ); //.replace("\"", "&quot;");
1407 QString sSubTitle = p.attribute( "subTitle", "" );
1408 QDateTime startTs = MythDate::fromString( p.attribute( "startTime" ,"" ));
1409 QDateTime endTs = MythDate::fromString( p.attribute( "endTime" ,"" ));
1410 QDateTime recStartTs = MythDate::fromString( r.attribute( "recStartTs","" ));
1411 QDateTime statusTime = MythDate::fromString( e.attribute( "statusTime","" ));
1412 QDateTime schedRunTime = MythDate::fromString( e.attribute( "schedTime","" ));
1413 QString sHostname = e.attribute( "hostname", "master" );
1414 QString sComment = "";
1415
1416 QDomText text = e.firstChild().toText();
1417 if (!text.isNull())
1418 sComment = text.nodeValue();
1419
1420 os << "<a href=\"javascript:void(0)\">"
1423 << " - "
1424 << sTitle << " - <font" << jobColor << ">"
1425 << JobQueue::JobText( nType ) << "</font><br />"
1426 << "<span><strong>" << sTitle << "</strong> ("
1427 << MythDate::toString(startTs, MythDate::kTime) << "-"
1428 << MythDate::toString(endTs, MythDate::kTime) << ")<br />";
1429
1430 if (!sSubTitle.isEmpty())
1431 os << "<em>" << sSubTitle << "</em><br /><br />";
1432
1433 os << "Job: " << JobQueue::JobText( nType ) << "<br />";
1434
1435 if (schedRunTime > MythDate::current())
1436 {
1437 os << "Scheduled Run Time: "
1438 << MythDate::toString(schedRunTime,
1441 << "<br />";
1442 }
1443
1444 os << "Status: <font" << statusColor << ">"
1445 << JobQueue::StatusText( nStatus )
1446 << "</font><br />"
1447 << "Status Time: "
1450 << "<br />";
1451
1452 if ( nStatus != JOB_QUEUED)
1453 os << "Host: " << sHostname << "<br />";
1454
1455 if (!sComment.isEmpty())
1456 os << "<br />Comments:<br />" << sComment << "<br />";
1457
1458 os << "</span></a><hr />\r\n";
1459 }
1460 }
1461
1462 node = node.nextSibling();
1463 }
1464 os << " </div>\r\n";
1465 }
1466 else
1467 {
1468 os << " Job Queue is currently empty.\r\n\r\n";
1469 }
1470
1471 os << " </div>\r\n\r\n ";
1472
1473 return nNumJobs;
1474
1475}
1476
1478//
1480
1481int V2Status::PrintMachineInfo( QTextStream &os, const QDomElement& info )
1482{
1483 QString sRep;
1484
1485 if (info.isNull())
1486 return 0;
1487
1488 os << "<div class=\"content\">\r\n"
1489 << " <h2 class=\"status\">Machine Information</h2>\r\n";
1490
1491 // load average ---------------------
1492
1493 QDomNode node = info.namedItem( "Load" );
1494
1495 if (!node.isNull())
1496 {
1497 QDomElement e = node.toElement();
1498
1499 if (!e.isNull())
1500 {
1501 double dAvg1 = e.attribute( "avg1" , "0" ).toDouble();
1502 double dAvg2 = e.attribute( "avg2" , "0" ).toDouble();
1503 double dAvg3 = e.attribute( "avg3" , "0" ).toDouble();
1504
1505 os << " <div class=\"loadstatus\">\r\n"
1506 << " This machine's load average:"
1507 << "\r\n <ul>\r\n <li>"
1508 << "1 Minute: " << dAvg1 << "</li>\r\n"
1509 << " <li>5 Minutes: " << dAvg2 << "</li>\r\n"
1510 << " <li>15 Minutes: " << dAvg3
1511 << "</li>\r\n </ul>\r\n"
1512 << " </div>\r\n";
1513 }
1514 }
1515
1516 // local drive space ---------------------
1517 node = info.namedItem( "Storage" );
1518 QDomElement storage = node.toElement();
1519 node = storage.firstChild();
1520
1521 // Loop once until we find id == "total". This should be first, but a loop
1522 // separate from the per-filesystem details loop ensures total is first,
1523 // regardless.
1524 while (!node.isNull())
1525 {
1526 QDomElement g = node.toElement();
1527
1528 if (!g.isNull() && g.tagName() == "Group")
1529 {
1530 QString id = g.attribute("id", "" );
1531
1532 if (id == "total")
1533 {
1534 int nFree = g.attribute("free" , "0" ).toInt();
1535 int nTotal = g.attribute("total", "0" ).toInt();
1536 int nUsed = g.attribute("used" , "0" ).toInt();
1537 int nLiveTV = g.attribute("livetv" , "0" ).toInt();
1538 int nDeleted = g.attribute("deleted", "0" ).toInt();
1539 int nExpirable = g.attribute("expirable" , "0" ).toInt();
1540 QString nDir = g.attribute("dir" , "" );
1541
1542 nDir.replace(",", ", ");
1543
1544 os << " Disk Usage Summary:<br />\r\n";
1545 os << " <ul>\r\n";
1546
1547 os << " <li>Total Disk Space:\r\n"
1548 << " <ul>\r\n";
1549
1550 os << " <li>Total Space: ";
1551 sRep = QString("%L1").arg(nTotal) + " MB";
1552 os << sRep << "</li>\r\n";
1553
1554 os << " <li>Space Used: ";
1555 sRep = QString("%L1").arg(nUsed) + " MB";
1556 os << sRep << "</li>\r\n";
1557
1558 os << " <li>Space Free: ";
1559 sRep = QString("%L1").arg(nFree) + " MB";
1560 os << sRep << "</li>\r\n";
1561
1562 if ((nLiveTV + nDeleted + nExpirable) > 0)
1563 {
1564 os << " <li>Space Available "
1565 "After Auto-expire: ";
1566 sRep = QString("%L1").arg(nUsed) + " MB";
1567 sRep = QString("%L1").arg(nFree + nLiveTV +
1568 nDeleted + nExpirable) + " MB";
1569 os << sRep << "\r\n";
1570 os << " <ul>\r\n";
1571 os << " <li>Space Used by LiveTV: ";
1572 sRep = QString("%L1").arg(nLiveTV) + " MB";
1573 os << sRep << "</li>\r\n";
1574 os << " <li>Space Used by "
1575 "Deleted Recordings: ";
1576 sRep = QString("%L1").arg(nDeleted) + " MB";
1577 os << sRep << "</li>\r\n";
1578 os << " <li>Space Used by "
1579 "Auto-expirable Recordings: ";
1580 sRep = QString("%L1").arg(nExpirable) + " MB";
1581 os << sRep << "</li>\r\n";
1582 os << " </ul>\r\n";
1583 os << " </li>\r\n";
1584 }
1585
1586 os << " </ul>\r\n"
1587 << " </li>\r\n";
1588
1589 os << " </ul>\r\n";
1590 break;
1591 }
1592 }
1593
1594 node = node.nextSibling();
1595 }
1596
1597 // Loop again to handle per-filesystem details.
1598 node = storage.firstChild();
1599
1600 os << " Disk Usage Details:<br />\r\n";
1601 os << " <ul>\r\n";
1602
1603
1604 while (!node.isNull())
1605 {
1606 QDomElement g = node.toElement();
1607
1608 if (!g.isNull() && g.tagName() == "Group")
1609 {
1610 int nFree = g.attribute("free" , "0" ).toInt();
1611 int nTotal = g.attribute("total", "0" ).toInt();
1612 int nUsed = g.attribute("used" , "0" ).toInt();
1613 QString nDir = g.attribute("dir" , "" );
1614 QString id = g.attribute("id" , "" );
1615
1616 nDir.replace(",", ", ");
1617
1618
1619 if (id != "total")
1620 {
1621
1622 os << " <li>MythTV Drive #" << id << ":"
1623 << "\r\n"
1624 << " <ul>\r\n";
1625
1626 if (nDir.contains(','))
1627 os << " <li>Directories: ";
1628 else
1629 os << " <li>Directory: ";
1630
1631 os << nDir << "</li>\r\n";
1632
1633 os << " <li>Total Space: ";
1634 sRep = QString("%L1").arg(nTotal) + " MB";
1635 os << sRep << "</li>\r\n";
1636
1637 os << " <li>Space Used: ";
1638 sRep = QString("%L1").arg(nUsed) + " MB";
1639 os << sRep << "</li>\r\n";
1640
1641 os << " <li>Space Free: ";
1642 sRep = QString("%L1").arg(nFree) + " MB";
1643 os << sRep << "</li>\r\n";
1644
1645 os << " </ul>\r\n"
1646 << " </li>\r\n";
1647 }
1648
1649 }
1650
1651 node = node.nextSibling();
1652 }
1653
1654 os << " </ul>\r\n";
1655
1656 // Guide Info ---------------------
1657
1658 node = info.namedItem( "Guide" );
1659
1660 if (!node.isNull())
1661 {
1662 QDomElement e = node.toElement();
1663
1664 if (!e.isNull())
1665 {
1666 int nDays = e.attribute( "guideDays", "0" ).toInt();
1667 QString sStart = e.attribute( "start" , "" );
1668 QString sEnd = e.attribute( "end" , "" );
1669 QString sStatus = e.attribute( "status" , "" );
1670 QDateTime next = MythDate::fromString( e.attribute( "next" , "" ));
1671 QString sNext = next.isNull() ? "" :
1673 QString sMsg = "";
1674
1675 QDateTime thru = MythDate::fromString( e.attribute( "guideThru", "" ));
1676
1677 QDomText text = e.firstChild().toText();
1678
1679 QString mfdblrs =
1680 gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
1681 QDateTime lastrunstart = MythDate::fromString(mfdblrs);
1682
1683 if (!text.isNull())
1684 sMsg = text.nodeValue();
1685
1686 os << " Last mythfilldatabase run started on " << sStart
1687 << " and ";
1688
1689 if (sEnd < sStart)
1690 os << "is ";
1691 else
1692 os << "ended on " << sEnd << ". ";
1693
1694 os << sStatus << "<br />\r\n";
1695
1696 if (!next.isNull() && next >= lastrunstart)
1697 {
1698 os << " Suggested next mythfilldatabase run: "
1699 << sNext << ".<br />\r\n";
1700 }
1701
1702 if (!thru.isNull())
1703 {
1704 os << " There's guide data until "
1706
1707 if (nDays > 0)
1708 os << " " << QObject::tr("(%n day(s))", "", nDays);
1709
1710 os << ".";
1711
1712 if (nDays <= 3)
1713 os << " <strong>WARNING</strong>: is mythfilldatabase running?";
1714 }
1715 else
1716 {
1717 os << " There's <strong>no guide data</strong> available! "
1718 << "Have you run mythfilldatabase?";
1719 }
1720 }
1721 }
1722 os << "\r\n </div>\r\n";
1723
1724 return 1;
1725}
1726
1727int V2Status::PrintMiscellaneousInfo( QTextStream &os, const QDomElement& info )
1728{
1729 if (info.isNull())
1730 return 0;
1731
1732 // Miscellaneous information
1733
1734 QDomNodeList nodes = info.elementsByTagName("Information");
1735 uint count = nodes.count();
1736 if (count > 0)
1737 {
1738 QString display;
1739 QString linebreak;
1740 //QString name, value;
1741 os << "<div class=\"content\">\r\n"
1742 << " <h2 class=\"status\">Miscellaneous</h2>\r\n";
1743 for (unsigned int i = 0; i < count; i++)
1744 {
1745 QDomNode node = nodes.item(i);
1746 if (node.isNull())
1747 continue;
1748
1749 QDomElement e = node.toElement();
1750 if (e.isNull())
1751 continue;
1752
1753 display = e.attribute("display", "");
1754 //name = e.attribute("name", "");
1755 //value = e.attribute("value", "");
1756
1757 if (display.isEmpty())
1758 continue;
1759
1760 // Only include HTML line break if display value doesn't already
1761 // contain breaks.
1762 if (display.contains("<p>", Qt::CaseInsensitive) ||
1763 display.contains("<br", Qt::CaseInsensitive))
1764 {
1765 // matches <BR> or <br /
1766 linebreak = "\r\n";
1767 }
1768 else
1769 {
1770 linebreak = "<br />\r\n";
1771 }
1772
1773 os << " " << display << linebreak;
1774 }
1775 os << "</div>\r\n";
1776 }
1777
1778 return 1;
1779}
1780
1781void V2Status::FillProgramInfo(QDomDocument *pDoc,
1782 QDomNode &node,
1783 ProgramInfo *pInfo,
1784 bool bIncChannel /* = true */,
1785 bool bDetails /* = true */)
1786{
1787 if ((pDoc == nullptr) || (pInfo == nullptr))
1788 return;
1789
1790 // Build Program Element
1791
1792 QDomElement program = pDoc->createElement( "Program" );
1793 node.appendChild( program );
1794
1795 program.setAttribute( "startTime" ,
1797 program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(MythDate::ISODate));
1798 program.setAttribute( "title" , pInfo->GetTitle() );
1799 program.setAttribute( "subTitle" , pInfo->GetSubtitle());
1800 program.setAttribute( "category" , pInfo->GetCategory());
1801 program.setAttribute( "catType" , pInfo->GetCategoryTypeString());
1802 program.setAttribute( "repeat" , static_cast<int>(pInfo->IsRepeat()));
1803
1804 if (bDetails)
1805 {
1806
1807 program.setAttribute( "seriesId" , pInfo->GetSeriesID() );
1808 program.setAttribute( "programId" , pInfo->GetProgramID() );
1809 program.setAttribute( "stars" , pInfo->GetStars() );
1810 program.setAttribute( "fileSize" ,
1811 QString::number( pInfo->GetFilesize() ));
1812 program.setAttribute( "lastModified",
1814 program.setAttribute( "programFlags", pInfo->GetProgramFlags() );
1815 program.setAttribute( "hostname" , pInfo->GetHostname() );
1816
1817 if (pInfo->GetOriginalAirDate().isValid())
1818 program.setAttribute(
1819 "airdate", pInfo->GetOriginalAirDate().toString());
1820
1821 QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() );
1822 program.appendChild( textNode );
1823
1824 }
1825
1826 if ( bIncChannel )
1827 {
1828 // Build Channel Child Element
1829
1830 QDomElement channel = pDoc->createElement( "Channel" );
1831 program.appendChild( channel );
1832
1833 FillChannelInfo( channel, pInfo, bDetails );
1834 }
1835
1836 // Build Recording Child Element
1837
1838 if ( pInfo->GetRecordingStatus() != RecStatus::Unknown )
1839 {
1840 QDomElement recording = pDoc->createElement( "Recording" );
1841 program.appendChild( recording );
1842
1843 recording.setAttribute( "recStatus" ,
1844 pInfo->GetRecordingStatus() );
1845 recording.setAttribute( "recPriority" ,
1846 pInfo->GetRecordingPriority() );
1847 recording.setAttribute( "recStartTs" ,
1849 recording.setAttribute( "recEndTs" ,
1851
1852 if (bDetails)
1853 {
1854 recording.setAttribute( "recordId" ,
1855 pInfo->GetRecordingRuleID() );
1856 recording.setAttribute( "recGroup" ,
1857 pInfo->GetRecordingGroup() );
1858 recording.setAttribute( "playGroup" ,
1859 pInfo->GetPlaybackGroup() );
1860 recording.setAttribute( "recType" ,
1861 pInfo->GetRecordingRuleType() );
1862 recording.setAttribute( "dupInType" ,
1863 pInfo->GetDuplicateCheckSource() );
1864 recording.setAttribute( "dupMethod" ,
1865 pInfo->GetDuplicateCheckMethod() );
1866 recording.setAttribute( "encoderId" ,
1867 pInfo->GetInputID() );
1868 const RecordingInfo ri(*pInfo);
1869 recording.setAttribute( "recProfile" ,
1871 //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds );
1872 }
1873 }
1874}
1875
1877//
1879
1880void V2Status::FillChannelInfo( QDomElement &channel,
1881 ProgramInfo *pInfo,
1882 bool bDetails /* = true */ )
1883{
1884 if (pInfo)
1885 {
1886/*
1887 QString sHostName = gCoreContext->GetHostName();
1888 QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort",
1889 sHostName);
1890 QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" )
1891 .arg( sHostName )
1892 .arg( sPort )
1893 .arg( pInfo->chanid );
1894*/
1895
1896 channel.setAttribute( "chanId" , pInfo->GetChanID() );
1897 channel.setAttribute( "chanNum" , pInfo->GetChanNum());
1898 channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID());
1899 //channel.setAttribute( "iconURL" , sIconURL );
1900 channel.setAttribute( "channelName", pInfo->GetChannelName());
1901
1902 if (bDetails)
1903 {
1904 channel.setAttribute( "chanFilters",
1905 pInfo->GetChannelPlaybackFilters() );
1906 channel.setAttribute( "sourceId" , pInfo->GetSourceID() );
1907 channel.setAttribute( "inputId" , pInfo->GetInputID() );
1908 channel.setAttribute( "commFree" ,
1909 (pInfo->IsCommercialFree()) ? 1 : 0 );
1910 }
1911 }
1912}
1913
1915{
1916 static QRegularExpression re(".*\\.sql\\.gz$");
1917 QString thisHost = gCoreContext->GetHostName();
1918 StorageGroup sg1("DB Backups", thisHost);
1919 QStringList fileList = sg1.GetFileList("/");
1920 QStringList result = fileList.filter(re);
1921 StorageGroup sg2("Default", thisHost);
1922 fileList = sg2.GetFileList("/");
1923 result.append(fileList.filter(re));
1924 return result;
1925}
1926
1927
1928
1929// vim:set shiftwidth=4 tabstop=4 expandtab:
QMap< int, EncoderLink * > gTVList
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
Definition: cardutil.cpp:2654
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)
void GetActiveBackends(QStringList &hosts)
PlaybackSock * GetMediaServerByHostname(const QString &hostname)
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...
bool IsMasterHost(void)
is this the same host as the master
int GetNumSetting(const QString &key, int defaultval=0)
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
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()
void setIP(const QString &lip)
Definition: playbacksock.h:60
QString getIP(void) const
Definition: playbacksock.h:61
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
MainServer * GetMainServer()
Definition: scheduler.h:104
bool GetAllPending(RecList &retList, int recRuleId=0) const
Definition: scheduler.cpp:1756
QStringList GetFileList(const QString &Path, bool recursive=false)
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:434
static QList< QHostAddress > g_IPAddrList
Definition: upnp.h:49
QObject * Program
V2StorageGroup * AddNewStorageGroup()
Preformat * GetStatus()
Definition: v2status.cpp:105
static void PrintStatus(QTextStream &os, QDomDocument *pDoc)
Definition: v2status.cpp:895
Preformat * Status()
Definition: v2status.cpp:93
static void FillChannelInfo(QDomElement &channel, ProgramInfo *pInfo, bool bDetails=true)
Definition: v2status.cpp:1880
QMap< int, EncoderLink * > * m_pEncoders
Definition: v2status.h:64
static int PrintBackends(QTextStream &os, const QDomElement &backends)
Definition: v2status.cpp:1297
static void FillProgramInfo(QDomDocument *pDoc, QDomNode &node, ProgramInfo *pInfo, bool bIncChannel=true, bool bDetails=true)
Definition: v2status.cpp:1781
int m_nPreRollSeconds
Definition: v2status.h:67
static int PrintEncoderStatus(QTextStream &os, const QDomElement &encoders)
Definition: v2status.cpp:982
MainServer * m_pMainServer
Definition: v2status.h:65
static int PrintMiscellaneousInfo(QTextStream &os, const QDomElement &info)
Definition: v2status.cpp:1727
Preformat * GetStatusHTML()
Definition: v2status.cpp:121
static int PrintFrontends(QTextStream &os, const QDomElement &frontends)
Definition: v2status.cpp:1259
static int PrintScheduled(QTextStream &os, const QDomElement &scheduled)
Definition: v2status.cpp:1126
V2Status()
Definition: v2status.cpp:82
static int PrintMachineInfo(QTextStream &os, const QDomElement &info)
Definition: v2status.cpp:1481
static V2RecStats * GetRecStats()
Definition: v2status.cpp:316
Preformat * xml()
Definition: v2status.cpp:99
void FillStatusXML(QDomDocument *pDoc)
Definition: v2status.cpp:450
bool m_bIsMaster
Definition: v2status.h:66
Scheduler * m_pSched
Definition: v2status.h:63
static QStringList GetBackupsList()
Definition: v2status.cpp:1914
void FillDriveSpace(V2MachineInfo *pMachineInfo)
Definition: v2status.cpp:382
static int PrintJobQueue(QTextStream &os, const QDomElement &jobs)
Definition: v2status.cpp:1336
static void RegisterCustomTypes()
V2BackendStatus * GetBackendStatus()
Definition: v2status.cpp:149
unsigned int uint
Definition: compat.h:60
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
@ 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.
#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
const char * GetMythSourceVersion()
Definition: mythversion.cpp:7
const char * GetMythSourcePath()
Definition: mythversion.cpp:12
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
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:339
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
void FillEncoderList(QVariantList &list, QObject *parent)
void FillFrontendList(QVariantList &list, QObject *parent, bool OnLine)
void V2FillProgramInfo(V2Program *pProgram, ProgramInfo *pInfo, bool bIncChannel, bool bDetails, bool bIncCast, bool bIncArtwork, bool bIncRecording)
int FillUpcomingList(QVariantList &list, QObject *parent, int &nStartIndex, int &nCount, bool bShowAll, int nRecordId, int nRecStatus, const QString &Sort, const QString &RecGroup)
static QDateTime setting_to_qdatetime(const char *setting)
Definition: v2status.cpp:141
Q_GLOBAL_STATIC_WITH_ARGS(MythHTTPMetaService, s_service,(STATUS_HANDLE, V2Status::staticMetaObject, &V2Status::RegisterCustomTypes)) void V2Status
Definition: v2status.cpp:57
static QString setting_to_localtime(const char *setting)
Definition: v2status.cpp:134
#define STATUS_HANDLE
Definition: v2status.h:36