mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-04-22 08:52:12 +02:00
* Added obsolete / stale file detection to MusicScanner and corresponding DatabaseCommands.
This commit is contained in:
parent
643b8fac5d
commit
fa81b0647a
@ -45,6 +45,7 @@ set( libSources
|
||||
database/databasecommand_allalbums.cpp
|
||||
database/databasecommand_alltracks.cpp
|
||||
database/databasecommand_addfiles.cpp
|
||||
database/databasecommand_deletefiles.cpp
|
||||
database/databasecommand_dirmtimes.cpp
|
||||
database/databasecommand_loadfile.cpp
|
||||
database/databasecommand_logplayback.cpp
|
||||
@ -187,6 +188,7 @@ set( libHeaders
|
||||
database/databasecommand_allalbums.h
|
||||
database/databasecommand_alltracks.h
|
||||
database/databasecommand_addfiles.h
|
||||
database/databasecommand_deletefiles.h
|
||||
database/databasecommand_dirmtimes.h
|
||||
database/databasecommand_loadfile.h
|
||||
database/databasecommand_logplayback.h
|
||||
|
@ -153,10 +153,40 @@ Collection::setDynamicPlaylists( const QList< Tomahawk::dynplaylist_ptr >& plist
|
||||
|
||||
|
||||
void
|
||||
Collection::setTracks( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::collection_ptr collection )
|
||||
Collection::setTracks( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << tracks.count() << collection->name();
|
||||
|
||||
m_tracks << tracks;
|
||||
emit tracksAdded( tracks, collection );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Collection::delTracks( const QStringList& files, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << files.count() << collection->name();
|
||||
|
||||
QList<Tomahawk::query_ptr> tracks;
|
||||
|
||||
int i = 0;
|
||||
foreach ( const query_ptr& query, m_tracks )
|
||||
{
|
||||
foreach ( QString file, files )
|
||||
{
|
||||
foreach ( const result_ptr& result, query->results() )
|
||||
{
|
||||
if ( file == result->url() )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Found deleted result:" << file;
|
||||
tracks << query;
|
||||
m_tracks.removeAt( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
emit tracksRemoved( tracks, collection );
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define TOMAHAWK_COLLECTION_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
#include <QDebug>
|
||||
@ -56,7 +57,7 @@ public:
|
||||
|
||||
signals:
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& );
|
||||
void tracksRemoved( const QList<QVariant>&, const Tomahawk::collection_ptr& );
|
||||
void tracksRemoved( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& );
|
||||
void tracksFinished( const Tomahawk::collection_ptr& );
|
||||
|
||||
void playlistsAdded( const QList<Tomahawk::playlist_ptr>& );
|
||||
@ -66,12 +67,14 @@ signals:
|
||||
void dynamicPlaylistsDeleted( const QList<Tomahawk::dynplaylist_ptr>& );
|
||||
|
||||
public slots:
|
||||
virtual void addTracks( const QList<QVariant> &newitems ) = 0;
|
||||
virtual void removeTracks( const QList<QVariant> &olditems ) = 0;
|
||||
virtual void addTracks( const QList<QVariant>& newitems ) = 0;
|
||||
virtual void removeTracks( const QDir& dir ) = 0;
|
||||
|
||||
void setPlaylists( const QList<Tomahawk::playlist_ptr>& plists );
|
||||
void setDynamicPlaylists( const QList< Tomahawk::dynplaylist_ptr >& dynplists );
|
||||
void setTracks( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::collection_ptr collection );
|
||||
void setTracks( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection );
|
||||
|
||||
void delTracks( const QStringList& files, const Tomahawk::collection_ptr& collection );
|
||||
|
||||
protected:
|
||||
QString m_name;
|
||||
@ -79,8 +82,8 @@ protected:
|
||||
|
||||
private:
|
||||
source_ptr m_source;
|
||||
QList< Tomahawk::playlist_ptr > m_playlists;
|
||||
QList< Tomahawk::query_ptr > m_tracks;
|
||||
QList< Tomahawk::playlist_ptr > m_playlists;
|
||||
QList< Tomahawk::dynplaylist_ptr > m_dynplaylists;
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "database/database.h"
|
||||
#include "databasecommand_alltracks.h"
|
||||
#include "databasecommand_addfiles.h"
|
||||
#include "databasecommand_deletefiles.h"
|
||||
#include "databasecommand_loadallplaylists.h"
|
||||
#include "databasecommand_loadalldynamicplaylists.h"
|
||||
|
||||
@ -58,7 +59,7 @@ DatabaseCollection::loadTracks()
|
||||
|
||||
|
||||
void
|
||||
DatabaseCollection::addTracks( const QList<QVariant> &newitems )
|
||||
DatabaseCollection::addTracks( const QList<QVariant>& newitems )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << newitems.length();
|
||||
DatabaseCommand_AddFiles* cmd = new DatabaseCommand_AddFiles( newitems, source() );
|
||||
@ -68,13 +69,12 @@ DatabaseCollection::addTracks( const QList<QVariant> &newitems )
|
||||
|
||||
|
||||
void
|
||||
DatabaseCollection::removeTracks( const QList<QVariant> &olditems )
|
||||
DatabaseCollection::removeTracks( const QDir& dir )
|
||||
{
|
||||
// FIXME
|
||||
Q_ASSERT( false );
|
||||
|
||||
// TODO RemoveTracks cmd, probably builds a temp table of all the URLs in
|
||||
// olditems, then joins on that to batch-delete.
|
||||
qDebug() << Q_FUNC_INFO << dir;
|
||||
DatabaseCommand_DeleteFiles* cmd = new DatabaseCommand_DeleteFiles( dir, source() );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef DATABASECOLLECTION_H
|
||||
#define DATABASECOLLECTION_H
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include "collection.h"
|
||||
#include "source.h"
|
||||
#include "typedefs.h"
|
||||
@ -27,8 +29,8 @@ public:
|
||||
virtual QList< Tomahawk::dynplaylist_ptr > dynamicPlaylists();
|
||||
|
||||
public slots:
|
||||
virtual void addTracks( const QList<QVariant> &newitems );
|
||||
virtual void removeTracks( const QList<QVariant> &olditems );
|
||||
virtual void addTracks( const QList<QVariant>& newitems );
|
||||
virtual void removeTracks( const QDir& dir );
|
||||
|
||||
private slots:
|
||||
void dynamicPlaylistCreated( const Tomahawk::source_ptr& source, const QVariantList& data );
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "databasecommand_addfiles.h"
|
||||
#include "databasecommand_createplaylist.h"
|
||||
#include "databasecommand_deletefiles.h"
|
||||
#include "databasecommand_deleteplaylist.h"
|
||||
#include "databasecommand_logplayback.h"
|
||||
#include "databasecommand_renameplaylist.h"
|
||||
@ -60,6 +61,13 @@ DatabaseCommand::factory( const QVariant& op, const source_ptr& source )
|
||||
QJson::QObjectHelper::qvariant2qobject( op.toMap(), cmd );
|
||||
return cmd;
|
||||
}
|
||||
else if( name == "deletefiles" )
|
||||
{
|
||||
DatabaseCommand_DeleteFiles * cmd = new DatabaseCommand_DeleteFiles;
|
||||
cmd->setSource( source );
|
||||
QJson::QObjectHelper::qvariant2qobject( op.toMap(), cmd );
|
||||
return cmd;
|
||||
}
|
||||
else if( name == "createplaylist" )
|
||||
{
|
||||
DatabaseCommand_CreatePlaylist * cmd = new DatabaseCommand_CreatePlaylist;
|
||||
|
@ -73,19 +73,14 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
|
||||
TomahawkSqlQuery query_trackattr = dbi->newquery();
|
||||
TomahawkSqlQuery query_file_del = dbi->newquery();
|
||||
|
||||
query_file.prepare( "INSERT INTO file(source, url, size, mtime, md5, mimetype, duration, bitrate) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)" );
|
||||
query_filejoin.prepare( "INSERT INTO file_join(file, artist, album, track, albumpos) "
|
||||
"VALUES (?,?,?,?,?)" );
|
||||
query_trackattr.prepare( "INSERT INTO track_attributes(id, k, v) "
|
||||
"VALUES (?,?,?)" );
|
||||
query_file.prepare( "INSERT INTO file(source, url, size, mtime, md5, mimetype, duration, bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" );
|
||||
query_filejoin.prepare( "INSERT INTO file_join(file, artist, album, track, albumpos) VALUES (?, ?, ?, ?, ?)" );
|
||||
query_trackattr.prepare( "INSERT INTO track_attributes(id, k, v) VALUES (?, ?, ?)" );
|
||||
query_file_del.prepare( QString( "DELETE FROM file WHERE source %1 AND url = ?" )
|
||||
.arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) ) );
|
||||
|
||||
int added = 0;
|
||||
QVariant srcid = source()->isLocal() ?
|
||||
QVariant( QVariant::Int ) : source()->id();
|
||||
|
||||
QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id();
|
||||
qDebug() << "Adding" << m_files.length() << "files to db for source" << srcid;
|
||||
|
||||
QList<QVariant>::iterator it;
|
||||
@ -94,18 +89,18 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
|
||||
QVariant& v = *it;
|
||||
QVariantMap m = v.toMap();
|
||||
|
||||
QString url = m.value( "url" ).toString();
|
||||
int mtime = m.value( "mtime" ).toInt();
|
||||
int size = m.value( "size" ).toInt();
|
||||
QString hash = m.value( "hash" ).toString();
|
||||
QString mimetype = m.value( "mimetype" ).toString();
|
||||
int duration = m.value( "duration" ).toInt();
|
||||
int bitrate = m.value( "bitrate" ).toInt();
|
||||
QString artist = m.value( "artist" ).toString();
|
||||
QString album = m.value( "album" ).toString();
|
||||
QString track = m.value( "track" ).toString();
|
||||
int albumpos = m.value( "albumpos" ).toInt();
|
||||
int year = m.value( "year" ).toInt();
|
||||
QString url = m.value( "url" ).toString();
|
||||
int mtime = m.value( "mtime" ).toInt();
|
||||
uint size = m.value( "size" ).toUInt();
|
||||
QString hash = m.value( "hash" ).toString();
|
||||
QString mimetype = m.value( "mimetype" ).toString();
|
||||
uint duration = m.value( "duration" ).toUInt();
|
||||
uint bitrate = m.value( "bitrate" ).toUInt();
|
||||
QString artist = m.value( "artist" ).toString();
|
||||
QString album = m.value( "album" ).toString();
|
||||
QString track = m.value( "track" ).toString();
|
||||
uint albumpos = m.value( "albumpos" ).toUInt();
|
||||
int year = m.value( "year" ).toInt();
|
||||
|
||||
int fileid = 0, artistid = 0, albumid = 0, trackid = 0;
|
||||
query_file_del.bindValue( 0, url );
|
||||
@ -139,9 +134,7 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
|
||||
v = m;
|
||||
|
||||
if( !source()->isLocal() )
|
||||
url = QString( "servent://%1\t%2" )
|
||||
.arg( source()->userName() )
|
||||
.arg( url );
|
||||
url = QString( "servent://%1\t%2" ).arg( source()->userName() ).arg( url );
|
||||
|
||||
bool isnew;
|
||||
artistid = dbi->artistId( artist, isnew );
|
||||
|
@ -36,8 +36,8 @@ public:
|
||||
void setFiles( const QVariantList& f ) { m_files = f; }
|
||||
|
||||
signals:
|
||||
void done( const QList<QVariant>&, Tomahawk::collection_ptr );
|
||||
void notify( const QList<Tomahawk::query_ptr>&, Tomahawk::collection_ptr );
|
||||
void done( const QList<QVariant>&, const Tomahawk::collection_ptr& );
|
||||
void notify( const QList<Tomahawk::query_ptr>&, const Tomahawk::collection_ptr& );
|
||||
|
||||
private:
|
||||
QVariantList m_files;
|
||||
|
122
src/libtomahawk/database/databasecommand_deletefiles.cpp
Normal file
122
src/libtomahawk/database/databasecommand_deletefiles.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "databasecommand_deletefiles.h"
|
||||
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "artist.h"
|
||||
#include "album.h"
|
||||
#include "collection.h"
|
||||
#include "database/database.h"
|
||||
#include "databasecommand_collectionstats.h"
|
||||
#include "databaseimpl.h"
|
||||
#include "network/controlconnection.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
// After changing a collection, we need to tell other bits of the system:
|
||||
void
|
||||
DatabaseCommand_DeleteFiles::postCommitHook()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
// make the collection object emit its tracksAdded signal, so the
|
||||
// collection browser will update/fade in etc.
|
||||
Collection* coll = source()->collection().data();
|
||||
|
||||
connect( this, SIGNAL( notify( QStringList, Tomahawk::collection_ptr ) ),
|
||||
coll, SLOT( delTracks( QStringList, Tomahawk::collection_ptr ) ), Qt::QueuedConnection );
|
||||
|
||||
emit notify( m_files, source()->collection() );
|
||||
|
||||
// also re-calc the collection stats, to updates the "X tracks" in the sidebar etc:
|
||||
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( source() );
|
||||
connect( cmd, SIGNAL( done( QVariantMap ) ),
|
||||
source().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
|
||||
if( source()->isLocal() )
|
||||
Servent::instance()->triggerDBSync();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCommand_DeleteFiles::exec( DatabaseImpl* dbi )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
Q_ASSERT( !source().isNull() );
|
||||
|
||||
int deleted = 0;
|
||||
QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id();
|
||||
TomahawkSqlQuery delquery = dbi->newquery();
|
||||
|
||||
if ( !m_dir.path().isEmpty() && source()->isLocal() )
|
||||
{
|
||||
qDebug() << "Deleting" << m_dir.path() << "from db for localsource" << srcid;
|
||||
TomahawkSqlQuery dirquery = dbi->newquery();
|
||||
|
||||
dirquery.prepare( QString( "SELECT id, url FROM file WHERE source %1 AND url LIKE ?" )
|
||||
.arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) ) );
|
||||
delquery.prepare( QString( "DELETE FROM file WHERE source %1 AND id = ?" )
|
||||
.arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) ) );
|
||||
|
||||
dirquery.bindValue( 0, "file://" + m_dir.absolutePath() + "/%" );
|
||||
dirquery.exec();
|
||||
|
||||
while ( dirquery.next() )
|
||||
{
|
||||
QFileInfo fi( dirquery.value( 1 ).toString().mid( 7 ) ); // remove file://
|
||||
if ( fi.absolutePath() != m_dir.absolutePath() )
|
||||
{
|
||||
qDebug() << "Skipping subdir:" << fi.absolutePath();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_ids << dirquery.value( 0 ).toUInt();
|
||||
m_files << dirquery.value( 1 ).toString();
|
||||
}
|
||||
|
||||
foreach ( const QVariant& id, m_ids )
|
||||
{
|
||||
delquery.bindValue( 0, id.toUInt() );
|
||||
if( !delquery.exec() )
|
||||
{
|
||||
qDebug() << "Failed to delete file:"
|
||||
<< delquery.lastError().databaseText()
|
||||
<< delquery.lastError().driverText()
|
||||
<< delquery.boundValues();
|
||||
continue;
|
||||
}
|
||||
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delquery.prepare( QString( "DELETE FROM file WHERE source %1 AND url = ?" )
|
||||
.arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) ) );
|
||||
|
||||
foreach( const QVariant& id, m_ids )
|
||||
{
|
||||
qDebug() << "Deleting" << id.toUInt() << "from db for source" << srcid;
|
||||
|
||||
const QString url = QString( "servent://%1\t%2" ).arg( source()->userName() ).arg( id.toString() );
|
||||
m_files << url;
|
||||
|
||||
delquery.bindValue( 0, id.toUInt() );
|
||||
if( !delquery.exec() )
|
||||
{
|
||||
qDebug() << "Failed to delete file:"
|
||||
<< delquery.lastError().databaseText()
|
||||
<< delquery.lastError().driverText()
|
||||
<< delquery.boundValues();
|
||||
continue;
|
||||
}
|
||||
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Deleted" << deleted << m_ids << m_files;
|
||||
|
||||
emit done( m_files, source()->collection() );
|
||||
}
|
52
src/libtomahawk/database/databasecommand_deletefiles.h
Normal file
52
src/libtomahawk/database/databasecommand_deletefiles.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef DATABASECOMMAND_DELETEFILES_H
|
||||
#define DATABASECOMMAND_DELETEFILES_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDir>
|
||||
#include <QVariantMap>
|
||||
|
||||
#include "database/databasecommandloggable.h"
|
||||
#include "typedefs.h"
|
||||
#include "query.h"
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
class DLLEXPORT DatabaseCommand_DeleteFiles : public DatabaseCommandLoggable
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QVariantList ids READ ids WRITE setIds )
|
||||
|
||||
public:
|
||||
explicit DatabaseCommand_DeleteFiles( QObject* parent = 0 )
|
||||
: DatabaseCommandLoggable( parent )
|
||||
{}
|
||||
|
||||
explicit DatabaseCommand_DeleteFiles( const QDir& dir, const Tomahawk::source_ptr& source, QObject* parent = 0 )
|
||||
: DatabaseCommandLoggable( parent ), m_dir( dir )
|
||||
{
|
||||
setSource( source );
|
||||
}
|
||||
|
||||
virtual QString commandname() const { return "deletefiles"; }
|
||||
|
||||
virtual void exec( DatabaseImpl* );
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual void postCommitHook();
|
||||
|
||||
QStringList files() const { return m_files; }
|
||||
void setFiles( const QStringList& f ) { m_files = f; }
|
||||
|
||||
QVariantList ids() const { return m_ids; }
|
||||
void setIds( const QVariantList& i ) { m_ids = i; }
|
||||
|
||||
signals:
|
||||
void done( const QStringList&, const Tomahawk::collection_ptr& );
|
||||
void notify( const QStringList&, const Tomahawk::collection_ptr& );
|
||||
|
||||
private:
|
||||
QDir m_dir;
|
||||
QStringList m_files;
|
||||
QVariantList m_ids;
|
||||
};
|
||||
|
||||
#endif // DATABASECOMMAND_DELETEFILES_H
|
@ -26,7 +26,7 @@ DatabaseCommand_DirMtimes::execSelect( DatabaseImpl* dbi )
|
||||
{
|
||||
query.prepare( QString( "SELECT name, mtime "
|
||||
"FROM dirs_scanned "
|
||||
"WHERE name LIKE '%1%'" ).arg(m_prefix.replace( '\'',"''" ) ) );
|
||||
"WHERE name LIKE '%1%'" ).arg( m_prefix.replace( '\'',"''" ) ) );
|
||||
query.exec();
|
||||
}
|
||||
while( query.next() )
|
||||
@ -44,7 +44,7 @@ DatabaseCommand_DirMtimes::execUpdate( DatabaseImpl* dbi )
|
||||
qDebug() << "Saving mtimes...";
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
query.exec( "DELETE FROM dirs_scanned" );
|
||||
query.prepare( "INSERT INTO dirs_scanned(name, mtime) VALUES(?,?)" );
|
||||
query.prepare( "INSERT INTO dirs_scanned(name, mtime) VALUES(?, ?)" );
|
||||
|
||||
foreach( const QString& k, m_tosave.keys() )
|
||||
{
|
||||
|
@ -19,7 +19,7 @@
|
||||
*/
|
||||
#include "schema.sql.h"
|
||||
|
||||
#define CURRENT_SCHEMA_VERSION 21
|
||||
#define CURRENT_SCHEMA_VERSION 22
|
||||
|
||||
|
||||
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
||||
|
@ -219,7 +219,7 @@ CREATE INDEX artist_tags_tag ON artist_tags(tag);
|
||||
-- so that we can always do range queries.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS track_attributes (
|
||||
id INTEGER NOT NULL, -- track id
|
||||
id INTEGER REFERENCES track(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- track id
|
||||
k TEXT NOT NULL,
|
||||
v TEXT NOT NULL
|
||||
);
|
||||
@ -241,6 +241,8 @@ CREATE TABLE IF NOT EXISTS playback_log (
|
||||
CREATE INDEX playback_log_source ON playback_log(source);
|
||||
CREATE INDEX playback_log_track ON playback_log(track);
|
||||
|
||||
|
||||
|
||||
-- auth information for http clients
|
||||
|
||||
CREATE TABLE IF NOT EXISTS http_client_auth (
|
||||
@ -253,6 +255,7 @@ CREATE TABLE IF NOT EXISTS http_client_auth (
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Schema version, and misc tomahawk settings relating to the collection db
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
@ -260,4 +263,4 @@ CREATE TABLE IF NOT EXISTS settings (
|
||||
v TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT INTO settings(k,v) VALUES('schema_version', '21');
|
||||
INSERT INTO settings(k,v) VALUES('schema_version', '22');
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
This file was automatically generated from schema.sql on Thu Feb 24 19:05:46 EST 2011.
|
||||
This file was automatically generated from ./schema.sql on Wed Mar 2 01:40:39 CET 2011.
|
||||
*/
|
||||
|
||||
static const char * tomahawk_schema_sql =
|
||||
@ -146,7 +146,7 @@ static const char * tomahawk_schema_sql =
|
||||
");"
|
||||
"CREATE INDEX artist_tags_tag ON artist_tags(tag);"
|
||||
"CREATE TABLE IF NOT EXISTS track_attributes ("
|
||||
" id INTEGER NOT NULL, "
|
||||
" id INTEGER REFERENCES track(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, "
|
||||
" k TEXT NOT NULL,"
|
||||
" v TEXT NOT NULL"
|
||||
");"
|
||||
@ -173,7 +173,7 @@ static const char * tomahawk_schema_sql =
|
||||
" k TEXT NOT NULL PRIMARY KEY,"
|
||||
" v TEXT NOT NULL DEFAULT ''"
|
||||
");"
|
||||
"INSERT INTO settings(k,v) VALUES('schema_version', '21');"
|
||||
"INSERT INTO settings(k,v) VALUES('schema_version', '22');"
|
||||
;
|
||||
|
||||
const char * get_tomahawk_sql()
|
||||
|
@ -108,7 +108,7 @@ ControlConnection::setupDbSyncConnection( bool ondemand )
|
||||
if ( m_dbsyncconn || !m_registered )
|
||||
return;
|
||||
|
||||
qDebug() << Q_FUNC_INFO << ondemand << m_source->id();
|
||||
qDebug() << Q_FUNC_INFO << ondemand << m_source->id() << ondemand << m_dbconnkey;
|
||||
Q_ASSERT( m_source->id() > 0 );
|
||||
|
||||
if( !m_dbconnkey.isEmpty() )
|
||||
|
@ -11,14 +11,14 @@ RemoteCollection::RemoteCollection( source_ptr source, QObject* parent )
|
||||
|
||||
// adding/removing is done by dbsyncconnection, and the dbcmd objects that modify
|
||||
// the database will make us emit the appropriate signals (tracksAdded etc.)
|
||||
void RemoteCollection::addTracks( const QList<QVariant> &newitems )
|
||||
void RemoteCollection::addTracks( const QList<QVariant>& newitems )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
|
||||
|
||||
void RemoteCollection::removeTracks( const QList<QVariant> &olditems )
|
||||
void RemoteCollection::removeTracks( const QDir& dir )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
Q_ASSERT( false );
|
||||
|
@ -20,8 +20,8 @@ public:
|
||||
}
|
||||
|
||||
public slots:
|
||||
virtual void addTracks( const QList<QVariant> &newitems );
|
||||
virtual void removeTracks( const QList<QVariant> &olditems );
|
||||
virtual void addTracks( const QList<QVariant>& newitems );
|
||||
virtual void removeTracks( const QDir& dir );
|
||||
};
|
||||
|
||||
#endif // REMOTECOLLECTION_H
|
||||
|
@ -60,7 +60,9 @@ CollectionFlatModel::addCollection( const collection_ptr& collection )
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::collection_ptr ) ) );
|
||||
connect( collection.data(), SIGNAL( tracksFinished( Tomahawk::collection_ptr ) ),
|
||||
SLOT( onTracksAddingFinished( Tomahawk::collection_ptr ) ) );
|
||||
|
||||
connect( collection.data(), SIGNAL( tracksRemoved( QList<Tomahawk::query_ptr>, Tomahawk::collection_ptr ) ),
|
||||
SLOT( onTracksRemoved( QList<Tomahawk::query_ptr>, Tomahawk::collection_ptr ) ) );
|
||||
|
||||
if ( collection->source()->isLocal() )
|
||||
setTitle( tr( "Your Collection" ) );
|
||||
else
|
||||
@ -93,6 +95,8 @@ CollectionFlatModel::addFilteredCollection( const collection_ptr& collection, un
|
||||
void
|
||||
CollectionFlatModel::removeCollection( const collection_ptr& collection )
|
||||
{
|
||||
return; // FIXME
|
||||
|
||||
disconnect( collection.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::collection_ptr ) ),
|
||||
this, SLOT( onTracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::collection_ptr ) ) );
|
||||
disconnect( collection.data(), SIGNAL( tracksFinished( Tomahawk::collection_ptr ) ),
|
||||
@ -163,6 +167,8 @@ CollectionFlatModel::removeCollection( const collection_ptr& collection )
|
||||
void
|
||||
CollectionFlatModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !tracks.count() )
|
||||
{
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
@ -202,6 +208,39 @@ CollectionFlatModel::onTracksAddingFinished( const Tomahawk::collection_ptr& col
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
QList<Tomahawk::query_ptr> t = tracks;
|
||||
for ( int i = rowCount( QModelIndex() ); i > 0 && t.count(); i-- )
|
||||
{
|
||||
PlItem* item = itemFromIndex( index( i, 0, QModelIndex() ) );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
int j = 0;
|
||||
foreach ( const query_ptr& query, t )
|
||||
{
|
||||
if ( item->query().data() == query.data() )
|
||||
{
|
||||
qDebug() << "Removing row:" << i << query->toString();
|
||||
emit beginRemoveRows( QModelIndex(), i, i );
|
||||
delete item;
|
||||
emit endRemoveRows();
|
||||
|
||||
t.removeAt( j );
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
qDebug() << Q_FUNC_INFO << rowCount( QModelIndex() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::onDataChanged()
|
||||
{
|
||||
|
@ -54,6 +54,8 @@ private slots:
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection );
|
||||
void onTracksAddingFinished( const Tomahawk::collection_ptr& collection );
|
||||
|
||||
void onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks, const Tomahawk::collection_ptr& collection );
|
||||
|
||||
void onSourceOffline( const Tomahawk::source_ptr& src );
|
||||
|
||||
private:
|
||||
|
@ -5,10 +5,19 @@
|
||||
#include "database/database.h"
|
||||
#include "database/databasecommand_dirmtimes.h"
|
||||
#include "database/databasecommand_addfiles.h"
|
||||
#include "database/databasecommand_deletefiles.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
void
|
||||
DirLister::go()
|
||||
{
|
||||
scanDir( m_dir, 0 );
|
||||
emit finished( m_newdirmtimes );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DirLister::scanDir( QDir dir, int depth )
|
||||
{
|
||||
@ -16,13 +25,15 @@ DirLister::scanDir( QDir dir, int depth )
|
||||
const uint mtime = QFileInfo( dir.absolutePath() ).lastModified().toUTC().toTime_t();
|
||||
m_newdirmtimes.insert( dir.absolutePath(), mtime );
|
||||
|
||||
if ( m_dirmtimes.contains( dir.absolutePath() ) &&
|
||||
mtime == m_dirmtimes.value( dir.absolutePath() ) )
|
||||
if ( m_dirmtimes.contains( dir.absolutePath() ) && mtime == m_dirmtimes.value( dir.absolutePath() ) )
|
||||
{
|
||||
// dont scan this dir, unchanged since last time.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_dirmtimes.contains( dir.absolutePath() ) )
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( new DatabaseCommand_DeleteFiles( dir, SourceList::instance()->getLocal() ) ) );
|
||||
|
||||
dir.setFilter( QDir::Files | QDir::Readable | QDir::NoDotAndDotDot );
|
||||
dir.setSorting( QDir::Name );
|
||||
dirs = dir.entryInfoList();
|
||||
@ -143,6 +154,7 @@ void
|
||||
MusicScanner::listerFinished( const QMap<QString, unsigned int>& newmtimes )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
// any remaining stuff that wasnt emitted as a batch:
|
||||
if( m_scannedfiles.length() )
|
||||
{
|
||||
@ -150,13 +162,23 @@ MusicScanner::listerFinished( const QMap<QString, unsigned int>& newmtimes )
|
||||
commitBatch( m_scannedfiles );
|
||||
}
|
||||
|
||||
// remove obsolete / stale files
|
||||
foreach ( const QString& path, m_dirmtimes.keys() )
|
||||
{
|
||||
if ( !newmtimes.keys().contains( path ) )
|
||||
{
|
||||
qDebug() << "Removing stale dir:" << path;
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( new DatabaseCommand_DeleteFiles( path, SourceList::instance()->getLocal() ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// save mtimes, then quit thread
|
||||
DatabaseCommand_DirMtimes* cmd = new DatabaseCommand_DirMtimes( newmtimes );
|
||||
connect( cmd, SIGNAL( finished() ), SLOT( deleteLister() ) );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
|
||||
qDebug() << "Scanning complete, saving to database. "
|
||||
"(scanned" << m_scanned << "skipped" << m_skipped << ")";
|
||||
"( scanned" << m_scanned << "skipped" << m_skipped << ")";
|
||||
|
||||
qDebug() << "Skipped the following files (no tags / no valid audio):";
|
||||
foreach( const QString& s, m_skippedFiles )
|
||||
@ -227,7 +249,9 @@ MusicScanner::scanFile( const QFileInfo& fi )
|
||||
QVariant
|
||||
MusicScanner::readFile( const QFileInfo& fi )
|
||||
{
|
||||
if ( ! m_ext2mime.contains( fi.suffix().toLower() ) )
|
||||
const QString suffix = fi.suffix().toLower();
|
||||
|
||||
if ( ! m_ext2mime.contains( suffix ) )
|
||||
{
|
||||
m_skipped++;
|
||||
return QVariantMap(); // invalid extension
|
||||
@ -240,7 +264,7 @@ MusicScanner::readFile( const QFileInfo& fi )
|
||||
qDebug() << "SCAN" << m_scanned << fi.absoluteFilePath();
|
||||
|
||||
#ifdef COMPLEX_TAGLIB_FILENAME
|
||||
const wchar_t *encodedName = reinterpret_cast< const wchar_t *>(fi.absoluteFilePath().utf16());
|
||||
const wchar_t *encodedName = reinterpret_cast< const wchar_t * >( fi.absoluteFilePath().utf16() );
|
||||
#else
|
||||
QByteArray fileName = QFile::encodeName( fi.absoluteFilePath() );
|
||||
const char *encodedName = fileName.constData();
|
||||
@ -277,14 +301,13 @@ MusicScanner::readFile( const QFileInfo& fi )
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
QString mimetype = m_ext2mime.value( fi.suffix().toLower() );
|
||||
QString mimetype = m_ext2mime.value( suffix );
|
||||
QString url( "file://%1" );
|
||||
|
||||
QVariantMap m;
|
||||
m["url"] = url.arg( fi.absoluteFilePath() );
|
||||
m["mtime"] = fi.lastModified().toUTC().toTime_t();
|
||||
m["size"] = (unsigned int)fi.size();
|
||||
m["hash"] = ""; // TODO
|
||||
m["mimetype"] = mimetype;
|
||||
m["duration"] = duration;
|
||||
m["bitrate"] = bitrate;
|
||||
@ -293,7 +316,8 @@ MusicScanner::readFile( const QFileInfo& fi )
|
||||
m["track"] = track;
|
||||
m["albumpos"] = tag->track();
|
||||
m["year"] = tag->year();
|
||||
|
||||
m["hash"] = ""; // TODO
|
||||
|
||||
m_scanned++;
|
||||
return m;
|
||||
}
|
||||
|
@ -36,12 +36,7 @@ signals:
|
||||
void finished( const QMap<QString, unsigned int>& );
|
||||
|
||||
private slots:
|
||||
void go()
|
||||
{
|
||||
scanDir( m_dir, 0 );
|
||||
emit finished( m_newdirmtimes );
|
||||
}
|
||||
|
||||
void go();
|
||||
void scanDir( QDir dir, int depth );
|
||||
|
||||
private:
|
||||
@ -87,7 +82,7 @@ private:
|
||||
|
||||
QMap<QString, unsigned int> m_dirmtimes;
|
||||
QMap<QString, unsigned int> m_newdirmtimes;
|
||||
|
||||
|
||||
QList<QVariant> m_scannedfiles;
|
||||
quint32 m_batchsize;
|
||||
|
||||
|
@ -39,7 +39,7 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ )
|
||||
Servent::instance()->connectToPeer( nodeSet[0], nodeSet[1].toInt(), "whitelist", nodeSet[2], nodeSet[3] );
|
||||
delete currNode;
|
||||
}
|
||||
m_cachedNodes.empty();
|
||||
m_cachedNodes.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -48,6 +48,9 @@ void
|
||||
ZeroconfPlugin::disconnectPlugin()
|
||||
{
|
||||
m_isOnline = false;
|
||||
|
||||
|
||||
|
||||
delete m_zeroconf;
|
||||
m_zeroconf = 0;
|
||||
}
|
||||
|
@ -18,9 +18,14 @@ public:
|
||||
: m_zeroconf( 0 )
|
||||
, m_isOnline( false )
|
||||
, m_cachedNodes()
|
||||
{}
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
virtual ~ZeroconfPlugin() {}
|
||||
virtual ~ZeroconfPlugin()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
virtual bool isValid() { return true; }
|
||||
virtual const QString name();
|
||||
|
Loading…
x
Reference in New Issue
Block a user