Changeset View
Changeset View
Standalone View
Standalone View
src/abstractfile/abstractfilelisting.cpp
Show All 13 Lines | |||||
14 | * You should have received a copy of the GNU Lesser General Public License | 14 | * You should have received a copy of the GNU Lesser General Public License | ||
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
16 | */ | 16 | */ | ||
17 | 17 | | |||
18 | #include "abstractfilelisting.h" | 18 | #include "abstractfilelisting.h" | ||
19 | 19 | | |||
20 | #include "config-upnp-qt.h" | 20 | #include "config-upnp-qt.h" | ||
21 | 21 | | |||
22 | #include "abstractfile/indexercommon.h" | ||||
23 | | ||||
22 | #include "musicaudiotrack.h" | 24 | #include "musicaudiotrack.h" | ||
23 | #include "notificationitem.h" | 25 | #include "notificationitem.h" | ||
24 | #include "filescanner.h" | 26 | #include "filescanner.h" | ||
25 | 27 | | |||
26 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | 28 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | ||
27 | #include <KFileMetaData/EmbeddedImageData> | 29 | #include <KFileMetaData/EmbeddedImageData> | ||
28 | #endif | 30 | #endif | ||
29 | 31 | | |||
Show All 13 Lines | |||||
43 | 45 | | |||
44 | #include <algorithm> | 46 | #include <algorithm> | ||
45 | #include <utility> | 47 | #include <utility> | ||
46 | 48 | | |||
47 | class AbstractFileListingPrivate | 49 | class AbstractFileListingPrivate | ||
48 | { | 50 | { | ||
49 | public: | 51 | public: | ||
50 | 52 | | |||
51 | explicit AbstractFileListingPrivate(QString sourceName) : mSourceName(std::move(sourceName)) | 53 | QStringList mAllRootPaths; | ||
52 | { | | |||
53 | } | | |||
54 | 54 | | |||
55 | QFileSystemWatcher mFileSystemWatcher; | 55 | QFileSystemWatcher mFileSystemWatcher; | ||
56 | 56 | | |||
57 | QHash<QString, QUrl> mAllAlbumCover; | 57 | QHash<QString, QUrl> mAllAlbumCover; | ||
58 | 58 | | |||
59 | QHash<QUrl, QSet<QPair<QUrl, bool>>> mDiscoveredFiles; | 59 | QHash<QUrl, QSet<QPair<QUrl, bool>>> mDiscoveredFiles; | ||
60 | 60 | | |||
61 | QString mSourceName; | | |||
62 | | ||||
63 | FileScanner mFileScanner; | 61 | FileScanner mFileScanner; | ||
64 | 62 | | |||
65 | QMimeDatabase mMimeDb; | 63 | QMimeDatabase mMimeDb; | ||
66 | 64 | | |||
67 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | 65 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | ||
68 | KFileMetaData::EmbeddedImageData mImageScanner; | 66 | KFileMetaData::EmbeddedImageData mImageScanner; | ||
69 | #endif | 67 | #endif | ||
70 | 68 | | |||
71 | QHash<QUrl, QDateTime> mAllFiles; | 69 | QHash<QUrl, QDateTime> mAllFiles; | ||
72 | 70 | | |||
73 | QAtomicInt mStopRequest = 0; | 71 | QAtomicInt mStopRequest = 0; | ||
74 | 72 | | |||
75 | int mImportedTracksCount = 0; | 73 | int mImportedTracksCount = 0; | ||
76 | 74 | | |||
77 | int mNotificationUpdateInterval = 1; | 75 | int mNotificationUpdateInterval = 1; | ||
78 | 76 | | |||
79 | int mNewFilesEmitInterval = 1; | 77 | int mNewFilesEmitInterval = 1; | ||
80 | 78 | | |||
81 | bool mHandleNewFiles = true; | 79 | bool mHandleNewFiles = true; | ||
82 | 80 | | |||
81 | bool mWaitEndTrackRemoval = false; | ||||
82 | | ||||
83 | }; | 83 | }; | ||
84 | 84 | | |||
85 | AbstractFileListing::AbstractFileListing(const QString &sourceName, QObject *parent) : QObject(parent), d(std::make_unique<AbstractFileListingPrivate>(sourceName)) | 85 | AbstractFileListing::AbstractFileListing(QObject *parent) : QObject(parent), d(std::make_unique<AbstractFileListingPrivate>()) | ||
86 | { | 86 | { | ||
87 | connect(&d->mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, | 87 | connect(&d->mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, | ||
88 | this, &AbstractFileListing::directoryChanged); | 88 | this, &AbstractFileListing::directoryChanged); | ||
89 | connect(&d->mFileSystemWatcher, &QFileSystemWatcher::fileChanged, | 89 | connect(&d->mFileSystemWatcher, &QFileSystemWatcher::fileChanged, | ||
90 | this, &AbstractFileListing::fileChanged); | 90 | this, &AbstractFileListing::fileChanged); | ||
91 | } | 91 | } | ||
92 | 92 | | |||
93 | AbstractFileListing::~AbstractFileListing() | 93 | AbstractFileListing::~AbstractFileListing() | ||
94 | = default; | 94 | = default; | ||
95 | 95 | | |||
96 | void AbstractFileListing::init() | 96 | void AbstractFileListing::init() | ||
97 | { | 97 | { | ||
98 | Q_EMIT askRestoredTracks(sourceName()); | 98 | Q_EMIT askRestoredTracks(); | ||
99 | } | 99 | } | ||
100 | 100 | | |||
101 | void AbstractFileListing::newTrackFile(const MusicAudioTrack &partialTrack) | 101 | void AbstractFileListing::newTrackFile(const MusicAudioTrack &partialTrack) | ||
102 | { | 102 | { | ||
103 | auto scanFileInfo = QFileInfo(partialTrack.resourceURI().toLocalFile()); | 103 | auto scanFileInfo = QFileInfo(partialTrack.resourceURI().toLocalFile()); | ||
104 | const auto &newTrack = scanOneFile(partialTrack.resourceURI(), scanFileInfo); | 104 | const auto &newTrack = scanOneFile(partialTrack.resourceURI(), scanFileInfo); | ||
105 | 105 | | |||
106 | if (newTrack.isValid() && newTrack != partialTrack) { | 106 | if (newTrack.isValid() && newTrack != partialTrack) { | ||
107 | Q_EMIT modifyTracksList({newTrack}, d->mAllAlbumCover, d->mSourceName); | 107 | Q_EMIT modifyTracksList({newTrack}, d->mAllAlbumCover); | ||
108 | } | 108 | } | ||
109 | } | 109 | } | ||
110 | 110 | | |||
111 | void AbstractFileListing::restoredTracks(const QString &musicSource, QHash<QUrl, QDateTime> allFiles) | 111 | void AbstractFileListing::restoredTracks(QHash<QUrl, QDateTime> allFiles) | ||
112 | { | 112 | { | ||
113 | if (musicSource == sourceName()) { | | |||
114 | executeInit(std::move(allFiles)); | 113 | executeInit(std::move(allFiles)); | ||
115 | 114 | | |||
116 | refreshContent(); | 115 | refreshContent(); | ||
117 | } | 116 | } | ||
117 | | ||||
118 | void AbstractFileListing::setAllRootPaths(const QStringList &allRootPaths) | ||||
119 | { | ||||
120 | if (d->mAllRootPaths == allRootPaths) { | ||||
121 | return; | ||||
122 | } | ||||
123 | | ||||
124 | d->mAllRootPaths = allRootPaths; | ||||
125 | } | ||||
126 | | ||||
127 | void AbstractFileListing::databaseFinishedInsertingTracksList() | ||||
128 | { | ||||
129 | } | ||||
130 | | ||||
131 | void AbstractFileListing::databaseFinishedRemovingTracksList() | ||||
132 | { | ||||
133 | if (waitEndTrackRemoval()) { | ||||
134 | Q_EMIT indexingFinished(); | ||||
135 | setWaitEndTrackRemoval(false); | ||||
136 | } | ||||
118 | } | 137 | } | ||
119 | 138 | | |||
120 | void AbstractFileListing::applicationAboutToQuit() | 139 | void AbstractFileListing::applicationAboutToQuit() | ||
121 | { | 140 | { | ||
122 | d->mStopRequest = 1; | 141 | d->mStopRequest = 1; | ||
123 | } | 142 | } | ||
124 | 143 | | |||
144 | const QStringList &AbstractFileListing::allRootPaths() const | ||||
145 | { | ||||
146 | return d->mAllRootPaths; | ||||
147 | } | ||||
148 | | ||||
125 | void AbstractFileListing::scanDirectory(QList<MusicAudioTrack> &newFiles, const QUrl &path) | 149 | void AbstractFileListing::scanDirectory(QList<MusicAudioTrack> &newFiles, const QUrl &path) | ||
126 | { | 150 | { | ||
127 | if (d->mStopRequest == 1) { | 151 | if (d->mStopRequest == 1) { | ||
128 | return; | 152 | return; | ||
129 | } | 153 | } | ||
130 | 154 | | |||
131 | QDir rootDirectory(path.toLocalFile()); | 155 | QDir rootDirectory(path.toLocalFile()); | ||
132 | rootDirectory.refresh(); | 156 | rootDirectory.refresh(); | ||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Line(s) | 208 | for (const auto &newFilePath : currentFilesList) { | |||
225 | } | 249 | } | ||
226 | 250 | | |||
227 | if (d->mStopRequest == 1) { | 251 | if (d->mStopRequest == 1) { | ||
228 | break; | 252 | break; | ||
229 | } | 253 | } | ||
230 | } | 254 | } | ||
231 | } | 255 | } | ||
232 | 256 | | |||
233 | const QString &AbstractFileListing::sourceName() const | | |||
234 | { | | |||
235 | return d->mSourceName; | | |||
236 | } | | |||
237 | | ||||
238 | void AbstractFileListing::directoryChanged(const QString &path) | 257 | void AbstractFileListing::directoryChanged(const QString &path) | ||
239 | { | 258 | { | ||
240 | const auto directoryEntry = d->mDiscoveredFiles.find(QUrl::fromLocalFile(path)); | 259 | const auto directoryEntry = d->mDiscoveredFiles.find(QUrl::fromLocalFile(path)); | ||
241 | if (directoryEntry == d->mDiscoveredFiles.end()) { | 260 | if (directoryEntry == d->mDiscoveredFiles.end()) { | ||
242 | return; | 261 | return; | ||
243 | } | 262 | } | ||
244 | 263 | | |||
245 | Q_EMIT indexingStarted(); | 264 | Q_EMIT indexingStarted(); | ||
246 | 265 | | |||
247 | scanDirectoryTree(path); | 266 | scanDirectoryTree(path); | ||
248 | 267 | | |||
249 | Q_EMIT indexingFinished(); | 268 | Q_EMIT indexingFinished(); | ||
250 | } | 269 | } | ||
251 | 270 | | |||
252 | void AbstractFileListing::fileChanged(const QString &modifiedFileName) | 271 | void AbstractFileListing::fileChanged(const QString &modifiedFileName) | ||
253 | { | 272 | { | ||
254 | QFileInfo modifiedFileInfo(modifiedFileName); | 273 | QFileInfo modifiedFileInfo(modifiedFileName); | ||
255 | auto modifiedFile = QUrl::fromLocalFile(modifiedFileName); | 274 | auto modifiedFile = QUrl::fromLocalFile(modifiedFileName); | ||
256 | 275 | | |||
257 | auto modifiedTrack = scanOneFile(modifiedFile, modifiedFileInfo); | 276 | auto modifiedTrack = scanOneFile(modifiedFile, modifiedFileInfo); | ||
258 | 277 | | |||
259 | if (modifiedTrack.isValid()) { | 278 | if (modifiedTrack.isValid()) { | ||
260 | Q_EMIT modifyTracksList({modifiedTrack}, d->mAllAlbumCover, d->mSourceName); | 279 | Q_EMIT modifyTracksList({modifiedTrack}, d->mAllAlbumCover); | ||
261 | } | 280 | } | ||
262 | } | 281 | } | ||
263 | 282 | | |||
264 | void AbstractFileListing::executeInit(QHash<QUrl, QDateTime> allFiles) | 283 | void AbstractFileListing::executeInit(QHash<QUrl, QDateTime> allFiles) | ||
265 | { | 284 | { | ||
266 | d->mAllFiles = std::move(allFiles); | 285 | d->mAllFiles = std::move(allFiles); | ||
267 | } | 286 | } | ||
268 | 287 | | |||
269 | void AbstractFileListing::triggerRefreshOfContent() | 288 | void AbstractFileListing::triggerRefreshOfContent() | ||
270 | { | 289 | { | ||
271 | d->mImportedTracksCount = 0; | 290 | d->mImportedTracksCount = 0; | ||
272 | } | 291 | } | ||
273 | 292 | | |||
274 | void AbstractFileListing::refreshContent() | 293 | void AbstractFileListing::refreshContent() | ||
275 | { | 294 | { | ||
276 | triggerRefreshOfContent(); | 295 | triggerRefreshOfContent(); | ||
277 | } | 296 | } | ||
278 | 297 | | |||
279 | MusicAudioTrack AbstractFileListing::scanOneFile(const QUrl &scanFile, const QFileInfo &scanFileInfo) | 298 | MusicAudioTrack AbstractFileListing::scanOneFile(const QUrl &scanFile, const QFileInfo &scanFileInfo) | ||
280 | { | 299 | { | ||
281 | MusicAudioTrack newTrack; | 300 | MusicAudioTrack newTrack; | ||
282 | 301 | | |||
302 | qCDebug(orgKdeElisaIndexer) << "AbstractFileListing::scanOneFile" << scanFile; | ||||
303 | | ||||
283 | auto localFileName = scanFile.toLocalFile(); | 304 | auto localFileName = scanFile.toLocalFile(); | ||
284 | 305 | | |||
285 | const auto &fileMimeType = d->mMimeDb.mimeTypeForFile(localFileName); | 306 | const auto &fileMimeType = d->mMimeDb.mimeTypeForFile(localFileName); | ||
286 | if (!fileMimeType.name().startsWith(QStringLiteral("audio/"))) { | 307 | if (!fileMimeType.name().startsWith(QStringLiteral("audio/"))) { | ||
287 | return newTrack; | 308 | return newTrack; | ||
288 | } | 309 | } | ||
289 | 310 | | |||
290 | if (scanFileInfo.exists()) { | 311 | if (scanFileInfo.exists()) { | ||
Show All 18 Lines | |||||
309 | } | 330 | } | ||
310 | 331 | | |||
311 | return newTrack; | 332 | return newTrack; | ||
312 | } | 333 | } | ||
313 | 334 | | |||
314 | void AbstractFileListing::watchPath(const QString &pathName) | 335 | void AbstractFileListing::watchPath(const QString &pathName) | ||
315 | { | 336 | { | ||
316 | if (!d->mFileSystemWatcher.addPath(pathName)) { | 337 | if (!d->mFileSystemWatcher.addPath(pathName)) { | ||
317 | Q_EMIT errorWatchingFiles(); | 338 | qCDebug(orgKdeElisaIndexer) << "AbstractFileListing::watchPath" << "fail for" << pathName; | ||
318 | | ||||
319 | qDebug() << "AbstractFileListing::watchPath" << "fail for" << pathName; | | |||
320 | } | 339 | } | ||
321 | } | 340 | } | ||
322 | 341 | | |||
323 | void AbstractFileListing::addFileInDirectory(const QUrl &newFile, const QUrl &directoryName) | 342 | void AbstractFileListing::addFileInDirectory(const QUrl &newFile, const QUrl &directoryName) | ||
324 | { | 343 | { | ||
325 | const auto directoryEntry = d->mDiscoveredFiles.find(directoryName); | 344 | const auto directoryEntry = d->mDiscoveredFiles.find(directoryName); | ||
326 | if (directoryEntry == d->mDiscoveredFiles.end()) { | 345 | if (directoryEntry == d->mDiscoveredFiles.end()) { | ||
327 | watchPath(directoryName.toLocalFile()); | 346 | watchPath(directoryName.toLocalFile()); | ||
Show All 31 Lines | |||||
359 | 378 | | |||
360 | void AbstractFileListing::setHandleNewFiles(bool handleThem) | 379 | void AbstractFileListing::setHandleNewFiles(bool handleThem) | ||
361 | { | 380 | { | ||
362 | d->mHandleNewFiles = handleThem; | 381 | d->mHandleNewFiles = handleThem; | ||
363 | } | 382 | } | ||
364 | 383 | | |||
365 | void AbstractFileListing::emitNewFiles(const QList<MusicAudioTrack> &tracks) | 384 | void AbstractFileListing::emitNewFiles(const QList<MusicAudioTrack> &tracks) | ||
366 | { | 385 | { | ||
367 | Q_EMIT tracksList(tracks, d->mAllAlbumCover, d->mSourceName); | 386 | Q_EMIT tracksList(tracks, d->mAllAlbumCover); | ||
368 | } | 387 | } | ||
369 | 388 | | |||
370 | void AbstractFileListing::addCover(const MusicAudioTrack &newTrack) | 389 | void AbstractFileListing::addCover(const MusicAudioTrack &newTrack) | ||
371 | { | 390 | { | ||
372 | auto itCover = d->mAllAlbumCover.find(newTrack.albumName()); | 391 | auto itCover = d->mAllAlbumCover.find(newTrack.albumName()); | ||
373 | if (itCover != d->mAllAlbumCover.end()) { | 392 | if (itCover != d->mAllAlbumCover.end()) { | ||
374 | return; | 393 | return; | ||
375 | } | 394 | } | ||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | |||||
419 | void AbstractFileListing::removeFile(const QUrl &oneRemovedTrack, QList<QUrl> &allRemovedFiles) | 438 | void AbstractFileListing::removeFile(const QUrl &oneRemovedTrack, QList<QUrl> &allRemovedFiles) | ||
420 | { | 439 | { | ||
421 | auto itRemovedDirectory = d->mDiscoveredFiles.find(oneRemovedTrack); | 440 | auto itRemovedDirectory = d->mDiscoveredFiles.find(oneRemovedTrack); | ||
422 | if (itRemovedDirectory != d->mDiscoveredFiles.end()) { | 441 | if (itRemovedDirectory != d->mDiscoveredFiles.end()) { | ||
423 | removeDirectory(oneRemovedTrack, allRemovedFiles); | 442 | removeDirectory(oneRemovedTrack, allRemovedFiles); | ||
424 | } | 443 | } | ||
425 | } | 444 | } | ||
426 | 445 | | |||
427 | void AbstractFileListing::setSourceName(const QString &name) | | |||
428 | { | | |||
429 | d->mSourceName = name; | | |||
430 | } | | |||
431 | | ||||
432 | QHash<QUrl, QDateTime> &AbstractFileListing::allFiles() | 446 | QHash<QUrl, QDateTime> &AbstractFileListing::allFiles() | ||
433 | { | 447 | { | ||
434 | return d->mAllFiles; | 448 | return d->mAllFiles; | ||
435 | } | 449 | } | ||
436 | 450 | | |||
437 | void AbstractFileListing::checkFilesToRemove() | 451 | void AbstractFileListing::checkFilesToRemove() | ||
438 | { | 452 | { | ||
439 | QList<QUrl> allRemovedFiles; | 453 | QList<QUrl> allRemovedFiles; | ||
440 | 454 | | |||
441 | for (auto itFile = d->mAllFiles.begin(); itFile != d->mAllFiles.end(); ++itFile) { | 455 | for (auto itFile = d->mAllFiles.begin(); itFile != d->mAllFiles.end(); ++itFile) { | ||
442 | allRemovedFiles.push_back(itFile.key()); | 456 | allRemovedFiles.push_back(itFile.key()); | ||
443 | } | 457 | } | ||
444 | 458 | | |||
445 | if (!allRemovedFiles.isEmpty()) { | 459 | if (!allRemovedFiles.isEmpty()) { | ||
460 | setWaitEndTrackRemoval(true); | ||||
446 | Q_EMIT removedTracksList(allRemovedFiles); | 461 | Q_EMIT removedTracksList(allRemovedFiles); | ||
447 | } | 462 | } | ||
448 | } | 463 | } | ||
449 | 464 | | |||
450 | FileScanner &AbstractFileListing::fileScanner() | 465 | FileScanner &AbstractFileListing::fileScanner() | ||
451 | { | 466 | { | ||
452 | return d->mFileScanner; | 467 | return d->mFileScanner; | ||
453 | } | 468 | } | ||
454 | 469 | | |||
455 | bool AbstractFileListing::checkEmbeddedCoverImage(const QString &localFileName) | 470 | bool AbstractFileListing::checkEmbeddedCoverImage(const QString &localFileName) | ||
456 | { | 471 | { | ||
457 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | 472 | #if defined KF5FileMetaData_FOUND && KF5FileMetaData_FOUND | ||
458 | auto imageData = d->mImageScanner.imageData(localFileName); | 473 | auto imageData = d->mImageScanner.imageData(localFileName); | ||
459 | 474 | | |||
460 | if (imageData.contains(KFileMetaData::EmbeddedImageData::FrontCover)) { | 475 | if (imageData.contains(KFileMetaData::EmbeddedImageData::FrontCover)) { | ||
461 | if (!imageData[KFileMetaData::EmbeddedImageData::FrontCover].isEmpty()) { | 476 | if (!imageData[KFileMetaData::EmbeddedImageData::FrontCover].isEmpty()) { | ||
462 | return true; | 477 | return true; | ||
463 | } | 478 | } | ||
464 | } | 479 | } | ||
465 | #endif | 480 | #endif | ||
466 | 481 | | |||
467 | return false; | 482 | return false; | ||
468 | } | 483 | } | ||
469 | 484 | | |||
485 | bool AbstractFileListing::waitEndTrackRemoval() const | ||||
486 | { | ||||
487 | return d->mWaitEndTrackRemoval; | ||||
488 | } | ||||
489 | | ||||
490 | void AbstractFileListing::setWaitEndTrackRemoval(bool wait) | ||||
491 | { | ||||
492 | d->mWaitEndTrackRemoval = wait; | ||||
493 | } | ||||
494 | | ||||
495 | const QMimeDatabase &AbstractFileListing::mimeDatabase() const | ||||
496 | { | ||||
497 | return d->mMimeDb; | ||||
498 | } | ||||
499 | | ||||
470 | 500 | | |||
471 | #include "moc_abstractfilelisting.cpp" | 501 | #include "moc_abstractfilelisting.cpp" |