Ticket #756: queueManagement.patch

File queueManagement.patch, 16.9 KB (added by anonymous, 15 years ago)
  • mythflix/mythflix.cpp

     
    2222#include <iostream>
    2323
    2424#include <qnetwork.h>
     25#include <qapplication.h>
    2526#include <qdatetime.h>
    2627#include <qpainter.h>
    2728#include <qdir.h>
    2829#include <qtimer.h>
    2930#include <qregexp.h>
     31#include <qprocess.h>
    3032
    3133#include <qurl.h>
    3234#include "mythtv/mythcontext.h"
     
    9597            this, SLOT(slotNewsRetrieved(NewsSite*)));
    9698   
    9799    slotRetrieveNews();
    98 
    99     netflixShopperId = gContext->GetSetting("NetflixShopperId");
    100     VERBOSE(VB_GENERAL, QString("MythFlix: Using NetflixShopperId %1").arg(netflixShopperId));
    101100}
    102101
    103102MythFlix::~MythFlix()
     
    533532        if(article)
    534533        {
    535534
    536 //            updateAddingView();
     535            QStringList args = QStringList::split(' ',
     536                    gContext->GetSetting("NetFlixAddQueueCommandLine",
     537                    gContext->GetShareDir() + "mythflix/scripts/netflix.pl -A"));
    537538
    538539            QString cmdUrl(article->articleURL());
    539540            cmdUrl.replace('\'', "%27");
     
    541542            QUrl url(cmdUrl);
    542543
    543544            QString query = url.query();
     545            QStringList getArgs = QStringList::split('&', query);
    544546
    545             QString get("/AddToQueue?");
    546             get.append(query);
     547            for (QStringList::Iterator it = getArgs.begin();it != getArgs.end(); ++it)
     548            {
     549                QString name = (*it).section('=', 0, 0);
     550                QString vale = (*it).section('=', 1);
    547551
    548             http = new QHttp();
    549             connect(http, SIGNAL(responseHeaderReceived (const QHttpResponseHeader&)), this, SLOT(slotMovieAdded(const QHttpResponseHeader&)));
    550             //connect(http, SIGNAL(done (const QHttpResponseHeader&)), this, SLOT(slotMovieAdded(const QHttpResponseHeader&)));
    551            
    552             QHttpRequestHeader header( "GET", get );
    553             header.setValue( "Cookie", "validReEntryCookie=Y; validReEntryConfirmed=Y; NetflixShopperId=" + netflixShopperId + ";" );
    554             header.setValue( "Host", "www.netflix.com" );
    555 
    556             http->setHost( "www.netflix.com" );
    557             http->request( header );
     552                args += vale;
     553            }
     554               
     555                        // execute external command to obtain list of possible movie matches
     556                        QString results = executeExternal(args, "Add Movie");
     557               
    558558        }
    559559    }
    560560}
    561561
    562 void MythFlix::slotMovieAdded(const QHttpResponseHeader &resp)
     562// Execute an external command and return results in string
     563//   probably should make this routing async vs polling like this
     564//   but it would require a lot more code restructuring
     565QString MythFlix::executeExternal(const QStringList& args, const QString& purpose)
    563566{
    564     QString location = resp.value(QString("Location"));
     567    QString ret = "";
     568    QString err = "";
    565569
    566     if (location)
     570    VERBOSE(VB_GENERAL, QString("%1: Executing '%2'").arg(purpose).
     571                      arg(args.join(" ")).local8Bit() );
     572    QProcess proc(args, this);
     573
     574    QString cmd = args[0];
     575    QFileInfo info(cmd);
     576   
     577    if (!info.exists())
    567578    {
    568         //How do you clean up http objects
    569         //do you listen for signal done
    570         //delete http;
     579       err = QString("\"%1\" failed: does not exist").arg(cmd.local8Bit());
     580    }
     581    else if (!info.isExecutable())
     582    {
     583       err = QString("\"%1\" failed: not executable").arg(cmd.local8Bit());
     584    }
     585    else if (proc.start())
     586    {
     587        while (true)
     588        {
     589            while (proc.canReadLineStdout() || proc.canReadLineStderr())
     590            {
     591                if (proc.canReadLineStdout())
     592                {
     593                    ret += QString::fromLocal8Bit(proc.readLineStdout(),-1) + "\n";
     594                }
     595             
     596                if (proc.canReadLineStderr())
     597                {
     598                    if (err == "")
     599                    {
     600                        err = cmd + ": ";
     601                    }                   
     602                 
     603                    err += QString::fromLocal8Bit(proc.readLineStderr(),-1) + "\n";
     604                }
     605            }
     606           
     607            if (proc.isRunning())
     608            {
     609                qApp->processEvents();
     610                usleep(10000);
     611            }
     612            else
     613            {
     614                if (!proc.normalExit())
     615                {
     616                    err = QString("\"%1\" failed: Process exited abnormally")
     617                                  .arg(cmd.local8Bit());
     618                }
     619               
     620                break;
     621            }
     622        }
     623    }
     624    else
     625    {
     626        err = QString("\"%1\" failed: Could not start process")
     627                      .arg(cmd.local8Bit());
     628    }
    571629
    572         VERBOSE(VB_NETWORK, QString("MythFlix: Redirecting to (%1)").arg(location));
     630    while (proc.canReadLineStdout() || proc.canReadLineStderr())
     631    {
     632        if (proc.canReadLineStdout())
     633        {
     634            ret += QString::fromLocal8Bit(proc.readLineStdout(),-1) + "\n";
     635        }
     636       
     637        if (proc.canReadLineStderr())
     638        {
     639            if (err == "")
     640            {
     641                err = cmd + ": ";
     642            }               
     643           
     644            err += QString::fromLocal8Bit(proc.readLineStderr(), -1) + "\n";
     645        }
     646    }
    573647
    574         http = new QHttp();
    575         connect(http, SIGNAL(responseHeaderReceived (const QHttpResponseHeader&)), this, SLOT(slotMovieAdded(const QHttpResponseHeader&)));
     648    if (err != "")
     649    {
     650        QString tempPurpose(purpose);
     651       
     652        if (tempPurpose == "")
     653            tempPurpose = "Command";
    576654
    577         QHttpRequestHeader header( "GET", location );
    578         header.setValue( "Cookie", "validReEntryCookie=Y; validReEntryConfirmed=Y; NetflixShopperId=" + netflixShopperId + ";" );
    579         header.setValue( "Host", "www.netflix.com" );
    580         http->setHost( "www.netflix.com" );
    581         http->request( header );
     655        cerr << err << endl;
     656        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     657        QObject::tr(tempPurpose + " failed"), QObject::tr(err + "\n\nCheck NetFlix Settings"));
     658        ret = "#ERROR";
    582659    }
     660   
     661    VERBOSE(VB_ALL, ret);
     662    return ret;
    583663}
     664
     665
  • mythflix/mythflixqueue.cpp

     
    2222#include <iostream>
    2323
    2424#include <qnetwork.h>
     25#include <qapplication.h>
    2526#include <qdatetime.h>
    2627#include <qpainter.h>
    2728#include <qdir.h>
    2829#include <qtimer.h>
    2930#include <qregexp.h>
     31#include <qprocess.h>
    3032
    3133#include <qurl.h>
    3234#include "mythtv/mythcontext.h"
     
    327329            cursorDown();
    328330        else if (action == "PAGEDOWN")
    329331             cursorDown(true);
     332        else if (action == "REMOVE")
     333             removeFromQueue();
     334        else if (action == "MOVETOTOP")
     335             moveToTop();
    330336        else
    331337            handled = false;
    332338    }
     
    388394    }
    389395}
    390396
     397void MythFlixQueue::moveToTop()
     398{
     399    UIListBtnTypeItem *articleUIItem = m_UIArticles->GetItemCurrent();
     400
     401    if (articleUIItem && articleUIItem->getData())
     402    {
     403        NewsArticle *article = (NewsArticle*) articleUIItem->getData();
     404        if(article)
     405        {
     406
     407            QStringList args = QStringList::split(' ',
     408                    gContext->GetSetting("NetFlixMoveToTopCommandLine",
     409                    gContext->GetShareDir() + "mythflix/scripts/netflix.pl -1"));
     410
     411            QString cmdUrl(article->articleURL());
     412            cmdUrl.replace('\'', "%27");
     413
     414            QUrl url(cmdUrl);
     415
     416            QString query = url.query();
     417            QStringList getArgs = QStringList::split('&', query);
     418
     419            for (QStringList::Iterator it = getArgs.begin();it != getArgs.end(); ++it)
     420            {
     421                QString name = (*it).section('=', 0, 0);
     422                QString vale = (*it).section('=', 1);
     423
     424                args += vale;
     425            }
     426            // execute external command to obtain list of possible movie matches
     427            QString results = executeExternal(args, "Move To Top");
     428       
     429            slotRetrieveNews();
     430   
     431        }
     432    }
     433
     434}
     435
     436void MythFlixQueue::removeFromQueue()
     437{
     438    UIListBtnTypeItem *articleUIItem = m_UIArticles->GetItemCurrent();
     439
     440    if (articleUIItem && articleUIItem->getData())
     441    {
     442        NewsArticle *article = (NewsArticle*) articleUIItem->getData();
     443        if(article)
     444        {
     445
     446            QStringList args = QStringList::split(' ',
     447                    gContext->GetSetting("NetFlixRemoveFromQueueCommandLine",
     448                    gContext->GetShareDir() + "mythflix/scripts/netflix.pl -R"));
     449
     450            QString cmdUrl(article->articleURL());
     451            cmdUrl.replace('\'', "%27");
     452
     453            QUrl url(cmdUrl);
     454
     455            QString query = url.query();
     456            QStringList getArgs = QStringList::split('&', query);
     457
     458            for (QStringList::Iterator it = getArgs.begin();it != getArgs.end(); ++it)
     459            {
     460                QString name = (*it).section('=', 0, 0);
     461                QString vale = (*it).section('=', 1);
     462
     463                args += vale;
     464            }
     465            // execute external command to obtain list of possible movie matches
     466            QString results = executeExternal(args, "Remove From Queue");
     467       
     468            slotRetrieveNews();
     469   
     470        }
     471    }
     472
     473}
     474
    391475void MythFlixQueue::slotArticleSelected(UIListBtnTypeItem*)
    392476{
    393477    update(m_ArticlesRect);
    394478    update(m_InfoRect);
    395479}
    396480
     481// Execute an external command and return results in string
     482//   probably should make this routing async vs polling like this
     483//   but it would require a lot more code restructuring
     484QString MythFlixQueue::executeExternal(const QStringList& args, const QString& purpose)
     485{
     486    QString ret = "";
     487    QString err = "";
     488
     489    VERBOSE(VB_GENERAL, QString("%1: Executing '%2'").arg(purpose).
     490                      arg(args.join(" ")).local8Bit() );
     491    QProcess proc(args, this);
     492
     493    QString cmd = args[0];
     494    QFileInfo info(cmd);
     495   
     496    if (!info.exists())
     497    {
     498       err = QString("\"%1\" failed: does not exist").arg(cmd.local8Bit());
     499    }
     500    else if (!info.isExecutable())
     501    {
     502       err = QString("\"%1\" failed: not executable").arg(cmd.local8Bit());
     503    }
     504    else if (proc.start())
     505    {
     506        while (true)
     507        {
     508            while (proc.canReadLineStdout() || proc.canReadLineStderr())
     509            {
     510                if (proc.canReadLineStdout())
     511                {
     512                    ret += QString::fromLocal8Bit(proc.readLineStdout(),-1) + "\n";
     513                }
     514             
     515                if (proc.canReadLineStderr())
     516                {
     517                    if (err == "")
     518                    {
     519                        err = cmd + ": ";
     520                    }                   
     521                 
     522                    err += QString::fromLocal8Bit(proc.readLineStderr(),-1) + "\n";
     523                }
     524            }
     525           
     526            if (proc.isRunning())
     527            {
     528                qApp->processEvents();
     529                usleep(10000);
     530            }
     531            else
     532            {
     533                if (!proc.normalExit())
     534                {
     535                    err = QString("\"%1\" failed: Process exited abnormally")
     536                                  .arg(cmd.local8Bit());
     537                }
     538               
     539                break;
     540            }
     541        }
     542    }
     543    else
     544    {
     545        err = QString("\"%1\" failed: Could not start process")
     546                      .arg(cmd.local8Bit());
     547    }
     548
     549    while (proc.canReadLineStdout() || proc.canReadLineStderr())
     550    {
     551        if (proc.canReadLineStdout())
     552        {
     553            ret += QString::fromLocal8Bit(proc.readLineStdout(),-1) + "\n";
     554        }
     555       
     556        if (proc.canReadLineStderr())
     557        {
     558            if (err == "")
     559            {
     560                err = cmd + ": ";
     561            }               
     562           
     563            err += QString::fromLocal8Bit(proc.readLineStderr(), -1) + "\n";
     564        }
     565    }
     566
     567    if (err != "")
     568    {
     569        QString tempPurpose(purpose);
     570       
     571        if (tempPurpose == "")
     572            tempPurpose = "Command";
     573
     574        cerr << err << endl;
     575        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     576        QObject::tr(tempPurpose + " failed"), QObject::tr(err + "\n\nCheck NetFlix Settings"));
     577        ret = "#ERROR";
     578    }
     579   
     580    VERBOSE(VB_ALL, ret);
     581    return ret;
     582}
     583
     584
     585
  • mythflix/mythflix.h

     
    6262    void cancelRetrieve();
    6363    void processAndShowNews(NewsSite *site);
    6464
     65    QString executeExternal(const QStringList& args, const QString& purpose);
     66
    6567    XMLParse      *m_Theme;
    6668
    6769    UIListBtnType *m_UISites;
     
    7375
    7476    NewsSite::List m_NewsSites;
    7577
    76     QHttp         *http;
    77 
    78     QString        netflixShopperId;
    79 
    8078private slots:
    8179    void slotViewArticle();
    8280    void slotRetrieveNews();
     
    8583    void slotSiteSelected(UIListBtnTypeItem *item);
    8684    void slotArticleSelected(UIListBtnTypeItem *item);
    8785
    88     void slotMovieAdded(const QHttpResponseHeader &resp);
    8986};
    9087
    9188#endif /* MYTHFLIX_H */
  • mythflix/mythflixqueue.h

     
    6060    void cancelRetrieve();
    6161    void processAndShowNews(NewsSite *site);
    6262
     63    void moveToTop();
     64    void removeFromQueue();
     65    QString executeExternal(const QStringList& args, const QString& purpose);
     66
    6367    XMLParse      *m_Theme;
    6468
    6569    UIListBtnType *m_UIArticles;
  • mythflix/mythflix.pro

     
    1515installfiles.files = netflix-rss.xml
    1616installimages.path = $${PREFIX}/share/mythtv/themes/default
    1717installimages.files = images/*.png
     18installscripts.path = $${PREFIX}/share/mythtv/mythflix/scripts
     19installscripts.files = scripts/*.pl
    1820
    19 INSTALLS += installfiles installimages installmenus uifiles
     21INSTALLS += installfiles installimages installmenus installscripts uifiles
    2022
    2123# Input
    2224HEADERS += mythflixqueue.h mythflix.h mythflixconfig.h newsengine.h
  • mythflix/main.cpp

     
    105105{
    106106    REG_JUMP("Browse", "", "", browse);
    107107
    108     REG_KEY("NetFlix", "RETRIEVENEWS", "Update news items", "I");
    109     REG_KEY("NetFlix", "FORCERETRIEVE", "Force update news items", "M");
    110     REG_KEY("NetFlix", "CANCEL", "Cancel news item updating", "C");
     108    REG_KEY("NetFlix", "MOVETOTOP", "Moves movie to top of queue", "1");
     109    REG_KEY("NetFlix", "REMOVE", "Removes movie from queue", "D");
    111110
    112111    //REG_JUMP("MythFlix", "NetFlix", "", runNews);
    113112
  • README

     
    2323  /usr/local/share/mythtv/mythflix directory
    2424- image files and ui file go to /usr/local/share/mythtv/themes/default
    2525
    26 Mythtv menu needs to be modified to support MythFlix plugin.  Patches for the menu
    27 xml files are provided.  Apply each patch: patch -p0 < xxxx.patch.  When prompted for
    28 which file to patch:
    29 - main_settings.xml.patch ->  /usr/local/share/mythtv/main_settings.xml
    30 - info_menu.xml.patch  -> /usr/local/share/mythtv/info_menu.xml
    31 - info_settings.xml.patch -> /usr/local/share/mythtv/info_settings.xml
    32 - theme.xml.patch  -> /usr/local/share/mythtv/themes/G.A.N.T./theme.xml
    33 
    34 Insert you Netflix ShopperId in the database.  Your Netflix shopperId can be found in
    35 your browser's cookie. For KDE Konqueuer users, your cookie file is .kde/share/apps//kcookiejar/cookies
    36 look for cookie key NetflixShopperId.  The cookie value should look like something like P234214938249083290480903298
    37 
    38     insert settings values ('NetflixShopperId','[NetflixShooperId]', null);
    39 
    4026Run mythfrontend and setup the Netflix RSS feeds to include when you browse for movies.
    4127You MUST run the mythfrontend first to give the plugin a chance to intial the database
    4228before continuing. See CONFIGURATION/USAGE.
    4329
     30Currenty, MythFlix plugin lacks a more rebust configuration UI.  So your netflix account settings need to be initilized manually.
     31To do this run the following command.  For some reason to properly intialized the netflix cookie you must run script twice.
     32
     33/usr/local/share/mythtv/mythflix/scripts/netflix.pl -L <userid> <passwd>
     34/usr/local/share/mythtv/mythflix/scripts/netflix.pl -L <userid> <passwd>
     35
    4436FINAL INSTALLATION
    4537---------------------------------------------------------------------
    4638