MythTV master
dirscan.cpp
Go to the documentation of this file.
1#include <map>
2
3#include <QDir>
4#include <QUrl>
5
9
10#include "dbaccess.h"
11#include "dirscan.h"
12#include "videoutils.h"
13
14namespace
15{
17 {
18 private:
19 using ext_map = std::map<QString, bool>;
22
23 public:
25 bool list_unknown) : m_listUnknown(list_unknown)
26 {
27 for (const auto & ext : ext_disposition)
28 {
29 m_extensions.insert(ext_map::value_type(ext.first.toLower(),
30 ext.second));
31 }
32 }
33
34 bool extension_ignored(const QString &extension) const
35 {
36 //NOLINTNEXTLINE(modernize-use-auto)
37 ext_map::const_iterator p = m_extensions.find(extension.toLower());
38 if (p != m_extensions.end())
39 return p->second;
40 return !m_listUnknown;
41 }
42 };
43
44 bool scan_dir(const QString &start_path, DirectoryHandler *handler,
45 const ext_lookup &ext_settings)
46 {
47 QDir d(start_path);
48
49 // Return a fail if directory doesn't exist.
50 if (!d.exists())
51 return false;
52
53 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
54 QFileInfoList list = d.entryInfoList();
55 // An empty directory is fine
56 if (list.isEmpty())
57 return true;
58
59 QDir dir_tester;
60
61 for (const auto& entry : std::as_const(list))
62 {
63 if (entry.fileName() == "Thumbs.db")
64 continue;
65
66 if (!entry.isDir() &&
67 ext_settings.extension_ignored(entry.suffix())) continue;
68
69 bool add_as_file = true;
70
71 if (entry.isDir())
72 {
73 add_as_file = false;
74
75 dir_tester.setPath(entry.absoluteFilePath() + "/VIDEO_TS");
76 QDir bd_dir_tester;
77 bd_dir_tester.setPath(entry.absoluteFilePath() + "/BDMV");
78 if (dir_tester.exists() || bd_dir_tester.exists())
79 {
80 add_as_file = true;
81 }
82 else
83 {
84#if 0
85 LOG(VB_GENERAL, LOG_DEBUG,
86 QString(" -- Dir : %1").arg(entry.!absoluteFilePath()));
87#endif
89 handler->newDir(entry.fileName(),
90 entry.absoluteFilePath());
91
92 // Since we are dealing with a subdirectory failure is fine,
93 // so we'll just ignore the failue and continue
94 (void) scan_dir(entry.absoluteFilePath(), dh, ext_settings);
95 }
96 }
97
98 if (add_as_file)
99 {
100#if 0
101 LOG(VB_GENERAL, LOG_DEBUG,
102 QString(" -- File : %1").arg(entry.fileName()));
103#endif
104 handler->handleFile(entry.fileName(), entry.absoluteFilePath(),
105 entry.suffix(), "");
106 }
107 }
108
109 return true;
110 }
111
112 bool scan_sg_dir(const QString &start_path, const QString &host,
113 const QString &base_path, DirectoryHandler *handler,
114 const ext_lookup &ext_settings, bool isMaster = false)
115 {
116 QString path = start_path;
117
118 if (path.startsWith(base_path))
119 path.remove(0, base_path.length());
120
121 if (!path.endsWith("/"))
122 path += "/";
123
124 if (path == "/")
125 path = "";
126
127 QStringList list;
128 bool ok = false;
129
130 if (isMaster)
131 {
132 StorageGroup sg("Videos", host);
133 list = sg.GetFileInfoList(start_path);
134 ok = true;
135 }
136 else
137 {
138 ok = StorageGroup::remoteGetFileList(host, start_path, &list, "Videos");
139 }
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 (const auto& entry : std::as_const(list))
153 {
154 QStringList fInfo = entry.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, 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
227bool 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}
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
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:155
QString GetHostName(void)
bool IsMasterHost(void)
is this the same host as the master
static bool remoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly=false)
QStringList GetFileInfoList(const QString &Path)
std::map< QString, bool > ext_map
Definition: dirscan.cpp:19
bool extension_ignored(const QString &extension) const
Definition: dirscan.cpp:34
ext_lookup(const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown)
Definition: dirscan.cpp:24
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 iso6937table * d
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
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:112
bool scan_dir(const QString &start_path, DirectoryHandler *handler, const ext_lookup &ext_settings)
Definition: dirscan.cpp:44