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([[maybe_unused]] void *data, QString &selection)
256 {
257  QString sel = selection.toLower();
258 
259  if (sel == "archive_create_dvd")
260  runCreateDVD();
261  else if (sel == "archive_create_archive")
263  else if (sel == "archive_encode_video")
264  runEncodeVideo();
265  else if (sel == "archive_import_video")
266  runImportVideo();
267  else if (sel == "archive_last_log")
268  runShowLog();
269  else if (sel == "archive_test_dvd")
270  runTestDVD();
271  else if (sel == "archive_burn_dvd")
272  runBurnDVD();
273  else
274  {
275  // if we have found the mainmenu callback
276  // pass the selection on to it
277  if (m_callback && m_callbackdata)
278  m_callback(m_callbackdata, selection);
279  }
280 }
281 
282 static int runMenu(const QString& which_menu)
283 {
284  // find the 'mainmenu' MythThemedMenu so we can use the callback from it
285  MythThemedMenu *mainMenu = nullptr;
286  QObject *parentObject = GetMythMainWindow()->GetMainStack()->GetTopScreen();
287 
288  while (parentObject)
289  {
290  mainMenu = qobject_cast<MythThemedMenu *>(parentObject);
291 
292  if (mainMenu && mainMenu->objectName() == "mainmenu")
293  break;
294 
295  parentObject = parentObject->parent();
296  }
297 
298  QString themedir = GetMythUI()->GetThemeDir();
299  auto *diag = new MythThemedMenu(themedir, which_menu,
300  GetMythMainWindow()->GetMainStack(),
301  "archive menu");
302 
303  // save the callback from the main menu
304  if (mainMenu)
305  mainMenu->getCallback(&m_callback, &m_callbackdata);
306  else
307  {
308  m_callback = nullptr;
309  m_callbackdata = nullptr;
310  }
311 
312  diag->setCallback(ArchiveCallback, nullptr);
313  diag->setKillable();
314 
315  if (diag->foundTheme())
316  {
318  return 0;
319  }
320 
321  LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find menu %1 or theme %2")
322  .arg(which_menu, themedir));
323  delete diag;
324  return -1;
325 }
326 
327 static void initKeys(void)
328 {
329  REG_KEY("Archive", "TOGGLECUT", QT_TRANSLATE_NOOP("MythControls",
330  "Toggle use cut list state for selected program"), "C");
331 
332  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create DVD"),
333  "", "", runCreateDVD);
334  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create Archive"),
335  "", "", runCreateArchive);
336  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Import Archive"),
337  "", "", runImportVideo);
338  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "View Archive Log"),
339  "", "", runShowLog);
340  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Play Created DVD"),
341  "", "", runTestDVD);
342  REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Burn DVD"),
343  "", "", runBurnDVD);
344 }
345 
346 int mythplugin_init(const char *libversion)
347 {
348  if (!MythCoreContext::TestPluginVersion("mytharchive", libversion,
349  MYTH_BINARY_VERSION))
350  {
351  LOG(VB_GENERAL, LOG_ERR, "Test Popup Version Failed");
352  return -1;
353  }
354 
357  {
358  LOG(VB_GENERAL, LOG_ERR,
359  "Couldn't upgrade database to new schema, exiting.");
360  return -1;
361  }
363 
364  ArchiveSettings settings;
365  settings.Load();
366  settings.Save();
367 
368  initKeys();
369 
370  return 0;
371 }
372 
373 int mythplugin_run(void)
374 {
375  return runMenu("archivemenu.xml");
376 }
377 
379 {
381  auto *ssd = new StandardSettingDialog(mainStack, "archivesettings",
382  new ArchiveSettings());
383 
384  if (ssd->Create())
385  {
386  mainStack->AddScreen(ssd);
387  }
388  else
389  {
390  delete ssd;
391  }
392 
393  return 0;
394 }
themedir
static QString themedir
Definition: mythdirs.cpp:23
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:317
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:282
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:2087
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:378
initKeys
static void initKeys(void)
Definition: mytharchive.cpp:327
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:1496
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:274
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:373
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:55
SelectDestination
Definition: selectdestination.h:20
mythplugin_init
int mythplugin_init(const char *libversion)
Definition: mytharchive.cpp:346
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:150
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:104
UpgradeArchiveDatabaseSchema
bool UpgradeArchiveDatabaseSchema(void)
Definition: archivedbcheck.cpp:18
MythCoreContext::ActivateSettingsCache
void ActivateSettingsCache(bool activate=true)
Definition: mythcorecontext.cpp:837
importnative.h
MythThemedMenu
Themed menu class, used for main menus in MythTV frontend.
Definition: myththemedmenu.h:57
myththemedmenu.h
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
ArchiveCallback
static void ArchiveCallback([[maybe_unused]] void *data, QString &selection)
Definition: mytharchive.cpp:255
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
MythScreenStack::GetTopScreen
virtual MythScreenType * GetTopScreen(void) const
Definition: mythscreenstack.cpp:182
runBurnDVD
static void runBurnDVD(void)
Definition: mytharchive.cpp:245