Ticket #7195: 7195-v2.patch

File 7195-v2.patch, 22.3 KB (added by danielk, 16 years ago)

updated patch

  • mythplugins/mythweb/classes/MythBackend.php

     
    1515
    1616// MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
    1717// and should be the current MythTV protocol version.
    18     static $protocol_version        = 48;
     18    static $protocol_version        = 49;
    1919
    2020// The character string used by the backend to separate records
    2121    static $backend_separator       = '[]:[]';
  • mythtv/libs/libmyth/remoteutil.h

     
    5252MPUBLIC vector<uint> RemoteRequestFreeRecorderList(void);
    5353MPUBLIC void RemoteGeneratePreviewPixmap(const ProgramInfo *pginfo);
    5454MPUBLIC QDateTime RemoteGetPreviewLastModified(const ProgramInfo *pginfo);
     55MPUBLIC QDateTime RemoteGetPreviewIfModified(
     56    const ProgramInfo &pginfo, const QString &cachefile);
    5557MPUBLIC void RemoteFillProginfo(ProgramInfo *pginfo,
    5658                                const QString &playbackhostname);
    5759MPUBLIC QStringList RemoteRecordings(void);
  • mythtv/libs/libmyth/remoteutil.cpp

     
    11#include <unistd.h>
    22
     3#include <QFileInfo>
    34#include <QFile>
     5#include <QDir>
    46
    57#include "remoteutil.h"
    68#include "programinfo.h"
     
    287289    return retdatetime;
    288290}
    289291
     292/// Download preview & get timestamp if newer than cachefile's
     293/// last modified time, otherwise just get the timestamp
     294QDateTime 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
    290414void RemoteFillProginfo(ProgramInfo *pginfo, const QString &playbackhostname)
    291415{
    292416    QStringList strlist( "FILL_PROGRAM_INFO" );
  • mythtv/libs/libmythdb/mythversion.h

     
    2727 *       mythtv/bindings/python/MythTV/MythTV.py (version number)
    2828 *       mythtv/bindings/python/MythTV/MythTV.py (layout)
    2929 */
    30 #define MYTH_PROTO_VERSION "48"
     30#define MYTH_PROTO_VERSION "49"
    3131
    3232#endif
    3333
  • mythtv/programs/mythfrontend/playbackbox.cpp

     
    602602    QString oldimgfile = item->GetImage("preview");
    603603    QString imagefile;
    604604    if (oldimgfile.isEmpty() || force_preview_reload)
    605         imagefile = getPreviewImage(pginfo);
     605        imagefile = GetPreviewImage(pginfo);
    606606
    607607    if (!imagefile.isEmpty())
    608608        item->SetImage(imagefile, "preview", force_preview_reload);
     
    27082708    QDateTime recendts = program->recendts;
    27092709
    27102710    QString timedate = QString("%1, %2 - %3")
    2711                         .arg(recstartts.date().toString(m_formatLongDate))
    2712                         .arg(recstartts.time().toString(m_formatTime))
    2713                         .arg(recendts.time().toString(m_formatTime));
     2711        .arg(recstartts.date().toString(m_formatLongDate))
     2712        .arg(recstartts.time().toString(m_formatTime))
     2713        .arg(recendts.time().toString(m_formatTime));
    27142714
    27152715    QString title = program->title;
    27162716
     
    35123512    return false;
    35133513}
    35143514
    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     else
    3527     {
    3528         datetime = RemoteGetPreviewLastModified(pginfo);
    3529     }
    3530 
    3531     return datetime;
    3532 }
    3533 
    35343515void PlaybackBox::IncPreviewGeneratorPriority(const QString &xfn)
    35353516{
    35363517    QString fn = xfn.mid(qMax(xfn.lastIndexOf('/') + 1,0));
     
    36923673    UpdateProgramInfo(item, item == sel_item, true);
    36933674}
    36943675
    3695 bool check_lastmod(LastCheckedMap &elapsedtime, const QString &filename)
     3676QString PlaybackBox::GetPreviewImage(ProgramInfo *pginfo)
    36963677{
    3697     LastCheckedMap::iterator it = elapsedtime.find(filename);
     3678    if (!pginfo || pginfo->availableStatus == asPendingDelete)
     3679        return QString();
    36983680
    3699     if (it != elapsedtime.end() && ((*it).elapsed() < 300))
    3700         return false;
     3681    QString filename = pginfo->GetPlaybackURL() + ".png";
    37013682
    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);
    37053687
    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;
    37093693
    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));
    37123700
    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        }
    37143725
    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    }
    37163736
    3717     bool check_date = check_lastmod(m_previewLastModifyCheck, filename);
     3737    bool up_to_date_preview_exists =
     3738        locally_accessible || previewLastModified.isValid();
    37183739
    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    }
    37203751
    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) &&
    37303753        !IsGeneratingPreview(filename))
    37313754    {
    37323755        uint attempts = IncPreviewGeneratorAttempts(filename);
     
    37433766                            "%2 times, giving up.")
    37443767                    .arg(filename).arg(PreviewGenState::maxAttempts));
    37453768        }
    3746 
    3747         if (attempts >= PreviewGenState::maxAttempts)
    3748             return filename;
    37493769    }
    37503770
    37513771    UpdatePreviewGeneratorThreads();
    37523772
    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();
    37563777
    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));
    37813779
    3782     if (cachefileinfo.exists())
    3783         return cachefile;
    3784 
    3785     return "";
     3780    return ret;
    37863781}
    37873782
    37883783void PlaybackBox::showIconHelp(void)
  • mythtv/programs/mythfrontend/playbackbox.h

     
    5656typedef QMap<QString,ProgramList>       ProgramMap;
    5757typedef QMap<QString,QString>           Str2StrMap;
    5858typedef QMap<QString,PreviewGenState>   PreviewMap;
    59 typedef QMap<QString,MythTimer>         LastCheckedMap;
    6059
    6160class PlaybackBox : public ScheduleCommon
    6261{
     
    272271    void UpdateProgressBar(void);
    273272
    274273    QString cutDown(const QString &, QFont *, int);
    275     QDateTime getPreviewLastModified(ProgramInfo *);
    276     QString getPreviewImage(ProgramInfo *);
     274    QString GetPreviewImage(ProgramInfo *);
    277275
    278276    bool play(ProgramInfo *rec, bool inPlaylist = false);
    279277    void stop(ProgramInfo *);
     
    431429    // Preview Pixmap Variables ///////////////////////////////////////////////
    432430    bool                m_previewFromBookmark;
    433431    uint                m_previewGeneratorMode;
    434     LastCheckedMap      m_previewLastModifyCheck;
    435432    QMap<QString,QDateTime> m_previewFileTS;
    436433    bool                m_previewSuspend;
    437434    mutable QMutex      m_previewGeneratorLock;
  • mythtv/programs/mythbackend/playbacksock.h

     
    5959                                 const QString     &outputFile,
    6060                                 const QSize       &outputSize);
    6161    QDateTime PixmapLastModified(const ProgramInfo *pginfo);
     62
    6263    bool CheckFile(ProgramInfo *pginfo);
    6364
    6465    bool IsBusy(int        capturecardnum,
     
    7879                                    const vector<uint> &excluded_cardids);
    7980    void CancelNextRecording(int capturecardnum, bool cancel);
    8081
     82    QStringList ForwardRequest(const QStringList&);
     83
    8184  private:
    8285    bool SendReceiveStringList(QStringList &strlist, uint min_reply_length = 0);
    8386
  • mythtv/programs/mythbackend/mainserver.h

     
    128128    void HandleSetVerbose(QStringList &slist, PlaybackSock *pbs);
    129129    void HandleGenPreviewPixmap(QStringList &slist, PlaybackSock *pbs);
    130130    void HandlePixmapLastModified(QStringList &slist, PlaybackSock *pbs);
     131    void HandlePixmapGetIfModified(const QStringList &slist, PlaybackSock *pbs);
    131132    void HandleIsRecording(QStringList &slist, PlaybackSock *pbs);
    132133    void HandleCheckRecordingActive(QStringList &slist, PlaybackSock *pbs);
    133134    void HandleFillProgramInfo(QStringList &slist, PlaybackSock *pbs);
  • mythtv/programs/mythbackend/playbacksock.cpp

     
    481481    SendReceiveStringList(strlist);
    482482}
    483483
     484QStringList PlaybackSock::ForwardRequest(const QStringList &slist)
     485{
     486    QStringList strlist = slist;
     487
     488    if (SendReceiveStringList(strlist))
     489        return strlist;
     490
     491    return QStringList();
     492}
     493
    484494/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythtv/programs/mythbackend/mainserver.cpp

     
    532532    {
    533533        HandlePixmapLastModified(listline, pbs);
    534534    }
     535    else if (command == "QUERY_PIXMAP_GET_IF_MODIFIED")
     536    {
     537        HandlePixmapGetIfModified(listline, pbs);
     538    }
    535539    else if (command == "QUERY_ISRECORDING")
    536540    {
    537541        HandleIsRecording(listline, pbs);
     
    46144618        strlist = QStringList( "BAD" );
    46154619
    46164620    SendResponse(pbssock, strlist);
    4617     delete pginfo;
    46184621}
    46194622
     4623void 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
    46204748void MainServer::HandleBackendRefresh(MythSocket *socket)
    46214749{
    46224750    gContext->RefreshBackendConfig();
  • mythtv/bindings/python/MythTV/MythTV.py

     
    4646                }
    4747
    4848BACKEND_SEP = '[]:[]'
    49 PROTO_VERSION = 48
     49PROTO_VERSION = 49
    5050PROGRAM_FIELDS = 47
    5151
    5252class MythTV:
  • mythtv/bindings/perl/MythTV.pm

     
    101101
    102102# MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
    103103# and should be the current MythTV protocol version.
    104     our $PROTO_VERSION = 48;
     104    our $PROTO_VERSION = 49;
    105105
    106106# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
    107107# the number of items in a ProgramInfo QStringList group used by