Index: mythplugins/mythvideo/mythvideo/globalsettings.cpp
===================================================================
--- mythplugins/mythvideo/mythvideo/globalsettings.cpp	(revision 20185)
+++ mythplugins/mythvideo/mythvideo/globalsettings.cpp	(working copy)
@@ -246,6 +246,29 @@
     return gc;
 }
 
+HostLineEdit *TVExportDirectoryFormat()
+{
+    HostLineEdit *gc = new HostLineEdit("TVExportDirFormat");
+    gc->setLabel(QObject::tr("TV Export Directory Format"));
+    gc->setValue(DEFAULT_TVEXPORTDIRFORMAT);
+    gc->setHelpText(QObject::tr("Directory format for recording export "
+                    "to MythVideo, using user job style variables. Directory "
+                    "is off of base MythVideo directory. Example: "
+                    "Television/%CATEGORY%/%TITLE%"));
+    return gc;
+}
+
+HostLineEdit *TVExportFileFormat()
+{
+    HostLineEdit *gc = new HostLineEdit("TVExportFileFormat");
+    gc->setLabel(QObject::tr("TV Export File Format"));
+    gc->setValue(DEFAULT_TVEXPORTFILEFORMAT);
+    gc->setHelpText(QObject::tr("File format for recording export "
+                    "to MythVideo, using user job style variables. Example: "
+                    "%TITLE% - %SUBTITLE% (%STARTTIMEISO%)"));
+    return gc;
+}
+
 HostLineEdit *VideoArtworkDirectory()
 {
     HostLineEdit *gc = new HostLineEdit("VideoArtworkDir");
@@ -779,6 +802,8 @@
             new VerticalConfigurationGroup(true, false);
     trlr->addChild(TrailerDirectory());
     trlr->addChild(new RandomTrailers());
+    trlr->addChild(TVExportFileFormat());
+    trlr->addChild(TVExportDirectoryFormat());
     VConfigPage page7(pages, false);
     page7->addChild(trlr);
 
Index: mythplugins/mythvideo/mythvideo/globals.cpp
===================================================================
--- mythplugins/mythvideo/mythvideo/globals.cpp	(revision 20185)
+++ mythplugins/mythvideo/mythvideo/globals.cpp	(working copy)
@@ -28,6 +28,8 @@
 const QString JUMP_VIDEO_TREE = "Video Listings";
 const QString JUMP_VIDEO_GALLERY = "Video Gallery";
 const QString JUMP_VIDEO_DEFAULT = "MythVideo";
+const QString DEFAULT_TVEXPORTDIRFORMAT = "Television/%TITLE%";
+const QString DEFAULT_TVEXPORTFILEFORMAT = "%TITLE% - %SUBTITLE%";
 
 #ifdef Q_WS_MACX
 const QString DEFAULT_VIDEOSTARTUP_DIR = QDir::homePath() + "/Movies";
Index: mythplugins/mythvideo/mythvideo/globals.h
===================================================================
--- mythplugins/mythvideo/mythvideo/globals.h	(revision 20185)
+++ mythplugins/mythvideo/mythvideo/globals.h	(working copy)
@@ -28,5 +28,7 @@
 extern const QString JUMP_VIDEO_DEFAULT;
 
 extern const QString DEFAULT_VIDEOSTARTUP_DIR;
+extern const QString DEFAULT_TVEXPORTDIRFORMAT;
+extern const QString DEFAULT_TVEXPORTFILEFORMAT;
 
 #endif // GLOBALS_H_
Index: mythtv/programs/mythfrontend/playbackbox.cpp
===================================================================
--- mythtv/programs/mythfrontend/playbackbox.cpp	(revision 20185)
+++ mythtv/programs/mythfrontend/playbackbox.cpp	(working copy)
@@ -20,6 +20,7 @@
 #include "mythdirs.h"
 #include "mythcontext.h"
 #include "mythdbcon.h"
+#include "mythdb.h"
 #include "mythverbose.h"
 #include "programinfo.h"
 #include "scheduledrecording.h"
@@ -35,6 +36,7 @@
 #include "mythuibutton.h"
 #include "mythuibuttonlist.h"
 #include "mythuistatetype.h"
+#include "mythuispinbox.h"
 #include "mythdialogbox.h"
 #include "mythuitextedit.h"
 #include "mythuiimage.h"
@@ -44,6 +46,11 @@
 #define LOC QString("PlaybackBox: ")
 #define LOC_ERR QString("PlaybackBox Error: ")
 
+QString customExportFile = NULL;
+QString customExportDir = NULL;
+unsigned int customExportSeason = 0;
+unsigned int customExportEpisode = 0;
+
 #define REC_CAN_BE_DELETED(rec) \
     ((((rec)->programflags & FL_INUSEPLAYING) == 0) && \
      ((((rec)->programflags & FL_INUSERECORDING) == 0) || \
@@ -1812,6 +1819,320 @@
     RemoteStopRecording(rec);
 }
 
+void PlaybackBox::mvexport(ProgramInfo *rec)
+{
+
+    // User Rating Adjustment
+    QString exportRating = QString::number((int)((rec->stars * 10.0) + 0.5));
+
+    // Stuff necessary to perform the copy command
+
+    QString copyFrom = rec->GetPlaybackURL(false, true);
+    QString baseMVDir = gContext->GetSetting("VideoStartupDir");
+    QString MVFileFormat;
+    QString MVDirFormat;
+    QString copyToDir;
+    QString copyToFile;
+    QString extension;
+    unsigned int seasonValue;
+    unsigned int episodeValue;
+
+    // Check the original extension
+
+    QRegExp rx(".*\\.(\\w+)$");
+    int pos = rx.indexIn(copyFrom);
+    if (pos > -1)
+    {
+        extension = rx.cap(1);
+    }
+    else
+    {
+        extension = "";
+    }
+
+    // If a custom export string is used, use it.
+    // Also replace %VARIABLES% with actual values. 
+
+    if (customExportFile.isEmpty() && customExportDir.isEmpty() 
+        && customExportSeason == 0 && customExportEpisode == 0)
+    {
+        QString defaultDir = gContext->GetSetting("TVExportDirFormat",
+                              "Television/%TITLE%/");
+        QString defaultFile = gContext->GetSetting("TVExportFileFormat", 
+                              "%TITLE% - %SUBTITLE%");
+        MVDirFormat = replaceExportVariables(rec, defaultDir);
+        MVFileFormat = replaceExportVariables(rec, defaultFile);
+        QString recType = rec->catType; 
+        if (recType == "movie")
+        {
+            seasonValue = 0;
+            episodeValue = 0;
+        }
+        else
+        {
+            seasonValue = getLastSeason(rec->title);
+            episodeValue = (getLastEpisode(rec->title, seasonValue) + 1);
+        }
+    }
+    else
+    {
+        MVDirFormat = replaceExportVariables(rec, customExportDir);
+        MVFileFormat = replaceExportVariables(rec, customExportFile);
+        seasonValue = customExportSeason;
+        episodeValue = customExportEpisode;
+    }
+
+    copyToDir = QString("%1/%2").arg(baseMVDir).arg(MVDirFormat);
+    copyToFile = QString("%1/%2.%3").arg(copyToDir)
+                         .arg(MVFileFormat).arg(extension);
+
+    // replace double slash with single
+
+    copyToFile.replace("//", "/");
+
+    // File and Directory Definitions
+
+    QFile fromFile(copyFrom);
+    QDir toDir(copyToDir);
+    QFile toFile(copyToFile);
+
+    if (!toDir.exists())
+    {
+        // Attempt to create path to export point.
+        toDir.mkpath(copyToDir);
+        toDir.mkdir(copyToDir);
+        if (!toDir.exists())
+        {
+            VERBOSE(VB_IMPORTANT, QString("Unable to create directory %1! "
+                                          "Please ensure the preceding path "
+                                          "exists and is writeable.").arg(copyToDir));    
+            return;
+        }
+    }
+
+    // Perform the actual copy. 
+
+    long long int bytesCopied = copy(toFile,fromFile);
+
+    if (bytesCopied != -1)
+    {
+        // Add File into videometadata
+
+        MSqlQuery query(MSqlQuery::InitCon());
+
+        query.prepare("INSERT INTO videometadata (title,subtitle,director,"
+                          "plot,rating,year,userrating,length,season,"
+                          "episode,filename,showlevel,coverfile,inetref,"
+                          "browse, trailer, screenshot, banner, fanart) VALUES "
+                          "(:TITLE, :SUBTITLE, :DIRECTOR, :PLOT, :RATING, :YEAR, "
+                          ":USERRATING, :LENGTH, :SEASON, :EPISODE, :FILENAME, "
+                          ":SHOWLEVEL, :COVERFILE, :INETREF, :BROWSE, :TRAILER, "
+                          ":SCREENSHOT, :BANNER, :FANART)");
+
+        query.bindValue(":TITLE", rec->title);
+        query.bindValue(":SUBTITLE", rec->subtitle);
+        query.bindValue(":DIRECTOR", "Unknown");
+        query.bindValue(":PLOT", rec->description);
+        query.bindValue(":RATING", "NR");
+        query.bindValue(":YEAR", rec->originalAirDate.toString("yyyy"));
+        query.bindValue(":USERRATING", exportRating);
+        query.bindValue(":LENGTH", rec->lenMins);
+        query.bindValue(":SEASON", seasonValue);
+        query.bindValue(":EPISODE", episodeValue);   
+        query.bindValue(":FILENAME", copyToFile);
+        query.bindValue(":SHOWLEVEL", 1);
+        query.bindValue(":COVERFILE", "No Cover");
+        query.bindValue(":INETREF", 0);
+        query.bindValue(":BROWSE", 1);
+        query.bindValue(":TRAILER", "");
+        query.bindValue(":SCREENSHOT", "");
+        query.bindValue(":BANNER", "");
+        query.bindValue(":FANART", "");
+
+        if (!query.exec() || !query.isActive())
+        {
+            MythDB::DBError("video metadata update", query);
+            return;
+        }
+
+        // Move recordedmarkup for file into videometadata
+
+        MSqlQuery markup(MSqlQuery::InitCon());
+
+        markup.prepare("INSERT INTO filemarkup (filename,mark,offset,type) "
+                      "SELECT :FILENAME, mark, data, type from "
+                      "recordedmarkup where chanid=:CHANID and starttime=:STARTTIME");
+
+        markup.bindValue(":FILENAME", copyToFile);
+        markup.bindValue(":CHANID", rec->chanid);
+        markup.bindValue(":STARTTIME", rec->recstartts);
+
+        if (!markup.exec() || !markup.isActive())
+        {
+            MythDB::DBError("video metadata update", markup);
+            return;
+        }
+
+        // Copy and set preview image as screenshot
+        // If Banners, cover files, or fanart exist with
+        // seriesID as the name, use them automatically.
+
+        QString screenshotFile = getPreviewImage(rec);
+        QString MVScreenshotDir = gContext->GetSetting("mythvideo.screenshotDir");
+        QString MVScreenshotFile = QString("%1/%2.png").arg(MVScreenshotDir).arg(MVFileFormat);
+
+        QString MVBannerDir = gContext->GetSetting("mythvideo.bannerDir");
+        QString bannerFile = testImageFiles(MVBannerDir, rec->seriesid, rec->title);
+        if (!bannerFile.isNull()) 
+            VERBOSE(VB_IMPORTANT, QString("Found Banner File Match: %1").arg(bannerFile));
+
+        QString MVFanartDir = gContext->GetSetting("mythvideo.fanartDir");
+        QString fanartFile = testImageFiles(MVFanartDir, rec->seriesid, rec->title);
+        if (!fanartFile.isNull()) 
+            VERBOSE(VB_IMPORTANT, QString("Found Fanart File Match: %1").arg(fanartFile));
+
+        QString MVCoverDir = gContext->GetSetting("VideoArtworkDir");
+        QString coverFile = testImageFiles(MVCoverDir, rec->seriesid, rec->title);
+        if (!coverFile.isNull()) 
+            VERBOSE(VB_IMPORTANT, QString("Found Cover File Match: %1").arg(coverFile));
+
+        VERBOSE(VB_IMPORTANT, QString("Copying %1 to %2").arg(screenshotFile).arg(MVScreenshotFile)); 
+
+        QFile fromScreenshot(screenshotFile);
+        QFile toScreenshot(MVScreenshotFile);
+        long long int screenshotBytesCopied;
+        
+        if (!screenshotFile.isNull())
+            screenshotBytesCopied = copy(toScreenshot,fromScreenshot);
+
+        if (!bannerFile.isNull() || !fanartFile.isNull() || !coverFile.isNull())
+        {
+            MSqlQuery images(MSqlQuery::InitCon());
+
+            images.prepare("UPDATE videometadata set screenshot=:SCREENSHOTFILE, "
+                           "banner=:BANNERFILE, fanart=:FANARTFILE, coverfile=:COVERFILE "
+                           "where filename=:FILENAME");
+
+            images.bindValue(":SCREENSHOTFILE", MVScreenshotFile);
+            images.bindValue(":BANNERFILE", bannerFile);
+            images.bindValue(":FANARTFILE", fanartFile);
+            images.bindValue(":COVERFILE", coverFile);
+            images.bindValue(":FILENAME", copyToFile);
+
+            if (!images.exec() || !images.isActive())
+            {
+                MythDB::DBError("video metadata update", images);
+                 return;
+            }
+        }
+        else
+        {
+            VERBOSE(VB_IMPORTANT, QString("Copy succeeded, but no images "
+                    "were copied or found.").arg(screenshotBytesCopied));
+            return;
+        }
+        VERBOSE(VB_IMPORTANT, QString("Copy succeeded, %1 bytes copied.").arg(bytesCopied));
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, QString("Copy unsuccessful, check all permissions."));
+    }
+
+customExportDir.clear();
+customExportFile.clear();
+customExportSeason = 0;
+customExportEpisode = 0;
+}
+
+unsigned int PlaybackBox::getLastSeason(QString title)
+{
+    unsigned int retSeason;
+
+    if (!title.isEmpty())
+    {
+        MSqlQuery season(MSqlQuery::InitCon());
+     
+        season.prepare("SELECT season from videometadata where "
+                     "title = :TITLE ORDER BY season DESC LIMIT 1");
+
+        season.bindValue(":TITLE", title);
+
+        if (season.exec() && season.next())
+        {
+            retSeason = season.value(0).toInt();
+        }
+        else
+            retSeason = 1;
+    }
+
+    return retSeason;
+} 
+
+unsigned int PlaybackBox::getLastEpisode(QString title, unsigned int season)
+{       
+    unsigned int retEpisode;
+
+    if (!title.isEmpty()) 
+    {
+        MSqlQuery episode(MSqlQuery::InitCon());
+                 
+        episode.prepare("SELECT episode from videometadata where "
+                     "title = :TITLE AND season = :SEASON ORDER BY "
+                     "episode DESC LIMIT 1");
+            
+        episode.bindValue(":TITLE", title);
+        episode.bindValue(":SEASON", season);
+
+        if (episode.exec() && episode.next())
+        {
+            retEpisode = episode.value(0).toInt();
+        }
+        else
+            retEpisode = 0;
+    }
+
+    return retEpisode;
+}
+
+QString PlaybackBox::replaceExportVariables(ProgramInfo *rec, QString &repString)
+{
+    if (!repString.isEmpty())
+    {
+         repString.replace(QRegExp("%FILE%"), rec->GetRecordBasename(true));
+         repString.replace(QRegExp("%TITLE%"), rec->title);
+         repString.replace(QRegExp("%SUBTITLE%"), rec->subtitle);
+         repString.replace(QRegExp("%DESCRIPTION%"), rec->description);
+         repString.replace(QRegExp("%HOSTNAME%"), rec->hostname);
+         repString.replace(QRegExp("%CATEGORY%"), rec->category);
+         repString.replace(QRegExp("%RECGROUP%"), rec->recgroup);
+         repString.replace(QRegExp("%PLAYGROUP%"), rec->playgroup);
+         repString.replace(QRegExp("%ORIGAIRYEAR%"),
+                         rec->originalAirDate.toString("yyyy"));
+         repString.replace(QRegExp("%ORIGAIRDATE%"),
+                         rec->originalAirDate.toString("yyyyMMdd"));
+         repString.replace(QRegExp("%CALLSIGN%"), rec->chansign);
+         repString.replace(QRegExp("%CHANNAME%"), rec->channame);
+         repString.replace(QRegExp("%CHANID%"), rec->chanid);
+         repString.replace(QRegExp("%STARTTIME%"),
+                         rec->recstartts.toString("yyyyMMddhhmmss"));
+         repString.replace(QRegExp("%ENDTIME%"),
+                         rec->recendts.toString("yyyyMMddhhmmss"));
+         repString.replace(QRegExp("%STARTTIMEISO%"),
+                         rec->recstartts.toString(Qt::ISODate));
+         repString.replace(QRegExp("%ENDTIMEISO%"),
+                         rec->recendts.toString(Qt::ISODate));
+         repString.replace(QRegExp("%PROGSTART%"),
+                         rec->startts.toString("yyyyMMddhhmmss"));
+         repString.replace(QRegExp("%PROGEND%"),
+                         rec->endts.toString("yyyyMMddhhmmss"));
+         repString.replace(QRegExp("%PROGSTARTISO%"),
+                         rec->startts.toString(Qt::ISODate));
+         repString.replace(QRegExp("%PROGENDISO%"),
+                         rec->endts.toString(Qt::ISODate));
+    }
+    return repString;
+}
+
 bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
                            bool forceMetadataDelete)
 {
@@ -1952,6 +2273,55 @@
         showActionPopup(pginfo);
 }
 
