|
MythTV
0.26-pre
|
00001 00002 // Program Name: httpstatus.cpp 00003 // 00004 // Purpose - Html & XML status HttpServerExtension 00005 // 00006 // Created By : David Blain Created On : Oct. 24, 2005 00007 // Modified By : Modified On: 00008 // 00010 00011 // POSIX headers 00012 #include <unistd.h> 00013 00014 // ANSI C headers 00015 #include <cmath> 00016 #include <cstdio> 00017 #include <cstdlib> 00018 00019 // Qt headers 00020 #include <QTextStream> 00021 #include <QRegExp> 00022 #include <QLocale> 00023 00024 // MythTV headers 00025 #include "httpstatus.h" 00026 00027 #include "mythcorecontext.h" 00028 #include "mythversion.h" 00029 #include "mythdbcon.h" 00030 #include "compat.h" 00031 #include "mythconfig.h" 00032 #include "autoexpire.h" 00033 #include "tv.h" 00034 #include "encoderlink.h" 00035 #include "scheduler.h" 00036 #include "mainserver.h" 00037 #include "cardutil.h" 00038 #include "mythsystem.h" 00039 #include "exitcodes.h" 00040 #include "jobqueue.h" 00041 #include "upnp.h" 00042 #include <mythmiscutil.h> 00043 00045 // 00047 00048 HttpStatus::HttpStatus( QMap<int, EncoderLink *> *tvList, Scheduler *sched, 00049 AutoExpire *expirer, bool bIsMaster ) 00050 : HttpServerExtension( "HttpStatus" , QString()) 00051 { 00052 m_pEncoders = tvList; 00053 m_pSched = sched; 00054 m_pExpirer = expirer; 00055 m_bIsMaster = bIsMaster; 00056 00057 m_nPreRollSeconds = gCoreContext->GetNumSetting("RecordPreRoll", 0); 00058 00059 m_pMainServer = NULL; 00060 } 00061 00063 // 00065 00066 HttpStatus::~HttpStatus() 00067 { 00068 } 00069 00071 // 00073 00074 HttpStatusMethod HttpStatus::GetMethod( const QString &sURI ) 00075 { 00076 if (sURI == "Status" ) return( HSM_GetStatusHTML ); 00077 if (sURI == "GetStatusHTML" ) return( HSM_GetStatusHTML ); 00078 if (sURI == "GetStatus" ) return( HSM_GetStatusXML ); 00079 if (sURI == "xml" ) return( HSM_GetStatusXML ); 00080 00081 return( HSM_Unknown ); 00082 } 00083 00085 // 00087 00088 QStringList HttpStatus::GetBasePaths() 00089 { 00090 return QStringList( "/Status" ); 00091 } 00092 00094 // 00096 00097 bool HttpStatus::ProcessRequest( HTTPRequest *pRequest ) 00098 { 00099 try 00100 { 00101 if (pRequest) 00102 { 00103 if ((pRequest->m_sBaseUrl != "/Status" ) && 00104 (pRequest->m_sResourceUrl != "/Status" )) 00105 { 00106 return( false ); 00107 } 00108 00109 switch( GetMethod( pRequest->m_sMethod )) 00110 { 00111 case HSM_GetStatusXML : GetStatusXML ( pRequest ); return true; 00112 case HSM_GetStatusHTML : GetStatusHTML ( pRequest ); return true; 00113 00114 default: 00115 { 00116 pRequest->m_eResponseType = ResponseTypeHTML; 00117 pRequest->m_nResponseStatus = 200; 00118 00119 break; 00120 } 00121 } 00122 } 00123 } 00124 catch( ... ) 00125 { 00126 LOG(VB_GENERAL, LOG_ERR, 00127 "HttpStatus::ProcessRequest() - Unexpected Exception"); 00128 } 00129 00130 return( false ); 00131 } 00132 00134 // 00136 00137 void HttpStatus::GetStatusXML( HTTPRequest *pRequest ) 00138 { 00139 QDomDocument doc( "Status" ); 00140 00141 // UTF-8 is the default, but good practice to specify it anyway 00142 QDomProcessingInstruction encoding = 00143 doc.createProcessingInstruction("xml", 00144 "version=\"1.0\" encoding=\"UTF-8\""); 00145 doc.appendChild(encoding); 00146 00147 FillStatusXML( &doc ); 00148 00149 pRequest->m_eResponseType = ResponseTypeXML; 00150 pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000"; 00151 00152 QTextStream stream( &pRequest->m_response ); 00153 stream.setCodec("UTF-8"); // Otherwise locale default is used. 00154 stream << doc.toString(); 00155 } 00156 00158 // 00160 00161 void HttpStatus::GetStatusHTML( HTTPRequest *pRequest ) 00162 { 00163 pRequest->m_eResponseType = ResponseTypeHTML; 00164 pRequest->m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000"; 00165 00166 QDomDocument doc( "Status" ); 00167 00168 FillStatusXML( &doc ); 00169 00170 QTextStream stream( &pRequest->m_response ); 00171 PrintStatus( stream, &doc ); 00172 } 00173 00174 void HttpStatus::FillStatusXML( QDomDocument *pDoc ) 00175 { 00176 QDateTime qdtNow = QDateTime::currentDateTime(); 00177 00178 // Add Root Node. 00179 00180 QDomElement root = pDoc->createElement("Status"); 00181 pDoc->appendChild(root); 00182 00183 root.setAttribute("date" , MythDateTimeToString(qdtNow, 00184 kDateFull | kAddYear)); 00185 root.setAttribute("time" , MythDateTimeToString(qdtNow, kTime)); 00186 root.setAttribute("ISODate" , qdtNow.toString(Qt::ISODate) ); 00187 root.setAttribute("version" , MYTH_BINARY_VERSION ); 00188 root.setAttribute("protoVer", MYTH_PROTO_VERSION ); 00189 00190 // Add all encoders, if any 00191 00192 QDomElement encoders = pDoc->createElement("Encoders"); 00193 root.appendChild(encoders); 00194 00195 int numencoders = 0; 00196 bool isLocal = true; 00197 00198 QMap<int, EncoderLink *>::Iterator iter = m_pEncoders->begin(); 00199 00200 for (; iter != m_pEncoders->end(); ++iter) 00201 { 00202 EncoderLink *elink = *iter; 00203 00204 if (elink != NULL) 00205 { 00206 TVState state = elink->GetState(); 00207 isLocal = elink->IsLocal(); 00208 00209 QDomElement encoder = pDoc->createElement("Encoder"); 00210 encoders.appendChild(encoder); 00211 00212 encoder.setAttribute("id" , elink->GetCardID() ); 00213 encoder.setAttribute("local" , isLocal ); 00214 encoder.setAttribute("connected" , elink->IsConnected() ); 00215 encoder.setAttribute("state" , state ); 00216 encoder.setAttribute("sleepstatus" , elink->GetSleepStatus() ); 00217 //encoder.setAttribute("lowOnFreeSpace", elink->isLowOnFreeSpace()); 00218 00219 if (isLocal) 00220 encoder.setAttribute("hostname", gCoreContext->GetHostName()); 00221 else 00222 encoder.setAttribute("hostname", elink->GetHostName()); 00223 00224 encoder.setAttribute("devlabel", 00225 CardUtil::GetDeviceLabel(elink->GetCardID()) ); 00226 00227 if (elink->IsConnected()) 00228 numencoders++; 00229 00230 switch (state) 00231 { 00232 case kState_WatchingLiveTV: 00233 case kState_RecordingOnly: 00234 case kState_WatchingRecording: 00235 { 00236 ProgramInfo *pInfo = elink->GetRecording(); 00237 00238 if (pInfo) 00239 { 00240 FillProgramInfo(pDoc, encoder, pInfo); 00241 delete pInfo; 00242 } 00243 00244 break; 00245 } 00246 00247 default: 00248 break; 00249 } 00250 } 00251 } 00252 00253 encoders.setAttribute("count", numencoders); 00254 00255 // Add upcoming shows 00256 00257 QDomElement scheduled = pDoc->createElement("Scheduled"); 00258 root.appendChild(scheduled); 00259 00260 RecList recordingList; 00261 00262 if (m_pSched) 00263 m_pSched->GetAllPending(recordingList); 00264 00265 unsigned int iNum = 10; 00266 unsigned int iNumRecordings = 0; 00267 00268 RecConstIter itProg = recordingList.begin(); 00269 for (; (itProg != recordingList.end()) && iNumRecordings < iNum; ++itProg) 00270 { 00271 if (((*itProg)->GetRecordingStatus() <= rsWillRecord) && 00272 ((*itProg)->GetRecordingStartTime() >= 00273 QDateTime::currentDateTime())) 00274 { 00275 iNumRecordings++; 00276 FillProgramInfo(pDoc, scheduled, *itProg); 00277 } 00278 } 00279 00280 while (!recordingList.empty()) 00281 { 00282 ProgramInfo *pginfo = recordingList.back(); 00283 delete pginfo; 00284 recordingList.pop_back(); 00285 } 00286 00287 scheduled.setAttribute("count", iNumRecordings); 00288 00289 // Add known frontends 00290 00291 QDomElement frontends = pDoc->createElement("Frontends"); 00292 root.appendChild(frontends); 00293 00294 SSDPCacheEntries *fes = SSDP::Find( 00295 "urn:schemas-mythtv-org:service:MythFrontend:1"); 00296 if (fes) 00297 { 00298 EntryMap map; 00299 fes->GetEntryMap(map); 00300 fes->Release(); 00301 fes = NULL; 00302 00303 frontends.setAttribute( "count", map.size() ); 00304 QMapIterator< QString, DeviceLocation * > i(map); 00305 while (i.hasNext()) 00306 { 00307 i.next(); 00308 QDomElement fe = pDoc->createElement("Frontend"); 00309 frontends.appendChild(fe); 00310 QUrl url(i.value()->m_sLocation); 00311 fe.setAttribute("name", url.host()); 00312 fe.setAttribute("url", url.toString(QUrl::RemovePath)); 00313 i.value()->Release(); 00314 } 00315 } 00316 00317 // Other backends 00318 00319 QDomElement backends = pDoc->createElement("Backends"); 00320 root.appendChild(backends); 00321 00322 int numbes = 0; 00323 if (!gCoreContext->IsMasterBackend()) 00324 { 00325 numbes++; 00326 QString masterhost = gCoreContext->GetMasterHostName(); 00327 QString masterip = gCoreContext->GetSetting("MasterServerIP"); 00328 QString masterport = gCoreContext->GetSettingOnHost("BackendStatusPort", masterhost, "6544"); 00329 00330 QDomElement mbe = pDoc->createElement("Backend"); 00331 backends.appendChild(mbe); 00332 mbe.setAttribute("type", "Master"); 00333 mbe.setAttribute("name", masterhost); 00334 mbe.setAttribute("url" , masterip + ":" + masterport); 00335 } 00336 00337 SSDPCacheEntries *sbes = SSDP::Find( 00338 "urn:schemas-mythtv-org:device:SlaveMediaServer:1"); 00339 if (sbes) 00340 { 00341 00342 QString ipaddress = QString(); 00343 if (!UPnp::g_IPAddrList.isEmpty()) 00344 ipaddress = UPnp::g_IPAddrList.at(0); 00345 00346 EntryMap map; 00347 sbes->GetEntryMap(map); 00348 sbes->Release(); 00349 sbes = NULL; 00350 00351 QMapIterator< QString, DeviceLocation * > i(map); 00352 while (i.hasNext()) 00353 { 00354 i.next(); 00355 QUrl url(i.value()->m_sLocation); 00356 if (url.host() != ipaddress) 00357 { 00358 numbes++; 00359 QDomElement mbe = pDoc->createElement("Backend"); 00360 backends.appendChild(mbe); 00361 mbe.setAttribute("type", "Slave"); 00362 mbe.setAttribute("name", url.host()); 00363 mbe.setAttribute("url" , url.toString(QUrl::RemovePath)); 00364 } 00365 i.value()->Release(); 00366 } 00367 } 00368 00369 backends.setAttribute("count", numbes); 00370 00371 // Add Job Queue Entries 00372 00373 QDomElement jobqueue = pDoc->createElement("JobQueue"); 00374 root.appendChild(jobqueue); 00375 00376 QMap<int, JobQueueEntry> jobs; 00377 QMap<int, JobQueueEntry>::Iterator it; 00378 00379 JobQueue::GetJobsInQueue(jobs, 00380 JOB_LIST_NOT_DONE | JOB_LIST_ERROR | 00381 JOB_LIST_RECENT); 00382 00383 for (it = jobs.begin(); it != jobs.end(); ++it) 00384 { 00385 ProgramInfo pginfo((*it).chanid, (*it).recstartts); 00386 if (!pginfo.GetChanID()) 00387 continue; 00388 00389 QDomElement job = pDoc->createElement("Job"); 00390 jobqueue.appendChild(job); 00391 00392 job.setAttribute("id" , (*it).id ); 00393 job.setAttribute("chanId" , (*it).chanid ); 00394 job.setAttribute("startTime" , 00395 (*it).recstartts.toString(Qt::ISODate)); 00396 job.setAttribute("startTs" , (*it).startts ); 00397 job.setAttribute("insertTime", 00398 (*it).inserttime.toString(Qt::ISODate)); 00399 job.setAttribute("type" , (*it).type ); 00400 job.setAttribute("cmds" , (*it).cmds ); 00401 job.setAttribute("flags" , (*it).flags ); 00402 job.setAttribute("status" , (*it).status ); 00403 job.setAttribute("statusTime", 00404 (*it).statustime.toString(Qt::ISODate)); 00405 job.setAttribute("schedTime" , 00406 (*it).schedruntime.toString(Qt::ISODate)); 00407 job.setAttribute("args" , (*it).args ); 00408 00409 if ((*it).hostname.isEmpty()) 00410 job.setAttribute("hostname", QObject::tr("master")); 00411 else 00412 job.setAttribute("hostname",(*it).hostname); 00413 00414 QDomText textNode = pDoc->createTextNode((*it).comment); 00415 job.appendChild(textNode); 00416 00417 FillProgramInfo(pDoc, job, &pginfo); 00418 } 00419 00420 jobqueue.setAttribute( "count", jobs.size() ); 00421 00422 // Add Machine information 00423 00424 QDomElement mInfo = pDoc->createElement("MachineInfo"); 00425 QDomElement storage = pDoc->createElement("Storage" ); 00426 QDomElement load = pDoc->createElement("Load" ); 00427 QDomElement guide = pDoc->createElement("Guide" ); 00428 00429 root.appendChild (mInfo ); 00430 mInfo.appendChild(storage); 00431 mInfo.appendChild(load ); 00432 mInfo.appendChild(guide ); 00433 00434 // drive space --------------------- 00435 00436 QStringList strlist; 00437 QString dirs; 00438 QString hostname; 00439 QString directory; 00440 QString isLocalstr; 00441 QString fsID; 00442 QString ids; 00443 long long iTotal = -1, iUsed = -1, iAvail = -1; 00444 00445 if (m_pMainServer) 00446 m_pMainServer->BackendQueryDiskSpace(strlist, true, m_bIsMaster); 00447 00448 QDomElement total; 00449 00450 // Make a temporary list to hold the per-filesystem elements so that the 00451 // total is always the first element. 00452 QList<QDomElement> fsXML; 00453 QStringList::const_iterator sit = strlist.begin(); 00454 while (sit != strlist.end()) 00455 { 00456 hostname = *(sit++); 00457 directory = *(sit++); 00458 isLocalstr = *(sit++); 00459 fsID = *(sit++); 00460 ++sit; // ignore dirID 00461 ++sit; // ignore blocksize 00462 iTotal = (*(sit++)).toLongLong(); 00463 iUsed = (*(sit++)).toLongLong();; 00464 iAvail = iTotal - iUsed; 00465 00466 if (fsID == "-2") 00467 fsID = "total"; 00468 00469 QDomElement group = pDoc->createElement("Group"); 00470 00471 group.setAttribute("id" , fsID ); 00472 group.setAttribute("total", (int)(iTotal>>10) ); 00473 group.setAttribute("used" , (int)(iUsed>>10) ); 00474 group.setAttribute("free" , (int)(iAvail>>10) ); 00475 group.setAttribute("dir" , directory ); 00476 00477 if (fsID == "total") 00478 { 00479 long long iLiveTV = -1, iDeleted = -1, iExpirable = -1; 00480 MSqlQuery query(MSqlQuery::InitCon()); 00481 query.prepare("SELECT SUM(filesize) FROM recorded " 00482 " WHERE recgroup = :RECGROUP;"); 00483 00484 query.bindValue(":RECGROUP", "LiveTV"); 00485 if (query.exec() && query.next()) 00486 { 00487 iLiveTV = query.value(0).toLongLong(); 00488 } 00489 query.bindValue(":RECGROUP", "Deleted"); 00490 if (query.exec() && query.next()) 00491 { 00492 iDeleted = query.value(0).toLongLong(); 00493 } 00494 query.prepare("SELECT SUM(filesize) FROM recorded " 00495 " WHERE autoexpire = 1 " 00496 " AND recgroup NOT IN ('LiveTV', 'Deleted');"); 00497 if (query.exec() && query.next()) 00498 { 00499 iExpirable = query.value(0).toLongLong(); 00500 } 00501 group.setAttribute("livetv", (int)(iLiveTV>>20) ); 00502 group.setAttribute("deleted", (int)(iDeleted>>20) ); 00503 group.setAttribute("expirable", (int)(iExpirable>>20) ); 00504 total = group; 00505 } 00506 else 00507 fsXML << group; 00508 } 00509 00510 storage.appendChild(total); 00511 int num_elements = fsXML.size(); 00512 for (int fs_index = 0; fs_index < num_elements; fs_index++) 00513 { 00514 storage.appendChild(fsXML[fs_index]); 00515 } 00516 00517 // load average --------------------- 00518 00519 double rgdAverages[3]; 00520 00521 if (getloadavg(rgdAverages, 3) != -1) 00522 { 00523 load.setAttribute("avg1", rgdAverages[0]); 00524 load.setAttribute("avg2", rgdAverages[1]); 00525 load.setAttribute("avg3", rgdAverages[2]); 00526 } 00527 00528 // Guide Data --------------------- 00529 00530 QDateTime GuideDataThrough; 00531 00532 MSqlQuery query(MSqlQuery::InitCon()); 00533 query.prepare("SELECT MAX(endtime) FROM program WHERE manualid = 0;"); 00534 00535 if (query.exec() && query.next()) 00536 { 00537 GuideDataThrough = QDateTime::fromString( 00538 query.value(0).toString(), Qt::ISODate); 00539 } 00540 00541 guide.setAttribute("start", 00542 gCoreContext->GetSetting("mythfilldatabaseLastRunStart")); 00543 guide.setAttribute("end", 00544 gCoreContext->GetSetting("mythfilldatabaseLastRunEnd")); 00545 guide.setAttribute("status", 00546 gCoreContext->GetSetting("mythfilldatabaseLastRunStatus")); 00547 if (gCoreContext->GetNumSetting("MythFillGrabberSuggestsTime", 0)) 00548 { 00549 guide.setAttribute("next", 00550 gCoreContext->GetSetting("MythFillSuggestedRunTime")); 00551 } 00552 00553 if (!GuideDataThrough.isNull()) 00554 { 00555 guide.setAttribute("guideThru", 00556 QDateTime(GuideDataThrough).toString(Qt::ISODate)); 00557 guide.setAttribute("guideDays", qdtNow.daysTo(GuideDataThrough)); 00558 } 00559 00560 QDomText dataDirectMessage = 00561 pDoc->createTextNode(gCoreContext->GetSetting("DataDirectMessage")); 00562 guide.appendChild(dataDirectMessage); 00563 00564 // Add Miscellaneous information 00565 00566 QString info_script = gCoreContext->GetSetting("MiscStatusScript"); 00567 if ((!info_script.isEmpty()) && (info_script != "none")) 00568 { 00569 QDomElement misc = pDoc->createElement("Miscellaneous"); 00570 root.appendChild(misc); 00571 00572 uint flags = kMSRunShell | kMSStdOut | kMSBuffered; 00573 MythSystem ms(info_script, flags); 00574 ms.Run(10); 00575 if (ms.Wait() != GENERIC_EXIT_OK) 00576 { 00577 LOG(VB_GENERAL, LOG_ERR, 00578 QString("Error running miscellaneous " 00579 "status information script: %1").arg(info_script)); 00580 return; 00581 } 00582 00583 QByteArray input = ms.ReadAll(); 00584 00585 QStringList output = QString(input).split('\n', 00586 QString::SkipEmptyParts); 00587 00588 QStringList::iterator iter; 00589 for (iter = output.begin(); iter != output.end(); ++iter) 00590 { 00591 QDomElement info = pDoc->createElement("Information"); 00592 00593 QStringList list = (*iter).split("[]:[]"); 00594 unsigned int size = list.size(); 00595 unsigned int hasAttributes = 0; 00596 00597 if ((size > 0) && (!list[0].isEmpty())) 00598 { 00599 info.setAttribute("display", list[0]); 00600 hasAttributes++; 00601 } 00602 if ((size > 1) && (!list[1].isEmpty())) 00603 { 00604 info.setAttribute("name", list[1]); 00605 hasAttributes++; 00606 } 00607 if ((size > 2) && (!list[2].isEmpty())) 00608 { 00609 info.setAttribute("value", list[2]); 00610 hasAttributes++; 00611 } 00612 00613 if (hasAttributes > 0) 00614 misc.appendChild(info); 00615 } 00616 } 00617 } 00618 00620 // 00622 00623 void HttpStatus::PrintStatus( QTextStream &os, QDomDocument *pDoc ) 00624 { 00625 00626 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d"); 00627 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 00628 00629 os.setCodec("UTF-8"); 00630 00631 QDateTime qdtNow = QDateTime::currentDateTime(); 00632 00633 QDomElement docElem = pDoc->documentElement(); 00634 00635 os << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " 00636 << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n" 00637 << "<html xmlns=\"http://www.w3.org/1999/xhtml\"" 00638 << " xml:lang=\"en\" lang=\"en\">\r\n" 00639 << "<head>\r\n" 00640 << " <meta http-equiv=\"Content-Type\"" 00641 << "content=\"text/html; charset=UTF-8\" />\r\n" 00642 << " <link rel=\"stylesheet\" href=\"/css/Status.css\" type=\"text/css\">\r\n" 00643 << " <title>MythTV Status - " 00644 << docElem.attribute( "date", qdtNow.toString(shortdateformat) ) 00645 << " " 00646 << docElem.attribute( "time", qdtNow.toString(timeformat) ) << " - " 00647 << docElem.attribute( "version", MYTH_BINARY_VERSION ) << "</title>\r\n" 00648 << "</head>\r\n" 00649 << "<body bgcolor=\"#fff\">\r\n" 00650 << "<div class=\"status\">\r\n" 00651 << " <h1 class=\"status\">MythTV Status</h1>\r\n"; 00652 00653 // encoder information --------------------- 00654 00655 QDomNode node = docElem.namedItem( "Encoders" ); 00656 00657 if (!node.isNull()) 00658 PrintEncoderStatus( os, node.toElement() ); 00659 00660 // upcoming shows -------------------------- 00661 00662 node = docElem.namedItem( "Scheduled" ); 00663 00664 if (!node.isNull()) 00665 PrintScheduled( os, node.toElement()); 00666 00667 // Frontends 00668 00669 node = docElem.namedItem( "Frontends" ); 00670 00671 if (!node.isNull()) 00672 PrintFrontends (os, node.toElement()); 00673 00674 // Backends 00675 00676 node = docElem.namedItem( "Backends" ); 00677 00678 if (!node.isNull()) 00679 PrintBackends (os, node.toElement()); 00680 00681 // Job Queue Entries ----------------------- 00682 00683 node = docElem.namedItem( "JobQueue" ); 00684 00685 if (!node.isNull()) 00686 PrintJobQueue( os, node.toElement()); 00687 00688 // Machine information --------------------- 00689 00690 node = docElem.namedItem( "MachineInfo" ); 00691 00692 if (!node.isNull()) 00693 PrintMachineInfo( os, node.toElement()); 00694 00695 // Miscellaneous information --------------- 00696 00697 node = docElem.namedItem( "Miscellaneous" ); 00698 00699 if (!node.isNull()) 00700 PrintMiscellaneousInfo( os, node.toElement()); 00701 00702 os << "\r\n</div>\r\n</body>\r\n</html>\r\n"; 00703 00704 } 00705 00707 // 00709 00710 int HttpStatus::PrintEncoderStatus( QTextStream &os, QDomElement encoders ) 00711 { 00712 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 00713 int nNumEncoders = 0; 00714 00715 if (encoders.isNull()) 00716 return 0; 00717 00718 os << " <div class=\"content\">\r\n" 00719 << " <h2 class=\"status\">Encoder Status</h2>\r\n"; 00720 00721 QDomNode node = encoders.firstChild(); 00722 00723 while (!node.isNull()) 00724 { 00725 QDomElement e = node.toElement(); 00726 00727 if (!e.isNull()) 00728 { 00729 if (e.tagName() == "Encoder") 00730 { 00731 QString sIsLocal = (e.attribute( "local" , "remote" )== "1") 00732 ? "local" : "remote"; 00733 QString sCardId = e.attribute( "id" , "0" ); 00734 QString sHostName = e.attribute( "hostname" , "Unknown"); 00735 bool bConnected= e.attribute( "connected", "0" ).toInt(); 00736 00737 bool bIsLowOnFreeSpace=e.attribute( "lowOnFreeSpace", "0").toInt(); 00738 00739 QString sDevlabel = e.attribute( "devlabel", "[ UNKNOWN ]"); 00740 00741 os << " Encoder " << sCardId << " " << sDevlabel 00742 << " is " << sIsLocal << " on " << sHostName; 00743 00744 if ((sIsLocal == "remote") && !bConnected) 00745 { 00746 SleepStatus sleepStatus = 00747 (SleepStatus) e.attribute("sleepstatus", 00748 QString((int)sStatus_Undefined)).toInt(); 00749 00750 if (sleepStatus == sStatus_Asleep) 00751 os << " (currently asleep).<br />"; 00752 else 00753 os << " (currently not connected).<br />"; 00754 00755 node = node.nextSibling(); 00756 continue; 00757 } 00758 00759 nNumEncoders++; 00760 00761 TVState encState = (TVState) e.attribute( "state", "0").toInt(); 00762 00763 switch( encState ) 00764 { 00765 case kState_WatchingLiveTV: 00766 os << " and is watching Live TV"; 00767 break; 00768 00769 case kState_RecordingOnly: 00770 case kState_WatchingRecording: 00771 os << " and is recording"; 00772 break; 00773 00774 default: 00775 os << " and is not recording."; 00776 break; 00777 } 00778 00779 // Display first Program Element listed under the encoder 00780 00781 QDomNode tmpNode = e.namedItem( "Program" ); 00782 00783 if (!tmpNode.isNull()) 00784 { 00785 QDomElement program = tmpNode.toElement(); 00786 00787 if (!program.isNull()) 00788 { 00789 os << " '" << program.attribute( "title", "Unknown" ) << "'"; 00790 00791 // Get Channel information 00792 00793 tmpNode = program.namedItem( "Channel" ); 00794 00795 if (!tmpNode.isNull()) 00796 { 00797 QDomElement channel = tmpNode.toElement(); 00798 00799 if (!channel.isNull()) 00800 os << " on " 00801 << channel.attribute( "callSign", "unknown" ); 00802 } 00803 00804 // Get Recording Information (if any) 00805 00806 tmpNode = program.namedItem( "Recording" ); 00807 00808 if (!tmpNode.isNull()) 00809 { 00810 QDomElement recording = tmpNode.toElement(); 00811 00812 if (!recording.isNull()) 00813 { 00814 QDateTime endTs = QDateTime::fromString( 00815 recording.attribute( "recEndTs", "" ), 00816 Qt::ISODate ); 00817 00818 os << ". This recording "; 00819 if (endTs < QDateTime::currentDateTime()) 00820 os << "was "; 00821 else 00822 os << "is "; 00823 00824 os << "scheduled to end at " 00825 << endTs.toString(timeformat); 00826 } 00827 } 00828 } 00829 00830 os << "."; 00831 } 00832 00833 if (bIsLowOnFreeSpace) 00834 { 00835 os << " <strong>WARNING</strong>:" 00836 << " This backend is low on free disk space!"; 00837 } 00838 00839 os << "<br />\r\n"; 00840 } 00841 } 00842 00843 node = node.nextSibling(); 00844 } 00845 00846 os << " </div>\r\n\r\n"; 00847 00848 return( nNumEncoders ); 00849 } 00850 00852 // 00854 00855 int HttpStatus::PrintScheduled( QTextStream &os, QDomElement scheduled ) 00856 { 00857 QDateTime qdtNow = QDateTime::currentDateTime(); 00858 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d"); 00859 QString longdateformat = gCoreContext->GetSetting("DateFormat", "M/d/yyyy"); 00860 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 00861 00862 if (scheduled.isNull()) 00863 return( 0 ); 00864 00865 int nNumRecordings= scheduled.attribute( "count", "0" ).toInt(); 00866 00867 os << " <div class=\"content\">\r\n" 00868 << " <h2 class=\"status\">Schedule</h2>\r\n"; 00869 00870 if (nNumRecordings == 0) 00871 { 00872 os << " There are no shows scheduled for recording.\r\n" 00873 << " </div>\r\n"; 00874 return( 0 ); 00875 } 00876 00877 os << " The next " << nNumRecordings << " show" << (nNumRecordings == 1 ? "" : "s" ) 00878 << " that " << (nNumRecordings == 1 ? "is" : "are") 00879 << " scheduled for recording:\r\n"; 00880 00881 os << " <div class=\"schedule\">\r\n"; 00882 00883 // Iterate through all scheduled programs 00884 00885 QDomNode node = scheduled.firstChild(); 00886 00887 while (!node.isNull()) 00888 { 00889 QDomElement e = node.toElement(); 00890 00891 if (!e.isNull()) 00892 { 00893 QDomNode recNode = e.namedItem( "Recording" ); 00894 QDomNode chanNode = e.namedItem( "Channel" ); 00895 00896 if ((e.tagName() == "Program") && !recNode.isNull() && !chanNode.isNull()) 00897 { 00898 QDomElement r = recNode.toElement(); 00899 QDomElement c = chanNode.toElement(); 00900 00901 QString sTitle = e.attribute( "title" , "" ); 00902 QString sSubTitle = e.attribute( "subTitle", "" ); 00903 QDateTime airDate = QDateTime::fromString( e.attribute( "airdate" ,"" ), Qt::ISODate ); 00904 QDateTime startTs = QDateTime::fromString( e.attribute( "startTime" ,"" ), Qt::ISODate ); 00905 QDateTime endTs = QDateTime::fromString( e.attribute( "endTime" ,"" ), Qt::ISODate ); 00906 QDateTime recStartTs = QDateTime::fromString( r.attribute( "recStartTs","" ), Qt::ISODate ); 00907 // QDateTime recEndTs = QDateTime::fromString( r.attribute( "recEndTs" ,"" ), Qt::ISODate ); 00908 int nPreRollSecs = r.attribute( "preRollSeconds", "0" ).toInt(); 00909 int nEncoderId = r.attribute( "encoderId" , "0" ).toInt(); 00910 QString sProfile = r.attribute( "recProfile" , "" ); 00911 QString sChanName = c.attribute( "channelName" , "" ); 00912 QString sDesc = ""; 00913 00914 QDomText text = e.firstChild().toText(); 00915 if (!text.isNull()) 00916 sDesc = text.nodeValue(); 00917 00918 // Build Time to recording start. 00919 00920 int nTotalSecs = qdtNow.secsTo( recStartTs ) - nPreRollSecs; 00921 00922 //since we're not displaying seconds 00923 00924 nTotalSecs -= 60; 00925 00926 int nTotalDays = nTotalSecs / 86400; 00927 int nTotalHours = (nTotalSecs / 3600) 00928 - (nTotalDays * 24); 00929 int nTotalMins = (nTotalSecs / 60) % 60; 00930 00931 QString sTimeToStart = "in"; 00932 00933 sTimeToStart += QObject::tr(" %n day(s),", "", nTotalDays ); 00934 sTimeToStart += QObject::tr(" %n hour(s) and", "", nTotalHours); 00935 sTimeToStart += QObject::tr(" %n minute(s)", "", nTotalMins); 00936 00937 if ( nTotalHours == 0 && nTotalMins == 0) 00938 sTimeToStart = QObject::tr("within one minute", "Recording starting"); 00939 00940 if ( nTotalSecs < 0) 00941 sTimeToStart = QObject::tr("soon", "Recording starting"); 00942 00943 // Output HTML 00944 00945 os << " <a href=\"#\">"; 00946 if (shortdateformat.indexOf("ddd") == -1) { 00947 // If day-of-week not already present somewhere, prepend it. 00948 os << recStartTs.addSecs(-nPreRollSecs).toString("ddd") 00949 << " "; 00950 } 00951 os << recStartTs.addSecs(-nPreRollSecs).toString(shortdateformat) << " " 00952 << recStartTs.addSecs(-nPreRollSecs).toString(timeformat) << " - "; 00953 00954 if (nEncoderId > 0) 00955 os << "Encoder " << nEncoderId << " - "; 00956 00957 os << sChanName << " - " << sTitle << "<br />" 00958 << "<span><strong>" << sTitle << "</strong> (" 00959 << startTs.toString(timeformat) << "-" 00960 << endTs.toString(timeformat) << ")<br />"; 00961 00962 if ( !sSubTitle.isEmpty()) 00963 os << "<em>" << sSubTitle << "</em><br /><br />"; 00964 00965 if ( airDate.isValid()) 00966 os << "Orig. Airdate: " 00967 << airDate.toString(longdateformat) 00968 << "<br /><br />"; 00969 00970 os << sDesc << "<br /><br />" 00971 << "This recording will start " << sTimeToStart 00972 << " using encoder " << nEncoderId << " with the '" 00973 << sProfile << "' profile.</span></a><hr />\r\n"; 00974 } 00975 } 00976 00977 node = node.nextSibling(); 00978 } 00979 os << " </div>\r\n"; 00980 os << " </div>\r\n\r\n"; 00981 00982 return( nNumRecordings ); 00983 } 00984 00986 // 00988 00989 int HttpStatus::PrintFrontends( QTextStream &os, QDomElement frontends ) 00990 { 00991 if (frontends.isNull()) 00992 return( 0 ); 00993 00994 int nNumFES= frontends.attribute( "count", "0" ).toInt(); 00995 00996 if (nNumFES < 1) 00997 return( 0 ); 00998 00999 01000 os << " <div class=\"content\">\r\n" 01001 << " <h2 class=\"status\">Frontends</h2>\r\n"; 01002 01003 QDomNode node = frontends.firstChild(); 01004 while (!node.isNull()) 01005 { 01006 QDomElement e = node.toElement(); 01007 01008 if (!e.isNull()) 01009 { 01010 QString name = e.attribute( "name" , "" ); 01011 QString url = e.attribute( "url" , "" ); 01012 os << name << " (<a href=\"" << url << "\">Status page</a>)<br />"; 01013 } 01014 01015 node = node.nextSibling(); 01016 } 01017 01018 os << " </div>\r\n\r\n"; 01019 01020 return nNumFES; 01021 } 01022 01024 // 01026 01027 int HttpStatus::PrintBackends( QTextStream &os, QDomElement backends ) 01028 { 01029 if (backends.isNull()) 01030 return( 0 ); 01031 01032 int nNumBES= backends.attribute( "count", "0" ).toInt(); 01033 01034 if (nNumBES < 1) 01035 return( 0 ); 01036 01037 01038 os << " <div class=\"content\">\r\n" 01039 << " <h2 class=\"status\">Other Backends</h2>\r\n"; 01040 01041 QDomNode node = backends.firstChild(); 01042 while (!node.isNull()) 01043 { 01044 QDomElement e = node.toElement(); 01045 01046 if (!e.isNull()) 01047 { 01048 QString type = e.attribute( "type", "" ); 01049 QString name = e.attribute( "name" , "" ); 01050 QString url = e.attribute( "url" , "" ); 01051 os << type << ": " << name << " (<a href=\"" << url << "\">Status page</a>)<br />"; 01052 } 01053 01054 node = node.nextSibling(); 01055 } 01056 01057 os << " </div>\r\n\r\n"; 01058 01059 return nNumBES; 01060 } 01061 01063 // 01065 01066 int HttpStatus::PrintJobQueue( QTextStream &os, QDomElement jobs ) 01067 { 01068 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d"); 01069 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 01070 01071 if (jobs.isNull()) 01072 return( 0 ); 01073 01074 int nNumJobs= jobs.attribute( "count", "0" ).toInt(); 01075 01076 os << " <div class=\"content\">\r\n" 01077 << " <h2 class=\"status\">Job Queue</h2>\r\n"; 01078 01079 if (nNumJobs != 0) 01080 { 01081 QString statusColor; 01082 QString jobColor; 01083 QString timeDateFormat; 01084 01085 timeDateFormat = gCoreContext->GetSetting("DateFormat", "ddd MMMM d") + 01086 ' ' + gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 01087 01088 os << " Jobs currently in Queue or recently ended:\r\n<br />" 01089 << " <div class=\"schedule\">\r\n"; 01090 01091 01092 QDomNode node = jobs.firstChild(); 01093 01094 while (!node.isNull()) 01095 { 01096 QDomElement e = node.toElement(); 01097 01098 if (!e.isNull()) 01099 { 01100 QDomNode progNode = e.namedItem( "Program" ); 01101 01102 if ((e.tagName() == "Job") && !progNode.isNull() ) 01103 { 01104 QDomElement p = progNode.toElement(); 01105 01106 QDomNode recNode = p.namedItem( "Recording" ); 01107 QDomNode chanNode = p.namedItem( "Channel" ); 01108 01109 QDomElement r = recNode.toElement(); 01110 QDomElement c = chanNode.toElement(); 01111 01112 int nType = e.attribute( "type" , "0" ).toInt(); 01113 int nStatus = e.attribute( "status", "0" ).toInt(); 01114 01115 switch( nStatus ) 01116 { 01117 case JOB_ABORTED: 01118 statusColor = " class=\"jobaborted\""; 01119 jobColor = ""; 01120 break; 01121 01122 case JOB_ERRORED: 01123 statusColor = " class=\"joberrored\""; 01124 jobColor = " class=\"joberrored\""; 01125 break; 01126 01127 case JOB_FINISHED: 01128 statusColor = " class=\"jobfinished\""; 01129 jobColor = " class=\"jobfinished\""; 01130 break; 01131 01132 case JOB_RUNNING: 01133 statusColor = " class=\"jobrunning\""; 01134 jobColor = " class=\"jobrunning\""; 01135 break; 01136 01137 default: 01138 statusColor = " class=\"jobqueued\""; 01139 jobColor = " class=\"jobqueued\""; 01140 break; 01141 } 01142 01143 QString sTitle = p.attribute( "title" , "" ); //.replace(QRegExp("\""), """); 01144 QString sSubTitle = p.attribute( "subTitle", "" ); 01145 QDateTime startTs = QDateTime::fromString( p.attribute( "startTime" ,"" ), Qt::ISODate ); 01146 QDateTime endTs = QDateTime::fromString( p.attribute( "endTime" ,"" ), Qt::ISODate ); 01147 QDateTime recStartTs = QDateTime::fromString( r.attribute( "recStartTs","" ), Qt::ISODate ); 01148 QDateTime statusTime = QDateTime::fromString( e.attribute( "statusTime","" ), Qt::ISODate ); 01149 QDateTime schedRunTime = QDateTime::fromString( e.attribute( "schedTime","" ), Qt::ISODate ); 01150 QString sHostname = e.attribute( "hostname", "master" ); 01151 QString sComment = ""; 01152 01153 QDomText text = e.firstChild().toText(); 01154 if (!text.isNull()) 01155 sComment = text.nodeValue(); 01156 01157 os << "<a href=\"javascript:void(0)\">" 01158 << recStartTs.toString("ddd") << " " 01159 << recStartTs.toString(shortdateformat) << " " 01160 << recStartTs.toString(timeformat) << " - " 01161 << sTitle << " - <font" << jobColor << ">" 01162 << JobQueue::JobText( nType ) << "</font><br />" 01163 << "<span><strong>" << sTitle << "</strong> (" 01164 << startTs.toString(timeformat) << "-" 01165 << endTs.toString(timeformat) << ")<br />"; 01166 01167 if (!sSubTitle.isEmpty()) 01168 os << "<em>" << sSubTitle << "</em><br /><br />"; 01169 01170 os << "Job: " << JobQueue::JobText( nType ) << "<br />"; 01171 01172 if (schedRunTime > QDateTime::currentDateTime()) 01173 os << "Scheduled Run Time: " 01174 << schedRunTime.toString(timeDateFormat) 01175 << "<br />"; 01176 01177 os << "Status: <font" << statusColor << ">" 01178 << JobQueue::StatusText( nStatus ) 01179 << "</font><br />" 01180 << "Status Time: " 01181 << statusTime.toString(timeDateFormat) 01182 << "<br />"; 01183 01184 if ( nStatus != JOB_QUEUED) 01185 os << "Host: " << sHostname << "<br />"; 01186 01187 if (!sComment.isEmpty()) 01188 os << "<br />Comments:<br />" << sComment << "<br />"; 01189 01190 os << "</span></a><hr />\r\n"; 01191 } 01192 } 01193 01194 node = node.nextSibling(); 01195 } 01196 os << " </div>\r\n"; 01197 } 01198 else 01199 os << " Job Queue is currently empty.\r\n\r\n"; 01200 01201 os << " </div>\r\n\r\n "; 01202 01203 return( nNumJobs ); 01204 01205 } 01206 01208 // 01210 01211 int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info ) 01212 { 01213 QString shortdateformat = gCoreContext->GetSetting("ShortDateFormat", "M/d"); 01214 QString timeformat = gCoreContext->GetSetting("TimeFormat", "h:mm AP"); 01215 QString sRep; 01216 01217 if (info.isNull()) 01218 return( 0 ); 01219 01220 os << "<div class=\"content\">\r\n" 01221 << " <h2 class=\"status\">Machine Information</h2>\r\n"; 01222 01223 // load average --------------------- 01224 01225 QDomNode node = info.namedItem( "Load" ); 01226 01227 if (!node.isNull()) 01228 { 01229 QDomElement e = node.toElement(); 01230 01231 if (!e.isNull()) 01232 { 01233 double dAvg1 = e.attribute( "avg1" , "0" ).toDouble(); 01234 double dAvg2 = e.attribute( "avg2" , "0" ).toDouble(); 01235 double dAvg3 = e.attribute( "avg3" , "0" ).toDouble(); 01236 01237 os << " <div class=\"loadstatus\">\r\n" 01238 << " This machine's load average:" 01239 << "\r\n <ul>\r\n <li>" 01240 << "1 Minute: " << dAvg1 << "</li>\r\n" 01241 << " <li>5 Minutes: " << dAvg2 << "</li>\r\n" 01242 << " <li>15 Minutes: " << dAvg3 01243 << "</li>\r\n </ul>\r\n" 01244 << " </div>\r\n"; 01245 } 01246 } 01247 01248 // local drive space --------------------- 01249 node = info.namedItem( "Storage" ); 01250 QDomElement storage = node.toElement(); 01251 node = storage.firstChild(); 01252 01253 // Loop once until we find id == "total". This should be first, but a loop 01254 // separate from the per-filesystem details loop ensures total is first, 01255 // regardless. 01256 while (!node.isNull()) 01257 { 01258 QDomElement g = node.toElement(); 01259 01260 if (!g.isNull() && g.tagName() == "Group") 01261 { 01262 QString id = g.attribute("id", "" ); 01263 01264 if (id == "total") 01265 { 01266 int nFree = g.attribute("free" , "0" ).toInt(); 01267 int nTotal = g.attribute("total", "0" ).toInt(); 01268 int nUsed = g.attribute("used" , "0" ).toInt(); 01269 int nLiveTV = g.attribute("livetv" , "0" ).toInt(); 01270 int nDeleted = g.attribute("deleted", "0" ).toInt(); 01271 int nExpirable = g.attribute("expirable" , "0" ).toInt(); 01272 QString nDir = g.attribute("dir" , "" ); 01273 01274 nDir.replace(QRegExp(","), ", "); 01275 01276 os << " Disk Usage Summary:<br />\r\n"; 01277 os << " <ul>\r\n"; 01278 01279 os << " <li>Total Disk Space:\r\n" 01280 << " <ul>\r\n"; 01281 QLocale c(QLocale::C); 01282 01283 os << " <li>Total Space: "; 01284 sRep = c.toString(nTotal) + " MB"; 01285 os << sRep << "</li>\r\n"; 01286 01287 os << " <li>Space Used: "; 01288 sRep = c.toString(nUsed) + " MB"; 01289 os << sRep << "</li>\r\n"; 01290 01291 os << " <li>Space Free: "; 01292 sRep = c.toString(nFree) + " MB"; 01293 os << sRep << "</li>\r\n"; 01294 01295 if ((nLiveTV + nDeleted + nExpirable) > 0) 01296 { 01297 os << " <li>Space Available " 01298 "After Auto-expire: "; 01299 sRep = c.toString(nFree + nLiveTV + 01300 nDeleted + nExpirable) + " MB"; 01301 os << sRep << "\r\n"; 01302 os << " <ul>\r\n"; 01303 os << " <li>Space Used by LiveTV: "; 01304 sRep = c.toString(nLiveTV) + " MB"; 01305 os << sRep << "</li>\r\n"; 01306 os << " <li>Space Used by " 01307 "Deleted Recordings: "; 01308 sRep = c.toString(nDeleted) + " MB"; 01309 os << sRep << "</li>\r\n"; 01310 os << " <li>Space Used by " 01311 "Auto-expirable Recordings: "; 01312 sRep = c.toString(nExpirable) + " MB"; 01313 os << sRep << "</li>\r\n"; 01314 os << " </ul>\r\n"; 01315 os << " </li>\r\n"; 01316 } 01317 01318 os << " </ul>\r\n" 01319 << " </li>\r\n"; 01320 01321 os << " </ul>\r\n"; 01322 break; 01323 } 01324 } 01325 01326 node = node.nextSibling(); 01327 } 01328 01329 // Loop again to handle per-filesystem details. 01330 node = storage.firstChild(); 01331 01332 os << " Disk Usage Details:<br />\r\n"; 01333 os << " <ul>\r\n"; 01334 01335 01336 while (!node.isNull()) 01337 { 01338 QDomElement g = node.toElement(); 01339 01340 if (!g.isNull() && g.tagName() == "Group") 01341 { 01342 int nFree = g.attribute("free" , "0" ).toInt(); 01343 int nTotal = g.attribute("total", "0" ).toInt(); 01344 int nUsed = g.attribute("used" , "0" ).toInt(); 01345 QString nDir = g.attribute("dir" , "" ); 01346 QString id = g.attribute("id" , "" ); 01347 01348 nDir.replace(QRegExp(","), ", "); 01349 01350 01351 if (id != "total") 01352 { 01353 01354 os << " <li>MythTV Drive #" << id << ":" 01355 << "\r\n" 01356 << " <ul>\r\n"; 01357 01358 if (nDir.contains(',')) 01359 os << " <li>Directories: "; 01360 else 01361 os << " <li>Directory: "; 01362 01363 os << nDir << "</li>\r\n"; 01364 01365 QLocale c(QLocale::C); 01366 01367 os << " <li>Total Space: "; 01368 sRep = c.toString(nTotal) + " MB"; 01369 os << sRep << "</li>\r\n"; 01370 01371 os << " <li>Space Used: "; 01372 sRep = c.toString(nUsed) + " MB"; 01373 os << sRep << "</li>\r\n"; 01374 01375 os << " <li>Space Free: "; 01376 sRep = c.toString(nFree) + " MB"; 01377 os << sRep << "</li>\r\n"; 01378 01379 os << " </ul>\r\n" 01380 << " </li>\r\n"; 01381 } 01382 01383 } 01384 01385 node = node.nextSibling(); 01386 } 01387 01388 os << " </ul>\r\n"; 01389 01390 // Guide Info --------------------- 01391 01392 node = info.namedItem( "Guide" ); 01393 01394 if (!node.isNull()) 01395 { 01396 QDomElement e = node.toElement(); 01397 01398 if (!e.isNull()) 01399 { 01400 QString datetimefmt = "yyyy-MM-dd hh:mm"; 01401 int nDays = e.attribute( "guideDays", "0" ).toInt(); 01402 QString sStart = e.attribute( "start" , "" ); 01403 QString sEnd = e.attribute( "end" , "" ); 01404 QString sStatus = e.attribute( "status" , "" ); 01405 QDateTime next = QDateTime::fromString( e.attribute( "next" , "" ), Qt::ISODate); 01406 QString sNext = next.isNull() ? "" : next.toString(datetimefmt); 01407 QString sMsg = ""; 01408 01409 QDateTime thru = QDateTime::fromString( e.attribute( "guideThru", "" ), Qt::ISODate); 01410 01411 QDomText text = e.firstChild().toText(); 01412 01413 if (!text.isNull()) 01414 sMsg = text.nodeValue(); 01415 01416 os << " Last mythfilldatabase run started on " << sStart 01417 << " and "; 01418 01419 if (sEnd < sStart) 01420 os << "is "; 01421 else 01422 os << "ended on " << sEnd << ". "; 01423 01424 os << sStatus << "<br />\r\n"; 01425 01426 if (!next.isNull() && sNext >= sStart) 01427 { 01428 os << " Suggested next mythfilldatabase run: " 01429 << sNext << ".<br />\r\n"; 01430 } 01431 01432 if (!thru.isNull()) 01433 { 01434 os << " There's guide data until " 01435 << QDateTime( thru ).toString(datetimefmt); 01436 01437 if (nDays > 0) 01438 os << " (" << nDays << " day" << (nDays == 1 ? "" : "s" ) << ")"; 01439 01440 os << "."; 01441 01442 if (nDays <= 3) 01443 os << " <strong>WARNING</strong>: is mythfilldatabase running?"; 01444 } 01445 else 01446 os << " There's <strong>no guide data</strong> available! " 01447 << "Have you run mythfilldatabase?"; 01448 01449 if (!sMsg.isEmpty()) 01450 os << "<br />\r\n DataDirect Status: " << sMsg; 01451 } 01452 } 01453 os << "\r\n </div>\r\n"; 01454 01455 return( 1 ); 01456 } 01457 01458 int HttpStatus::PrintMiscellaneousInfo( QTextStream &os, QDomElement info ) 01459 { 01460 if (info.isNull()) 01461 return( 0 ); 01462 01463 // Miscellaneous information 01464 01465 QDomNodeList nodes = info.elementsByTagName("Information"); 01466 uint count = nodes.count(); 01467 if (count > 0) 01468 { 01469 QString display, linebreak; 01470 //QString name, value; 01471 os << "<div class=\"content\">\r\n" 01472 << " <h2 class=\"status\">Miscellaneous</h2>\r\n"; 01473 for (unsigned int i = 0; i < count; i++) 01474 { 01475 QDomNode node = nodes.item(i); 01476 if (node.isNull()) 01477 continue; 01478 01479 QDomElement e = node.toElement(); 01480 if (e.isNull()) 01481 continue; 01482 01483 display = e.attribute("display", ""); 01484 //name = e.attribute("name", ""); 01485 //value = e.attribute("value", ""); 01486 01487 if (display.isEmpty()) 01488 continue; 01489 01490 // Only include HTML line break if display value doesn't already 01491 // contain breaks. 01492 if ((display.contains("<p>", Qt::CaseInsensitive) > 0) || 01493 (display.contains("<br", Qt::CaseInsensitive) > 0)) 01494 { 01495 // matches <BR> or <br / 01496 linebreak = "\r\n"; 01497 } 01498 else 01499 linebreak = "<br />\r\n"; 01500 01501 os << " " << display << linebreak; 01502 } 01503 os << "</div>\r\n"; 01504 } 01505 01506 return( 1 ); 01507 } 01508 01509 void HttpStatus::FillProgramInfo(QDomDocument *pDoc, 01510 QDomNode &node, 01511 ProgramInfo *pInfo, 01512 bool bIncChannel /* = true */, 01513 bool bDetails /* = true */) 01514 { 01515 if ((pDoc == NULL) || (pInfo == NULL)) 01516 return; 01517 01518 // Build Program Element 01519 01520 QDomElement program = pDoc->createElement( "Program" ); 01521 node.appendChild( program ); 01522 01523 program.setAttribute( "startTime" , 01524 pInfo->GetScheduledStartTime(ISODate)); 01525 program.setAttribute( "endTime" , pInfo->GetScheduledEndTime(ISODate)); 01526 program.setAttribute( "title" , pInfo->GetTitle() ); 01527 program.setAttribute( "subTitle" , pInfo->GetSubtitle()); 01528 program.setAttribute( "category" , pInfo->GetCategory()); 01529 program.setAttribute( "catType" , pInfo->GetCategoryType()); 01530 program.setAttribute( "repeat" , pInfo->IsRepeat() ); 01531 01532 if (bDetails) 01533 { 01534 01535 program.setAttribute( "seriesId" , pInfo->GetSeriesID() ); 01536 program.setAttribute( "programId" , pInfo->GetProgramID() ); 01537 program.setAttribute( "stars" , pInfo->GetStars() ); 01538 program.setAttribute( "fileSize" , 01539 QString::number( pInfo->GetFilesize() )); 01540 program.setAttribute( "lastModified", 01541 pInfo->GetLastModifiedTime(ISODate) ); 01542 program.setAttribute( "programFlags", pInfo->GetProgramFlags() ); 01543 program.setAttribute( "hostname" , pInfo->GetHostname() ); 01544 01545 if (pInfo->GetOriginalAirDate().isValid()) 01546 program.setAttribute( "airdate" , pInfo->GetOriginalAirDate() 01547 .toString(Qt::ISODate) ); 01548 01549 QDomText textNode = pDoc->createTextNode( pInfo->GetDescription() ); 01550 program.appendChild( textNode ); 01551 01552 } 01553 01554 if ( bIncChannel ) 01555 { 01556 // Build Channel Child Element 01557 01558 QDomElement channel = pDoc->createElement( "Channel" ); 01559 program.appendChild( channel ); 01560 01561 FillChannelInfo( channel, pInfo, bDetails ); 01562 } 01563 01564 // Build Recording Child Element 01565 01566 if ( pInfo->GetRecordingStatus() != rsUnknown ) 01567 { 01568 QDomElement recording = pDoc->createElement( "Recording" ); 01569 program.appendChild( recording ); 01570 01571 recording.setAttribute( "recStatus" , 01572 pInfo->GetRecordingStatus() ); 01573 recording.setAttribute( "recPriority" , 01574 pInfo->GetRecordingPriority() ); 01575 recording.setAttribute( "recStartTs" , 01576 pInfo->GetRecordingStartTime(ISODate) ); 01577 recording.setAttribute( "recEndTs" , 01578 pInfo->GetRecordingEndTime(ISODate) ); 01579 01580 if (bDetails) 01581 { 01582 recording.setAttribute( "recordId" , 01583 pInfo->GetRecordingRuleID() ); 01584 recording.setAttribute( "recGroup" , 01585 pInfo->GetRecordingGroup() ); 01586 recording.setAttribute( "playGroup" , 01587 pInfo->GetPlaybackGroup() ); 01588 recording.setAttribute( "recType" , 01589 pInfo->GetRecordingRuleType() ); 01590 recording.setAttribute( "dupInType" , 01591 pInfo->GetDuplicateCheckSource() ); 01592 recording.setAttribute( "dupMethod" , 01593 pInfo->GetDuplicateCheckMethod() ); 01594 recording.setAttribute( "encoderId" , 01595 pInfo->GetCardID() ); 01596 const RecordingInfo ri(*pInfo); 01597 recording.setAttribute( "recProfile" , 01598 ri.GetProgramRecordingProfile()); 01599 //recording.setAttribute( "preRollSeconds", m_nPreRollSeconds ); 01600 } 01601 } 01602 } 01603 01605 // 01607 01608 void HttpStatus::FillChannelInfo( QDomElement &channel, 01609 ProgramInfo *pInfo, 01610 bool bDetails /* = true */ ) 01611 { 01612 if (pInfo) 01613 { 01614 /* 01615 QString sHostName = gCoreContext->GetHostName(); 01616 QString sPort = gCoreContext->GetSettingOnHost( "BackendStatusPort", 01617 sHostName); 01618 QString sIconURL = QString( "http://%1:%2/getChannelIcon?ChanId=%3" ) 01619 .arg( sHostName ) 01620 .arg( sPort ) 01621 .arg( pInfo->chanid ); 01622 */ 01623 01624 channel.setAttribute( "chanId" , pInfo->GetChanID() ); 01625 channel.setAttribute( "chanNum" , pInfo->GetChanNum()); 01626 channel.setAttribute( "callSign" , pInfo->GetChannelSchedulingID()); 01627 //channel.setAttribute( "iconURL" , sIconURL ); 01628 channel.setAttribute( "channelName", pInfo->GetChannelName()); 01629 01630 if (bDetails) 01631 { 01632 channel.setAttribute( "chanFilters", 01633 pInfo->GetChannelPlaybackFilters() ); 01634 channel.setAttribute( "sourceId" , pInfo->GetSourceID() ); 01635 channel.setAttribute( "inputId" , pInfo->GetInputID() ); 01636 channel.setAttribute( "commFree" , 01637 (pInfo->IsCommercialFree()) ? 1 : 0 ); 01638 } 01639 } 01640 } 01641 01642 01643 01644 01645 // vim:set shiftwidth=4 tabstop=4 expandtab:
1.7.6.1