Ticket #7195: 7195-v1.patch
File 7195-v1.patch, 20.8 KB (added by , 15 years ago) |
---|
-
libs/libmythtv/previewgenerator.cpp
361 361 else 362 362 { 363 363 VERBOSE(VB_IMPORTANT, LOC_ERR + 364 "Remote Preview failed due to an u known error.");364 "Remote Preview failed due to an unknown error."); 365 365 } 366 366 return false; 367 367 } … … 372 372 QDir remotecachedir(remotecachedirname); 373 373 374 374 if (!remotecachedir.exists()) 375 remotecachedir.mkdir(remotecachedirname); 375 { 376 if (!remotecachedir.mkdir(remotecachedirname)) 377 { 378 VERBOSE(VB_IMPORTANT, LOC_ERR + 379 "Remote Preview failed because we could not create a " 380 "remote cache directory"); 381 return false; 382 } 383 } 376 384 377 385 QString filename = programInfo.pathname.section('/',-1) + ".png"; 378 386 outFileName = QString("%1/%2").arg(remotecachedirname).arg(filename); -
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); -
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" ); -
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); … … 3498 3498 return false; 3499 3499 } 3500 3500 3501 QDateTime PlaybackBox::getPreviewLastModified(ProgramInfo *pginfo)3502 {3503 QDateTime datetime;3504 QString filename = pginfo->pathname + ".png";3505 3506 if (filename.left(7) != "myth://")3507 {3508 QFileInfo retfinfo(filename);3509 if (retfinfo.exists())3510 datetime = retfinfo.lastModified();3511 }3512 else3513 {3514 datetime = RemoteGetPreviewLastModified(pginfo);3515 }3516 3517 return datetime;3518 }3519 3520 3501 void PlaybackBox::IncPreviewGeneratorPriority(const QString &xfn) 3521 3502 { 3522 3503 QString fn = xfn.mid(qMax(xfn.lastIndexOf('/') + 1,0)); … … 3678 3659 UpdateProgramInfo(item, item == sel_item, true); 3679 3660 } 3680 3661 3681 bool check_lastmod(LastCheckedMap &elapsedtime, const QString &filename)3662 QString PlaybackBox::GetPreviewImage(ProgramInfo *pginfo) 3682 3663 { 3683 LastCheckedMap::iterator it = elapsedtime.find(filename); 3664 if (!pginfo || pginfo->availableStatus == asPendingDelete) 3665 return QString(); 3684 3666 3685 if (it != elapsedtime.end() && ((*it).elapsed() < 300)) 3686 return false; 3667 QString filename = pginfo->GetPlaybackURL() + ".png"; 3687 3668 3688 elapsedtime[filename].restart(); 3689 return true; 3690 } 3669 // If someone is asking for this preview it must be on screen 3670 // and hence higher priority than anything else we may have 3671 // queued up recently.... 3672 IncPreviewGeneratorPriority(filename); 3691 3673 3692 QString PlaybackBox::getPreviewImage(ProgramInfo *pginfo) 3693 { 3694 QString filename; 3674 QDateTime previewLastModified; 3675 QString ret_file = filename; 3676 bool streaming = filename.left(1) != "/"; 3677 bool locally_accessible = false; 3678 bool bookmark_updated = false; 3695 3679 3696 if (!pginfo || pginfo->availableStatus == asPendingDelete) 3697 return filename; 3680 if (m_previewFromBookmark || streaming) 3681 { 3682 if (streaming) 3683 { 3684 ret_file = QString("%1/remotecache/%2") 3685 .arg(GetConfDir()).arg(filename.section('/', -1)); 3698 3686 3699 filename = pginfo->GetPlaybackURL() + ".png"; 3687 QFileInfo finfo(ret_file); 3688 if (finfo.exists() && 3689 (!m_previewFromBookmark || 3690 (finfo.lastModified() >= pginfo->lastmodified))) 3691 { 3692 // This is just an optimization to avoid 3693 // hitting the backend if our cached copy 3694 // is newer than the bookmark, or if we have 3695 // a preview and do not update it when the 3696 // bookmark changes. 3697 previewLastModified = finfo.lastModified(); 3698 } 3699 else 3700 { 3701 previewLastModified = 3702 RemoteGetPreviewIfModified(*pginfo, ret_file); 3703 } 3704 } 3705 else 3706 { 3707 QFileInfo fi(filename); 3708 if ((locally_accessible = fi.exists())) 3709 previewLastModified = fi.lastModified(); 3710 } 3700 3711 3701 IncPreviewGeneratorPriority(filename); 3712 bookmark_updated = 3713 m_previewFromBookmark && 3714 ((!previewLastModified.isValid() || 3715 (previewLastModified < pginfo->lastmodified && 3716 previewLastModified >= pginfo->recendts))); 3717 } 3718 else 3719 { 3720 locally_accessible = QFileInfo(filename).exists(); 3721 } 3702 3722 3703 bool check_date = check_lastmod(m_previewLastModifyCheck, filename); 3723 bool up_to_date_preview_exists = 3724 locally_accessible || previewLastModified.isValid(); 3704 3725 3705 QDateTime previewLastModified; 3726 if (0) 3727 { 3728 VERBOSE(VB_IMPORTANT, 3729 QString("File '%1' \n\t\t\tCache '%2'") 3730 .arg(filename).arg(ret_file) + 3731 QString("\n\t\t\tPreview Exists: %1, " 3732 "Bookmark Updated: %2, " 3733 "Need Preview: %3") 3734 .arg(up_to_date_preview_exists).arg(bookmark_updated) 3735 .arg((bookmark_updated || !up_to_date_preview_exists))); 3736 } 3706 3737 3707 if (check_date) 3708 previewLastModified = getPreviewLastModified(pginfo); 3709 3710 if (m_previewFromBookmark && check_date && 3711 (!previewLastModified.isValid() || 3712 (previewLastModified < pginfo->lastmodified && 3713 previewLastModified >= pginfo->recendts)) && 3714 !pginfo->IsEditing() && 3715 !JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo) && 3738 if ((bookmark_updated || !up_to_date_preview_exists) && 3716 3739 !IsGeneratingPreview(filename)) 3717 3740 { 3718 3741 uint attempts = IncPreviewGeneratorAttempts(filename); … … 3729 3752 "%2 times, giving up.") 3730 3753 .arg(filename).arg(PreviewGenState::maxAttempts)); 3731 3754 } 3732 3733 if (attempts >= PreviewGenState::maxAttempts)3734 return filename;3735 3755 } 3736 3756 3737 3757 UpdatePreviewGeneratorThreads(); 3738 3758 3739 // Image is local 3740 if (QFileInfo(filename).exists()) 3741 return filename; 3759 QString ret = (locally_accessible) ? 3760 filename : (previewLastModified.isValid()) ? 3761 ret_file : (QFileInfo(ret_file).exists()) ? 3762 ret_file : QString(); 3742 3763 3743 // If this is a remote frontend then check the remote file cache 3744 QString cachefile = QString("%1/remotecache/%3").arg(GetConfDir()) 3745 .arg(filename.section('/', -1)); 3746 QFileInfo cachefileinfo(cachefile); 3747 if (!cachefileinfo.exists() || 3748 previewLastModified.addSecs(-60) > cachefileinfo.lastModified()) 3749 { 3750 if (!IsGeneratingPreview(filename)) 3751 { 3752 uint attempts = IncPreviewGeneratorAttempts(filename); 3753 if (attempts < PreviewGenState::maxAttempts) 3754 { 3755 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, 3756 (PreviewGenerator::Mode)m_previewGeneratorMode)); 3757 } 3758 else if (attempts == PreviewGenState::maxAttempts) 3759 { 3760 VERBOSE(VB_IMPORTANT, LOC_ERR + 3761 QString("Attempted to generate m_preview for '%1' " 3762 "%2 times, giving up.") 3763 .arg(filename).arg(PreviewGenState::maxAttempts)); 3764 } 3765 } 3766 } 3764 //VERBOSE(VB_IMPORTANT, QString("Returning: '%1'").arg(ret)); 3767 3765 3768 if (cachefileinfo.exists()) 3769 return cachefile; 3770 3771 return ""; 3766 return ret; 3772 3767 } 3773 3768 3774 3769 void PlaybackBox::showIconHelp(void) -
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; -
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 -
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); -
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: */ -
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();