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