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