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
15namespace
16{
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
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
228bool 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}
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
QStringList GetFileInfoList(const QString &Path)
std::map< QString, bool > ext_map
Definition: dirscan.cpp:20
bool extension_ignored(const QString &extension) const
Definition: dirscan.cpp:35
ext_lookup(const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown)
Definition: dirscan.cpp:25
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:228
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:113
bool scan_dir(const QString &start_path, DirectoryHandler *handler, const ext_lookup &ext_settings)
Definition: dirscan.cpp:45
bool RemoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly)
Definition: remoteutil.cpp:429