+void PlaybackBox::showExportPopup(ProgramInfo *program)
+{
+    if (m_popupMenu)
+        return;
+
+    QString label = tr("Are you sure you want to export:");
+
+    m_expItem = CurrentItem();
+    popupString(m_expItem, label);
+
+    m_popupMenu = new MythDialogBox(label, m_popupStack, "pbbmainmenupopup");
+
+    connect(m_popupMenu, SIGNAL(Exiting()), SLOT(popupClosed()));
+
+    if (m_popupMenu->Create())
+        m_popupStack->AddScreen(m_popupMenu);
+    else
+    {
+        delete m_popupMenu;
+        m_popupMenu = NULL;
+    }
+
+    m_popupMenu->SetReturnEvent(this, "slotmenu");
+
+    m_freeSpaceNeedsUpdate = true;
+    QString tmpmessage;
+    const char *tmpslot = NULL;
+
+    if (program->IsSameProgram(*program))
+        {
+        tmpmessage = tr("Yes, Export to MythVideo");
+        tmpslot = SLOT(doMVExport());
+        m_popupMenu->AddButton(tmpmessage, tmpslot);
+
+        tmpmessage = tr("Export (Start New Season)");
+        tmpslot = SLOT(doNewSeasonExport());
+        m_popupMenu->AddButton(tmpmessage, tmpslot);
+
+        tmpmessage = tr("Export with custom name/location");
+        tmpslot = SLOT(showCustomExportEditor());
+        m_popupMenu->AddButton(tmpmessage, tmpslot);
+
+        tmpmessage = tr("No, I don't want to Export");
+        tmpslot = SLOT(noExport());
+        m_popupMenu->AddButton(tmpmessage, tmpslot);
+        }
+}
+
+
 void PlaybackBox::doPIPPlay(void)
 {
     doPIPPlay(kPIPonTV);
@@ -2378,6 +2748,10 @@
         else
             m_popupMenu->AddButton(tr("Preserve this episode"),
                                             SLOT(togglePreserveEpisode()));
+
+        QString MVlocation = FindPluginName("mythvideo");
+        if (QFile(MVlocation).exists())
+            m_popupMenu->AddButton(tr("Export to MythVideo"), SLOT(askMVExport()));
     }
 }
 
@@ -2754,6 +3128,12 @@
     stop(pginfo);
 }
 
+void PlaybackBox::doMVExport()
+{
+    ProgramInfo *pginfo = CurrentItem();
+    mvexport(pginfo);
+}
+
 void PlaybackBox::showProgramDetails()
 {
    ProgramInfo *pginfo = CurrentItem();
@@ -2892,6 +3272,13 @@
     }
 }
 
+void PlaybackBox::askMVExport(ProgramInfo *pginfo)
+{
+    if (!pginfo)
+        pginfo = CurrentItem();
+    showExportPopup(pginfo);
+}
+
 void PlaybackBox::askDelete()
 {
     if (m_delItem)
@@ -4130,6 +4517,74 @@
         m_recordingList->RemoveItem(item);
 }
 
+void PlaybackBox::showCustomExportEditor()
+{
+
+    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+
+    CustomExportEdit *editExport = new CustomExportEdit(mainStack);
+
+    if (editExport->Create())
+    {
+        connect(editExport, SIGNAL(result(const QString &, const QString &,
+                                        unsigned int, unsigned int)),
+                SLOT(startCustomExport(const QString &, const QString &,
+                                        unsigned int, unsigned int)));
+        mainStack->AddScreen(editExport);
+    }
+    else
+        delete editExport;
+}
+
+void PlaybackBox::doNewSeasonExport()
+{
+MythUIButtonListItem *item = m_recordingList->GetItemCurrent();
+
+    if (!item)
+        return;
+
+    ProgramInfo *pginfo = CurrentItem();
+
+    if (!pginfo)
+        return;
+
+        QString defaultDir = gContext->GetSetting("TVExportDirFormat",
+                              "Television/%TITLE%/");
+        QString defaultFile = gContext->GetSetting("TVExportFileFormat",
+                              "%TITLE% - %SUBTITLE%");
+
+
+    customExportFile = gContext->GetSetting("TVExportFileFormat",
+                              "%TITLE% - %SUBTITLE%");
+    customExportDir = gContext->GetSetting("TVExportDirFormat",
+                              "Television/%TITLE%/");
+    customExportSeason = (getLastSeason(pginfo->title) + 1);
+    customExportEpisode = 1;
+
+    mvexport(pginfo);
+}
+
+void PlaybackBox::startCustomExport(const QString &newFile, const QString &newDir,
+                                    unsigned int newSeason, unsigned int newEpisode)
+{
+    MythUIButtonListItem *item = m_recordingList->GetItemCurrent();
+
+    if (!item)
+        return;
+
+    ProgramInfo *pginfo = CurrentItem();
+
+    if (!pginfo)
+        return;
+
+    customExportFile = newFile;
+    customExportDir = newDir;
+    customExportSeason = newSeason;
+    customExportEpisode = newEpisode;
+
+    mvexport(pginfo);
+}
+
 void PlaybackBox::setRecGroup(QString newRecGroup)
 {
     ProgramInfo *tmpItem = CurrentItem();
@@ -4515,6 +4970,60 @@
     Close();
 }
 
+////////////////////////////////////////////////////////
+
+CustomExportEdit::CustomExportEdit(MythScreenStack *lparent)
+                : MythScreenType(lparent, "customexportedit")
+{
+    m_dirEdit = m_fileEdit = NULL;
+}
+
+bool CustomExportEdit::Create()
+{
+    if (!LoadWindowFromXML("recordings-ui.xml", "customexport", this))
+        return false;
+        
+    m_dirEdit = dynamic_cast<MythUITextEdit*>(GetChild("dir"));
+    m_fileEdit = dynamic_cast<MythUITextEdit*>(GetChild("file"));
+    m_seasonSpin = dynamic_cast<MythUISpinBox *>(GetChild("season"));
+    m_episodeSpin = dynamic_cast<MythUISpinBox *>(GetChild("episode"));
+
+    MythUIButton *okButton = dynamic_cast<MythUIButton*>(GetChild("ok"));
+ 
+    if (!m_dirEdit || !m_fileEdit || !m_seasonSpin || 
+                           !m_episodeSpin || !okButton)
+    {
+        VERBOSE(VB_IMPORTANT, "Window 'customexport' is missing required "
+                              "elements.");
+        return false;
+    }
+    
+    m_dirEdit->SetText(gContext->GetSetting("TVExportDirFormat"));
+    m_fileEdit->SetText(gContext->GetSetting("TVExportFileFormat"));
+    m_seasonSpin->SetRange(0,100,1);
+    m_seasonSpin->SetValue(1);
+    m_episodeSpin->SetRange(0,999,1);
+    m_episodeSpin->SetValue(1);
+
+    connect(okButton, SIGNAL(Clicked()), SLOT(ReturnExport()));
+     
+    if (!BuildFocusList())
+        VERBOSE(VB_IMPORTANT, "Failed to build a focuslist.");
+ 
+    return true;
+}
+
+void CustomExportEdit::ReturnExport()
+{
+    QString newExportDir = m_dirEdit->GetText();
+    QString newExportFile = m_fileEdit->GetText();
+    unsigned int newSeason = m_seasonSpin->GetIntValue();
+    unsigned int newEpisode = m_episodeSpin->GetIntValue();
+
+    emit result(newExportFile, newExportDir, newSeason, newEpisode);
+    Close();
+}
+
 //////////////////////////////////////////
 
 HelpPopup::HelpPopup(MythScreenStack *lparent)
