MythTV  master
dirscan.cpp
Go to the documentation of this file.
1 #include <map>
2 
3 #include <QDir>
4 #include <QUrl>
5 
10 
11 #include "dbaccess.h"
12 #include "dirscan.h"
13 #include "videoutils.h"
14 
15 namespace
16 {
17  class ext_lookup
18  {
19  private:
20  using ext_map = std::map<QString, bool>;
23 
24  public:
26  bool list_unknown) : m_listUnknown(list_unknown)
27  {
28  for (const auto & ext : ext_disposition)
29  {
30  m_extensions.insert(ext_map::value_type(ext.first.toLower(),
31  ext.second));
32  }
33  }
34 
35  bool extension_ignored(const QString &extension) const
36  {
37  //NOLINTNEXTLINE(modernize-use-auto)
38  ext_map::const_iterator p = m_extensions.find(extension.toLower());
39  if (p != m_extensions.end())
40  return p->second;
41  return !m_listUnknown;
42  }
43  };
44 
45  bool scan_dir(const QString &start_path, DirectoryHandler *handler,
46  const ext_lookup &ext_settings)
47  {
48  QDir d(start_path);
49 
50  // Return a fail if directory doesn't exist.
51  if (!d.exists())
52  return false;
53 
54  d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
55  QFileInfoList list = d.entryInfoList();
56  // An empty directory is fine
57  if (list.isEmpty())
58  return true;
59 
60  QDir dir_tester;
61 
62  for (const auto& entry : std::as_const(list))
63  {
64  if (entry.fileName() == "Thumbs.db")
65  continue;
66 
67  if (!entry.isDir() &&
68  ext_settings.extension_ignored(entry.suffix())) continue;
69 
70  bool add_as_file = true;
71 
72  if (entry.isDir())
73  {
74  add_as_file = false;
75 
76  dir_tester.setPath(entry.absoluteFilePath() + "/VIDEO_TS");
77  QDir bd_dir_tester;
78  bd_dir_tester.setPath(entry.absoluteFilePath() + "/BDMV");
79  if (dir_tester.exists() || bd_dir_tester.exists())
80  {
81  add_as_file = true;
82  }
83  else
84  {
85 #if 0
86  LOG(VB_GENERAL, LOG_DEBUG,
87  QString(" -- Dir : %1").arg(entry.!absoluteFilePath()));
88 #endif
89  DirectoryHandler *dh =
90  handler->newDir(entry.fileName(),
91  entry.absoluteFilePath());
92 
93  // Since we are dealing with a subdirectory failure is fine,
94  // so we'll just ignore the failue and continue
95  (void) scan_dir(entry.absoluteFilePath(), dh, ext_settings);
96  }
97  }
98 
99  if (add_as_file)
100  {
101 #if 0
102  LOG(VB_GENERAL, LOG_DEBUG,
103  QString(" -- File : %1").arg(entry.fileName()));
104 #endif
105  handler->handleFile(entry.fileName(), entry.absoluteFilePath(),
106  entry.suffix(), "");
107  }
108  }
109 
110  return true;
111  }
112 
113  bool scan_sg_dir(const QString &start_path, const QString &host,
114  const QString &base_path, DirectoryHandler *handler,
115  const ext_lookup &ext_settings, bool isMaster = false)
116  {
117  QString path = start_path;
118 
119  if (path.startsWith(base_path))
120  path.remove(0, base_path.length());
121 
122  if (!path.endsWith("/"))
123  path += "/";
124 
125  if (path == "/")
126  path = "";
127 
128  QStringList list;
129  bool ok = false;
130 
131  if (isMaster)
132  {
133  StorageGroup sg("Videos", host);
134  list = sg.GetFileInfoList(start_path);
135  ok = true;
136  }
137  else
138  {
139  ok = RemoteGetFileList(host, start_path, &list, "Videos");
140  }
141 
142  if (!ok || (!list.isEmpty() && list.at(0).startsWith("SLAVE UNREACHABLE")))
143  {
144  LOG(VB_GENERAL, LOG_INFO,
145  QString("Backend : %1 : Is currently Unreachable. Skipping "
146  "this one.") .arg(host));
147  return false;
148  }
149 
150  if (list.isEmpty() || (list.at(0) == "EMPTY LIST"))
151  return true;
152 
153  for (const auto& entry : std::as_const(list))
154  {
155  QStringList fInfo = entry.split("::");
156  const QString& type = fInfo.at(0);
157  QString fileName = fInfo.at(1);
158 
159  if (type == "nop")
160  continue;
161 
162  QFileInfo fi(fileName);
163 
164  if ((type != "dir") &&
165  ext_settings.extension_ignored(fi.suffix())) continue;
166 
167  if (type == "dir" &&
168  !fileName.endsWith("VIDEO_TS") &&
169  !fileName.endsWith("BDMV"))
170  {
171 #if 0
172  LOG(VB_GENERAL, LOG_DEBUG,
173  QString(" -- Dir : %1").arg(fileName));
174 #endif
175  DirectoryHandler *dh =
176  handler->newDir(fileName,
177  start_path);
178 
179  // Same as a normal scan_dir we don't care if we can't read
180  // subdirectories so ignore the results and continue. As long
181  // as we reached it once to make it this far than we know the
182  // SG/Path exists
183  (void) scan_sg_dir(start_path + "/" + fileName, host, base_path,
184  dh, ext_settings, isMaster);
185  }
186  else
187  {
188  QString suffix;
189  QString URL;
190 
191  if (fileName.endsWith("VIDEO_TS") || fileName.endsWith("BDMV"))
192  {
193  if (path.startsWith("/"))
194  path = path.right(path.length() - 1);
195  if (path.endsWith("/"))
196  path = path.left(path.length() - 1);
197  QStringList upDirs = path.split("/");
198  if (upDirs.count() > 1)
199  fileName = upDirs.takeLast();
200  else
201  fileName = path;
202  suffix = "";
203  URL = path;
204  }
205  else
206  {
207  suffix = fi.suffix();
208  URL = QString("%1/%2").arg(path, fileName);
209  }
210 
211  URL.replace("//","/");
212 
213  if (URL.startsWith("/"))
214  URL = URL.right(URL.length() - 1);
215 #if 0
216  LOG(VB_GENERAL, LOG_GENERAL,
217  QString(" -- File Filename: %1 URL: %2 Suffix: %3 Host: %4")
218  .arg(fileName).arg(URL).arg(suffix).arg(QString(host)));
219 #endif
220  handler->handleFile(fileName, URL, fi.suffix(), QString(host));
221  }
222  }
223 
224  return true;
225  }
226 }
227 
228 bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler,
229  const FileAssociations::ext_ignore_list &ext_disposition,
230  bool list_unknown_extensions)
231 {
232  ext_lookup extlookup(ext_disposition, list_unknown_extensions);
233 
234  bool pathScanned = true;
235 
236  if (!start_path.startsWith("myth://"))
237  {
238  LOG(VB_GENERAL, LOG_INFO,
239  QString("MythVideo::ScanVideoDirectory Scanning (%1)")
240  .arg(start_path));
241 
242  if (!scan_dir(start_path, handler, extlookup))
243  {
244  LOG(VB_GENERAL, LOG_ERR,
245  QString("MythVideo::ScanVideoDirectory failed to scan %1")
246  .arg(start_path));
247  pathScanned = false;
248  }
249  }
250  else
251  {
252  LOG(VB_GENERAL, LOG_INFO,
253  QString("MythVideo::ScanVideoDirectory Scanning Group (%1)")
254  .arg(start_path));
255  QUrl sgurl = start_path;
256  QString host = sgurl.host();
257  QString path = sgurl.path();
258 
259  if (!scan_sg_dir(path, host, path, handler, extlookup,
260  (gCoreContext->IsMasterHost(host) &&
261  (gCoreContext->GetHostName().toLower() == host.toLower()))))
262  {
263  LOG(VB_GENERAL, LOG_ERR,
264  QString("MythVideo::ScanVideoDirectory failed to scan %1 ")
265  .arg(host));
266  pathScanned = false;
267  }
268  }
269 
270  return pathScanned;
271 }
dirscan.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
remoteutil.h
dbaccess.h
anonymous_namespace{dirscan.cpp}::ext_lookup::m_listUnknown
bool m_listUnknown
Definition: dirscan.cpp:22
anonymous_namespace{dirscan.cpp}::ext_lookup
Definition: dirscan.cpp:17
mythlogging.h
hardwareprofile.config.p
p
Definition: config.py:33
FileAssociations::ext_ignore_list
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:155
anonymous_namespace{dirscan.cpp}::scan_sg_dir
bool scan_sg_dir(const QString &start_path, const QString &host, const QString &base_path, DirectoryHandler *handler, const ext_lookup &ext_settings, bool isMaster=false)
Definition: dirscan.cpp:113
anonymous_namespace{dirscan.cpp}::ext_lookup::m_extensions
ext_map m_extensions
Definition: dirscan.cpp:21
storagegroup.h
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
anonymous_namespace{dirscan.cpp}::ext_lookup::ext_map
std::map< QString, bool > ext_map
Definition: dirscan.cpp:20
mythcorecontext.h
ScanVideoDirectory
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:228
StorageGroup::GetFileInfoList
QStringList GetFileInfoList(const QString &Path)
Definition: storagegroup.cpp:289
StorageGroup
Definition: storagegroup.h:11
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:845
MythCoreContext::IsMasterHost
bool IsMasterHost(void)
is this the same host as the master
Definition: mythcorecontext.cpp:666
DirectoryHandler::newDir
virtual DirectoryHandler * newDir(const QString &dir_name, const QString &fq_dir_name)=0
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
anonymous_namespace{dirscan.cpp}::ext_lookup::ext_lookup
ext_lookup(const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown)
Definition: dirscan.cpp:25
anonymous_namespace{dirscan.cpp}::ext_lookup::extension_ignored
bool extension_ignored(const QString &extension) const
Definition: dirscan.cpp:35
DirectoryHandler
Definition: dirscan.h:6
videoutils.h
DirectoryHandler::handleFile
virtual void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension, const QString &host)=0
anonymous_namespace{dirscan.cpp}::scan_dir
bool scan_dir(const QString &start_path, DirectoryHandler *handler, const ext_lookup &ext_settings)
Definition: dirscan.cpp:45
RemoteGetFileList
bool RemoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly)
Definition: remoteutil.cpp:429