diff --git a/autotests/localfilelistingtest.cpp b/autotests/localfilelistingtest.cpp index 21875ff5..b0bc8b0a 100644 --- a/autotests/localfilelistingtest.cpp +++ b/autotests/localfilelistingtest.cpp @@ -1,336 +1,441 @@ /* * Copyright 2015-2017 Matthieu Gallien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "file/localfilelisting.h" #include "musicaudiotrack.h" #include "config-upnp-qt.h" #include #include #include #include #include #include #include #include #include #include #include #include class LocalFileListingTests: public QObject { Q_OBJECT private: QHash> mNewTracks; QHash mNewCovers; private Q_SLOTS: void initTestCase() { qRegisterMetaType>("QHash"); qRegisterMetaType>("QHash"); qRegisterMetaType>("QList"); qRegisterMetaType>("QVector"); qRegisterMetaType>("QHash"); qRegisterMetaType>("QList"); } void initialTestWithNoTrack() { LocalFileListing myListing; QSignalSpy tracksListSpy(&myListing, &LocalFileListing::tracksList); QSignalSpy removedTracksListSpy(&myListing, &LocalFileListing::removedTracksList); QSignalSpy rootPathChangedSpy(&myListing, &LocalFileListing::rootPathChanged); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.init(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.setRootPath(QStringLiteral("/directoryNotExist")); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QCOMPARE(myListing.rootPath(), QStringLiteral("/directoryNotExist")); myListing.refreshContent(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); } void initialTestWithTracks() { LocalFileListing myListing; QString musicPath = QStringLiteral(LOCAL_FILE_TESTS_SAMPLE_FILES_PATH) + QStringLiteral("/music"); QSignalSpy tracksListSpy(&myListing, &LocalFileListing::tracksList); QSignalSpy removedTracksListSpy(&myListing, &LocalFileListing::removedTracksList); QSignalSpy rootPathChangedSpy(&myListing, &LocalFileListing::rootPathChanged); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.init(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.setRootPath(musicPath); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QCOMPARE(myListing.rootPath(), musicPath); myListing.refreshContent(); QCOMPARE(tracksListSpy.count(), 1); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); auto newTracksSignal = tracksListSpy.at(0); auto newTracks = newTracksSignal.at(0).value>(); auto newCovers = newTracksSignal.at(1).value>(); QCOMPARE(newTracks.count(), 3); QCOMPARE(newCovers.count(), 1); } void addAndRemoveTracks() { LocalFileListing myListing; QString musicOriginPath = QStringLiteral(LOCAL_FILE_TESTS_SAMPLE_FILES_PATH) + QStringLiteral("/music"); QString musicPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2/data/innerData"); QDir musicDirectory(musicPath); QString musicParentPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2"); QDir musicParentDirectory(musicParentPath); QDir rootDirectory(QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH)); musicParentDirectory.removeRecursively(); rootDirectory.mkpath(QStringLiteral("music2/data/innerData")); QSignalSpy tracksListSpy(&myListing, &LocalFileListing::tracksList); QSignalSpy removedTracksListSpy(&myListing, &LocalFileListing::removedTracksList); QSignalSpy rootPathChangedSpy(&myListing, &LocalFileListing::rootPathChanged); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.init(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.setRootPath(musicParentPath); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QCOMPARE(myListing.rootPath(), musicParentPath); myListing.refreshContent(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QFile myTrack(musicOriginPath + QStringLiteral("/test.ogg")); myTrack.copy(musicPath + QStringLiteral("/test.ogg")); QFile myCover(musicOriginPath + QStringLiteral("/cover.jpg")); myCover.copy(musicPath + QStringLiteral("/cover.jpg")); QCOMPARE(tracksListSpy.wait(), true); QCOMPARE(tracksListSpy.count(), 1); QCOMPARE(removedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); auto newTracksSignal = tracksListSpy.at(0); auto newTracks = newTracksSignal.at(0).value>(); auto newCovers = newTracksSignal.at(1).value>(); QCOMPARE(newTracks.count(), 1); QCOMPARE(newCovers.count(), 1); QString commandLine(QStringLiteral("rm -rf ") + musicPath); system(commandLine.toLatin1().data()); QCOMPARE(removedTracksListSpy.wait(), true); QCOMPARE(tracksListSpy.count(), 1); QCOMPARE(removedTracksListSpy.count(), 1); QCOMPARE(rootPathChangedSpy.count(), 1); auto removeSignal = removedTracksListSpy.at(0); auto removedTracks = removeSignal.at(0).value>(); QCOMPARE(removedTracks.isEmpty(), false); QCOMPARE(rootDirectory.mkpath(QStringLiteral("music2/data/innerData")), true); QCOMPARE(myTrack.copy(musicPath + QStringLiteral("/test.ogg")), true); QCOMPARE(myCover.copy(musicPath + QStringLiteral("/cover.jpg")), true); if (tracksListSpy.count() == 1) { QCOMPARE(tracksListSpy.wait(), true); } QCOMPARE(tracksListSpy.count(), 2); QCOMPARE(removedTracksListSpy.count(), 1); QCOMPARE(rootPathChangedSpy.count(), 1); auto newTracksSignalLast = tracksListSpy.at(1); auto newTracksLast = newTracksSignalLast.at(0).value>(); auto newCoversLast = newTracksSignalLast.at(1).value>(); QCOMPARE(newTracksLast.count(), 1); QCOMPARE(newCoversLast.count(), 1); } + void addTracksAndRemoveDirectory() + { + LocalFileListing myListing; + + QString musicOriginPath = QStringLiteral(LOCAL_FILE_TESTS_SAMPLE_FILES_PATH) + QStringLiteral("/music"); + + QString musicPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2/data/innerData"); + QDir musicDirectory(musicPath); + + QString innerMusicPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2/data"); + + QString musicParentPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2"); + QDir musicParentDirectory(musicParentPath); + QDir rootDirectory(QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH)); + + musicParentDirectory.removeRecursively(); + rootDirectory.mkpath(QStringLiteral("music2/data/innerData")); + + QSignalSpy tracksListSpy(&myListing, &LocalFileListing::tracksList); + QSignalSpy removedTracksListSpy(&myListing, &LocalFileListing::removedTracksList); + QSignalSpy rootPathChangedSpy(&myListing, &LocalFileListing::rootPathChanged); + + QCOMPARE(tracksListSpy.count(), 0); + QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(rootPathChangedSpy.count(), 0); + + myListing.init(); + + QCOMPARE(tracksListSpy.count(), 0); + QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(rootPathChangedSpy.count(), 0); + + myListing.setRootPath(musicParentPath); + + QCOMPARE(tracksListSpy.count(), 0); + QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(rootPathChangedSpy.count(), 1); + + QCOMPARE(myListing.rootPath(), musicParentPath); + + myListing.refreshContent(); + + QCOMPARE(tracksListSpy.count(), 0); + QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(rootPathChangedSpy.count(), 1); + + QFile myTrack(musicOriginPath + QStringLiteral("/test.ogg")); + myTrack.copy(musicPath + QStringLiteral("/test.ogg")); + QFile myCover(musicOriginPath + QStringLiteral("/cover.jpg")); + myCover.copy(musicPath + QStringLiteral("/cover.jpg")); + + QCOMPARE(tracksListSpy.wait(), true); + + QCOMPARE(tracksListSpy.count(), 1); + QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(rootPathChangedSpy.count(), 1); + + auto newTracksSignal = tracksListSpy.at(0); + auto newTracks = newTracksSignal.at(0).value>(); + auto newCovers = newTracksSignal.at(1).value>(); + + QCOMPARE(newTracks.count(), 1); + QCOMPARE(newCovers.count(), 1); + + QString commandLine(QStringLiteral("rm -rf ") + innerMusicPath); + system(commandLine.toLatin1().data()); + + QCOMPARE(removedTracksListSpy.wait(), true); + + QCOMPARE(tracksListSpy.count(), 1); + QCOMPARE(removedTracksListSpy.count(), 1); + QCOMPARE(rootPathChangedSpy.count(), 1); + + auto removeSignal = removedTracksListSpy.at(0); + auto removedTracks = removeSignal.at(0).value>(); + QCOMPARE(removedTracks.isEmpty(), false); + + QCOMPARE(rootDirectory.mkpath(QStringLiteral("music2/data/innerData")), true); + QCOMPARE(myTrack.copy(musicPath + QStringLiteral("/test.ogg")), true); + QCOMPARE(myCover.copy(musicPath + QStringLiteral("/cover.jpg")), true); + + if (tracksListSpy.count() == 1) { + QCOMPARE(tracksListSpy.wait(), true); + } + + QCOMPARE(tracksListSpy.count(), 2); + QCOMPARE(removedTracksListSpy.count(), 1); + QCOMPARE(rootPathChangedSpy.count(), 1); + + auto newTracksSignalLast = tracksListSpy.at(1); + auto newTracksLast = newTracksSignalLast.at(0).value>(); + auto newCoversLast = newTracksSignalLast.at(1).value>(); + + QCOMPARE(newTracksLast.count(), 1); + QCOMPARE(newCoversLast.count(), 1); + } + void addAndMoveTracks() { LocalFileListing myListing; QString musicOriginPath = QStringLiteral(LOCAL_FILE_TESTS_SAMPLE_FILES_PATH) + QStringLiteral("/music"); QString musicPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2/data/innerData"); QDir musicDirectory(musicPath); QString musicParentPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music2"); QDir musicParentDirectory(musicParentPath); QString musicFriendPath = QStringLiteral(LOCAL_FILE_TESTS_WORKING_PATH) + QStringLiteral("/music3"); QDir musicFriendDirectory(musicFriendPath); QCOMPARE(musicFriendDirectory.removeRecursively(), true); QCOMPARE(musicParentDirectory.removeRecursively(), true); musicFriendDirectory.mkpath(musicFriendPath); musicDirectory.mkpath(musicPath); QSignalSpy tracksListSpy(&myListing, &LocalFileListing::tracksList); QSignalSpy removedTracksListSpy(&myListing, &LocalFileListing::removedTracksList); + QSignalSpy modifiedTracksListSpy(&myListing, &LocalFileListing::modifyTracksList); QSignalSpy rootPathChangedSpy(&myListing, &LocalFileListing::rootPathChanged); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.init(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 0); myListing.setRootPath(musicParentPath); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QCOMPARE(myListing.rootPath(), musicParentPath); myListing.refreshContent(); QCOMPARE(tracksListSpy.count(), 0); QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); QFile myTrack(musicOriginPath + QStringLiteral("/test.ogg")); myTrack.copy(musicPath + QStringLiteral("/test.ogg")); QFile myCover(musicOriginPath + QStringLiteral("/cover.jpg")); myCover.copy(musicPath + QStringLiteral("/cover.jpg")); QCOMPARE(tracksListSpy.wait(), true); QCOMPARE(tracksListSpy.count(), 1); QCOMPARE(removedTracksListSpy.count(), 0); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); auto newTracksSignal = tracksListSpy.at(0); auto newTracks = newTracksSignal.at(0).value>(); auto newCovers = newTracksSignal.at(1).value>(); QCOMPARE(newTracks.count(), 1); QCOMPARE(newCovers.count(), 1); QString commandLine(QStringLiteral("mv ") + musicPath + QStringLiteral(" ") + musicFriendPath); system(commandLine.toLatin1().data()); QCOMPARE(removedTracksListSpy.wait(), true); QCOMPARE(tracksListSpy.count(), 1); QCOMPARE(removedTracksListSpy.count(), 1); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); auto removeSignal = removedTracksListSpy.at(0); auto removedTracks = removeSignal.at(0).value>(); QCOMPARE(removedTracks.isEmpty(), false); QCOMPARE(musicFriendDirectory.mkpath(musicFriendPath), true); QCOMPARE(musicDirectory.mkpath(musicPath), true); QCOMPARE(myTrack.copy(musicPath + QStringLiteral("/test.ogg")), true); QCOMPARE(myCover.copy(musicPath + QStringLiteral("/cover.jpg")), true); if (tracksListSpy.count() == 1) { QCOMPARE(tracksListSpy.wait(), true); } QCOMPARE(tracksListSpy.count(), 2); QCOMPARE(removedTracksListSpy.count(), 1); + QCOMPARE(modifiedTracksListSpy.count(), 0); QCOMPARE(rootPathChangedSpy.count(), 1); auto newTracksSignalLast = tracksListSpy.at(1); auto newTracksLast = newTracksSignalLast.at(0).value>(); auto newCoversLast = newTracksSignalLast.at(1).value>(); - QCOMPARE(newTracksLast.count(), 2); + QCOMPARE(newTracksLast.count(), 1); QCOMPARE(newCoversLast.count(), 1); } }; QTEST_MAIN(LocalFileListingTests) #include "localfilelistingtest.moc" diff --git a/src/abstractfile/abstractfilelisting.cpp b/src/abstractfile/abstractfilelisting.cpp index dff0623f..aa8283eb 100644 --- a/src/abstractfile/abstractfilelisting.cpp +++ b/src/abstractfile/abstractfilelisting.cpp @@ -1,394 +1,389 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "abstractfilelisting.h" #include "musicaudiotrack.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include #include class AbstractFileListingPrivate { public: explicit AbstractFileListingPrivate(const QString &sourceName) : mSourceName(sourceName) { } QFileSystemWatcher mFileSystemWatcher; QHash mAllAlbumCover; - QHash> mDiscoveredFiles; + QHash>> mDiscoveredFiles; QString mSourceName; bool mHandleNewFiles = true; }; AbstractFileListing::AbstractFileListing(const QString &sourceName, QObject *parent) : QObject(parent), d(new AbstractFileListingPrivate(sourceName)) { connect(&d->mFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &AbstractFileListing::directoryChanged); connect(&d->mFileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &AbstractFileListing::fileChanged); } AbstractFileListing::~AbstractFileListing() { } void AbstractFileListing::init() { executeInit(); } void AbstractFileListing::databaseIsReady() { refreshContent(); } void AbstractFileListing::newTrackFile(MusicAudioTrack partialTrack) { const auto &newTrack = scanOneFile(partialTrack.resourceURI()); if (newTrack.isValid() && newTrack != partialTrack) { Q_EMIT modifyTracksList({newTrack}, d->mAllAlbumCover); } } -void AbstractFileListing::scanDirectory(QList &newFiles, const QUrl &path, bool recursive) +void AbstractFileListing::scanDirectory(QList &newFiles, const QUrl &path) { QDir rootDirectory(path.toLocalFile()); rootDirectory.refresh(); if (rootDirectory.exists()) { watchPath(path.toLocalFile()); } auto ¤tDirectoryListingFiles = d->mDiscoveredFiles[path]; auto currentFilesList = QSet(); rootDirectory.refresh(); const auto entryList = rootDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); for (auto oneEntry : entryList) { auto newFilePath = QUrl::fromLocalFile(oneEntry.canonicalFilePath()); if (oneEntry.isDir() || oneEntry.isFile()) { currentFilesList.insert(newFilePath); } } - auto removedTracks = QList(); + auto removedTracks = QList>(); for (const auto &removedFilePath : currentDirectoryListingFiles) { - auto itFilePath = std::find(currentFilesList.begin(), currentFilesList.end(), removedFilePath); + auto itFilePath = std::find(currentFilesList.begin(), currentFilesList.end(), removedFilePath.first); if (itFilePath != currentFilesList.end()) { continue; } removedTracks.push_back(removedFilePath); } auto allRemovedTracks = QList(); for (const auto &oneRemovedTrack : removedTracks) { - removeFile(oneRemovedTrack, allRemovedTracks); + if (oneRemovedTrack.second) { + allRemovedTracks.push_back(oneRemovedTrack.first); + } else { + removeFile(oneRemovedTrack.first, allRemovedTracks); + } } for (const auto &oneRemovedTrack : removedTracks) { currentDirectoryListingFiles.remove(oneRemovedTrack); + currentDirectoryListingFiles.remove(oneRemovedTrack); } if (!allRemovedTracks.isEmpty()) { Q_EMIT removedTracksList(allRemovedTracks); } if (!d->mHandleNewFiles) { return; } for (auto newFilePath : currentFilesList) { - auto itFilePath = std::find(currentDirectoryListingFiles.begin(), currentDirectoryListingFiles.end(), newFilePath); + QFileInfo oneEntry(newFilePath.toLocalFile()); + + auto itFilePath = std::find(currentDirectoryListingFiles.begin(), currentDirectoryListingFiles.end(), QPair{newFilePath, oneEntry.isFile()}); if (itFilePath != currentDirectoryListingFiles.end()) { continue; } - QFileInfo oneEntry(newFilePath.toLocalFile()); - if (recursive && oneEntry.isDir()) { + if (oneEntry.isDir()) { + addFileInDirectory(newFilePath, path); scanDirectory(newFiles, newFilePath); continue; } if (!oneEntry.isFile()) { continue; } auto newTrack = scanOneFile(newFilePath); if (newTrack.isValid()) { addCover(newTrack); addFileInDirectory(newTrack.resourceURI(), path); newFiles.push_back(newTrack); } } } const QString &AbstractFileListing::sourceName() const { return d->mSourceName; } void AbstractFileListing::directoryChanged(const QString &path) { const auto directoryEntry = d->mDiscoveredFiles.find(QUrl::fromLocalFile(path)); if (directoryEntry == d->mDiscoveredFiles.end()) { return; } scanDirectoryTree(path); } void AbstractFileListing::fileChanged(const QString &modifiedFileName) { auto modifiedFile = QUrl::fromLocalFile(modifiedFileName); auto modifiedTrack = scanOneFile(modifiedFile); if (modifiedTrack.isValid()) { Q_EMIT modifyTracksList({modifiedTrack}, d->mAllAlbumCover); } } void AbstractFileListing::executeInit() { } void AbstractFileListing::triggerRefreshOfContent() { } void AbstractFileListing::refreshContent() { triggerRefreshOfContent(); } MusicAudioTrack AbstractFileListing::scanOneFile(QUrl scanFile) { MusicAudioTrack newTrack; QMimeDatabase mimeDb; QString mimetype = mimeDb.mimeTypeForFile(scanFile.toLocalFile()).name(); KFileMetaData::ExtractorCollection extractors; QList exList = extractors.fetchExtractors(mimetype); if (exList.isEmpty()) { return newTrack; } QFileInfo scanFileInfo(scanFile.toLocalFile()); if (scanFileInfo.exists()) { watchPath(scanFile.toLocalFile()); } KFileMetaData::Extractor* ex = exList.first(); KFileMetaData::SimpleExtractionResult result(scanFile.toLocalFile(), mimetype, KFileMetaData::ExtractionResult::ExtractMetaData); ex->extract(&result); const auto &allProperties = result.properties(); auto titleProperty = allProperties.find(KFileMetaData::Property::Title); auto durationProperty = allProperties.find(KFileMetaData::Property::Duration); auto artistProperty = allProperties.find(KFileMetaData::Property::Artist); auto albumProperty = allProperties.find(KFileMetaData::Property::Album); auto albumArtistProperty = allProperties.find(KFileMetaData::Property::AlbumArtist); auto trackNumberProperty = allProperties.find(KFileMetaData::Property::TrackNumber); auto fileData = KFileMetaData::UserMetaData(scanFile.toLocalFile()); if (albumProperty != allProperties.end()) { auto albumValue = albumProperty->toString(); newTrack.setAlbumName(albumValue); if (artistProperty != allProperties.end()) { newTrack.setArtist(artistProperty->toString()); } if (durationProperty != allProperties.end()) { newTrack.setDuration(QTime::fromMSecsSinceStartOfDay(1000 * durationProperty->toDouble())); } if (titleProperty != allProperties.end()) { newTrack.setTitle(titleProperty->toString()); } if (trackNumberProperty != allProperties.end()) { newTrack.setTrackNumber(trackNumberProperty->toInt()); } if (albumArtistProperty != allProperties.end()) { newTrack.setAlbumArtist(albumArtistProperty->toString()); } if (newTrack.albumArtist().isEmpty()) { newTrack.setAlbumArtist(newTrack.artist()); } if (newTrack.artist().isEmpty()) { newTrack.setArtist(newTrack.albumArtist()); } newTrack.setResourceURI(scanFile); newTrack.setRating(fileData.rating()); newTrack.setValid(true); } return newTrack; } void AbstractFileListing::watchPath(const QString &pathName) { d->mFileSystemWatcher.addPath(pathName); } void AbstractFileListing::addFileInDirectory(const QUrl &newFile, const QUrl &directoryName) { const auto directoryEntry = d->mDiscoveredFiles.find(directoryName); if (directoryEntry == d->mDiscoveredFiles.end()) { watchPath(directoryName.toLocalFile()); QDir currentDirectory(directoryName.toLocalFile()); if (currentDirectory.cdUp()) { const auto parentDirectoryName = currentDirectory.absolutePath(); const auto parentDirectory = QUrl::fromLocalFile(parentDirectoryName); const auto parentDirectoryEntry = d->mDiscoveredFiles.find(parentDirectory); if (parentDirectoryEntry == d->mDiscoveredFiles.end()) { watchPath(parentDirectoryName); } auto &parentCurrentDirectoryListingFiles = d->mDiscoveredFiles[parentDirectory]; - parentCurrentDirectoryListingFiles.insert(directoryName); + parentCurrentDirectoryListingFiles.insert({directoryName, false}); } } auto ¤tDirectoryListingFiles = d->mDiscoveredFiles[directoryName]; - currentDirectoryListingFiles.insert(newFile); + QFileInfo isAFile(newFile.toLocalFile()); + currentDirectoryListingFiles.insert({newFile, isAFile.isFile()}); } void AbstractFileListing::scanDirectoryTree(const QString &path) { auto newFiles = QList(); scanDirectory(newFiles, QUrl::fromLocalFile(path)); if (!newFiles.isEmpty()) { emitNewFiles(newFiles); } } -bool AbstractFileListing::fileExists(const QUrl &fileName, const QUrl &directoryName) const -{ - const auto directoryEntry = d->mDiscoveredFiles.find(directoryName); - if (directoryEntry == d->mDiscoveredFiles.end()) { - return false; - } - - const auto fileEntry = directoryEntry->find(fileName); - if (fileEntry == directoryEntry->end()) { - return false; - } - - return true; -} - void AbstractFileListing::setHandleNewFiles(bool handleThem) { d->mHandleNewFiles = handleThem; } void AbstractFileListing::emitNewFiles(const QList &tracks) { Q_EMIT tracksList(tracks, d->mAllAlbumCover, d->mSourceName); } void AbstractFileListing::addCover(const MusicAudioTrack &newTrack) { auto itCover = d->mAllAlbumCover.find(newTrack.albumName()); if (itCover != d->mAllAlbumCover.end()) { return; } QFileInfo trackFilePath(newTrack.resourceURI().toLocalFile()); QFileInfo coverFilePath(trackFilePath.dir().filePath(QStringLiteral("cover.jpg"))); if (coverFilePath.exists()) { d->mAllAlbumCover[newTrack.albumName()] = QUrl::fromLocalFile(coverFilePath.absoluteFilePath()); } } void AbstractFileListing::removeDirectory(const QUrl &removedDirectory, QList &allRemovedFiles) { auto itRemovedDirectory = d->mDiscoveredFiles.find(removedDirectory); if (itRemovedDirectory == d->mDiscoveredFiles.end()) { return; } for (auto itFile : *itRemovedDirectory) { - if (itFile.isValid() && !itFile.isEmpty()) { - removeFile(itFile, allRemovedFiles); + if (itFile.first.isValid() && !itFile.first.isEmpty()) { + removeFile(itFile.first, allRemovedFiles); + if (itFile.second) { + allRemovedFiles.push_back(itFile.first); + } } } d->mDiscoveredFiles.erase(itRemovedDirectory); } void AbstractFileListing::removeFile(const QUrl &oneRemovedTrack, QList &allRemovedFiles) { auto itRemovedDirectory = d->mDiscoveredFiles.find(oneRemovedTrack); if (itRemovedDirectory != d->mDiscoveredFiles.end()) { removeDirectory(oneRemovedTrack, allRemovedFiles); } - - allRemovedFiles.push_back(oneRemovedTrack); } #include "moc_abstractfilelisting.cpp" diff --git a/src/abstractfile/abstractfilelisting.h b/src/abstractfile/abstractfilelisting.h index 643962ec..d0d029c4 100644 --- a/src/abstractfile/abstractfilelisting.h +++ b/src/abstractfile/abstractfilelisting.h @@ -1,107 +1,105 @@ /* * Copyright 2016-2017 Matthieu Gallien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef ABSTRACTFILELISTING_H #define ABSTRACTFILELISTING_H #include #include #include #include #include #include class AbstractFileListingPrivate; class MusicAudioTrack; class AbstractFileListing : public QObject { Q_OBJECT public: explicit AbstractFileListing(const QString &sourceName, QObject *parent = 0); virtual ~AbstractFileListing(); Q_SIGNALS: void tracksList(QList tracks, const QHash &covers, QString musicSource); void removedTracksList(const QList &removedTracks); void modifyTracksList(const QList &modifiedTracks, const QHash &covers); public Q_SLOTS: void refreshContent(); void init(); void databaseIsReady(); void newTrackFile(MusicAudioTrack partialTrack); protected Q_SLOTS: void directoryChanged(const QString &path); void fileChanged(const QString &modifiedFileName); protected: virtual void executeInit(); virtual void triggerRefreshOfContent(); - void scanDirectory(QList &newFiles, const QUrl &path, bool recursive = true); + void scanDirectory(QList &newFiles, const QUrl &path); const QString &sourceName() const; virtual MusicAudioTrack scanOneFile(QUrl scanFile); void watchPath(const QString &pathName); void addFileInDirectory(const QUrl &newFile, const QUrl &directoryName); void scanDirectoryTree(const QString &path); - bool fileExists(const QUrl &fileName, const QUrl &directoryName) const; - void setHandleNewFiles(bool handleThem); void emitNewFiles(const QList &tracks); void addCover(const MusicAudioTrack &newTrack); void removeDirectory(const QUrl &removedDirectory, QList &allRemovedFiles); void removeFile(const QUrl &oneRemovedTrack, QList &allRemovedFiles); private: std::unique_ptr d; }; #endif // ABSTRACTFILELISTING_H