MythTV  master
mytharchive.cpp
Go to the documentation of this file.
1 /*
2  main.cpp
3 
4  MythArchive - mythtv plugin
5 
6  Starting point for the MythArchive module
7 */
8 #include <csignal>
9 #include <cstdlib>
10 #include <iostream>
11 #ifdef _WIN32
12 #include <processthreadsapi.h>
13 #endif
14 
15 // Qt
16 #include <QApplication>
17 #include <QDir>
18 #include <QTimer>
19 
20 // mythtv
21 #include <libmyth/mythcontext.h>
23 #include <libmythbase/mythplugin.h>
26 #include <libmythbase/mythversion.h>
30 #include <libmythui/mythuihelper.h>
31 
32 // mytharchive
33 #include "archivedbcheck.h"
34 #include "archivesettings.h"
35 #include "archiveutil.h"
36 #include "exportnative.h"
37 #include "fileselector.h"
38 #include "importnative.h"
39 #include "logviewer.h"
40 #include "mythburn.h"
41 #include "recordingselector.h"
42 #include "selectdestination.h"
43 #include "videoselector.h"
44 
45 // return true if the process belonging to the lock file is still running
46 static bool checkProcess(const QString &lockFile)
47 {
48  // read the PID from the lock file
49  QFile file(lockFile);
50 
51  bool bOK = file.open(QIODevice::ReadOnly);
52 
53  if (!bOK)
54  {
55  LOG(VB_GENERAL, LOG_ERR,
56  QString("Unable to open file %1").arg(lockFile));
57 
58  return true;
59  }
60 
61  QString line(file.readLine(100));
62 
63  pid_t pid = line.toInt(&bOK);
64 
65  if (!bOK)
66  {
67  LOG(VB_GENERAL, LOG_ERR,
68  QString("Got bad PID '%1' from lock file").arg(pid));
69  return true;
70  }
71 
72  LOG(VB_GENERAL, LOG_NOTICE,
73  QString("Checking if PID %1 is still running").arg(pid));
74 
75 #ifdef _WIN32
76  HANDLE handy = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, TRUE, pid);
77  return TerminateProcess(handy,0) == 0;
78 #else
79  if (kill(pid, 0) == -1)
80  {
81  if (errno == ESRCH)
82  return false;
83  }
84 #endif
85 
86  return true;
87 }
88 
89 // return true if a lock file is found and the owning process is still running
90 static bool checkLockFile(const QString &lockFile)
91 {
92  QFile file(lockFile);
93 
94  //is a job already running?
95  if (file.exists())
96  {
97  // Is the process that created the lock still alive?
98  if (!checkProcess(lockFile))
99  {
100  showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
101  "Found a lock file but the owning process isn't running!\n"
102  "Removing stale lock file."));
103  if (!file.remove())
104  {
105  LOG(VB_GENERAL, LOG_ERR,
106  QString("Failed to remove stale lock file - %1")
107  .arg(lockFile));
108  }
109  }
110  else
111  {
112  return true;
113  }
114  }
115 
116  return false;
117 }
118 
119 static void runCreateDVD(void)
120 {
121  QString tempDir = getTempDirectory(true);
123 
124  if (tempDir == "")
125  return;
126 
127  QString logDir = tempDir + "logs";
128 
130 
131  if (checkLockFile(logDir + "/mythburn.lck"))
132  {
133  // a job is already running so just show the log viewer
134  showLogViewer();
135  return;
136  }
137 
138  // show the select destination dialog
139  auto *dest = new SelectDestination(mainStack, false, "SelectDestination");
140 
141  if (dest->Create())
142  mainStack->AddScreen(dest);
143 }
144 
145 static void runCreateArchive(void)
146 {
147  QString tempDir = getTempDirectory(true);
149 
150  if (tempDir == "")
151  return;
152 
153  QString logDir = tempDir + "logs";
154 
156 
157  if (checkLockFile(logDir + "/mythburn.lck"))
158  {
159  // a job is already running so just show the log viewer
160  showLogViewer();
161  return;
162  }
163 
164  // show the select destination dialog
165  auto *dest = new SelectDestination(mainStack, true, "SelectDestination");
166 
167  if (dest->Create())
168  mainStack->AddScreen(dest);
169 }
170 
171 static void runEncodeVideo(void)
172 {
173 
174 }
175 
176 static void runImportVideo(void)
177 {
178  QString tempDir = getTempDirectory(true);
179 
180  if (tempDir == "")
181  return;
182 
183  QString logDir = tempDir + "logs";
184 
186 
187  if (checkLockFile(logDir + "/mythburn.lck"))
188  {
189  // a job is already running so just show the log viewer
190  showLogViewer();
191  return;
192  }
193 
194  // show the find archive screen
196  auto *selector = new ArchiveFileSelector(mainStack);
197 
198  if (selector->Create())
199  mainStack->AddScreen(selector);
200 }
201 
202 static void runShowLog(void)
203 {
204  showLogViewer();
205 }
206 
207 static void runTestDVD(void)
208 {
209  if (!gCoreContext->GetSetting("MythArchiveLastRunType").startsWith("DVD"))
210  {
211  showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
212  "Last run did not create a playable DVD."));
213  return;
214  }
215 
216  if (!gCoreContext->GetSetting("MythArchiveLastRunStatus").startsWith("Success"))
217  {
218  showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
219  "Last run failed to create a DVD."));
220  return;
221  }
222 
223  QString tempDir = getTempDirectory(true);
224 
225  if (tempDir == "")
226  return;
227 
228  QString filename = tempDir + "work/dvd";
229  QString command = gCoreContext->GetSetting("MythArchiveDVDPlayerCmd", "");
230 
231  if ((command.indexOf("internal", 0, Qt::CaseInsensitive) > -1) ||
232  (command.length() < 1))
233  {
234  filename = QString("dvd:/") + filename;
235  command = "Internal";
237  return;
238  }
239 
240  if (command.contains("%f"))
241  command = command.replace("%f", filename);
242  myth_system(command);
243 }
244 
245 static void runBurnDVD(void)
246 {
247  auto *menu = new BurnMenu();
248  menu->start();
249 }
250 
251 // these point to the the mainmenu callback if found
252 static void (*m_callback)(void *, QString &) = nullptr;
253 static void *m_callbackdata = nullptr;
254 
255 static void ArchiveCallback(void *data, QString &selection)
256 {
257  (void) data;
258 
259  QString sel = selection.toLower();
260 
261  if (sel == "archive_create_dvd")
262  runCreateDVD();
263  else if (sel == "archive_create_archive")
265  else if (sel == "archive_encode_video")
266  runEncodeVideo();
267  else if (sel == "archive_import_video")
268  runImportVideo();
269  else if (sel == "archive_last_log")
270  runShowLog();
271  else if (sel == "archive_test_dvd")
272  runTestDVD();
273  else if (sel == "archive_burn_dvd")
274  runBurnDVD();
275  else
276  {
277  // if we have found the mainmenu callback
278  // pass the selection on to it
279  if (m_callback && m_callbackdata)
280  m_callback(m_callbackdata, selection);
281  }
282 }
283 
284 static int runMenu(const QString& which_menu)
285 {
286  // find the 'mainmenu' MythThemedMenu so we can use the callback from it
287  MythThemedMenu *mainMenu = nullptr;
288  QObject *parentObject = GetMythMainWindow()->GetMainStack()->GetTopScreen();
289 
290  while (parentObject)
291  {
292  mainMenu = qobject_cast<MythThemedMenu *>(parentObject);
293 
294  if (mainMenu && mainMenu->objectName() == "mainmenu")
295  break;
296 
297  parentObject = parentObject->parent();
298  }
299 
300  QString themedir = GetMythUI()->GetThemeDir();
301  auto *diag = new MythThemedMenu(themedir, which_menu,
302  GetMythMainWindow()->GetMainStack(),
303  "archive menu");
304 
305  // save the callback from the main menu
306  if (mainMenu)
307  mainMenu->getCallback(&m_callback, &m_callbackdata);
308  else
309  {
310  m_callback = nullptr;
311  m_callbackdata = nullptr;
312  }
313 
314  diag->setCallback(ArchiveCallback, nullptr);
315  diag->setKillable();
316 
317  if (diag->foundTheme())
318  {
320  return 0;
321  }
322 
323  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find menu %1 or theme %2")
324  .arg(which_menu, themedir));
325  delete diag;
326  return -1;
327 }
328 
329 static void initKeys(void)
330 {
331  REG_KEY("Archive", "TOGGLECUT", QT_TRANSLATE_NOOP("MythControls",
332  "Toggle use cut list state for selected program"), "C");
333 
334  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create DVD"),
335  "", "", runCreateDVD);
336  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create Archive"),
337  "", "", runCreateArchive);
338  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Import Archive"),
339  "", "", runImportVideo);
340  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "View Archive Log"),
341  "", "", runShowLog);
342  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Play Created DVD"),
343  "", "", runTestDVD);
344  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Burn DVD"),
345  "", "", runBurnDVD);
346 }
347 
348 int mythplugin_init(const char *libversion)
349 {
350  if (!MythCoreContext::TestPluginVersion("mytharchive", libversion,
351  MYTH_BINARY_VERSION))
352  {
353  LOG(VB_GENERAL, LOG_ERR, "Test Popup Version Failed");
354  return -1;
355  }
356 
359  {
360  LOG(VB_GENERAL, LOG_ERR,
361  "Couldn't upgrade database to new schema, exiting.");
362  return -1;
363  }
365 
366  ArchiveSettings settings;
367  settings.Load();
368  settings.Save();
369 
370  initKeys();
371 
372  return 0;
373 }
374 
375 int mythplugin_run(void)
376 {
377  return runMenu("archivemenu.xml");
378 }
379 
381 {
383  auto *ssd = new StandardSettingDialog(mainStack, "archivesettings",
384  new ArchiveSettings());
385 
386  if (ssd->Create())
387  {
388  mainStack->AddScreen(ssd);
389  }
390  else
391  delete ssd;
392 
393  return 0;
394 }
themedir
static QString themedir
Definition: mythdirs.cpp:21
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:315
build_compdb.dest
dest
Definition: build_compdb.py:9
archivesettings.h
exportnative.h
REG_KEY
static void REG_KEY(const QString &Context, const QString &Action, const QString &Description, const QString &Key)
Definition: mythmainwindow.h:175
runTestDVD
static void runTestDVD(void)
Definition: mytharchive.cpp:207
fileselector.h
checkProcess
static bool checkProcess(const QString &lockFile)
Definition: mytharchive.cpp:46
mythplugin.h
runMenu
static int runMenu(const QString &which_menu)
Definition: mytharchive.cpp:284
mythcoreutil.h
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
logviewer.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythCoreContext::TestPluginVersion
static bool TestPluginVersion(const QString &name, const QString &libversion, const QString &pluginversion)
Definition: mythcorecontext.cpp:2049
build_compdb.file
file
Definition: build_compdb.py:55
checkLockFile
static bool checkLockFile(const QString &lockFile)
Definition: mytharchive.cpp:90
myth_system
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
Definition: mythsystemlegacy.cpp:506
getTempDirectory
QString getTempDirectory(bool showError)
Definition: archiveutil.cpp:46
runCreateDVD
static void runCreateDVD(void)
Definition: mytharchive.cpp:119
mythplugin_config
int mythplugin_config(void)
Definition: mytharchive.cpp:380
initKeys
static void initKeys(void)
Definition: mytharchive.cpp:329
MythMainWindow::HandleMedia
bool HandleMedia(const QString &Handler, const QString &Mrl, const QString &Plot="", const QString &Title="", const QString &Subtitle="", const QString &Director="", int Season=0, int Episode=0, const QString &Inetref="", std::chrono::minutes LenMins=2h, const QString &Year="1895", const QString &Id="", bool UseBookmarks=false)
Definition: mythmainwindow.cpp:1489
m_callback
static void(* m_callback)(void *, QString &)
Definition: mytharchive.cpp:252
selectdestination.h
mythsystemlegacy.h
runImportVideo
static void runImportVideo(void)
Definition: mytharchive.cpp:176
showWarningDialog
void showWarningDialog(const QString &msg)
Definition: archiveutil.cpp:272
recordingselector.h
StandardSettingDialog
Definition: standardsettings.h:468
archiveutil.h
menu
static MythThemedMenu * menu
Definition: mythtv-setup.cpp:58
MythUIThemeHelper::GetThemeDir
QString GetThemeDir()
Definition: mythuithemehelper.cpp:141
ArchiveFileSelector
Definition: importnative.h:47
StandardSetting::Load
virtual void Load(void)
Definition: standardsettings.cpp:214
videoselector.h
mythplugin_run
int mythplugin_run(void)
Definition: mytharchive.cpp:375
runCreateArchive
static void runCreateArchive(void)
Definition: mytharchive.cpp:145
m_callbackdata
static void * m_callbackdata
Definition: mytharchive.cpp:253
showLogViewer
void showLogViewer(void)
Definition: logviewer.cpp:24
StandardSetting::Save
virtual void Save(void)
Definition: standardsettings.cpp:233
checkTempDirectory
void checkTempDirectory()
Definition: archiveutil.cpp:70
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
SelectDestination
Definition: selectdestination.h:20
mythplugin_init
int mythplugin_init(const char *libversion)
Definition: mytharchive.cpp:348
mythpluginapi.h
ArchiveSettings
Definition: archivesettings.h:15
runEncodeVideo
static void runEncodeVideo(void)
Definition: mytharchive.cpp:171
mythuihelper.h
BurnMenu
Definition: mythburn.h:136
runShowLog
static void runShowLog(void)
Definition: mytharchive.cpp:202
MythThemedMenu::getCallback
void getCallback(void(**lcallback)(void *, QString &), void **data)
Get the themed menus callback function and data for that function.
Definition: myththemedmenu.cpp:148
mythburn.h
archivedbcheck.h
REG_JUMP
static void REG_JUMP(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void))
Definition: mythmainwindow.h:188
mythcontext.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
UpgradeArchiveDatabaseSchema
bool UpgradeArchiveDatabaseSchema(void)
Definition: archivedbcheck.cpp:18
MythCoreContext::ActivateSettingsCache
void ActivateSettingsCache(bool activate=true)
Definition: mythcorecontext.cpp:831
importnative.h
MythThemedMenu
Themed menu class, used for main menus in MythTV frontend.
Definition: myththemedmenu.h:57
myththemedmenu.h
ArchiveCallback
static void ArchiveCallback(void *data, QString &selection)
Definition: mytharchive.cpp:255
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
build_compdb.filename
filename
Definition: build_compdb.py:21
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:896
MythScreenStack::GetTopScreen
virtual MythScreenType * GetTopScreen(void) const
Definition: mythscreenstack.cpp:182
runBurnDVD
static void runBurnDVD(void)
Definition: mytharchive.cpp:245