00001
00002
00003
00004
00005
00006
00007
00008 #include "config.h"
00009
00010 #include <iostream>
00011 #include <cstdlib>
00012 #include <signal.h>
00013
00014 using namespace std;
00015
00016
00017 #include <qapplication.h>
00018 #include <qdir.h>
00019 #include <qtimer.h>
00020
00021
00022 #include <mythtv/mythcontext.h>
00023 #include <mythtv/mythplugin.h>
00024 #include <mythtv/dialogbox.h>
00025 #include <mythtv/util.h>
00026 #include <mythtv/libmythui/myththemedmenu.h>
00027 #include <mythtv/mythpluginapi.h>
00028
00029
00030 #include "archivesettings.h"
00031 #include "logviewer.h"
00032 #include "fileselector.h"
00033 #include "recordingselector.h"
00034 #include "videoselector.h"
00035 #include "dbcheck.h"
00036 #include "archiveutil.h"
00037
00038 #ifdef CREATE_DVD
00039 #include "mythburnwizard.h"
00040 #endif
00041
00042 #ifdef CREATE_NATIVE
00043 #include "exportnativewizard.h"
00044 #include "importnativewizard.h"
00045 #endif
00046
00047
00048 bool checkProcess(const QString &lockFile)
00049 {
00050
00051 QFile file(lockFile);
00052 file.open(IO_ReadOnly);
00053 QString line;
00054
00055 file.readLine(line, 100);
00056
00057 bool bOK = false;
00058 pid_t pid = line.toInt(&bOK);
00059
00060 if (!bOK)
00061 {
00062 VERBOSE(VB_GENERAL, QString("Got bad PID '%1' from lock file").arg(pid));
00063 return true;
00064 }
00065
00066 VERBOSE(VB_GENERAL, QString("Checking if PID %1 is still running").arg(pid));
00067
00068 if (kill(pid, 0) == -1)
00069 {
00070 if (errno == ESRCH)
00071 return false;
00072 }
00073
00074 return true;
00075 }
00076
00077
00078 bool checkLockFile(const QString &lockFile)
00079 {
00080 QFile file(lockFile);
00081
00082
00083 if (file.exists())
00084 {
00085
00086 if (!checkProcess(lockFile))
00087 {
00088 showWarningDialog(QObject::tr("Found a lock file but the owning process isn't running!\n"
00089 "Removing stale lock file."));
00090 if (!file.remove())
00091 VERBOSE(VB_IMPORTANT, QString("Failed to remove stale lock file - %1")
00092 .arg(lockFile));
00093 }
00094 else
00095 {
00096 return true;
00097 }
00098 }
00099
00100 return false;
00101 }
00102
00103 void runCreateDVD(void)
00104 {
00105 #ifdef CREATE_DVD
00106 QString commandline;
00107 QString tempDir = getTempDirectory(true);
00108
00109 if (tempDir == "")
00110 return;
00111
00112 QString logDir = tempDir + "logs";
00113 QString configDir = tempDir + "config";
00114 QString workDir = tempDir + "work";
00115
00116 checkTempDirectory();
00117
00118 if (checkLockFile(logDir + "/mythburn.lck"))
00119 {
00120
00121 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00122 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00123 dialog.exec();
00124 return;
00125 }
00126
00127
00128 MythburnWizard *burnWiz;
00129
00130 burnWiz = new MythburnWizard(gContext->GetMainWindow(),
00131 "mythburn_wizard", "mythburn-");
00132 qApp->unlock();
00133 DialogCode res = burnWiz->exec();
00134 qApp->lock();
00135 qApp->processEvents();
00136 delete burnWiz;
00137
00138 if (kDialogCodeRejected == res)
00139 return;
00140
00141
00142 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00143 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00144 dialog.exec();
00145 #else
00146 cout << "DVD creation is not compiled in!!" << endl;
00147 #endif
00148 }
00149
00150 void runCreateArchive(void)
00151 {
00152 #ifdef CREATE_NATIVE
00153 QString commandline;
00154 QString tempDir = getTempDirectory(true);
00155
00156 if (tempDir == "")
00157 return;
00158
00159 QString logDir = tempDir + "logs";
00160 QString configDir = tempDir + "config";
00161 QString workDir = tempDir + "work";
00162
00163 checkTempDirectory();
00164
00165 if (checkLockFile(logDir + "/mythburn.lck"))
00166 {
00167
00168 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00169 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00170 dialog.exec();
00171 return;
00172 }
00173
00174
00175 ExportNativeWizard *nativeWiz;
00176
00177 nativeWiz = new ExportNativeWizard(gContext->GetMainWindow(),
00178 "exportnative_wizard", "mythnative-");
00179 qApp->unlock();
00180 DialogCode res = nativeWiz->exec();
00181 qApp->lock();
00182 qApp->processEvents();
00183 delete nativeWiz;
00184
00185 if (kDialogCodeRejected == res)
00186 return;
00187
00188
00189 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00190 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00191 dialog.exec();
00192 #else
00193 cout << "Native archive creation is not compiled in!!" << endl;
00194 #endif
00195 }
00196
00197 void runEncodeVideo(void)
00198 {
00199
00200 }
00201
00202 void runImportVideo(void)
00203 {
00204 #ifdef CREATE_NATIVE
00205 QString tempDir = getTempDirectory(true);
00206
00207 if (tempDir == "")
00208 return;
00209
00210 QString logDir = tempDir + "logs";
00211 QString configDir = tempDir + "config";
00212 QString workDir = tempDir + "work";
00213
00214 checkTempDirectory();
00215
00216 if (checkLockFile(logDir + "/mythburn.lck"))
00217 {
00218
00219 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00220 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00221 dialog.exec();
00222 return;
00223 }
00224
00225 QString filter = "*.xml";
00226
00227 ImportNativeWizard wiz("/", filter, gContext->GetMainWindow(),
00228 "import_native_wizard", "mythnative-", "import native wizard");
00229 qApp->unlock();
00230 DialogCode res = wiz.exec();
00231 qApp->lock();
00232
00233 if (kDialogCodeRejected == res)
00234 return;
00235
00236
00237 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00238 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00239 dialog.exec();
00240 #else
00241 cout << "Native archive creation is not compiled in!!" << endl;
00242 #endif
00243 }
00244
00245 void runShowLog(void)
00246 {
00247 QString tempDir = getTempDirectory(true);
00248
00249 if (tempDir == "")
00250 return;
00251
00252 QString logDir = tempDir + "logs";
00253
00254
00255 if (QFile::exists(logDir + "/progress.log") || QFile::exists(logDir + "/mythburn.log"))
00256 {
00257 LogViewer dialog(gContext->GetMainWindow(), "logviewer");
00258 dialog.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00259 dialog.exec();
00260 }
00261 else
00262 showWarningDialog(QObject::tr("Cannot find any logs to show!"));
00263 }
00264
00265 void runTestDVD(void)
00266 {
00267 if (!gContext->GetSetting("MythArchiveLastRunType").startsWith("DVD"))
00268 {
00269 showWarningDialog(QObject::tr("Last run did not create a playable DVD."));
00270 return;
00271 }
00272
00273 if (!gContext->GetSetting("MythArchiveLastRunStatus").startsWith("Success"))
00274 {
00275 showWarningDialog(QObject::tr("Last run failed to create a DVD."));
00276 return;
00277 }
00278
00279 QString tempDir = getTempDirectory(true);
00280
00281 if (tempDir == "")
00282 return;
00283
00284 QString filename = tempDir + "work/dvd/";
00285 QString command = gContext->GetSetting("MythArchiveDVDPlayerCmd", "");
00286
00287 if ((command.find("internal", 0, false) > -1) || (command.length() < 1))
00288 {
00289 filename = QString("dvd:/") + filename;
00290 command = "Internal";
00291 gContext->GetMainWindow()->HandleMedia(command, filename);
00292 return;
00293 }
00294 else
00295 {
00296 if (command.contains("%f"))
00297 command = command.replace(QRegExp("%f"), filename);
00298 myth_system(command);
00299 }
00300 }
00301
00302 void runBurnDVD(void)
00303 {
00304 if (!gContext->GetSetting("MythArchiveLastRunStatus").startsWith("Success"))
00305 {
00306 showWarningDialog(QObject::tr("Cannot burn a DVD.\nThe last run failed to create a DVD."));
00307 return;
00308 }
00309
00310
00311 DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
00312 QObject::tr("\nPlace a blank DVD in the drive and select an option below."));
00313
00314 dialog->AddButton(QObject::tr("Burn DVD"));
00315 dialog->AddButton(QObject::tr("Burn DVD Rewritable"));
00316 dialog->AddButton(QObject::tr("Burn DVD Rewritable (Force Erase)"));
00317 dialog->AddButton(QObject::tr("Cancel"));
00318
00319 DialogCode res = dialog->exec();
00320 dialog->deleteLater();
00321
00322
00323 if ((kDialogCodeButton3 == res) || (kDialogCodeRejected == res))
00324 return;
00325
00326 int fmt = MythDialog::CalcItemIndex(res);
00327 if ((fmt < 0) || (fmt > 2))
00328 return;
00329
00330 QString tempDir = getTempDirectory(true);
00331
00332 if (tempDir == "")
00333 return;
00334
00335 QString logDir = tempDir + "logs";
00336 QString configDir = tempDir + "config";
00337 QString commandline;
00338
00339
00340 if (QFile::exists(logDir + "/progress.log"))
00341 QFile::remove(logDir + "/progress.log");
00342
00343
00344 if (QFile::exists(logDir + "/mythburncancel.lck"))
00345 QFile::remove(logDir + "/mythburncancel.lck");
00346
00347 QString sArchiveFormat = QString::number(fmt);
00348 QString sEraseDVDRW = (kDialogCodeButton2 == res) ? "1" : "0";
00349 QString sNativeFormat = (gContext->GetSetting("MythArchiveLastRunType").startsWith("Native") ? "1" : "0");
00350
00351 commandline = "mytharchivehelper -b " + sArchiveFormat + " " + sEraseDVDRW + " " + sNativeFormat;
00352 commandline += " > " + logDir + "/progress.log 2>&1 &";
00353 int state = system(commandline);
00354
00355 if (state != 0)
00356 {
00357 showWarningDialog(QObject::tr("It was not possible to run mytharchivehelper to burn the DVD."));
00358 return;
00359 }
00360
00361
00362 LogViewer logViewer(gContext->GetMainWindow(), "logviewer");
00363 logViewer.setFilenames(logDir + "/progress.log", logDir + "/mythburn.log");
00364 logViewer.exec();
00365 }
00366
00367 void runRecordingSelector(void)
00368 {
00369 RecordingSelector selector(gContext->GetMainWindow(),
00370 "recording_selector", "mytharchive-", "recording selector");
00371 qApp->unlock();
00372 selector.exec();
00373 qApp->lock();
00374 }
00375
00376 void runVideoSelector(void)
00377 {
00378 MSqlQuery query(MSqlQuery::InitCon());
00379 query.prepare("SELECT title FROM videometadata");
00380 query.exec();
00381 if (query.isActive() && query.numRowsAffected())
00382 {
00383 }
00384 else
00385 {
00386 MythPopupBox::showOkPopup(gContext->GetMainWindow(), QObject::tr("Video Selector"),
00387 QObject::tr("You don't have any videos!"));
00388 return;
00389 }
00390
00391 VideoSelector selector(gContext->GetMainWindow(),
00392 "video_selector", "mytharchive-", "video selector");
00393 qApp->unlock();
00394 selector.exec();
00395 qApp->lock();
00396 }
00397
00398 void runFileSelector(void)
00399 {
00400 QString filter = gContext->GetSetting("MythArchiveFileFilter",
00401 "*.mpg *.mpeg *.mov *.avi *.nuv");
00402
00403 FileSelector selector(FSTYPE_FILELIST, "/", filter, gContext->GetMainWindow(),
00404 "file_selector", "mytharchive-", "file selector");
00405 qApp->unlock();
00406 selector.exec();
00407 qApp->lock();
00408 }
00409
00410 void SelectorCallback(void *data, QString &selection)
00411 {
00412 (void) data;
00413
00414 QString sel = selection.lower();
00415
00416 if (sel == "archive_select_recordings")
00417 runRecordingSelector();
00418 else if (sel == "archive_select_videos")
00419 runVideoSelector();
00420 else if (sel == "archive_select_files")
00421 runFileSelector();
00422 }
00423
00424 void runSelectMenu(QString which_menu)
00425 {
00426 QString themedir = gContext->GetThemeDir();
00427 MythThemedMenu *diag = new MythThemedMenu(themedir.ascii(), which_menu,
00428 GetMythMainWindow()->GetMainStack(),
00429 "select menu");
00430 diag->setCallback(SelectorCallback, NULL);
00431 diag->setKillable();
00432
00433 if (diag->foundTheme())
00434 {
00435 GetMythMainWindow()->GetMainStack()->AddScreen(diag);
00436 }
00437 else
00438 {
00439 cerr << "Couldn't find theme " << themedir << endl;
00440 }
00441 }
00442
00443 void FormatCallback(void *data, QString &selection)
00444 {
00445 (void) data;
00446
00447 QString sel = selection.lower();
00448 if (sel == "archive_create_dvd")
00449 runCreateDVD();
00450 else if (sel == "archive_create_archive")
00451 runCreateArchive();
00452 else if (sel == "archive_encode_video")
00453 runEncodeVideo();
00454 }
00455
00456 void runFormatMenu(QString which_menu)
00457 {
00458 QString themedir = gContext->GetThemeDir();
00459 MythThemedMenu *diag = new MythThemedMenu(themedir.ascii(), which_menu,
00460 GetMythMainWindow()->GetMainStack(),
00461 "format menu");
00462 diag->setCallback(FormatCallback, NULL);
00463 diag->setKillable();
00464
00465 if (diag->foundTheme())
00466 {
00467 GetMythMainWindow()->GetMainStack()->AddScreen(diag);
00468 }
00469 else
00470 {
00471 cerr << "Couldn't find theme " << themedir << endl;
00472 }
00473 }
00474
00475 void ArchiveCallback(void *data, QString &selection)
00476 {
00477 (void) data;
00478
00479 QString sel = selection.lower();
00480
00481 if (sel == "archive_finder")
00482 runSelectMenu("archiveselect.xml");
00483 else if (sel == "archive_export_video")
00484 runFormatMenu("archiveformat.xml");
00485 else if (sel == "archive_import_video")
00486 runImportVideo();
00487 else if (sel == "archive_last_log")
00488 runShowLog();
00489 else if (sel == "archive_test_dvd")
00490 runTestDVD();
00491 else if (sel == "archive_burn_dvd")
00492 runBurnDVD();
00493 }
00494
00495 void runMenu(QString which_menu)
00496 {
00497 QString themedir = gContext->GetThemeDir();
00498
00499 MythThemedMenu *diag = new MythThemedMenu(themedir.ascii(), which_menu,
00500 GetMythMainWindow()->GetMainStack(),
00501 "archive menu");
00502
00503 diag->setCallback(ArchiveCallback, NULL);
00504 diag->setKillable();
00505
00506 if (diag->foundTheme())
00507 {
00508 GetMythMainWindow()->GetMainStack()->AddScreen(diag);
00509 }
00510 else
00511 {
00512 cerr << "Couldn't find theme " << themedir << endl;
00513 }
00514 }
00515
00516 void initKeys(void)
00517 {
00518 REG_KEY("Archive", "TOGGLECUT", "Toggle use cut list state for selected program", "C");
00519 }
00520
00521 int mythplugin_init(const char *libversion)
00522 {
00523 if (!gContext->TestPopupVersion("mytharchive", libversion,
00524 MYTH_BINARY_VERSION))
00525 {
00526 cerr << "Test Popup Version Failed " << endl;
00527 return -1;
00528 }
00529
00530 gContext->ActivateSettingsCache(false);
00531 if (!UpgradeArchiveDatabaseSchema())
00532 {
00533 VERBOSE(VB_IMPORTANT,
00534 "Couldn't upgrade database to new schema, exiting.");
00535 return -1;
00536 }
00537 gContext->ActivateSettingsCache(false);
00538
00539 ArchiveSettings mpSettings;
00540 mpSettings.load();
00541 mpSettings.save();
00542
00543 initKeys();
00544
00545 return 0;
00546 }
00547
00548 int mythplugin_run(void)
00549 {
00550 runMenu("archivemenu.xml");
00551
00552 return 0;
00553 }
00554
00555 int mythplugin_config(void)
00556 {
00557 ArchiveSettings settings;
00558 settings.exec();
00559
00560 return 0;
00561 }