Index: mythtv/programs/mythfrontend/playbackbox.h
===================================================================
--- mythtv/programs/mythfrontend/playbackbox.h	(revision 20185)
+++ mythtv/programs/mythfrontend/playbackbox.h	(working copy)
@@ -142,6 +142,7 @@
     void showRecGroupChanger();
     void showPlayGroupChanger();
     void showMetadataEditor();
+    void showCustomExportEditor();
     void showGroupFilter();
     void showRecGroupPasswordChanger();
     void showPlayFromPopup();
@@ -173,6 +174,8 @@
 
     void askStop();
     void doStop();
+    void askMVExport(ProgramInfo *pginfo = NULL);
+    void doMVExport();
 
     void doEditScheduled();
     void doAllowRerecord();
@@ -203,6 +206,9 @@
     void setPlayGroup(QString newPlayGroup);
 
     void saveRecMetadata(const QString &newTitle, const QString &newSubtitle);
+    void startCustomExport(const QString &newFile, const QString &newDir,
+                           unsigned int newSeason, unsigned int newEpisode);
+    void doNewSeasonExport();
 
     void SetRecGroupPassword(const QString &newPasswd);
 
@@ -263,6 +269,10 @@
 
     bool play(ProgramInfo *rec, bool inPlaylist = false);
     void stop(ProgramInfo *);
