MythTV  0.26-pre
archiveutil.cpp
Go to the documentation of this file.
00001 // POSIX headers
00002 #include <sys/stat.h>
00003 #include <unistd.h>
00004 #include <errno.h>
00005 
00006 // ANSI C headers
00007 #include <cstdlib>
00008 
00009 // C++ headers
00010 #include <iostream>
00011 using namespace std;
00012 
00013 // qt
00014 #include <QDomDocument>
00015 #include <QDir>
00016 
00017 // myth
00018 #include <mythcontext.h>
00019 #include <programinfo.h>
00020 #include <mythmainwindow.h>
00021 #include <mythdialogbox.h>
00022 #include <mythmiscutil.h>
00023 #include <mythsystem.h>
00024 #include <exitcodes.h>
00025 #include <mythlogging.h>
00026 
00027 // mytharchive
00028 #include "archiveutil.h"
00029 
00030 
00031 struct ArchiveDestination ArchiveDestinations[] =
00032 {
00033     {AD_DVD_SL,
00034      QT_TRANSLATE_NOOP("SelectDestination", "Single Layer DVD"),
00035      QT_TRANSLATE_NOOP("SelectDestination", "Single Layer DVD (4,482 MB)"),
00036      4482*1024},
00037     {AD_DVD_DL,
00038      QT_TRANSLATE_NOOP("SelectDestination", "Dual Layer DVD"),
00039      QT_TRANSLATE_NOOP("SelectDestination", "Dual Layer DVD (8,964 MB)"),
00040      8964*1024},
00041     {AD_DVD_RW,
00042      QT_TRANSLATE_NOOP("SelectDestination", "DVD +/- RW"),
00043      QT_TRANSLATE_NOOP("SelectDestination", "Rewritable DVD"),
00044      4482*1024},
00045     {AD_FILE,
00046      QT_TRANSLATE_NOOP("SelectDestination", "File"),
00047      QT_TRANSLATE_NOOP("SelectDestination", "Any file accessable from your filesystem."),
00048      -1},
00049 };
00050 
00051 int ArchiveDestinationsCount = sizeof(ArchiveDestinations) / sizeof(ArchiveDestinations[0]);
00052 
00053 QString formatSize(int64_t sizeKB, int prec)
00054 {
00055     if (sizeKB>1024*1024*1024) // Terabytes
00056     {
00057         double sizeGB = sizeKB/(1024*1024*1024.0);
00058         return QString("%1 TB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
00059     }
00060     else if (sizeKB>1024*1024) // Gigabytes
00061     {
00062         double sizeGB = sizeKB/(1024*1024.0);
00063         return QString("%1 GB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
00064     }
00065     else if (sizeKB>1024) // Megabytes
00066     {
00067         double sizeMB = sizeKB/1024.0;
00068         return QString("%1 MB").arg(sizeMB, 0, 'f', (sizeMB>10)?0:prec);
00069     }
00070     // Kilobytes
00071     return QString("%1 KB").arg(sizeKB);
00072 }
00073 
00074 QString getTempDirectory(bool showError)
00075 {
00076     QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
00077 
00078     if (tempDir == "" && showError)
00079         ShowOkPopup(QObject::tr("Cannot find the MythArchive work directory.\n"
00080                                 "Have you set the correct path in the settings?"),
00081                                 NULL, NULL);
00082 
00083     if (tempDir == "")
00084         return "";
00085 
00086     // make sure the temp directory setting ends with a trailing "/"
00087     if (!tempDir.endsWith("/"))
00088     {
00089         tempDir += "/";
00090         gCoreContext->SaveSetting("MythArchiveTempDir", tempDir);
00091     }
00092 
00093     return tempDir;
00094 }
00095 
00096 void checkTempDirectory()
00097 {
00098     QString tempDir = getTempDirectory();
00099     QString logDir = tempDir + "logs";
00100     QString configDir = tempDir + "config";
00101     QString workDir = tempDir + "work";
00102 
00103     // make sure the 'work', 'logs', and 'config' directories exist
00104     QDir dir(tempDir);
00105     if (!dir.exists())
00106     {
00107         dir.mkdir(tempDir);
00108         if( chmod(qPrintable(tempDir), 0777) )
00109             LOG(VB_GENERAL, LOG_ERR,
00110                 "Failed to change permissions on archive directory: " + ENO);
00111     }
00112 
00113     dir = QDir(workDir);
00114     if (!dir.exists())
00115     {
00116         dir.mkdir(workDir);
00117         if( chmod(qPrintable(workDir), 0777) )
00118             LOG(VB_GENERAL, LOG_ERR,
00119                 "Failed to change permissions on archive work directory: " +
00120                 ENO);
00121     }
00122 
00123     dir = QDir(logDir);
00124     if (!dir.exists())
00125     {
00126         dir.mkdir(logDir);
00127         if( chmod(qPrintable(logDir), 0777) )
00128             LOG(VB_GENERAL, LOG_ERR,
00129                 "Failed to change permissions on archive log directory: " +
00130                 ENO);
00131     }
00132     dir = QDir(configDir);
00133     if (!dir.exists())
00134     {
00135         dir.mkdir(configDir);
00136         if( chmod(qPrintable(configDir), 0777) )
00137             LOG(VB_GENERAL, LOG_ERR, 
00138                 "Failed to change permissions on archive config directory: " +
00139                 ENO);
00140     }
00141 }
00142 
00143 QString getBaseName(const QString &filename)
00144 {
00145     QString baseName = filename;
00146     int pos = filename.lastIndexOf('/');
00147     if (pos > 0)
00148         baseName = filename.mid(pos + 1);
00149 
00150     return baseName;
00151 }
00152 
00153 bool extractDetailsFromFilename(const QString &inFile,
00154                                 QString &chanID, QString &startTime)
00155 {
00156     LOG(VB_JOBQUEUE, LOG_INFO, "Extracting details from: " + inFile);
00157 
00158     QString baseName = getBaseName(inFile);
00159 
00160     MSqlQuery query(MSqlQuery::InitCon());
00161     query.prepare("SELECT chanid, starttime FROM recorded "
00162             "WHERE basename = :BASENAME");
00163     query.bindValue(":BASENAME", baseName);
00164 
00165     if (query.exec() && query.next())
00166     {
00167         chanID = query.value(0).toString();
00168         startTime= query.value(1).toString();
00169     }
00170     else
00171     {
00172         LOG(VB_JOBQUEUE, LOG_ERR,
00173             QString("Cannot find details for %1").arg(inFile));
00174         return false;
00175     }
00176 
00177     LOG(VB_JOBQUEUE, LOG_INFO,
00178         QString("chanid: %1 starttime:%2 ").arg(chanID).arg(startTime));
00179 
00180     return true;
00181 }
00182 
00183 ProgramInfo *getProgramInfoForFile(const QString &inFile)
00184 {
00185     ProgramInfo *pinfo = NULL;
00186     QString chanID, startTime;
00187     bool bIsMythRecording = false;
00188 
00189     bIsMythRecording = extractDetailsFromFilename(inFile, chanID, startTime);
00190 
00191     if (bIsMythRecording)
00192     {
00193         uint chanid = chanID.toUInt();
00194         QDateTime recstartts = myth_dt_from_string(startTime);
00195         pinfo = new ProgramInfo(chanid, recstartts);
00196         if (pinfo->GetChanID())
00197         {
00198             pinfo->SetPathname(pinfo->GetPlaybackURL(false, true));
00199         }
00200         else
00201         {
00202             delete pinfo;
00203             pinfo = NULL;
00204         }
00205     }
00206 
00207     if (!pinfo)
00208     {
00209         // file is not a myth recording or is no longer in the db
00210         pinfo = new ProgramInfo(inFile);
00211         LOG(VB_JOBQUEUE, LOG_NOTICE, "File is not a MythTV recording.");
00212     }
00213     else
00214         LOG(VB_JOBQUEUE, LOG_NOTICE, "File is a MythTV recording.");
00215 
00216     return pinfo;
00217 }
00218 
00219 bool getFileDetails(ArchiveItem *a)
00220 {
00221     QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
00222 
00223     if (!tempDir.endsWith("/"))
00224         tempDir += "/";
00225 
00226     QString inFile;
00227     int lenMethod = 0;
00228     if (a->type == "Recording")
00229     {
00230         inFile = a->filename;
00231         lenMethod = 2;
00232     }
00233     else
00234     {
00235         inFile = a->filename;
00236     }
00237 
00238     inFile.replace("\'", "\\\'");
00239     inFile.replace("\"", "\\\"");
00240     inFile.replace("`", "\\`");
00241 
00242     QString outFile = tempDir + "work/file.xml";
00243 
00244     // call mytharchivehelper to get files stream info etc.
00245     QString command = QString("mytharchivehelper --getfileinfo --infile \"%1\" "
00246                               "--outfile \"%2\" --method %3")
00247             .arg(inFile).arg(outFile).arg(lenMethod);
00248     command += logPropagateArgs;
00249     if (!logPropagateQuiet())
00250         command += " --quiet";
00251 
00252     uint flags = kMSDontBlockInputDevs | kMSDontDisableDrawing;
00253     if (myth_system(command, flags) != GENERIC_EXIT_OK)
00254         return false;
00255 
00256     QDomDocument doc("mydocument");
00257     QFile file(outFile);
00258     if (!file.open(QIODevice::ReadOnly))
00259         return false;
00260 
00261     if (!doc.setContent( &file ))
00262     {
00263         file.close();
00264         return false;
00265     }
00266     file.close();
00267 
00268     // get file type and duration
00269     QDomElement docElem = doc.documentElement();
00270     QDomNodeList nodeList = doc.elementsByTagName("file");
00271     if (nodeList.count() < 1)
00272         return false;
00273     QDomNode n = nodeList.item(0);
00274     QDomElement e = n.toElement();
00275     a->fileCodec = e.attribute("type");
00276     a->duration = e.attribute("duration").toInt();
00277     a->cutDuration = e.attribute("cutduration").toInt();
00278 
00279     // get frame size and video codec
00280     nodeList = doc.elementsByTagName("video");
00281     if (nodeList.count() < 1)
00282         return false;
00283     n = nodeList.item(0);
00284     e = n.toElement();
00285     a->videoCodec = e.attribute("codec");
00286     a->videoWidth = e.attribute("width").toInt();
00287     a->videoHeight = e.attribute("height").toInt();
00288 
00289     return true;
00290 }
00291 
00292 void showWarningDialog(const QString msg)
00293 {
00294     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00295     MythConfirmationDialog *dialog = new MythConfirmationDialog(popupStack, msg, false);
00296 
00297     if (dialog->Create())
00298         popupStack->AddScreen(dialog);
00299 }
00300 
00301 void recalcItemSize(ArchiveItem *item)
00302 {
00303     EncoderProfile *profile = item->encoderProfile;
00304     if (!profile)
00305         return;
00306 
00307     if (profile->name == "NONE")
00308     {
00309         if (item->hasCutlist && item->useCutlist)
00310             item->newsize = (int64_t) (item->size /
00311                     ((float)item->duration / (float)item->cutDuration));
00312         else
00313             item->newsize = item->size;
00314     }
00315     else
00316     {
00317         if (item->duration == 0)
00318             return;
00319 
00320         int length;
00321 
00322         if (item->hasCutlist && item->useCutlist)
00323             length = item->cutDuration;
00324         else
00325             length = item->duration;
00326 
00327         float len = (float) length / 3600;
00328         item->newsize = (int64_t) (len * profile->bitrate * 1024 * 1024);
00329     }
00330 }
00331 
00332 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends