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
26#include <libmythbase/mythversion.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
46static 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
90static 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
119static 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
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
145static 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
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
171static void runEncodeVideo(void)
172{
173
174}
175
176static 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
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
202static void runShowLog(void)
203{
205}
206
207static 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
245static void runBurnDVD(void)
246{
247 auto *menu = new BurnMenu();
248 menu->start();
249}
250
251// these point to the the mainmenu callback if found
252static void (*m_callback)(void *, QString &) = nullptr;
253static void *m_callbackdata = nullptr;
254
255static 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")
265 else if (sel == "archive_import_video")
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
278 m_callback(m_callbackdata, selection);
279 }
280}
281
282static 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)
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
327static 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
346int 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
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}
bool UpgradeArchiveDatabaseSchema(void)
void checkTempDirectory()
Definition: archiveutil.cpp:70
void showWarningDialog(const QString &msg)
QString getTempDirectory(bool showError)
Definition: archiveutil.cpp:46
void ActivateSettingsCache(bool activate=true)
QString GetSetting(const QString &key, const QString &defaultval="")
static bool TestPluginVersion(const QString &name, const QString &libversion, const QString &pluginversion)
MythScreenStack * GetMainStack()
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)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
virtual MythScreenType * GetTopScreen(void) const
Themed menu class, used for main menus in MythTV frontend.
void getCallback(void(**lcallback)(void *, QString &), void **data)
Get the themed menus callback function and data for that function.
virtual void Save(void)
virtual void Load(void)
void showLogViewer(void)
Definition: logviewer.cpp:26
static bool checkLockFile(const QString &lockFile)
Definition: mytharchive.cpp:90
static void runTestDVD(void)
int mythplugin_config(void)
static void runCreateDVD(void)
static void(* m_callback)(void *, QString &)
static void runBurnDVD(void)
static bool checkProcess(const QString &lockFile)
Definition: mytharchive.cpp:46
static void initKeys(void)
static void runImportVideo(void)
static int runMenu(const QString &which_menu)
static void runEncodeVideo(void)
static void ArchiveCallback(void *data, QString &selection)
static void runShowLog(void)
int mythplugin_run(void)
int mythplugin_init(const char *libversion)
static void runCreateArchive(void)
static void * m_callbackdata
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static QString themedir
Definition: mythdirs.cpp:23
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
static void REG_JUMP(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void))
static void REG_KEY(const QString &Context, const QString &Action, const QString &Description, const QString &Key)
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
static MythThemedMenu * menu
MythUIHelper * GetMythUI()