+    void mvexport(ProgramInfo *);
+    unsigned int getLastSeason(QString title);
+    unsigned int getLastEpisode(QString title, unsigned int season);
+    QString replaceExportVariables(ProgramInfo *rec, QString &repString);
     void remove(ProgramInfo *);
     void showActions(ProgramInfo *);
     ProgramInfo *CurrentItem(void);
@@ -282,6 +292,7 @@
 
     bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete);
     void showDeletePopup(deletePopupType);
+    void showExportPopup(ProgramInfo *);
     void showActionPopup(ProgramInfo *program);
     void showFileNotFoundActionPopup(ProgramInfo *program);
     void popupString(ProgramInfo *program, QString &message);
@@ -382,6 +393,8 @@
     // Other state
     /// Program currently selected for deletion
     ProgramInfo *m_delItem;
+    /// Program currently selected for export
+    ProgramInfo *m_expItem;
     /// Program currently selected during an update
     ProgramInfo *m_currentItem;
     /// Group currently selected
@@ -522,6 +535,29 @@
     ProgramInfo *m_progInfo;
 };
 
+class CustomExportEdit : public MythScreenType
+{
+    Q_OBJECT
+
+  public:
+    CustomExportEdit(MythScreenStack *lparent);
+
+    bool Create(void);
+
+  signals:
+    void result(const QString &, const QString &, unsigned int, unsigned int);
+
+  protected slots:   
+    void ReturnExport(void);
+  
+  private:
+    MythUITextEdit     *m_dirEdit;
+    MythUITextEdit     *m_fileEdit; 
+    MythUISpinBox      *m_seasonSpin;
+    MythUISpinBox      *m_episodeSpin;
+
+};
+
 class HelpPopup : public MythScreenType
 {
     Q_OBJECT
