MythTV master
archiveutil.cpp
Go to the documentation of this file.
1// C++ headers
2#include <cerrno>
3#include <cstdlib>
4#include <iostream>
5#include <sys/stat.h>
6#include <unistd.h>
7
8// qt
9#include <QCoreApplication>
10#include <QDir>
11#include <QDomDocument>
12
13// myth
22
23// mytharchive
24#include "archiveutil.h"
25
26std::vector<ArchiveDestination> ArchiveDestinations
27{
28 {AD_DVD_SL,
29 QT_TRANSLATE_NOOP("SelectDestination", "Single Layer DVD"),
30 QT_TRANSLATE_NOOP("SelectDestination", "Single Layer DVD (4,482 MB)"),
31 4482*1024LL},
32 {AD_DVD_DL,
33 QT_TRANSLATE_NOOP("SelectDestination", "Dual Layer DVD"),
34 QT_TRANSLATE_NOOP("SelectDestination", "Dual Layer DVD (8,964 MB)"),
35 8964*1024LL},
36 {AD_DVD_RW,
37 QT_TRANSLATE_NOOP("SelectDestination", "DVD +/- RW"),
38 QT_TRANSLATE_NOOP("SelectDestination", "Rewritable DVD"),
39 4482*1024LL},
40 {AD_FILE,
41 QT_TRANSLATE_NOOP("SelectDestination", "File"),
42 QT_TRANSLATE_NOOP("SelectDestination", "Any file accessable from your filesystem."),
43 -1LL},
44};
45
46QString getTempDirectory(bool showError)
47{
48 QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
49
50 if (tempDir == "" && showError)
51 {
52 ShowOkPopup(QCoreApplication::translate("(ArchiveUtils)",
53 "Cannot find the MythArchive work directory.\n"
54 "Have you set the correct path in the settings?"));
55 }
56
57 if (tempDir == "")
58 return "";
59
60 // make sure the temp directory setting ends with a trailing "/"
61 if (!tempDir.endsWith("/"))
62 {
63 tempDir += "/";
64 gCoreContext->SaveSetting("MythArchiveTempDir", tempDir);
65 }
66
67 return tempDir;
68}
69
71{
72 QString tempDir = getTempDirectory();
73 QString logDir = tempDir + "logs";
74 QString configDir = tempDir + "config";
75 QString workDir = tempDir + "work";
76
77 // make sure the 'work', 'logs', and 'config' directories exist
78 QDir dir(tempDir);
79 if (!dir.exists())
80 {
81 dir.mkdir(tempDir);
82 if( chmod(qPrintable(tempDir), 0777) != 0 )
83 LOG(VB_GENERAL, LOG_ERR,
84 "Failed to change permissions on archive directory: " + ENO);
85 }
86
87 dir.setPath(workDir);;
88 if (!dir.exists())
89 {
90 dir.mkdir(workDir);
91 if( chmod(qPrintable(workDir), 0777) != 0 )
92 {
93 LOG(VB_GENERAL, LOG_ERR,
94 "Failed to change permissions on archive work directory: " +
95 ENO);
96 }
97 }
98
99 dir.setPath(logDir);;
100 if (!dir.exists())
101 {
102 dir.mkdir(logDir);
103 if( chmod(qPrintable(logDir), 0777) != 0 )
104 {
105 LOG(VB_GENERAL, LOG_ERR,
106 "Failed to change permissions on archive log directory: " +
107 ENO);
108 }
109 }
110 dir.setPath(configDir);;
111 if (!dir.exists())
112 {
113 dir.mkdir(configDir);
114 if( chmod(qPrintable(configDir), 0777) != 0 )
115 {
116 LOG(VB_GENERAL, LOG_ERR,
117 "Failed to change permissions on archive config directory: " +
118 ENO);
119 }
120 }
121}
122
123QString getBaseName(const QString &filename)
124{
125 QString baseName = filename;
126 int pos = filename.lastIndexOf('/');
127 if (pos > 0)
128 baseName = filename.mid(pos + 1);
129
130 return baseName;
131}
132
133bool extractDetailsFromFilename(const QString &inFile,
134 QString &chanID, QString &startTime)
135{
136 LOG(VB_JOBQUEUE, LOG_INFO, "Extracting details from: " + inFile);
137
138 QString baseName = getBaseName(inFile);
139
141 query.prepare("SELECT chanid, starttime FROM recorded "
142 "WHERE basename = :BASENAME");
143 query.bindValue(":BASENAME", baseName);
144
145 if (query.exec() && query.next())
146 {
147 chanID = query.value(0).toString();
148 startTime= query.value(1).toString();
149 }
150 else
151 {
152 LOG(VB_JOBQUEUE, LOG_ERR,
153 QString("Cannot find details for %1").arg(inFile));
154 return false;
155 }
156
157 LOG(VB_JOBQUEUE, LOG_INFO,
158 QString("chanid: %1 starttime:%2 ").arg(chanID, startTime));
159
160 return true;
161}
162
163ProgramInfo *getProgramInfoForFile(const QString &inFile)
164{
165 ProgramInfo *pinfo = nullptr;
166 QString chanID;
167 QString startTime;
168
169 bool bIsMythRecording = extractDetailsFromFilename(inFile, chanID, startTime);
170
171 if (bIsMythRecording)
172 {
173 uint chanid = chanID.toUInt();
174 QDateTime recstartts = MythDate::fromString(startTime);
175 pinfo = new ProgramInfo(chanid, recstartts);
176 if (pinfo->GetChanID())
177 {
178 pinfo->SetPathname(pinfo->GetPlaybackURL(false, true));
179 }
180 else
181 {
182 delete pinfo;
183 pinfo = nullptr;
184 }
185 }
186
187 if (!pinfo)
188 {
189 // file is not a myth recording or is no longer in the db
190 pinfo = new ProgramInfo(inFile);
191 LOG(VB_JOBQUEUE, LOG_NOTICE, "File is not a MythTV recording.");
192 }
193 else
194 {
195 LOG(VB_JOBQUEUE, LOG_NOTICE, "File is a MythTV recording.");
196 }
197
198 return pinfo;
199}
200
202{
203 QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
204
205 if (!tempDir.endsWith("/"))
206 tempDir += "/";
207
208 QString inFile;
209 int lenMethod = 0;
210 if (a->type == "Recording")
211 {
212 inFile = a->filename;
213 lenMethod = 2;
214 }
215 else
216 {
217 inFile = a->filename;
218 }
219
220 inFile.replace("\'", "\\\'");
221 inFile.replace("\"", "\\\"");
222 inFile.replace("`", "\\`");
223
224 QString outFile = tempDir + "work/file.xml";
225
226 // call mytharchivehelper to get files stream info etc.
227 QString command = QString("mytharchivehelper --getfileinfo --infile \"%1\" "
228 "--outfile \"%2\" --method %3")
229 .arg(inFile, outFile, QString::number(lenMethod));
230 command += logPropagateArgs;
231 if (!logPropagateQuiet())
232 command += " --quiet";
233
235 if (myth_system(command, flags) != GENERIC_EXIT_OK)
236 return false;
237
238 QDomDocument doc("mydocument");
239 QFile file(outFile);
240 if (!file.open(QIODevice::ReadOnly))
241 return false;
242
243 if (!doc.setContent( &file ))
244 {
245 file.close();
246 return false;
247 }
248 file.close();
249
250 // get file type and duration
251 QDomElement docElem = doc.documentElement();
252 QDomNodeList nodeList = doc.elementsByTagName("file");
253 if (nodeList.count() < 1)
254 return false;
255 QDomNode n = nodeList.item(0);
256 QDomElement e = n.toElement();
257 a->fileCodec = e.attribute("type");
258 a->duration = e.attribute("duration").toInt();
259 a->cutDuration = e.attribute("cutduration").toInt();
260
261 // get frame size and video codec
262 nodeList = doc.elementsByTagName("video");
263 if (nodeList.count() < 1)
264 return false;
265 n = nodeList.item(0);
266 e = n.toElement();
267 a->videoCodec = e.attribute("codec");
268 a->videoWidth = e.attribute("width").toInt();
269 a->videoHeight = e.attribute("height").toInt();
270
271 return true;
272}
273
274void showWarningDialog(const QString &msg)
275{
276 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
277 auto *dialog = new MythConfirmationDialog(popupStack, msg, false);
278
279 if (dialog->Create())
280 popupStack->AddScreen(dialog);
281}
282
284{
286 if (!profile)
287 return;
288
289 if (profile->name == "NONE")
290 {
291 if (item->hasCutlist && item->useCutlist)
292 {
293 item->newsize = (int64_t) (item->size /
294 ((float)item->duration / (float)item->cutDuration));
295 }
296 else
297 {
298 item->newsize = item->size;
299 }
300 }
301 else
302 {
303 if (item->duration == 0)
304 return;
305
306 int length = 0;
307 if (item->hasCutlist && item->useCutlist)
308 length = item->cutDuration;
309 else
310 length = item->duration;
311
312 float len = (float) length / 3600;
313 item->newsize = (int64_t) (len * profile->bitrate * 1024 * 1024);
314 }
315}
316
317/* vim: set expandtab tabstop=4 shiftwidth=4: */
void recalcItemSize(ArchiveItem *item)
void checkTempDirectory()
Definition: archiveutil.cpp:70
bool getFileDetails(ArchiveItem *a)
void showWarningDialog(const QString &msg)
bool extractDetailsFromFilename(const QString &inFile, QString &chanID, QString &startTime)
QString getBaseName(const QString &filename)
std::vector< ArchiveDestination > ArchiveDestinations
Definition: archiveutil.cpp:27
ProgramInfo * getProgramInfoForFile(const QString &inFile)
QString getTempDirectory(bool showError)
Definition: archiveutil.cpp:46
@ AD_DVD_SL
Definition: archiveutil.h:18
@ AD_FILE
Definition: archiveutil.h:21
@ AD_DVD_DL
Definition: archiveutil.h:19
@ AD_DVD_RW
Definition: archiveutil.h:20
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
Dialog asking for user confirmation.
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Holds information on recordings and videos.
Definition: programinfo.h:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
void SetPathname(const QString &pn)
unsigned int uint
Definition: compat.h:68
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
bool logPropagateQuiet(void)
Check if we are propagating a "--quiet".
Definition: logging.cpp:634
QString logPropagateArgs
Definition: logging.cpp:82
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:37
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
int64_t size
Definition: archiveutil.h:60
QString videoCodec
Definition: archiveutil.h:66
bool hasCutlist
Definition: archiveutil.h:69
QString type
Definition: archiveutil.h:53
QString fileCodec
Definition: archiveutil.h:65
int videoHeight
Definition: archiveutil.h:68
int64_t newsize
Definition: archiveutil.h:61
int cutDuration
Definition: archiveutil.h:63
QString filename
Definition: archiveutil.h:59
bool useCutlist
Definition: archiveutil.h:70
EncoderProfile * encoderProfile
Definition: archiveutil.h:64
int videoWidth
Definition: archiveutil.h:67