18 m_dir(m_dbfs.GetImageFilters())
38 m_mutexQueue.unlock();
40 QMutexLocker locker(&m_mutexState);
52 QMutexLocker locker(&m_mutexState);
64 QMutexLocker locker(&m_mutexQueue);
65 return !m_clearQueue.isEmpty();
79 QMutexLocker locker(&m_mutexState);
99 m_clearQueue << qMakePair(devId,
action);
100 m_mutexQueue.unlock();
110 template <
class DBFS>
113 QMutexLocker locker(&m_mutexProgress);
115 << QString::number(m_progressCount)
116 << QString::number(m_progressTotalCount);
125 template <
class DBFS>
130 setPriority(QThread::LowPriority);
135 while (ClearsPending())
138 if (m_clearQueue.isEmpty())
140 ClearTask task = m_clearQueue.takeFirst();
141 m_mutexQueue.unlock();
143 int devId = task.first;
144 QString
action = task.second;
146 LOG(VB_GENERAL, LOG_INFO,
147 QString(
"Clearing Filesystem: %1 %2").arg(
action).arg(devId));
150 m_dbfs.ClearDb(devId,
action);
153 m_thumb.ClearThumbs(devId,
action);
159 LOG(VB_GENERAL, LOG_INFO,
"Starting scan");
162 if (!m_dbfs.ReadAllImages(m_dbFileMap, m_dbDirMap))
166 bool firstScan = m_dbFileMap.isEmpty();
169 m_thumb.PauseBackground(
true);
174 CountFiles(
paths.values());
178 m_changedImages.clear();
179 StringMap::const_iterator i =
paths.constBegin();
180 while (i !=
paths.constEnd() && IsScanning())
182 SyncSubTree(QFileInfo(i.value()),
GALLERY_DB_ID, i.key(), i.value());
187 m_thumb.PauseBackground(
false);
192 m_dbfs.RemoveFromDB(QVector<ImagePtr>::fromList(m_dbDirMap.values()));
193 m_dbfs.RemoveFromDB(QVector<ImagePtr>::fromList(m_dbFileMap.values()));
196 QStringList mesg(m_thumb.DeleteThumbs(QVector<ImagePtr>::fromList(m_dbFileMap.values())));
197 mesg << m_changedImages.join(
",");
204 m_mutexProgress.lock();
206 Broadcast(m_progressTotalCount);
208 m_progressCount = m_progressTotalCount = 0;
209 m_mutexProgress.unlock();
211 LOG(VB_GENERAL, LOG_INFO,
"Finished scan");
219 m_dbfs.Notify(
"IMAGE_DB_CHANGED", mesg);
224 while (ClearsPending());
239 template <
class DBFS>
241 int devId,
const QString &base)
244 if (m_exclusions.match(dirInfo.fileName()).hasMatch())
246 LOG(VB_FILE, LOG_INFO,
247 QString(
"Excluding dir %1").arg(dirInfo.absoluteFilePath()));
253 if (!dir.cd(dirInfo.absoluteFilePath()))
255 LOG(VB_FILE, LOG_INFO,
256 QString(
"Failed to open dir %1").arg(dirInfo.absoluteFilePath()));
261 int id = SyncDirectory(dirInfo, devId, base, parentId);
264 LOG(VB_FILE, LOG_INFO,
265 QString(
"Failed to sync dir %1").arg(dirInfo.absoluteFilePath()));
270 QFileInfoList entries = dir.entryInfoList();
271 for (
const auto & fileInfo : qAsConst(entries))
275 LOG(VB_GENERAL, LOG_INFO,
276 QString(
"Scan interrupted in %2").arg(dirInfo.absoluteFilePath()));
280 if (fileInfo.isDir())
283 SyncSubTree(fileInfo,
id, devId, base);
287 SyncFile(fileInfo, devId, base,
id);
289 QMutexLocker locker(&m_mutexProgress);
293 if (m_bcastTimer.elapsed() > 250)
294 Broadcast(m_progressCount);
314 template <
class DBFS>
317 QString absFilePath = dirInfo.absoluteFilePath();
319 LOG(VB_FILE, LOG_DEBUG, QString(
"Syncing directory %1").arg(absFilePath));
321 ImagePtr dir(m_dbfs.CreateItem(dirInfo, parentId, devId, base));
324 if (m_dbDirMap.contains(dir->m_filePath))
326 ImagePtr dbDir = m_dbDirMap.value(dir->m_filePath);
327 if (dbDir ==
nullptr)
331 dir->m_id = dbDir->m_id;
334 if (dir->m_modTime != dbDir->m_modTime
335 || dir->m_parentId != dbDir->m_parentId)
337 LOG(VB_FILE, LOG_INFO,
338 QString(
"Changed directory %1").arg(absFilePath));
341 dir->m_isHidden = dbDir->m_isHidden;
342 dir->m_userThumbnail = dbDir->m_userThumbnail;
344 m_dbfs.UpdateDbImage(*dir);
346 m_changedImages << QString::number(dir->m_id);
350 m_dbDirMap.remove(dir->m_filePath);
353 else if (m_seenDir.contains(dir->m_filePath))
355 ImagePtr cloneDir = m_seenDir.value(dir->m_filePath);
356 if (cloneDir ==
nullptr)
360 if (cloneDir->m_modTime >= dir->m_modTime )
362 LOG(VB_FILE, LOG_INFO, QString(
"Directory %1 is an older clone of %2")
363 .arg(absFilePath, cloneDir->m_filePath));
370 LOG(VB_FILE, LOG_INFO,
371 QString(
"Directory %1 is a more recent clone of %2")
372 .arg(absFilePath, cloneDir->m_filePath));
375 dir->m_id = cloneDir->m_id;
377 m_changedImages << QString::number(dir->m_id);
381 if (!dir->IsDevice())
384 m_dbfs.UpdateDbImage(*dir);
389 LOG(VB_FILE, LOG_INFO, QString(
"New directory %1").arg(absFilePath));
392 dir->m_id = m_dbfs.InsertDbImage(*dir);
396 m_seenDir.insert(dir->m_filePath, dir);
410 template <
class DBFS>
412 const QString &path,
int type, QString &comment,
413 std::chrono::seconds &time,
422 comment = metadata->
GetComment().simplified();
424 time = (dt.isValid()) ? std::chrono::seconds(dt.toSecsSinceEpoch()) : 0s;
444 template <
class DBFS>
446 const QString &base,
int parentId)
449 if (m_exclusions.match(fileInfo.fileName()).hasMatch())
451 LOG(VB_FILE, LOG_INFO,
452 QString(
"Excluding file %1").arg(fileInfo.absoluteFilePath()));
456 QString absFilePath = fileInfo.absoluteFilePath();
458 ImagePtr im(m_dbfs.CreateItem(fileInfo, parentId, devId, base));
463 if (m_dbFileMap.contains(im->m_filePath))
465 ImagePtrK dbIm = m_dbFileMap.value(im->m_filePath);
468 if (im->m_modTime == dbIm->m_modTime && im->m_parentId == dbIm->m_parentId)
472 m_dbFileMap.remove(im->m_filePath);
474 m_seenFile.insert(im->m_filePath, absFilePath);
478 LOG(VB_FILE, LOG_INFO, QString(
"Modified file %1").arg(absFilePath));
481 im->m_id = dbIm->m_id;
482 im->m_isHidden = dbIm->m_isHidden;
486 PopulateMetadata(absFilePath, im->m_type,
487 im->m_comment, im->m_date, fileOrient);
494 m_dbFileMap.remove(im->m_filePath);
496 m_changedImages << QString::number(im->m_id);
499 m_dbfs.UpdateDbImage(*im);
501 else if (m_seenFile.contains(im->m_filePath))
503 LOG(VB_GENERAL, LOG_WARNING, QString(
"Ignoring %1 (Duplicate of %2)")
504 .arg(absFilePath, m_seenFile.value(im->m_filePath)));
510 LOG(VB_FILE, LOG_INFO, QString(
"New file %1").arg(absFilePath));
514 PopulateMetadata(absFilePath, im->m_type,
515 im->m_comment, im->m_date, fileOrient);
521 im->m_id = m_dbfs.InsertDbImage(*im);
525 m_seenFile.insert(im->m_filePath, absFilePath);
528 im->m_filePath = absFilePath;
531 m_thumb.CreateThumbnail(im);
540 template <
class DBFS>
543 QFileInfoList entries = dir.entryInfoList();
544 for (
const auto & fileInfo : qAsConst(entries))
547 if (m_exclusions.match(fileInfo.fileName()).hasMatch())
550 if (fileInfo.isFile())
552 ++m_progressTotalCount;
555 else if (dir.cd(fileInfo.fileName()))
568 template <
class DBFS>
575 excPattern.replace(
".",
"\\.");
576 excPattern.replace(
"*",
".*");
577 excPattern.replace(
"?",
".");
578 excPattern.replace(
",",
"|");
580 QString pattern = QString(
"^(%1)$").arg(excPattern);
581 m_exclusions = QRegularExpression(pattern);
583 LOG(VB_FILE, LOG_DEBUG, QString(
"Exclude regexp is \"%1\"").arg(pattern));
586 QMutexLocker locker(&m_mutexProgress);
588 m_progressTotalCount = 0;
592 for (
const auto& sgDir : qAsConst(
paths))
609 template <
class DBFS>
616 << QString::number(m_progressTotalCount);
618 m_dbfs.Notify(
"IMAGE_SCAN_STATUS", status);
621 m_bcastTimer.start();