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