From 0a8e0daa5749e0c23ef98195c8629a60ef7f1b51 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 20 May 2011 13:00:37 -0400 Subject: [PATCH] WIP towards file mtime scanning --- src/libtomahawk/CMakeLists.txt | 2 + .../database/databasecommand_filemtimes.cpp | 71 +++++++++++++++++++ .../database/databasecommand_filemtimes.h | 64 +++++++++++++++++ src/libtomahawk/tomahawksettings.cpp | 15 ++++ src/libtomahawk/tomahawksettings.h | 5 +- src/musicscanner.cpp | 40 ++++++++--- src/musicscanner.h | 15 ++-- src/scanmanager.cpp | 29 +++++--- src/scanmanager.h | 3 +- src/tomahawkwindow.cpp | 2 +- 10 files changed, 222 insertions(+), 24 deletions(-) create mode 100644 src/libtomahawk/database/databasecommand_filemtimes.cpp create mode 100644 src/libtomahawk/database/databasecommand_filemtimes.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index def12ffd7..bf072ea51 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -54,6 +54,7 @@ set( libSources database/databasecommand_addfiles.cpp database/databasecommand_deletefiles.cpp database/databasecommand_dirmtimes.cpp + database/databasecommand_filemtimes.cpp database/databasecommand_loadfile.cpp database/databasecommand_logplayback.cpp database/databasecommand_addsource.cpp @@ -214,6 +215,7 @@ set( libHeaders database/databasecommand_addfiles.h database/databasecommand_deletefiles.h database/databasecommand_dirmtimes.h + database/databasecommand_filemtimes.h database/databasecommand_loadfile.h database/databasecommand_logplayback.h database/databasecommand_addsource.h diff --git a/src/libtomahawk/database/databasecommand_filemtimes.cpp b/src/libtomahawk/database/databasecommand_filemtimes.cpp new file mode 100644 index 000000000..838aa181f --- /dev/null +++ b/src/libtomahawk/database/databasecommand_filemtimes.cpp @@ -0,0 +1,71 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "databasecommand_filemtimes.h" + +#include + +#include "databaseimpl.h" + + +void +DatabaseCommand_FileMtimes::exec( DatabaseImpl* dbi ) +{ + execSelect( dbi ); +} + + +void +DatabaseCommand_FileMtimes::execSelect( DatabaseImpl* dbi ) +{ + //FIXME: If ever needed for a non-local source this will have to be fixed/updated + QMap mtimes; + TomahawkSqlQuery query = dbi->newquery(); + if( m_prefix.isEmpty() && m_prefixes.isEmpty() ) + { + query.exec( "SELECT id, mtime FROM file WHERE souce IS NULL" ); + while( query.next() ) + mtimes.insert( query.value( 0 ).toString(), query.value( 1 ).toUInt() ); + } + else if( m_prefixes.isEmpty() ) + execSelectPath( dbi, m_prefix, mtimes ); + else + { + if( !m_prefix.isEmpty() ) + execSelectPath( dbi, m_prefix, mtimes ); + foreach( QString path, m_prefixes ) + execSelectPath( dbi, path, mtimes ); + } + emit done( mtimes ); +} + +void +DatabaseCommand_FileMtimes::execSelectPath( DatabaseImpl *dbi, const QDir& path, QMap &mtimes ) +{ + TomahawkSqlQuery query = dbi->newquery(); + query.prepare( QString( "SELECT id, mtime " + "FROM file " + "WHERE source IS NULL " + "AND url LIKE :prefix" ) ); + + query.bindValue( ":prefix", "file://" + path.canonicalPath() + "%" ); + query.exec(); + + while( query.next() ) + mtimes.insert( query.value( 0 ).toString(), query.value( 1 ).toUInt() ); +} diff --git a/src/libtomahawk/database/databasecommand_filemtimes.h b/src/libtomahawk/database/databasecommand_filemtimes.h new file mode 100644 index 000000000..e9470605f --- /dev/null +++ b/src/libtomahawk/database/databasecommand_filemtimes.h @@ -0,0 +1,64 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef DATABASECOMMAND_FILEMTIMES_H +#define DATABASECOMMAND_FILEMTIMES_H + +#include +#include +#include + +#include "databasecommand.h" + +#include "dllmacro.h" + +// Not loggable, mtimes only used to speed up our local scanner. + +class DLLEXPORT DatabaseCommand_FileMtimes : public DatabaseCommand +{ +Q_OBJECT + +public: + explicit DatabaseCommand_FileMtimes( const QString& prefix = QString(), QObject* parent = 0 ) + : DatabaseCommand( parent ), m_prefix( prefix ) + {} + + explicit DatabaseCommand_FileMtimes( const QStringList& prefixes, QObject* parent = 0 ) + : DatabaseCommand( parent ), m_prefixes( prefixes ) + {} + + virtual void exec( DatabaseImpl* ); + virtual bool doesMutates() const { return false; } + virtual QString commandname() const { return "filemtimes"; } + +signals: + void done( const QMap& ); + +public slots: + +private: + void execSelectPath( DatabaseImpl *dbi, const QDir& path, QMap &mtimes ); + + void execSelect( DatabaseImpl* dbi ); + void execUpdate( DatabaseImpl* dbi ); + QString m_prefix; + QStringList m_prefixes; + QMap m_tosave; +}; + +#endif // DATABASECOMMAND_FILEMTIMES_H diff --git a/src/libtomahawk/tomahawksettings.cpp b/src/libtomahawk/tomahawksettings.cpp index 6ec09a432..2c06709d0 100644 --- a/src/libtomahawk/tomahawksettings.cpp +++ b/src/libtomahawk/tomahawksettings.cpp @@ -174,6 +174,21 @@ TomahawkSettings::hasScannerPaths() const } +TomahawkSettings::ScannerMode +TomahawkSettings::scannerMode() const +{ + //FIXME: Default to directories? + return (TomahawkSettings::ScannerMode) value( "scanner-mode", TomahawkSettings::Files ).toInt(); +} + + +void +TomahawkSettings::setScannerMode( ScannerMode mode ) +{ + setValue( "scanner-mode", mode ); +} + + bool TomahawkSettings::watchForChanges() const { diff --git a/src/libtomahawk/tomahawksettings.h b/src/libtomahawk/tomahawksettings.h index b61660b23..7c5f0c886 100644 --- a/src/libtomahawk/tomahawksettings.h +++ b/src/libtomahawk/tomahawksettings.h @@ -17,7 +17,7 @@ */ #ifndef TOMAHAWK_SETTINGS_H -#define TOMAHAWK_SETTINGS_h +#define TOMAHAWK_SETTINGS_H #include @@ -41,9 +41,12 @@ public: void applyChanges() { emit changed(); } /// General settings + enum ScannerMode { Dirs, Files }; QStringList scannerPaths(); /// QDesktopServices::MusicLocation by default void setScannerPaths( const QStringList& paths ); bool hasScannerPaths() const; + ScannerMode scannerMode() const; + void setScannerMode( ScannerMode mode ); bool watchForChanges() const; void setWatchForChanges( bool watch ); diff --git a/src/musicscanner.cpp b/src/musicscanner.cpp index 1076c93a6..52ccef7cc 100644 --- a/src/musicscanner.cpp +++ b/src/musicscanner.cpp @@ -25,6 +25,7 @@ #include "sourcelist.h" #include "database/database.h" #include "database/databasecommand_dirmtimes.h" +#include "database/databasecommand_filemtimes.h" #include "database/databasecommand_addfiles.h" #include "database/databasecommand_deletefiles.h" @@ -79,13 +80,15 @@ DirLister::scanDir( QDir dir, int depth, DirLister::Mode mode ) const uint mtime = QFileInfo( dir.canonicalPath() ).lastModified().toUTC().toTime_t(); m_newdirmtimes.insert( dir.canonicalPath(), mtime ); - if ( m_dirmtimes.contains( dir.canonicalPath() ) && mtime == m_dirmtimes.value( dir.canonicalPath() ) ) + if ( m_mode == TomahawkSettings::Dirs && m_dirmtimes.contains( dir.canonicalPath() ) && mtime == m_dirmtimes.value( dir.canonicalPath() ) ) { // dont scan this dir, unchanged since last time. } else { - if( m_dirmtimes.contains( dir.canonicalPath() ) || !m_recursive ) + if( m_mode == TomahawkSettings::Dirs + && ( m_dirmtimes.contains( dir.canonicalPath() ) || !m_recursive ) + && mtime == m_dirmtimes.value( dir.canonicalPath() ) ) Database::instance()->enqueue( QSharedPointer( new DatabaseCommand_DeleteFiles( dir, SourceList::instance()->getLocal() ) ) ); dir.setFilter( QDir::Files | QDir::Readable | QDir::NoDotAndDotDot ); @@ -112,9 +115,10 @@ DirLister::scanDir( QDir dir, int depth, DirLister::Mode mode ) } -MusicScanner::MusicScanner( const QStringList& dirs, bool recursive, quint32 bs ) +MusicScanner::MusicScanner( const QStringList& dirs, TomahawkSettings::ScannerMode mode, bool recursive, quint32 bs ) : QObject() , m_dirs( dirs ) + , m_mode( mode ) , m_recursive( recursive ) , m_batchsize( bs ) , m_dirListerThreadController( 0 ) @@ -172,19 +176,37 @@ MusicScanner::startScan() //FIXME: For multiple collection support make sure the right prefix gets passed in...or not... //bear in mind that simply passing in the top-level of a defined collection means it will not return items that need //to be removed that aren't in that root any longer -- might have to do the filtering in setMTimes based on strings - DatabaseCommand_DirMtimes* cmd = new DatabaseCommand_DirMtimes(); + DatabaseCommand_DirMtimes *cmd = new DatabaseCommand_DirMtimes(); connect( cmd, SIGNAL( done( QMap ) ), - SLOT( setMtimes( QMap ) ) ); + SLOT( setDirMtimes( QMap ) ) ); Database::instance()->enqueue( QSharedPointer(cmd) ); } void -MusicScanner::setMtimes( const QMap& m ) +MusicScanner::setDirMtimes( const QMap& m ) { qDebug() << Q_FUNC_INFO << m.count(); m_dirmtimes = m; + if ( m_mode == TomahawkSettings::Files ) + { + DatabaseCommand_FileMtimes *cmd = new DatabaseCommand_FileMtimes(); + connect( cmd, SIGNAL( done( QMap ) ), + SLOT( setFileMtimes( QMap ) ) ); + + Database::instance()->enqueue( QSharedPointer(cmd) ); + return; + } + scan(); +} + + +void +MusicScanner::setFileMtimes( const QMap& m ) +{ + qDebug() << Q_FUNC_INFO << m.count(); + m_filemtimes = m; scan(); } @@ -192,14 +214,16 @@ MusicScanner::setMtimes( const QMap& m ) void MusicScanner::scan() { - qDebug() << "Scanning, num saved mtimes from last scan:" << m_dirmtimes.size(); + qDebug() << "Scanning, num saved dir mtimes from last scan:" << m_dirmtimes.size(); + if ( m_mode == TomahawkSettings::Files ) + qDebug() << "Num saved file mtimes from last scan:" << m_filemtimes.size(); connect( this, SIGNAL( batchReady( QVariantList ) ), SLOT( commitBatch( QVariantList ) ), Qt::DirectConnection ); m_dirListerThreadController = new QThread( this ); - m_dirLister = QWeakPointer< DirLister >( new DirLister( m_dirs, m_dirmtimes, m_recursive ) ); + m_dirLister = QWeakPointer< DirLister >( new DirLister( m_dirs, m_dirmtimes, m_mode, m_recursive ) ); m_dirLister.data()->moveToThread( m_dirListerThreadController ); connect( m_dirLister.data(), SIGNAL( fileToScan( QFileInfo ) ), diff --git a/src/musicscanner.h b/src/musicscanner.h index 29da62d7e..37f5d14f6 100644 --- a/src/musicscanner.h +++ b/src/musicscanner.h @@ -19,6 +19,8 @@ #ifndef MUSICSCANNER_H #define MUSICSCANNER_H +#include + /* taglib */ #include #include @@ -47,8 +49,8 @@ public: MTimeOnly }; - DirLister( const QStringList& dirs, const QMap& mtimes, bool recursive ) - : QObject(), m_dirs( dirs ), m_dirmtimes( mtimes ), m_recursive( recursive ) + DirLister( const QStringList& dirs, const QMap& dirmtimes, TomahawkSettings::ScannerMode mode, bool recursive ) + : QObject(), m_dirs( dirs ), m_dirmtimes( dirmtimes ), m_mode( mode ), m_recursive( recursive ) { qDebug() << Q_FUNC_INFO; } @@ -69,17 +71,19 @@ private slots: private: QStringList m_dirs; QMap m_dirmtimes; + TomahawkSettings::ScannerMode m_mode; bool m_recursive; QMap m_newdirmtimes; }; + class MusicScanner : public QObject { Q_OBJECT public: - MusicScanner( const QStringList& dirs, bool recursive = true, quint32 bs = 0 ); + MusicScanner( const QStringList& dirs, TomahawkSettings::ScannerMode mode, bool recursive = true, quint32 bs = 0 ); ~MusicScanner(); signals: @@ -96,11 +100,13 @@ private slots: void scanFile( const QFileInfo& fi ); void startScan(); void scan(); - void setMtimes( const QMap& m ); + void setDirMtimes( const QMap& m ); + void setFileMtimes( const QMap& m ); void commitBatch( const QVariantList& ); private: QStringList m_dirs; + TomahawkSettings::ScannerMode m_mode; QMap m_ext2mime; // eg: mp3 -> audio/mpeg unsigned int m_scanned; unsigned int m_skipped; @@ -108,6 +114,7 @@ private: QList m_skippedFiles; QMap m_dirmtimes; + QMap m_filemtimes; QMap m_newdirmtimes; QList m_scannedfiles; diff --git a/src/scanmanager.cpp b/src/scanmanager.cpp index e4caffe6f..ea150af71 100644 --- a/src/scanmanager.cpp +++ b/src/scanmanager.cpp @@ -109,7 +109,7 @@ ScanManager::onSettingsChanged() m_currScannerPaths != TomahawkSettings::instance()->scannerPaths() ) { m_currScannerPaths = TomahawkSettings::instance()->scannerPaths(); - runManualScan( m_currScannerPaths ); + runScan(); } if ( TomahawkSettings::instance()->watchForChanges() && !m_scanTimer->isActive() ) @@ -121,10 +121,10 @@ void ScanManager::runStartupScan() { qDebug() << Q_FUNC_INFO; - if( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) + if ( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) QTimer::singleShot( 1000, this, SLOT( runStartupScan() ) ); else - runManualScan( m_currScannerPaths ); + runScan(); } @@ -132,25 +132,36 @@ void ScanManager::scanTimerTimeout() { qDebug() << Q_FUNC_INFO; - if( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) + if ( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) return; else - runManualScan( m_currScannerPaths ); + runScan(); } void -ScanManager::runManualScan( const QStringList& paths ) +ScanManager::runScan() +{ + qDebug() << Q_FUNC_INFO; + if ( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) + return; + + runDirScan( TomahawkSettings::instance()->scannerPaths() ); +} + + +void +ScanManager::runDirScan( const QStringList& paths ) { qDebug() << Q_FUNC_INFO; - if( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) + if ( !Database::instance() || ( Database::instance() && !Database::instance()->isReady() ) ) return; if ( !m_musicScannerThreadController && m_scanner.isNull() ) //still running if these are not zero { m_musicScannerThreadController = new QThread( this ); - m_scanner = QWeakPointer< MusicScanner>( new MusicScanner( paths ) ); + m_scanner = QWeakPointer< MusicScanner>( new MusicScanner( paths, TomahawkSettings::instance()->scannerMode() ) ); m_scanner.data()->moveToThread( m_musicScannerThreadController ); connect( m_scanner.data(), SIGNAL( finished() ), SLOT( scannerFinished() ) ); m_musicScannerThreadController->start( QThread::IdlePriority ); @@ -158,7 +169,7 @@ ScanManager::runManualScan( const QStringList& paths ) } else { - qDebug() << "Could not run manual scan, old scan still running"; + qDebug() << "Could not run dir scan, old scan still running"; return; } } diff --git a/src/scanmanager.h b/src/scanmanager.h index cf99fae39..87da4c238 100644 --- a/src/scanmanager.h +++ b/src/scanmanager.h @@ -47,7 +47,8 @@ signals: void finished(); public slots: - void runManualScan( const QStringList& paths ); + void runScan(); + void runDirScan( const QStringList& paths ); private slots: void scannerFinished(); diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 251fc7205..0bad7b41e 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -374,7 +374,7 @@ void TomahawkWindow::updateCollectionManually() { if ( TomahawkSettings::instance()->hasScannerPaths() ) - ScanManager::instance()->runManualScan( TomahawkSettings::instance()->scannerPaths() ); + ScanManager::instance()->runScan(); }