Ticket #7195: 7195-v2.patch
File 7195-v2.patch, 22.3 KB (added by , 16 years ago) |
---|
-
mythplugins/mythweb/classes/MythBackend.php
15 15 16 16 // MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h 17 17 // and should be the current MythTV protocol version. 18 static $protocol_version = 4 8;18 static $protocol_version = 49; 19 19 20 20 // The character string used by the backend to separate records 21 21 static $backend_separator = '[]:[]'; -
mythtv/libs/libmyth/remoteutil.h
52 52 MPUBLIC vector<uint> RemoteRequestFreeRecorderList(void); 53 53 MPUBLIC void RemoteGeneratePreviewPixmap(const ProgramInfo *pginfo); 54 54 MPUBLIC QDateTime RemoteGetPreviewLastModified(const ProgramInfo *pginfo); 55 MPUBLIC QDateTime RemoteGetPreviewIfModified( 56 const ProgramInfo &pginfo, const QString &cachefile); 55 57 MPUBLIC void RemoteFillProginfo(ProgramInfo *pginfo, 56 58 const QString &playbackhostname); 57 59 MPUBLIC QStringList RemoteRecordings(void); -
mythtv/libs/libmyth/remoteutil.cpp
1 1 #include <unistd.h> 2 2 3 #include <QFileInfo> 3 4 #include <QFile> 5 #include <QDir> 4 6 5 7 #include "remoteutil.h" 6 8 #include "programinfo.h" … … 287 289 return retdatetime; 288 290 } 289 291 292 /// Download preview & get timestamp if newer than cachefile's 293 /// last modified time, otherwise just get the timestamp 294 QDateTime RemoteGetPreviewIfModified( 295 const ProgramInfo &pginfo, const QString &cachefile) 296 { 297 QString loc_err("RemoteGetPreviewIfModified, Error: "); 298 299 QDateTime cacheLastModified; 300 QFileInfo cachefileinfo(cachefile); 301 if (cachefileinfo.exists()) 302 cacheLastModified = cachefileinfo.lastModified(); 303 304 QStringList strlist("QUERY_PIXMAP_GET_IF_MODIFIED"); 305 strlist << ((cacheLastModified.isValid()) ? // unix secs, UTC 306 QString::number(cacheLastModified.toTime_t()) : QString("-1")); 307 strlist << QString::number(200 * 1024); // max size of preview file 308 pginfo.ToStringList(strlist); 309 310 if (!gContext->SendReceiveStringList(strlist) || 311 strlist.empty() || strlist[0] == "ERROR") 312 { 313 VERBOSE(VB_IMPORTANT, loc_err + 314 QString("Remote error") + 315 ((strlist.size() >= 2) ? 316 (QString(":\n\t\t\t") + strlist[1]) : QString(""))); 317 318 return QDateTime(); 319 } 320 321 if (strlist[0] == "WARNING") 322 { 323 VERBOSE(VB_NETWORK, QString("RemoteGetPreviewIfModified, Warning: ") + 324 QString("Remote warning") + 325 ((strlist.size() >= 2) ? 326 (QString(":\n\t\t\t") + strlist[1]) : QString(""))); 327 328 return QDateTime(); 329 } 330 331 QDateTime retdatetime; 332 qlonglong timet = strlist[0].toLongLong(); 333 if (timet >= 0) 334 retdatetime.setTime_t(timet); 335 336 if (strlist.size() < 4) 337 { 338 return retdatetime; 339 } 340 341 size_t length = strlist[1].toLongLong(); 342 quint16 checksum16 = strlist[2].toUInt(); 343 QByteArray data = QByteArray::fromBase64(strlist[3].toAscii()); 344 if ((size_t) data.size() < length) 345 { // (note data.size() may be up to 3 bytes longer after decoding 346 VERBOSE(VB_IMPORTANT, loc_err + 347 QString("Preview size check failed %1 < %2") 348 .arg(data.size()).arg(length)); 349 return QDateTime(); 350 } 351 352 if (checksum16 != qChecksum(data.constData(), data.size())) 353 { 354 VERBOSE(VB_IMPORTANT, loc_err + "Preview checksum failed"); 355 return QDateTime(); 356 } 357 358 QString pdir(cachefile.section("/", 0, -2)); 359 QDir cfd(pdir); 360 if (!cfd.exists() && !cfd.mkdir(pdir)) 361 { 362 VERBOSE(VB_IMPORTANT, loc_err + 363 QString("Unable to create remote cache directory '%1'") 364 .arg(pdir)); 365 366 return QDateTime(); 367 } 368 369 QFile file(cachefile); 370 if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) 371 { 372 VERBOSE(VB_IMPORTANT, loc_err + 373 QString("Unable to open cached " 374 "preview file for writing '%1'") 375 .arg(cachefile)); 376 377 return QDateTime(); 378 } 379 380 off_t offset = 0; 381 size_t remaining = length; 382 uint failure_cnt = 0; 383 while ((remaining > 0) && (failure_cnt < 5)) 384 { 385 ssize_t written = file.write(data.data() + offset, remaining); 386 if (written < 0) 387 { 388 failure_cnt++; 389 usleep(50000); 390 continue; 391 } 392 393 failure_cnt = 0; 394 offset += written; 395 remaining -= written; 396 } 397 398 if (remaining) 399 { 400 VERBOSE(VB_IMPORTANT, loc_err + 401 QString("Failed to write cached preview file '%1'") 402 .arg(cachefile)); 403 404 file.resize(0); // in case unlink fails.. 405 file.remove(); // closes fd 406 return QDateTime(); 407 } 408 409 file.close(); 410 411 return retdatetime; 412 } 413 290 414 void RemoteFillProginfo(ProgramInfo *pginfo, const QString &playbackhostname) 291 415 { 292 416 QStringList strlist( "FILL_PROGRAM_INFO" ); -
mythtv/libs/libmythdb/mythversion.h
27 27 * mythtv/bindings/python/MythTV/MythTV.py (version number) 28 28 * mythtv/bindings/python/MythTV/MythTV.py (layout) 29 29 */ 30 #define MYTH_PROTO_VERSION "4 8"30 #define MYTH_PROTO_VERSION "49" 31 31 32 32 #endif 33 33 -
mythtv/programs/mythfrontend/playbackbox.cpp
602 602 QString oldimgfile = item->GetImage("preview"); 603 603 QString imagefile; 604 604 if (oldimgfile.isEmpty() || force_preview_reload) 605 imagefile = getPreviewImage(pginfo);605 imagefile = GetPreviewImage(pginfo); 606 606 607 607 if (!imagefile.isEmpty()) 608 608 item->SetImage(imagefile, "preview", force_preview_reload); … … 2708 2708 QDateTime recendts = program->recendts; 2709 2709 2710 2710 QString timedate = QString("%1, %2 - %3") 2711 2712 2713 2711 .arg(recstartts.date().toString(m_formatLongDate)) 2712 .arg(recstartts.time().toString(m_formatTime)) 2713 .arg(recendts.time().toString(m_formatTime)); 2714 2714 2715 2715 QString title = program->title; 2716 2716 … … 3512 3512 return false; 3513 3513 } 3514 3514 3515 QDateTime PlaybackBox::getPreviewLastModified(ProgramInfo *pginfo)3516 {3517 QDateTime datetime;3518 QString filename = pginfo->pathname + ".png";3519 3520 if (filename.left(7) != "myth://")3521 {3522 QFileInfo retfinfo(filename);3523 if (retfinfo.exists())3524 datetime = retfinfo.lastModified();3525 }3526 else3527 {3528 datetime = RemoteGetPreviewLastModified(pginfo);3529 }3530 3531 return datetime;3532 }3533 3534 3515 void PlaybackBox::IncPreviewGeneratorPriority(const QString &xfn) 3535 3516 { 3536 3517 QString fn = xfn.mid(qMax(xfn.lastIndexOf('/') + 1,0)); … … 3692 3673 UpdateProgramInfo(item, item == sel_item, true); 3693 3674 } 3694 3675 3695 bool check_lastmod(LastCheckedMap &elapsedtime, const QString &filename)3676 QString PlaybackBox::GetPreviewImage(ProgramInfo *pginfo) 3696 3677 { 3697 LastCheckedMap::iterator it = elapsedtime.find(filename); 3678 if (!pginfo || pginfo->availableStatus == asPendingDelete) 3679 return QString(); 3698 3680 3699 if (it != elapsedtime.end() && ((*it).elapsed() < 300)) 3700 return false; 3681 QString filename = pginfo->GetPlaybackURL() + ".png"; 3701 3682 3702 elapsedtime[filename].restart(); 3703 return true; 3704 } 3683 // If someone is asking for this preview it must be on screen 3684 // and hence higher priority than anything else we may have 3685 // queued up recently.... 3686 IncPreviewGeneratorPriority(filename); 3705 3687 3706 QString PlaybackBox::getPreviewImage(ProgramInfo *pginfo) 3707 { 3708 QString filename; 3688 QDateTime previewLastModified; 3689 QString ret_file = filename; 3690 bool streaming = filename.left(1) != "/"; 3691 bool locally_accessible = false; 3692 bool bookmark_updated = false; 3709 3693 3710 if (!pginfo || pginfo->availableStatus == asPendingDelete) 3711 return filename; 3694 if (m_previewFromBookmark || streaming) 3695 { 3696 if (streaming) 3697 { 3698 ret_file = QString("%1/remotecache/%2") 3699 .arg(GetConfDir()).arg(filename.section('/', -1)); 3712 3700 3713 filename = pginfo->GetPlaybackURL() + ".png"; 3701 QFileInfo finfo(ret_file); 3702 if (finfo.exists() && 3703 (!m_previewFromBookmark || 3704 (finfo.lastModified() >= pginfo->lastmodified))) 3705 { 3706 // This is just an optimization to avoid 3707 // hitting the backend if our cached copy 3708 // is newer than the bookmark, or if we have 3709 // a preview and do not update it when the 3710 // bookmark changes. 3711 previewLastModified = finfo.lastModified(); 3712 } 3713 else 3714 { 3715 previewLastModified = 3716 RemoteGetPreviewIfModified(*pginfo, ret_file); 3717 } 3718 } 3719 else 3720 { 3721 QFileInfo fi(filename); 3722 if ((locally_accessible = fi.exists())) 3723 previewLastModified = fi.lastModified(); 3724 } 3714 3725 3715 IncPreviewGeneratorPriority(filename); 3726 bookmark_updated = 3727 m_previewFromBookmark && 3728 ((!previewLastModified.isValid() || 3729 (previewLastModified < pginfo->lastmodified && 3730 previewLastModified >= pginfo->recendts))); 3731 } 3732 else 3733 { 3734 locally_accessible = QFileInfo(filename).exists(); 3735 } 3716 3736 3717 bool check_date = check_lastmod(m_previewLastModifyCheck, filename); 3737 bool up_to_date_preview_exists = 3738 locally_accessible || previewLastModified.isValid(); 3718 3739 3719 QDateTime previewLastModified; 3740 if (0) 3741 { 3742 VERBOSE(VB_IMPORTANT, 3743 QString("File '%1' \n\t\t\tCache '%2'") 3744 .arg(filename).arg(ret_file) + 3745 QString("\n\t\t\tPreview Exists: %1, " 3746 "Bookmark Updated: %2, " 3747 "Need Preview: %3") 3748 .arg(up_to_date_preview_exists).arg(bookmark_updated) 3749 .arg((bookmark_updated || !up_to_date_preview_exists))); 3750 } 3720 3751 3721 if (check_date) 3722 previewLastModified = getPreviewLastModified(pginfo); 3723 3724 if (m_previewFromBookmark && check_date && 3725 (!previewLastModified.isValid() || 3726 (previewLastModified < pginfo->lastmodified && 3727 previewLastModified >= pginfo->recendts)) && 3728 !pginfo->IsEditing() && 3729 !JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo) && 3752 if ((bookmark_updated || !up_to_date_preview_exists) && 3730 3753 !IsGeneratingPreview(filename)) 3731 3754 { 3732 3755 uint attempts = IncPreviewGeneratorAttempts(filename); … … 3743 3766 "%2 times, giving up.") 3744 3767 .arg(filename).arg(PreviewGenState::maxAttempts)); 3745 3768 } 3746 3747 if (attempts >= PreviewGenState::maxAttempts)3748 return filename;3749 3769 } 3750 3770 3751 3771 UpdatePreviewGeneratorThreads(); 3752 3772 3753 // Image is local 3754 if (QFileInfo(filename).exists()) 3755 return filename; 3773 QString ret = (locally_accessible) ? 3774 filename : (previewLastModified.isValid()) ? 3775 ret_file : (QFileInfo(ret_file).exists()) ? 3776 ret_file : QString(); 3756 3777 3757 // If this is a remote frontend then check the remote file cache 3758 QString cachefile = QString("%1/remotecache/%3").arg(GetConfDir()) 3759 .arg(filename.section('/', -1)); 3760 QFileInfo cachefileinfo(cachefile); 3761 if (!cachefileinfo.exists() || 3762 previewLastModified.addSecs(-60) > cachefileinfo.lastModified()) 3763 { 3764 if (!IsGeneratingPreview(filename)) 3765 { 3766 uint attempts = IncPreviewGeneratorAttempts(filename); 3767 if (attempts < PreviewGenState::maxAttempts) 3768 { 3769 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, 3770 (PreviewGenerator::Mode)m_previewGeneratorMode)); 3771 } 3772 else if (attempts == PreviewGenState::maxAttempts) 3773 { 3774 VERBOSE(VB_IMPORTANT, LOC_ERR + 3775 QString("Attempted to generate m_preview for '%1' " 3776 "%2 times, giving up.") 3777 .arg(filename).arg(PreviewGenState::maxAttempts)); 3778 } 3779 } 3780 } 3778 //VERBOSE(VB_IMPORTANT, QString("Returning: '%1'").arg(ret)); 3781 3779 3782 if (cachefileinfo.exists()) 3783 return cachefile; 3784 3785 return ""; 3780 return ret; 3786 3781 } 3787 3782 3788 3783 void PlaybackBox::showIconHelp(void) -
mythtv/programs/mythfrontend/playbackbox.h
56 56 typedef QMap<QString,ProgramList> ProgramMap; 57 57 typedef QMap<QString,QString> Str2StrMap; 58 58 typedef QMap<QString,PreviewGenState> PreviewMap; 59 typedef QMap<QString,MythTimer> LastCheckedMap;60 59 61 60 class PlaybackBox : public ScheduleCommon 62 61 { … … 272 271 void UpdateProgressBar(void); 273 272 274 273 QString cutDown(const QString &, QFont *, int); 275 QDateTime getPreviewLastModified(ProgramInfo *); 276 QString getPreviewImage(ProgramInfo *); 274 QString GetPreviewImage(ProgramInfo *); 277 275 278 276 bool play(ProgramInfo *rec, bool inPlaylist = false); 279 277 void stop(ProgramInfo *); … … 431 429 // Preview Pixmap Variables /////////////////////////////////////////////// 432 430 bool m_previewFromBookmark; 433 431 uint m_previewGeneratorMode; 434 LastCheckedMap m_previewLastModifyCheck;435 432 QMap<QString,QDateTime> m_previewFileTS; 436 433 bool m_previewSuspend; 437 434 mutable QMutex m_previewGeneratorLock; -
mythtv/programs/mythbackend/playbacksock.h
59 59 const QString &outputFile, 60 60 const QSize &outputSize); 61 61 QDateTime PixmapLastModified(const ProgramInfo *pginfo); 62 62 63 bool CheckFile(ProgramInfo *pginfo); 63 64 64 65 bool IsBusy(int capturecardnum, … … 78 79 const vector<uint> &excluded_cardids); 79 80 void CancelNextRecording(int capturecardnum, bool cancel); 80 81 82 QStringList ForwardRequest(const QStringList&); 83 81 84 private: 82 85 bool SendReceiveStringList(QStringList &strlist, uint min_reply_length = 0); 83 86 -
mythtv/programs/mythbackend/mainserver.h
128 128 void HandleSetVerbose(QStringList &slist, PlaybackSock *pbs); 129 129 void HandleGenPreviewPixmap(QStringList &slist, PlaybackSock *pbs); 130 130 void HandlePixmapLastModified(QStringList &slist, PlaybackSock *pbs); 131 void HandlePixmapGetIfModified(const QStringList &slist, PlaybackSock *pbs); 131 132 void HandleIsRecording(QStringList &slist, PlaybackSock *pbs); 132 133 void HandleCheckRecordingActive(QStringList &slist, PlaybackSock *pbs); 133 134 void HandleFillProgramInfo(QStringList &slist, PlaybackSock *pbs); -
mythtv/programs/mythbackend/playbacksock.cpp
481 481 SendReceiveStringList(strlist); 482 482 } 483 483 484 QStringList PlaybackSock::ForwardRequest(const QStringList &slist) 485 { 486 QStringList strlist = slist; 487 488 if (SendReceiveStringList(strlist)) 489 return strlist; 490 491 return QStringList(); 492 } 493 484 494 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
mythtv/programs/mythbackend/mainserver.cpp
532 532 { 533 533 HandlePixmapLastModified(listline, pbs); 534 534 } 535 else if (command == "QUERY_PIXMAP_GET_IF_MODIFIED") 536 { 537 HandlePixmapGetIfModified(listline, pbs); 538 } 535 539 else if (command == "QUERY_ISRECORDING") 536 540 { 537 541 HandleIsRecording(listline, pbs); … … 4614 4618 strlist = QStringList( "BAD" ); 4615 4619 4616 4620 SendResponse(pbssock, strlist); 4617 delete pginfo;4618 4621 } 4619 4622 4623 void MainServer::HandlePixmapGetIfModified( 4624 const QStringList &slist, PlaybackSock *pbs) 4625 { 4626 QStringList strlist; 4627 4628 MythSocket *pbssock = pbs->getSocket(); 4629 if (slist.size() < (3 + NUMPROGRAMLINES)) 4630 { 4631 strlist = QStringList("ERROR"); 4632 strlist += "1: Parameter list too short"; 4633 SendResponse(pbssock, strlist); 4634 return; 4635 } 4636 4637 QDateTime cachemodified; 4638 if (slist[1].toInt() != -1) 4639 cachemodified.setTime_t(slist[1].toInt()); 4640 4641 int max_file_size = slist[2].toInt(); 4642 4643 ProgramInfo pginfo; 4644 4645 if (!pginfo.FromStringList(slist, 3)) 4646 { 4647 strlist = QStringList("ERROR"); 4648 strlist += "2: Invalid ProgramInfo"; 4649 SendResponse(pbssock, strlist); 4650 return; 4651 } 4652 4653 pginfo.pathname = GetPlaybackURL(&pginfo) + ".png"; 4654 if (pginfo.pathname.left(1) == "/") 4655 { 4656 QFileInfo finfo(pginfo.pathname); 4657 if (finfo.exists()) 4658 { 4659 size_t fsize = finfo.size(); 4660 QDateTime lastmodified = finfo.lastModified(); 4661 bool out_of_date = !cachemodified.isValid() || 4662 (lastmodified > cachemodified); 4663 4664 if (out_of_date && (fsize > 0) && ((ssize_t)fsize < max_file_size)) 4665 { 4666 QByteArray data; 4667 QFile file(pginfo.pathname); 4668 bool open_ok = file.open(QIODevice::ReadOnly); 4669 if (open_ok) 4670 data = file.readAll(); 4671 4672 if (data.size()) 4673 { 4674 VERBOSE(VB_FILE, QString("Read preview file '%1'") 4675 .arg(pginfo.pathname)); 4676 strlist += QString::number(lastmodified.toTime_t()); 4677 strlist += QString::number(data.size()); 4678 strlist += QString::number( 4679 qChecksum(data.constData(), data.size())); 4680 strlist += QString(data.toBase64()); 4681 } 4682 else 4683 { 4684 VERBOSE(VB_IMPORTANT, 4685 QString("Failed to read preview file '%1'") 4686 .arg(pginfo.pathname)); 4687 4688 strlist = QStringList("ERROR"); 4689 strlist += 4690 QString("3: Failed to read preview file '%1'%2") 4691 .arg(pginfo.pathname) 4692 .arg((open_ok) ? "" : " open failed"); 4693 } 4694 } 4695 else if (out_of_date && (max_file_size > 0)) 4696 { 4697 if (fsize >= (size_t) max_file_size) 4698 { 4699 strlist = QStringList("WARNING"); 4700 strlist += QString("1: Preview file too big %1 > %2") 4701 .arg(fsize).arg(max_file_size); 4702 } 4703 else 4704 { 4705 strlist = QStringList("ERROR"); 4706 strlist += "4: Preview file is invalid"; 4707 } 4708 } 4709 else 4710 { 4711 strlist += QString::number(lastmodified.toTime_t()); 4712 } 4713 4714 SendResponse(pbssock, strlist); 4715 return; 4716 } 4717 } 4718 4719 // handle remote ... 4720 if (ismaster && pginfo.hostname != gContext->GetHostName()) 4721 { 4722 PlaybackSock *slave = getSlaveByHostname(pginfo.hostname); 4723 if (!slave) 4724 { 4725 strlist = QStringList("ERROR"); 4726 strlist += 4727 "5: Could not locate mythbackend that made this recording"; 4728 SendResponse(pbssock, strlist); 4729 return; 4730 } 4731 4732 strlist = slave->ForwardRequest(slist); 4733 4734 slave->DownRef(); slave = NULL; 4735 4736 if (!strlist.empty()) 4737 { 4738 SendResponse(pbssock, strlist); 4739 return; 4740 } 4741 } 4742 4743 strlist = QStringList("WARNING"); 4744 strlist += "2: Could not locate requested file"; 4745 SendResponse(pbssock, strlist); 4746 } 4747 4620 4748 void MainServer::HandleBackendRefresh(MythSocket *socket) 4621 4749 { 4622 4750 gContext->RefreshBackendConfig(); -
mythtv/bindings/python/MythTV/MythTV.py
46 46 } 47 47 48 48 BACKEND_SEP = '[]:[]' 49 PROTO_VERSION = 4 849 PROTO_VERSION = 49 50 50 PROGRAM_FIELDS = 47 51 51 52 52 class MythTV: -
mythtv/bindings/perl/MythTV.pm
101 101 102 102 # MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h 103 103 # and should be the current MythTV protocol version. 104 our $PROTO_VERSION = 4 8;104 our $PROTO_VERSION = 49; 105 105 106 106 # NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is 107 107 # the number of items in a ProgramInfo QStringList group used by