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  typedef std::map<QString, bool> ext_map;
21  ext_map m_extensions;
22  bool m_list_unknown;
23 
24  public:
25  ext_lookup(const FileAssociations::ext_ignore_list &ext_disposition,
26  bool list_unknown) : m_list_unknown(list_unknown)
27  {
28  for (FileAssociations::ext_ignore_list::const_iterator p =
29  ext_disposition.begin(); p != ext_disposition.end(); ++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  ext_map::const_iterator p = m_extensions.find(extension.toLower());
39  if (p != m_extensions.end())
40  return p->second;
41  return !m_list_unknown;
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 (QFileInfoList::iterator p = list.begin(); p != list.end(); ++p)
63  {
64  if (p->fileName() == "Thumbs.db")
65  continue;
66 
67  if (!p->isDir() &&
68  ext_settings.extension_ignored(p->suffix())) continue;
69 
70  bool add_as_file = true;
71 
72  if (p->isDir())
73  {
74  add_as_file = false;
75 
76  dir_tester.setPath(p->absoluteFilePath() + "/VIDEO_TS");
77  QDir bd_dir_tester;
78  bd_dir_tester.setPath(p->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(p->absoluteFilePath()));
88 #endif
89  DirectoryHandler *dh =
90  handler->newDir(p->fileName(),
91  p->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(p->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(p->fileName()));
104 #endif
105  handler->handleFile(p->fileName(), p->absoluteFilePath(),
106  p->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  ok = RemoteGetFileList(host, start_path, &list, "Videos");
139 
140  if (!ok || (!list.isEmpty() && list.at(0).startsWith("SLAVE UNREACHABLE")))
141  {
142  LOG(VB_GENERAL, LOG_INFO,
143  QString("Backend : %1 : Is currently Unreachable. Skipping "
144  "this one.") .arg(host));
145  return false;
146  }
147 
148  if (list.isEmpty() || (list.at(0) == "EMPTY LIST"))
149  return true;
150 
151  for (QStringList::iterator p = list.begin(); p != list.end(); ++p)
152  {
153  QStringList fInfo = p->split("::");
154  const QString& type = fInfo.at(0);
155  QString fileName = fInfo.at(1);
156 
157  if (type == "nop")
158  continue;
159 
160  QFileInfo fi(fileName);
161 
162  if ((type != "dir") &&
163  ext_settings.extension_ignored(fi.suffix())) continue;
164 
165  if (type == "dir" &&
166  !fileName.endsWith("VIDEO_TS") &&
167  !fileName.endsWith("BDMV"))
168  {
169 #if 0
170  LOG(VB_GENERAL, LOG_DEBUG,
171  QString(" -- Dir : %1").arg(fileName));
172 #endif
173  DirectoryHandler *dh =
174  handler->newDir(fileName,
175  start_path);
176 
177  // Same as a normal scan_dir we don't care if we can't read
178  // subdirectories so ignore the results and continue. As long
179  // as we reached it once to make it this far than we know the
180  // SG/Path exists
181  (void) scan_sg_dir(start_path + "/" + fileName, host, base_path,
182  dh, ext_settings, isMaster);
183  }
184  else
185  {
186  QString suffix;
187  QString URL;
188 
189  if (fileName.endsWith("VIDEO_TS") || fileName.endsWith("BDMV"))
190  {
191  if (path.startsWith("/"))
192  path = path.right(path.length() - 1);
193  if (path.endsWith("/"))
194  path = path.left(path.length() - 1);
195  QStringList upDirs = path.split("/");
196  if (upDirs.count() > 1)
197  fileName = upDirs.takeLast();
198  else
199  fileName = path;
200  suffix = "";
201  URL = path;
202  }
203  else
204  {
205  suffix = fi.suffix();
206  URL = QString("%1/%2").arg(path).arg(fileName);
207  }
208 
209  URL.replace("//","/");
210 
211  if (URL.startsWith("/"))
212  URL = URL.right(URL.length() - 1);
213 #if 0
214  LOG(VB_GENERAL, LOG_GENERAL,
215  QString(" -- File Filename: %1 URL: %2 Suffix: %3 Host: %4")
216  .arg(fileName).arg(URL).arg(suffix).arg(QString(host)));
217 #endif
218  handler->handleFile(fileName, URL, fi.suffix(), QString(host));
219  }
220  }
221 
222  return true;
223  }
224 }
225 
226 bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler,
227  const FileAssociations::ext_ignore_list &ext_disposition,
228  bool list_unknown_extensions)
229 {
230  ext_lookup extlookup(ext_disposition, list_unknown_extensions);
231 
232  bool pathScanned = true;
233 
234  if (!start_path.startsWith("myth://"))
235  {
236  LOG(VB_GENERAL, LOG_INFO,
237  QString("MythVideo::ScanVideoDirectory Scanning (%1)")
238  .arg(start_path));
239 
240  if (!scan_dir(start_path, handler, extlookup))
241  {
242  LOG(VB_GENERAL, LOG_ERR,
243  QString("MythVideo::ScanVideoDirectory failed to scan %1")
244  .arg(start_path));
245  pathScanned = false;
246  }
247  }
248  else
249  {
250  LOG(VB_GENERAL, LOG_INFO,
251  QString("MythVideo::ScanVideoDirectory Scanning Group (%1)")
252  .arg(start_path));
253  QUrl sgurl = start_path;
254  QString host = sgurl.host();
255  QString path = sgurl.path();
256 
257  if (!scan_sg_dir(path, host, path, handler, extlookup,
258  (gCoreContext->IsMasterHost(host) &&
259  (gCoreContext->GetHostName().toLower() == host.toLower()))))
260  {
261  LOG(VB_GENERAL, LOG_ERR,
262  QString("MythVideo::ScanVideoDirectory failed to scan %1 ")
263  .arg(host));
264  pathScanned = false;
265  }
266  }
267 
268  return pathScanned;
269 }
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:154
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:226
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:433
bool IsMasterHost(void)
is this the same host as the master
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString GetHostName(void)