File indexing completed on 2025-01-05 04:25:58

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>            *
0003  * Copyright (c) 2008 Seb Ruiz <ruiz@kde.org>                                           *
0004  * Copyright (c) 2009-2010 Jeff Mitchell <mitchell@kde.org>                             *
0005  * Copyright (c) 2013 Ralf Engels <ralf-engels@gmx.de>                                  *
0006  *                                                                                      *
0007  * This program is free software; you can redistribute it and/or modify it under        *
0008  * the terms of the GNU General Public License as published by the Free Software        *
0009  * Foundation; either version 2 of the License, or (at your option) any later           *
0010  * version.                                                                             *
0011  *                                                                                      *
0012  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0013  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0014  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0015  *                                                                                      *
0016  * You should have received a copy of the GNU General Public License along with         *
0017  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0018  ****************************************************************************************/
0019 
0020 #ifndef AMAROK_SQL_SCANRESULTPROCESSOR_H
0021 #define AMAROK_SQL_SCANRESULTPROCESSOR_H
0022 
0023 #include "scanner/AbstractScanResultProcessor.h"
0024 #include "core-impl/collections/db/sql/SqlCollection.h"
0025 
0026 /** The ScanResulProcessor class takes the results from the ScanManager and puts them into the database.
0027  */
0028 class SqlScanResultProcessor : public AbstractScanResultProcessor
0029 {
0030     Q_OBJECT
0031 
0032     public:
0033         SqlScanResultProcessor( GenericScanManager* manager,
0034                                 Collections::SqlCollection *collection,
0035                                 QObject *parent = nullptr );
0036         ~SqlScanResultProcessor() override;
0037 
0038 
0039     protected Q_SLOTS:
0040         void scanStarted( GenericScanManager::ScanType type ) override;
0041         void scanSucceeded() override;
0042 
0043         virtual void displayMessages();
0044 
0045     protected:
0046         void message( const QString& message ) override;
0047 
0048         void commitDirectory( QSharedPointer<CollectionScanner::Directory> directory ) override;
0049         void commitAlbum( CollectionScanner::Album *album ) override;
0050         void commitTrack( CollectionScanner::Track *track, CollectionScanner::Album *srcAlbum ) override;
0051 
0052         /** Deletes all directories (and it's tracks) not contained in m_foundDirectories */
0053         void deleteDeletedDirectories() override;
0054 
0055         void deleteDeletedTracksAndSubdirs( QSharedPointer<CollectionScanner::Directory> directory ) override;
0056 
0057         /** Removes all tracks contained in the directory dirId that are not contained in m_foundTracks. */
0058         virtual void deleteDeletedTracks( int directoryId );
0059 
0060         void cleanupMembers() override;
0061 
0062         void blockUpdates();
0063         void unblockUpdates();
0064 
0065     private:
0066         // to speed up the scanning we buffer the whole urls table
0067         struct UrlEntry {
0068             int id;
0069             QString path;
0070             int directoryId;
0071             QString uid;
0072         };
0073         friend QDebug operator<<( QDebug, const UrlEntry& );
0074 
0075         /**
0076          * Finds best url id of a track identified by @param uid uniqueid in caches. If
0077          * multiple entries are found, tries to use @param path as a hint.
0078          *
0079          * @returns url id or -1 if nothing is found.
0080          */
0081         int findBestUrlId( const QString &uid, const QString &path );
0082 
0083         /**
0084          * Directory id has changed from @param oldDirId to @param newDirId without
0085          * actual change in the absolute directory path or contents. Try to relocate
0086          * tracks to the new directory, updating necessary fields.
0087          * @return true if all tracks were successfully relocated and the old dir can be
0088          * deleted without losses, false otherwise.
0089          */
0090         bool relocateTracksToNewDirectory( int oldDirId, int newDirId );
0091 
0092         /**
0093          * Remove track from the database. Does not touch the cache - you should probably
0094          * call urlsCacheRemove( entry )
0095          */
0096         void removeTrack( const UrlEntry &entry );
0097 
0098         struct DirectoryEntry {
0099             int dirId;
0100             int deviceId;
0101             QString dir;
0102         };
0103 
0104         /**
0105          * Get a list of all mounted directories from the database.
0106          */
0107         QList<DirectoryEntry> mountedDirectories() const;
0108 
0109         /**
0110          * Get a list of directories that have been physically removed during the
0111          * PartialUpdateScan.
0112          */
0113         QList<DirectoryEntry> deletedDirectories() const;
0114 
0115         Collections::SqlCollection *m_collection;
0116 
0117         /**
0118          * Contains all found directories with their absolute path and id
0119          */
0120         QHash<QString, int> m_foundDirectories;
0121 
0122         /**
0123          * Contains all found tracks with the unique id and url id. QMultiHash only
0124          * because it implements contains( key, value )
0125          */
0126         QMultiHash<QString, int> m_foundTracks;
0127 
0128         /**
0129          * In UpdateScan and PartialUpdateScan this set gets filled with directory ids
0130          * that have been (non-recursively) fully scanned (not skipped). Direct child
0131          * directories from the database that are not contained in m_foundDirectories can
0132          * be considered deleted.
0133          */
0134         QSet<int> m_scannedDirectoryIds;
0135 
0136         // never dereference they key, it might be a stale pointer in corner cases
0137         QHash<CollectionScanner::Directory*, int> m_directoryIds;
0138         QHash<CollectionScanner::Album*, int> m_albumIds;
0139 
0140         void urlsCacheInit();
0141         /**
0142          * Inserts @param entry into caches. If an entry with same url id already exists
0143          * in cache, it will be replaced. Duplicates in uidUrl and path are _not_ avoided,
0144          * m_uidCache and m_pathCache will point to most recently added entry.
0145          */
0146         void urlsCacheInsert( const UrlEntry &entry );
0147         void urlsCacheRemove( const UrlEntry &entry );
0148 
0149         /// maps UrlEntry id to UrlEntry
0150         QHash<int, UrlEntry> m_urlsCache;
0151         /// maps uid to UrlEntry id
0152         QMultiHash<QString, int> m_uidCache;
0153         /// maps path to UrlEntry id
0154         QHash<QString, int> m_pathCache;
0155         /// maps directory id to UrlEntry id
0156         QMultiHash<int, int> m_directoryCache;
0157 
0158         QDateTime m_blockedTime;
0159         QStringList m_messages;
0160 };
0161 
0162 QDebug operator<<( QDebug dbg, const SqlScanResultProcessor::UrlEntry &entry );
0163 
0164 #endif