mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-06 14:16:32 +02:00
WIP towards file mtime scanning
This commit is contained in:
@@ -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
|
||||
|
71
src/libtomahawk/database/databasecommand_filemtimes.cpp
Normal file
71
src/libtomahawk/database/databasecommand_filemtimes.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "databasecommand_filemtimes.h"
|
||||
|
||||
#include <QSqlQuery>
|
||||
|
||||
#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<QString,unsigned int> 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<QString, unsigned int> &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() );
|
||||
}
|
64
src/libtomahawk/database/databasecommand_filemtimes.h
Normal file
64
src/libtomahawk/database/databasecommand_filemtimes.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DATABASECOMMAND_FILEMTIMES_H
|
||||
#define DATABASECOMMAND_FILEMTIMES_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariantMap>
|
||||
#include <QMap>
|
||||
|
||||
#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<QString, unsigned int>& );
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
void execSelectPath( DatabaseImpl *dbi, const QDir& path, QMap<QString, unsigned int> &mtimes );
|
||||
|
||||
void execSelect( DatabaseImpl* dbi );
|
||||
void execUpdate( DatabaseImpl* dbi );
|
||||
QString m_prefix;
|
||||
QStringList m_prefixes;
|
||||
QMap<QString, unsigned int> m_tosave;
|
||||
};
|
||||
|
||||
#endif // DATABASECOMMAND_FILEMTIMES_H
|
@@ -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
|
||||
{
|
||||
|
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#ifndef TOMAHAWK_SETTINGS_H
|
||||
#define TOMAHAWK_SETTINGS_h
|
||||
#define TOMAHAWK_SETTINGS_H
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
@@ -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 );
|
||||
|
@@ -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<DatabaseCommand>( 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<QString, unsigned int> ) ),
|
||||
SLOT( setMtimes( QMap<QString, unsigned int> ) ) );
|
||||
SLOT( setDirMtimes( QMap<QString, unsigned int> ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MusicScanner::setMtimes( const QMap<QString, unsigned int>& m )
|
||||
MusicScanner::setDirMtimes( const QMap<QString, unsigned int>& 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<QString, unsigned int> ) ),
|
||||
SLOT( setFileMtimes( QMap<QString, unsigned int> ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
return;
|
||||
}
|
||||
scan();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MusicScanner::setFileMtimes( const QMap<QString, unsigned int>& m )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m.count();
|
||||
m_filemtimes = m;
|
||||
scan();
|
||||
}
|
||||
|
||||
@@ -192,14 +214,16 @@ MusicScanner::setMtimes( const QMap<QString, unsigned int>& 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 ) ),
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#ifndef MUSICSCANNER_H
|
||||
#define MUSICSCANNER_H
|
||||
|
||||
#include <tomahawksettings.h>
|
||||
|
||||
/* taglib */
|
||||
#include <fileref.h>
|
||||
#include <tag.h>
|
||||
@@ -47,8 +49,8 @@ public:
|
||||
MTimeOnly
|
||||
};
|
||||
|
||||
DirLister( const QStringList& dirs, const QMap<QString, unsigned int>& mtimes, bool recursive )
|
||||
: QObject(), m_dirs( dirs ), m_dirmtimes( mtimes ), m_recursive( recursive )
|
||||
DirLister( const QStringList& dirs, const QMap<QString, unsigned int>& 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<QString, unsigned int> m_dirmtimes;
|
||||
TomahawkSettings::ScannerMode m_mode;
|
||||
bool m_recursive;
|
||||
|
||||
QMap<QString, unsigned int> 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<QString, unsigned int>& m );
|
||||
void setDirMtimes( const QMap<QString, unsigned int>& m );
|
||||
void setFileMtimes( const QMap<QString, unsigned int>& m );
|
||||
void commitBatch( const QVariantList& );
|
||||
|
||||
private:
|
||||
QStringList m_dirs;
|
||||
TomahawkSettings::ScannerMode m_mode;
|
||||
QMap<QString, QString> m_ext2mime; // eg: mp3 -> audio/mpeg
|
||||
unsigned int m_scanned;
|
||||
unsigned int m_skipped;
|
||||
@@ -108,6 +114,7 @@ private:
|
||||
QList<QString> m_skippedFiles;
|
||||
|
||||
QMap<QString, unsigned int> m_dirmtimes;
|
||||
QMap<QString, unsigned int> m_filemtimes;
|
||||
QMap<QString, unsigned int> m_newdirmtimes;
|
||||
|
||||
QList<QVariant> m_scannedfiles;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -374,7 +374,7 @@ void
|
||||
TomahawkWindow::updateCollectionManually()
|
||||
{
|
||||
if ( TomahawkSettings::instance()->hasScannerPaths() )
|
||||
ScanManager::instance()->runManualScan( TomahawkSettings::instance()->scannerPaths() );
|
||||
ScanManager::instance()->runScan();
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user