MythTV  master
recordingutils.cpp
Go to the documentation of this file.
1 
2 // C++ includes
3 #include <algorithm> // for max
4 #include <iostream> // for cout, endl
5 #include <sys/stat.h>
6 
7 // Qt
8 #include <QFileInfo>
9 #include <QScopedPointer>
10 
11 // libmyth* includes
12 #include "libmythbase/exitcodes.h"
13 #include "libmythbase/mythdirs.h"
15 #include "libmythbase/mythsystem.h"
16 #include "libmythbase/remotefile.h"
17 #include "libmythbase/remoteutil.h"
18 #include "libmythbase/stringutil.h"
19 
20 // Local includes
21 #include "recordingutils.h"
22 
23 static QString CreateProgramInfoString(const ProgramInfo &pginfo)
24 {
25  QDateTime recstartts = pginfo.GetRecordingStartTime();
26  QDateTime recendts = pginfo.GetRecordingEndTime();
27 
28  QString timedate = QString("%1 - %2")
29  .arg(MythDate::toString(
32 
33  QString title = pginfo.GetTitle();
34 
35  QString extra;
36 
37  if (!pginfo.GetSubtitle().isEmpty())
38  {
39  extra = QString(" ~ ") + pginfo.GetSubtitle();
40 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
41  int maxll = std::max(title.length(), 20);
42 #else
43  int maxll = std::max(title.length(), 20LL);
44 #endif
45  if (extra.length() > maxll)
46  extra = extra.left(maxll - 3) + "...";
47  }
48 
49  return QString("%1%2 - %3").arg(title, extra, timedate);
50 }
51 
53 {
54  std::cout << "Checking Recordings" << std::endl;
55 
56  std::vector<ProgramInfo *> *recordingList = RemoteGetRecordedList(-1);
57  std::vector<ProgramInfo *> missingRecordings;
58  std::vector<ProgramInfo *> zeroByteRecordings;
59  std::vector<ProgramInfo *> noSeektableRecordings;
60 
61  if (!recordingList)
62  {
63  std::cout << "ERROR - failed to get recording list from backend" << std::endl;
64  return GENERIC_EXIT_NOT_OK;
65  }
66 
67  bool fixSeektable = cmdline.toBool("fixseektable");
68 
69  std::cout << "Fix seektable is: " << fixSeektable << std::endl;
70 
71  if (!recordingList->empty())
72  {
73  for (auto i = recordingList->begin(); i != recordingList->end(); ++i)
74  {
75  ProgramInfo *p = *i;
76  // ignore live tv and deleted recordings
77  if (p->GetRecordingGroup() == "LiveTV" ||
78  p->GetRecordingGroup() == "Deleted")
79  {
80  i = recordingList->erase(i);
81  --i;
82  continue;
83  }
84 
85  std::cout << "Checking: " << qPrintable(CreateProgramInfoString(*p)) << std::endl;
86  bool foundFile = true;
87 
88  QString url = p->GetPlaybackURL();
89 
90  if (url.startsWith('/'))
91  {
92  QFileInfo fi(url);
93  if (!fi.exists())
94  {
95  std::cout << "File not found" << std::endl;
96  missingRecordings.push_back(p);
97  foundFile = false;
98  }
99  else
100  {
101  if (fi.size() == 0)
102  {
103  std::cout << "File was found but has zero length" << std::endl;
104  zeroByteRecordings.push_back(p);
105  }
106  }
107  }
108  else if (url.startsWith("myth:"))
109  {
110  if (!RemoteFile::Exists(url))
111  {
112  std::cout << "File not found" << std::endl;
113  missingRecordings.push_back(p);
114  foundFile = false;
115  }
116  else
117  {
118  RemoteFile rf(url);
119  if (rf.GetFileSize() == 0)
120  {
121  std::cout << "File was found but has zero length" << std::endl;
122  zeroByteRecordings.push_back(p);
123  }
124  }
125  }
126 
127  frm_pos_map_t posMap;
128  p->QueryPositionMap(posMap, MARK_GOP_BYFRAME);
129  if (posMap.isEmpty())
130  p->QueryPositionMap(posMap, MARK_GOP_START);
131  if (posMap.isEmpty())
132  p->QueryPositionMap(posMap, MARK_KEYFRAME);
133 
134  if (posMap.isEmpty())
135  {
136  std::cout << "No seektable found" << std::endl;
137 
138  noSeektableRecordings.push_back(p);
139 
140  if (foundFile && fixSeektable)
141  {
142  QString command = GetAppBinDir() + "mythcommflag " +
143  QString("--rebuild --chanid %1 --starttime %2")
144  .arg(p->GetChanID())
145  .arg(p->GetRecordingStartTime(MythDate::ISODate));
146  std::cout << "Running - " << qPrintable(command) << std::endl;
147  QScopedPointer<MythSystem> cmd(MythSystem::Create(command));
148  cmd->Wait(0s);
149  if (cmd.data()->GetExitCode() != GENERIC_EXIT_OK)
150  {
151  std::cout << "ERROR - mythcommflag exited with result: " << cmd.data()->GetExitCode() << std::endl;
152  }
153  }
154  }
155 
156  std::cout << "-------------------------------------------------------------------" << std::endl;
157  }
158  }
159 
160  if (!missingRecordings.empty())
161  {
162  std::cout << std::endl << std::endl;
163  std::cout << "MISSING RECORDINGS" << std::endl;
164  std::cout << "------------------" << std::endl;
165  for (auto *p : missingRecordings)
166  {
167  std::cout << qPrintable(CreateProgramInfoString(*p)) << std::endl;
168  std::cout << qPrintable(p->GetPlaybackURL()) << std::endl;
169  std::cout << "-------------------------------------------------------------------" << std::endl;
170  }
171  }
172 
173  if (!zeroByteRecordings.empty())
174  {
175  std::cout << std::endl << std::endl;
176  std::cout << "ZERO BYTE RECORDINGS" << std::endl;
177  std::cout << "--------------------" << std::endl;
178  for (auto *p : zeroByteRecordings)
179  {
180  std::cout << qPrintable(CreateProgramInfoString(*p)) << std::endl;
181  std::cout << qPrintable(p->GetPlaybackURL()) << std::endl;
182  std::cout << "-------------------------------------------------------------------" << std::endl;
183  }
184  }
185 
186  if (!noSeektableRecordings.empty())
187  {
188  std::cout << std::endl << std::endl;
189  std::cout << "NO SEEKTABLE RECORDINGS" << std::endl;
190  std::cout << "-----------------------" << std::endl;
191  for (auto *p : noSeektableRecordings)
192  {
193  std::cout << qPrintable(CreateProgramInfoString(*p)) << std::endl;
194  std::cout << qPrintable(p->GetPlaybackURL()) << std::endl;
195  std::cout << "File size is " << qPrintable(StringUtil::formatBytes(p->GetFilesize(), 2)) << std::endl;
196  std::cout << "-------------------------------------------------------------------" << std::endl;
197  }
198  }
199 
200  std::cout << std::endl << std::endl << "SUMMARY" << std::endl;
201  std::cout << "Recordings : " << recordingList->size() << std::endl;
202  std::cout << "Missing Recordings : " << missingRecordings.size() << std::endl;
203  std::cout << "Zero byte Recordings : " << zeroByteRecordings.size() << std::endl;
204  std::cout << "Missing Seektables : " << noSeektableRecordings.size() << std::endl;
205 
206  return GENERIC_EXIT_OK;
207 }
208 
210 {
211  utilMap["checkrecordings"] = &CheckRecordings;
212 }
213 
214 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:61
RemoteFile::GetFileSize
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
Definition: remotefile.cpp:1094
MARK_GOP_START
@ MARK_GOP_START
Definition: programtypes.h:60
cmdline
MythCommFlagCommandLineParser cmdline
Definition: mythcommflag.cpp:72
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:460
RemoteFile
Definition: remotefile.h:17
mythdirs.h
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:413
MythUtilCommandLineParser
Definition: mythutil_commandlineparser.h:8
remoteutil.h
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
mythsystem.h
mythlogging.h
remotefile.h
hardwareprofile.config.p
p
Definition: config.py:33
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:362
stringutil.h
MARK_GOP_BYFRAME
@ MARK_GOP_BYFRAME
Definition: programtypes.h:63
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:44
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:26
CreateProgramInfoString
static QString CreateProgramInfoString(const ProgramInfo &pginfo)
Definition: recordingutils.cpp:23
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
UtilMap
QMap< QString, UtilFunc > UtilMap
Definition: mythutil.h:15
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2197
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
GetAppBinDir
QString GetAppBinDir(void)
Definition: mythdirs.cpp:253
recordingutils.h
GENERIC_EXIT_NOT_OK
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:14
StringUtil::formatBytes
MBASE_PUBLIC QString formatBytes(int64_t sizeB, int prec=1)
Definition: stringutil.cpp:378
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:23
RemoteGetRecordedList
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
Definition: remoteutil.cpp:19
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
exitcodes.h
CheckRecordings
static int CheckRecordings(const MythUtilCommandLineParser &cmdline)
Definition: recordingutils.cpp:52
registerRecordingUtils
void registerRecordingUtils(UtilMap &utilMap)
Definition: recordingutils.cpp:209
MythSystem::Create
static MythSystem * Create(const QStringList &args, uint flags=kMSNone, const QString &startPath=QString(), Priority cpuPriority=kInheritPriority, Priority diskPriority=kInheritPriority)
Definition: mythsystem.cpp:205
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:364