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
12#include <QtGlobal>
13#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
14#include <QtSystemDetection>
15#endif
16#ifdef Q_OS_WINDOWS
17#include <processthreadsapi.h>
18#endif
19
20// Qt
21#include <QApplication>
22#include <QDir>
23#include <QTimer>
24
25// mythtv
31#include <libmythbase/mythversion.h>
36
37// mytharchive
38#include "archivedbcheck.h"
39#include "archivesettings.h"
40#include "archiveutil.h"
41#include "exportnative.h"
42#include "fileselector.h"
43#include "importnative.h"
44#include "logviewer.h"
45#include "mythburn.h"
46#include "recordingselector.h"
47#include "selectdestination.h"
48#include "videoselector.h"
49
50// return true if the process belonging to the lock file is still running
51static bool checkProcess(const QString &lockFile)
52{
53 // read the PID from the lock file
54 QFile file(lockFile);
55
56 bool bOK = file.open(QIODevice::ReadOnly);
57
58 if (!bOK)
59 {
60 LOG(VB_GENERAL, LOG_ERR,
61 QString("Unable to open file %1").arg(lockFile));
62
63 return true;
64 }
65
66 QString line(file.readLine(100));
67
68 pid_t pid = line.toInt(&bOK);
69
70 if (!bOK)
71 {
72 LOG(VB_GENERAL, LOG_ERR,
73 QString("Got bad PID '%1' from lock file").arg(pid));
74 return true;
75 }
76
77 LOG(VB_GENERAL, LOG_NOTICE,
78 QString("Checking if PID %1 is still running").arg(pid));
79
80#ifdef Q_OS_WINDOWS
81 HANDLE handy = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, TRUE, pid);
82 return TerminateProcess(handy,0) == 0;
83#else
84 if (kill(pid, 0) == -1)
85 {
86 if (errno == ESRCH)
87 return false;
88 }
89#endif
90
91 return true;
92}
93
94// return true if a lock file is found and the owning process is still running
95static bool checkLockFile(const QString &lockFile)
96{
97 QFile file(lockFile);
98
99 //is a job already running?
100 if (file.exists())
101 {
102 // Is the process that created the lock still alive?
103 if (!checkProcess(lockFile))
104 {
105 showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
106 "Found a lock file but the owning process isn't running!\n"
107 "Removing stale lock file."));
108 if (!file.remove())
109 {
110 LOG(VB_GENERAL, LOG_ERR,
111 QString("Failed to remove stale lock file - %1")
112 .arg(lockFile));
113 }
114 }
115 else
116 {
117 return true;
118 }
119 }
120
121 return false;
122}
123
124static void runCreateDVD(void)
125{
126 QString tempDir = getTempDirectory(true);
128
129 if (tempDir == "")
130 return;
131
132 QString logDir = tempDir + "logs";
133
135
136 if (checkLockFile(logDir + "/mythburn.lck"))
137 {
138 // a job is already running so just show the log viewer
140 return;
141 }
142
143 // show the select destination dialog
144 auto *dest = new SelectDestination(mainStack, false, "SelectDestination");
145
146 if (dest->Create())
147 mainStack->AddScreen(dest);
148}
149
150static void runCreateArchive(void)
151{
152 QString tempDir = getTempDirectory(true);
154
155 if (tempDir == "")
156 return;
157
158 QString logDir = tempDir + "logs";
159
161
162 if (checkLockFile(logDir + "/mythburn.lck"))
163 {
164 // a job is already running so just show the log viewer
166 return;
167 }
168
169 // show the select destination dialog
170 auto *dest = new SelectDestination(mainStack, true, "SelectDestination");
171
172 if (dest->Create())
173 mainStack->AddScreen(dest);
174}
175
176static void runEncodeVideo(void)
177{
178
179}
180
181static void runImportVideo(void)
182{
183 QString tempDir = getTempDirectory(true);
184
185 if (tempDir == "")
186 return;
187
188 QString logDir = tempDir + "logs";
189
191
192 if (checkLockFile(logDir + "/mythburn.lck"))
193 {
194 // a job is already running so just show the log viewer
196 return;
197 }
198
199 // show the find archive screen
201 auto *selector = new ArchiveFileSelector(mainStack);
202
203 if (selector->Create())
204 mainStack->AddScreen(selector);
205}
206
207static void runShowLog(void)
208{
210}
211
212static void runTestDVD(void)
213{
214 if (!gCoreContext->GetSetting("MythArchiveLastRunType").startsWith("DVD"))
215 {
216 showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
217 "Last run did not create a playable DVD."));
218 return;
219 }
220
221 if (!gCoreContext->GetSetting("MythArchiveLastRunStatus").startsWith("Success"))
222 {
223 showWarningDialog(QCoreApplication::translate("(MythArchiveMain)",
224 "Last run failed to create a DVD."));
225 return;
226 }
227
228 QString tempDir = getTempDirectory(true);
229
230 if (tempDir == "")
231 return;
232
233 QString filename = tempDir + "work/dvd";
234 QString command = gCoreContext->GetSetting("MythArchiveDVDPlayerCmd", "");
235
236 if ((command.indexOf("internal", 0, Qt::CaseInsensitive) > -1) ||
237 (command.length() < 1))
238 {
239 filename = QString("dvd:/") + filename;
240 command = "Internal";
242 return;
243 }
244
245 if (command.contains("%f"))
246 command = command.replace("%f", filename);
247 myth_system(command);
248}
249
250static void runBurnDVD(void)
251{
252 auto *menu = new BurnMenu();
253 menu->start();
254}
255
256// these point to the the mainmenu callback if found
257static void (*m_callback)(void *, QString &) = nullptr;
258static void *m_callbackdata = nullptr;
259
260static void ArchiveCallback([[maybe_unused]] void *data, QString &selection)
261{
262 QString sel = selection.toLower();
263
264 if (sel == "archive_create_dvd") {
265 runCreateDVD();
266 } else if (sel == "archive_create_archive") {
268 } else if (sel == "archive_encode_video") {
270 } else if (sel == "archive_import_video") {
272 } else if (sel == "archive_last_log") {
273 runShowLog();
274 } else if (sel == "archive_test_dvd") {
275 runTestDVD();
276 } else if (sel == "archive_burn_dvd") {
277 runBurnDVD();
278 } else {
279 // if we have found the mainmenu callback
280 // pass the selection on to it
282 m_callback(m_callbackdata, selection);
283 }
284}
285
286static 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 = qobject_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 auto *diag = new MythThemedMenu(themedir, which_menu,
304 GetMythMainWindow()->GetMainStack(),
305 "archive menu");
306
307 // save the callback from the main menu
308 if (mainMenu)
309 {
311 }
312 else
313 {
314 m_callback = nullptr;
315 m_callbackdata = nullptr;
316 }
317
318 diag->setCallback(ArchiveCallback, nullptr);
319 diag->setKillable();
320
321 if (diag->foundTheme())
322 {
324 return 0;
325 }
326
327 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find menu %1 or theme %2")
328 .arg(which_menu, themedir));
329 delete diag;
330 return -1;
331}
332
333static void initKeys(void)
334{
335 REG_KEY("Archive", "TOGGLECUT", QT_TRANSLATE_NOOP("MythControls",
336 "Toggle use cut list state for selected program"), "C");
337
338 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create DVD"),
339 "", "", runCreateDVD);
340 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Create Archive"),
341 "", "", runCreateArchive);
342 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Import Archive"),
343 "", "", runImportVideo);
344 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "View Archive Log"),
345 "", "", runShowLog);
346 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Play Created DVD"),
347 "", "", runTestDVD);
348 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Burn DVD"),
349 "", "", runBurnDVD);
350}
351
352int mythplugin_init(const char *libversion)
353{
354 if (!MythCoreContext::TestPluginVersion("mytharchive", libversion,
355 MYTH_BINARY_VERSION))
356 {
357 LOG(VB_GENERAL, LOG_ERR, "Test Popup Version Failed");
358 return -1;
359 }
360
363 {
364 LOG(VB_GENERAL, LOG_ERR,
365 "Couldn't upgrade database to new schema, exiting.");
366 return -1;
367 }
369
370 ArchiveSettings settings;
371 settings.Load();
372 settings.Save();
373
374 initKeys();
375
376 return 0;
377}
378
380{
381 return runMenu("archivemenu.xml");
382}
383
385{
387 auto *ssd = new StandardSettingDialog(mainStack, "archivesettings",
388 new ArchiveSettings());
389
390 if (ssd->Create())
391 {
392 mainStack->AddScreen(ssd);
393 }
394 else
395 {
396 delete ssd;
397 }
398
399 return 0;
400}
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:95
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:51
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:26
#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()