diff --git a/CMakeLists.txt b/CMakeLists.txt index 60b77d20e..69f6f6cfd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,16 @@ PROJECT( tomahawk ) CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) +### +### Tomahawk application info +### +SET( ORGANIZATION_NAME "Tomahawk" ) +SET( ORGANIZATION_DOMAIN "tomahawk-player.org" ) +SET( APPLICATION_NAME "Player" ) +SET( VERSION "0.0.0" ) + + +# set paths SET( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/CMakeModules" ) SET( THIRDPARTY_DIR ${CMAKE_SOURCE_DIR}/thirdparty ) diff --git a/admin/mac/Info.plist b/admin/mac/Info.plist index e1114d48c..ecf4c29fa 100644 --- a/admin/mac/Info.plist +++ b/admin/mac/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable tomahawk CFBundleIdentifier - org.tomahawk.Tomahawk + org.tomahawk-player.org.Tomahawk CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff --git a/admin/mac/deposx.sh b/admin/mac/deposx.sh index 116c0ece4..3500895ce 100755 --- a/admin/mac/deposx.sh +++ b/admin/mac/deposx.sh @@ -62,7 +62,7 @@ function deposx_change function deplib_change { install_name_tool -change /usr/local/Cellar/liblastfm/0.3.1/lib/liblastfm.0.dylib @executable_path/liblastfm.0.dylib $1 - install_name_tool -change libqjson.0.dylib @executable_path/libqjson.0.dylib $1 + install_name_tool -change /usr/local/Cellar/qjson/0.7.1/lib/libqjson.0.dylib @executable_path/libqjson.0.dylib $1 install_name_tool -change /usr/local/lib/libechonest.1.1.dylib @executable_path/libechonest.1.1.dylib $1 install_name_tool -change /usr/local/lib/libclucene-core.0.9.23.dylib @executable_path/libclucene-core.0.9.23.dylib $1 install_name_tool -change /usr/local/lib/libclucene-shared.0.9.23.dylib @executable_path/libclucene-shared.0.9.23.dylib $1 @@ -80,6 +80,11 @@ function deplib_change install_name_tool -change $ORIGROOT/libsip_zeroconf.dylib @executable_path/libsip_zeroconf.dylib $1 install_name_tool -change $ORIGROOT/thirdparty/jdns/libtomahawk_jdns.dylib @executable_path/libtomahawk_jdns.dylib $1 install_name_tool -change $ORIGROOT/thirdparty/qtweetlib/libtomahawk_qtweetlib.dylib @executable_path/libtomahawk_qtweetlib.dylib $1 + + install_name_tool -change libqjson.0.dylib @executable_path/libqjson.0.dylib $1 + install_name_tool -change libechonest.1.1.dylib @executable_path/libechonest.1.1.dylib $1 + install_name_tool -change libclucene-core.0.9.23.dylib @executable_path/libclucene-core.0.9.23.dylib $1 + install_name_tool -change libclucene-shared.0.9.23.dylib @executable_path/libclucene-shared.0.9.23.dylib $1 } ################################################################################ diff --git a/data/www/auth.html b/data/www/auth.html index a8aac4c37..49358ef7c 100644 --- a/data/www/auth.html +++ b/data/www/auth.html @@ -44,7 +44,7 @@ - Tomahawk - Powered by Playdar + Tomahawk - Powered by Playdar
diff --git a/data/www/tomahawk_banner_small.png b/data/www/tomahawk_banner_small.png new file mode 100644 index 000000000..83a818d17 Binary files /dev/null and b/data/www/tomahawk_banner_small.png differ diff --git a/resources.qrc b/resources.qrc index fc3705795..231eb32b2 100644 --- a/resources.qrc +++ b/resources.qrc @@ -85,5 +85,6 @@ ./data/icons/audio-x-generic-16x16.png ./data/www/auth.html ./data/www/auth.na.html +./data/www/tomahawk_banner_small.png diff --git a/src/config.h.in b/src/config.h.in index 8a8d1807d..59e6bc80e 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,6 +1,12 @@ #ifndef CONFIG_H_IN #define CONFIG_H_IN +#cmakedefine ORGANIZATION_NAME "${ORGANIZATION_NAME}" +#cmakedefine ORGANIZATION_DOMAIN "${ORGANIZATION_DOMAIN}" +#cmakedefine APPLICATION_NAME "${APPLICATION_NAME}" +#cmakedefine VERSION "${VERSION}" + + #define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" #cmakedefine SNOW_LEOPARD diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 90c3ec204..6373c1df1 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -43,6 +43,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 @@ -181,6 +182,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 diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 1287d24a0..f002e23dc 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -252,7 +252,7 @@ AudioEngine::playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& { qDebug() << Q_FUNC_INFO; - m_playlist = playlist; + setPlaylist( playlist ); m_currentTrackPlaylist = playlist; loadTrack( result ); @@ -298,6 +298,14 @@ AudioEngine::timerTriggered( qint64 time ) } +void +AudioEngine::setPlaylist( PlaylistInterface* playlist ) +{ + m_playlist = playlist; + emit playlistChanged( playlist ); +} + + void AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) { diff --git a/src/libtomahawk/audio/audioengine.h b/src/libtomahawk/audio/audioengine.h index 840b3b821..7faf5a076 100644 --- a/src/libtomahawk/audio/audioengine.h +++ b/src/libtomahawk/audio/audioengine.h @@ -53,7 +53,7 @@ public slots: void mute(); void playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& result ); - void setPlaylist( PlaylistInterface* playlist ) { m_playlist = playlist; } + void setPlaylist( PlaylistInterface* playlist ); void setQueue( PlaylistInterface* queue ) { m_queue = queue; } void onTrackAboutToFinish(); @@ -72,6 +72,8 @@ signals: void timerSeconds( unsigned int secondsElapsed ); void timerPercentage( unsigned int percentage ); + void playlistChanged( PlaylistInterface* playlist ); + void error( AudioErrorCode errorCode ); private slots: diff --git a/src/libtomahawk/collection.cpp b/src/libtomahawk/collection.cpp index b532a4c4a..7017257b9 100644 --- a/src/libtomahawk/collection.cpp +++ b/src/libtomahawk/collection.cpp @@ -153,10 +153,40 @@ Collection::setDynamicPlaylists( const QList< Tomahawk::dynplaylist_ptr >& plist void -Collection::setTracks( const QList& tracks, Tomahawk::collection_ptr collection ) +Collection::setTracks( const QList& 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 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 ); +} diff --git a/src/libtomahawk/collection.h b/src/libtomahawk/collection.h index 1628f92de..4b467ee3f 100644 --- a/src/libtomahawk/collection.h +++ b/src/libtomahawk/collection.h @@ -9,6 +9,7 @@ #define TOMAHAWK_COLLECTION_H #include +#include #include #include #include @@ -56,7 +57,7 @@ public: signals: void tracksAdded( const QList& tracks, const Tomahawk::collection_ptr& ); - void tracksRemoved( const QList&, const Tomahawk::collection_ptr& ); + void tracksRemoved( const QList& tracks, const Tomahawk::collection_ptr& ); void tracksFinished( const Tomahawk::collection_ptr& ); void playlistsAdded( const QList& ); @@ -66,12 +67,14 @@ signals: void dynamicPlaylistsDeleted( const QList& ); public slots: - virtual void addTracks( const QList &newitems ) = 0; - virtual void removeTracks( const QList &olditems ) = 0; + virtual void addTracks( const QList& newitems ) = 0; + virtual void removeTracks( const QDir& dir ) = 0; void setPlaylists( const QList& plists ); void setDynamicPlaylists( const QList< Tomahawk::dynplaylist_ptr >& dynplists ); - void setTracks( const QList& tracks, Tomahawk::collection_ptr collection ); + void setTracks( const QList& 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; }; diff --git a/src/libtomahawk/database/databasecollection.cpp b/src/libtomahawk/database/databasecollection.cpp index 55858c383..7d4a48e3a 100644 --- a/src/libtomahawk/database/databasecollection.cpp +++ b/src/libtomahawk/database/databasecollection.cpp @@ -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 &newitems ) +DatabaseCollection::addTracks( const QList& newitems ) { qDebug() << Q_FUNC_INFO << newitems.length(); DatabaseCommand_AddFiles* cmd = new DatabaseCommand_AddFiles( newitems, source() ); @@ -68,13 +69,12 @@ DatabaseCollection::addTracks( const QList &newitems ) void -DatabaseCollection::removeTracks( const QList &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( cmd ) ); } diff --git a/src/libtomahawk/database/databasecollection.h b/src/libtomahawk/database/databasecollection.h index 62b82eac6..cd5ea869f 100644 --- a/src/libtomahawk/database/databasecollection.h +++ b/src/libtomahawk/database/databasecollection.h @@ -1,6 +1,8 @@ #ifndef DATABASECOLLECTION_H #define DATABASECOLLECTION_H +#include + #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 &newitems ); - virtual void removeTracks( const QList &olditems ); + virtual void addTracks( const QList& newitems ); + virtual void removeTracks( const QDir& dir ); private slots: void dynamicPlaylistCreated( const Tomahawk::source_ptr& source, const QVariantList& data ); diff --git a/src/libtomahawk/database/databasecommand.cpp b/src/libtomahawk/database/databasecommand.cpp index f1074954b..82e0c5cad 100644 --- a/src/libtomahawk/database/databasecommand.cpp +++ b/src/libtomahawk/database/databasecommand.cpp @@ -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; diff --git a/src/libtomahawk/database/databasecommand_addfiles.cpp b/src/libtomahawk/database/databasecommand_addfiles.cpp index 8eec10a93..0026c1f13 100644 --- a/src/libtomahawk/database/databasecommand_addfiles.cpp +++ b/src/libtomahawk/database/databasecommand_addfiles.cpp @@ -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::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 ); diff --git a/src/libtomahawk/database/databasecommand_addfiles.h b/src/libtomahawk/database/databasecommand_addfiles.h index f1a79ca9a..8e8b5e11c 100644 --- a/src/libtomahawk/database/databasecommand_addfiles.h +++ b/src/libtomahawk/database/databasecommand_addfiles.h @@ -36,8 +36,8 @@ public: void setFiles( const QVariantList& f ) { m_files = f; } signals: - void done( const QList&, Tomahawk::collection_ptr ); - void notify( const QList&, Tomahawk::collection_ptr ); + void done( const QList&, const Tomahawk::collection_ptr& ); + void notify( const QList&, const Tomahawk::collection_ptr& ); private: QVariantList m_files; diff --git a/src/libtomahawk/database/databasecommand_deletefiles.cpp b/src/libtomahawk/database/databasecommand_deletefiles.cpp new file mode 100644 index 000000000..436bffcfc --- /dev/null +++ b/src/libtomahawk/database/databasecommand_deletefiles.cpp @@ -0,0 +1,122 @@ +#include "databasecommand_deletefiles.h" + +#include + +#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( 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() ); +} diff --git a/src/libtomahawk/database/databasecommand_deletefiles.h b/src/libtomahawk/database/databasecommand_deletefiles.h new file mode 100644 index 000000000..d10fb98c7 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_deletefiles.h @@ -0,0 +1,52 @@ +#ifndef DATABASECOMMAND_DELETEFILES_H +#define DATABASECOMMAND_DELETEFILES_H + +#include +#include +#include + +#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 diff --git a/src/libtomahawk/database/databasecommand_dirmtimes.cpp b/src/libtomahawk/database/databasecommand_dirmtimes.cpp index d8c11c799..42c7c7084 100644 --- a/src/libtomahawk/database/databasecommand_dirmtimes.cpp +++ b/src/libtomahawk/database/databasecommand_dirmtimes.cpp @@ -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() ) { diff --git a/src/libtomahawk/database/databasecommand_loadplaylistentries.cpp b/src/libtomahawk/database/databasecommand_loadplaylistentries.cpp index 1f6a9a155..f81c03980 100644 --- a/src/libtomahawk/database/databasecommand_loadplaylistentries.cpp +++ b/src/libtomahawk/database/databasecommand_loadplaylistentries.cpp @@ -56,7 +56,7 @@ void DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi ) e->setLastmodified( 0 ); // TODO e->lastmodified = query.value(6).toInt(); e->setResultHint( query.value( 8 ).toString() ); - Tomahawk::query_ptr q = Tomahawk::Query::get( query.value( 2 ).toString(), query.value( 1 ).toString(), query.value( 3 ).toString(), false ); + Tomahawk::query_ptr q = Tomahawk::Query::get( query.value( 2 ).toString(), query.value( 1 ).toString(), query.value( 3 ).toString() ); q->setResultHint( query.value( 8 ).toString() ); e->setQuery( q ); diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index 006177647..2fd075625 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -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 ) diff --git a/src/libtomahawk/database/schema.sql b/src/libtomahawk/database/schema.sql index c30132ab9..e35973508 100644 --- a/src/libtomahawk/database/schema.sql +++ b/src/libtomahawk/database/schema.sql @@ -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'); diff --git a/src/libtomahawk/database/schema.sql.h b/src/libtomahawk/database/schema.sql.h index 9283091f3..dfd468cf8 100644 --- a/src/libtomahawk/database/schema.sql.h +++ b/src/libtomahawk/database/schema.sql.h @@ -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() diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp index bfbff6550..0973b59ed 100644 --- a/src/libtomahawk/network/controlconnection.cpp +++ b/src/libtomahawk/network/controlconnection.cpp @@ -91,7 +91,7 @@ ControlConnection::setup() void ControlConnection::registerSource() { - qDebug() << Q_FUNC_INFO; + qDebug() << Q_FUNC_INFO << m_source->id(); Source* source = (Source*) sender(); Q_ASSERT( source == m_source.data() ); // .. but we'll use the shared pointer we've already made: @@ -105,10 +105,11 @@ ControlConnection::registerSource() void ControlConnection::setupDbSyncConnection( bool ondemand ) { + qDebug() << Q_FUNC_INFO << ondemand << m_source->id() << ondemand << m_dbconnkey << m_dbsyncconn << m_registered; + if ( m_dbsyncconn || !m_registered ) return; - qDebug() << Q_FUNC_INFO << ondemand << m_source->id(); Q_ASSERT( m_source->id() > 0 ); if( !m_dbconnkey.isEmpty() ) diff --git a/src/libtomahawk/network/remotecollection.cpp b/src/libtomahawk/network/remotecollection.cpp index c4d52538a..757164456 100644 --- a/src/libtomahawk/network/remotecollection.cpp +++ b/src/libtomahawk/network/remotecollection.cpp @@ -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 &newitems ) +void RemoteCollection::addTracks( const QList& newitems ) { qDebug() << Q_FUNC_INFO; Q_ASSERT( false ); } -void RemoteCollection::removeTracks( const QList &olditems ) +void RemoteCollection::removeTracks( const QDir& dir ) { qDebug() << Q_FUNC_INFO; Q_ASSERT( false ); diff --git a/src/libtomahawk/network/remotecollection.h b/src/libtomahawk/network/remotecollection.h index 63124d618..86d334f50 100644 --- a/src/libtomahawk/network/remotecollection.h +++ b/src/libtomahawk/network/remotecollection.h @@ -20,8 +20,8 @@ public: } public slots: - virtual void addTracks( const QList &newitems ); - virtual void removeTracks( const QList &olditems ); + virtual void addTracks( const QList& newitems ); + virtual void removeTracks( const QDir& dir ); }; #endif // REMOTECOLLECTION_H diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index fa42cda84..805b2f723 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -152,7 +152,6 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) } state = m_qidsState.value( qid ) - 1; - if ( state ) { qDebug() << Q_FUNC_INFO << "replacing" << qid << state; diff --git a/src/libtomahawk/playlist.cpp b/src/libtomahawk/playlist.cpp index 24e3d246b..00c644593 100644 --- a/src/libtomahawk/playlist.cpp +++ b/src/libtomahawk/playlist.cpp @@ -28,7 +28,7 @@ PlaylistEntry::setQueryVariant( const QVariant& v ) QString artist = m.value( "artist" ).toString(); QString album = m.value( "album" ).toString(); QString track = m.value( "track" ).toString(); - m_query = Tomahawk::Query::get( artist, track, album, false ); + m_query = Tomahawk::Query::get( artist, track, album ); } diff --git a/src/libtomahawk/playlist/collectionflatmodel.cpp b/src/libtomahawk/playlist/collectionflatmodel.cpp index bfaa3d259..5edf161d5 100644 --- a/src/libtomahawk/playlist/collectionflatmodel.cpp +++ b/src/libtomahawk/playlist/collectionflatmodel.cpp @@ -60,7 +60,9 @@ CollectionFlatModel::addCollection( const collection_ptr& collection ) SLOT( onTracksAdded( QList, Tomahawk::collection_ptr ) ) ); connect( collection.data(), SIGNAL( tracksFinished( Tomahawk::collection_ptr ) ), SLOT( onTracksAddingFinished( Tomahawk::collection_ptr ) ) ); - + connect( collection.data(), SIGNAL( tracksRemoved( QList, Tomahawk::collection_ptr ) ), + SLOT( onTracksRemoved( QList, 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::collection_ptr ) ), this, SLOT( onTracksAdded( QList, 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& 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& tracks, const Tomahawk::collection_ptr& collection ) +{ + QList 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() { diff --git a/src/libtomahawk/playlist/collectionflatmodel.h b/src/libtomahawk/playlist/collectionflatmodel.h index a87e6a32d..95abdf1ac 100644 --- a/src/libtomahawk/playlist/collectionflatmodel.h +++ b/src/libtomahawk/playlist/collectionflatmodel.h @@ -54,6 +54,8 @@ private slots: void onTracksAdded( const QList& tracks, const Tomahawk::collection_ptr& collection ); void onTracksAddingFinished( const Tomahawk::collection_ptr& collection ); + void onTracksRemoved( const QList& tracks, const Tomahawk::collection_ptr& collection ); + void onSourceOffline( const Tomahawk::source_ptr& src ); private: diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index 3f55f924b..32d8448ab 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -18,7 +18,7 @@ #include "dynamic/echonest/EchonestControl.h" #include "dynamic/echonest/EchonestSteerer.h" #include "query.h" -#include "tomahawk/tomahawkapp.h" +#include "utils/tomahawkutils.h" using namespace Tomahawk; @@ -285,7 +285,7 @@ query_ptr EchonestGenerator::queryFromSong(const Echonest::Song& song) { // track[ "album" ] = song.release(); // TODO should we include it? can be quite specific - return Query::get( song.artistName(), song.title(), QString() ); + return Query::get( song.artistName(), song.title(), QString(), uuid() ); } QWidget* diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index ee6763db8..e7829a6bb 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -92,6 +92,7 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget connect( PlaylistManager::instance(), SIGNAL( playClicked() ), this, SLOT( playPressed() ) ); connect( PlaylistManager::instance(), SIGNAL( pauseClicked() ), this, SLOT( pausePressed() ) ); + connect( AudioEngine::instance(), SIGNAL( playlistChanged( PlaylistInterface* ) ), this, SLOT( playlistStopped( PlaylistInterface* ) ) ); } DynamicWidget::~DynamicWidget() @@ -207,18 +208,22 @@ DynamicWidget::layoutFloatingWidgets() } void -DynamicWidget::hideEvent( QHideEvent* ev ) +DynamicWidget::playlistStopped( PlaylistInterface* pl ) { + if( pl == static_cast< PlaylistInterface* >( m_view->proxyModel() ) ) // same playlist, so don't stop + return; + + // user started playing something somewhere else, so give it a rest if( m_runningOnDemand ) { stopStation( false ); + m_model->clear(); } - QWidget::hideEvent( ev ); } void DynamicWidget::showEvent(QShowEvent* ) { - if( !m_playlist.isNull() ) { + if( !m_playlist.isNull() && !m_runningOnDemand ) { m_setup->fadeIn(); } } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h index e8653b2b7..78e133708 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h @@ -67,7 +67,6 @@ public: virtual QSize sizeHint() const; virtual void resizeEvent( QResizeEvent* ); - virtual void hideEvent(QHideEvent* ); virtual void showEvent(QShowEvent* ); static void paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity = .95 ); @@ -90,6 +89,8 @@ public slots: void pausePressed(); void stationFailed( const QString& ); + void playlistStopped( PlaylistInterface* ); + private slots: void generate( int = -1 ); void tracksGenerated( const QList< Tomahawk::query_ptr>& queries ); diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index 0c24deb26..2f959141c 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -79,6 +79,10 @@ Source::friendlyName() const if ( m_friendlyname.isEmpty() ) return m_username; + //TODO: this is a terrible assumption, help me clean this up, mighty muesli! + if ( m_friendlyname.contains( "@conference.") ) + return QString(m_friendlyname).remove( 0, m_friendlyname.lastIndexOf( "/" )+1 ).append(" via MUC"); + if ( m_friendlyname.contains( "/tomahawk" ) ) return m_friendlyname.left( m_friendlyname.indexOf( "/tomahawk" ) ); diff --git a/src/libtomahawk/utils/tomahawkutils.cpp b/src/libtomahawk/utils/tomahawkutils.cpp index 1b5db86fe..03b7e9161 100644 --- a/src/libtomahawk/utils/tomahawkutils.cpp +++ b/src/libtomahawk/utils/tomahawkutils.cpp @@ -116,6 +116,17 @@ appDataDir() } +QDir +appLogDir() +{ +#ifndef Q_WS_MAC + return appDataDir(); +#else + return QDir( QDir::homePath() + "/Library/Logs" ); +#endif +} + + QString timeToString( int seconds ) { diff --git a/src/libtomahawk/utils/tomahawkutils.h b/src/libtomahawk/utils/tomahawkutils.h index 1696dbd00..4161a8cde 100644 --- a/src/libtomahawk/utils/tomahawkutils.h +++ b/src/libtomahawk/utils/tomahawkutils.h @@ -26,15 +26,16 @@ namespace TomahawkUtils //a non-static non-singleton normal utility class then. class DLLEXPORT DNSResolver : public QObject { - Q_OBJECT + Q_OBJECT + public: explicit DNSResolver(); ~DNSResolver() {} - void resolve( QString &host, QString type ); + void resolve( QString& host, QString type ); signals: - void result( QString &result ); + void result( QString& result ); public slots: void resultsReady(); @@ -47,23 +48,24 @@ namespace TomahawkUtils class DLLEXPORT Sleep : public QThread { public: - static void sleep(unsigned long secs) + static void sleep( unsigned long secs ) { - QThread::sleep(secs); + QThread::sleep( secs ); } - static void msleep(unsigned long msecs) + static void msleep( unsigned long msecs ) { - QThread::msleep(msecs); + QThread::msleep( msecs ); } - static void usleep(unsigned long usecs) + static void usleep( unsigned long usecs ) { - QThread::usleep(usecs); + QThread::usleep( usecs ); } }; DLLEXPORT QDir appConfigDir(); DLLEXPORT QDir appDataDir(); - + DLLEXPORT QDir appLogDir(); + DLLEXPORT QString timeToString( int seconds ); DLLEXPORT QString ageToString( const QDateTime& time ); DLLEXPORT QString filesizeToString( unsigned int size ); diff --git a/src/libtomahawk/utils/xspfloader.cpp b/src/libtomahawk/utils/xspfloader.cpp index 9b68b342c..ccdba5b9b 100644 --- a/src/libtomahawk/utils/xspfloader.cpp +++ b/src/libtomahawk/utils/xspfloader.cpp @@ -104,7 +104,7 @@ XSPFLoader::gotBody() album = e.firstChildElement( "album" ).text(); track = e.firstChildElement( "title" ).text(); - p->setQuery( Tomahawk::Query::get( artist, track, album ) ); + p->setQuery( Tomahawk::Query::get( artist, track, album, uuid() ) ); p->query()->setDuration( e.firstChildElement( "duration" ).text().toInt() / 1000 ); m_entries << p; } diff --git a/src/main.cpp b/src/main.cpp index d755703d2..137172c69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,14 @@ #include "tomahawk/tomahawkapp.h" #ifdef Q_WS_MAC -#include "tomahawkapp_mac.h" -#include -static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long ); + #include "tomahawkapp_mac.h" + #include + static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long ); #endif #include -int main( int argc, char *argv[] ) +int +main( int argc, char *argv[] ) { #ifdef Q_WS_MAC // Do Mac specific startup to get media keys working. @@ -19,21 +20,25 @@ int main( int argc, char *argv[] ) AEInstallEventHandler( 'GURL', 'GURL', h, 0, false ); #endif - try { + try + { TomahawkApp a( argc, argv ); return a.exec(); - } catch( const std::runtime_error& e ) { + } + catch( const std::runtime_error& e ) + { return 0; } } #ifdef Q_WS_MAC -static pascal OSErr appleEventHandler( const AppleEvent* e, AppleEvent*, long ) +static pascal OSErr +appleEventHandler( const AppleEvent* e, AppleEvent*, long ) { OSType id = typeWildCard; - AEGetAttributePtr( e, keyEventIDAttr, typeType, 0, &id, sizeof(id), 0 ); + AEGetAttributePtr( e, keyEventIDAttr, typeType, 0, &id, sizeof( id ), 0 ); - switch (id) + switch ( id ) { case 'GURL': { diff --git a/src/musicscanner.cpp b/src/musicscanner.cpp index 5bbe24c3b..c2a80210d 100644 --- a/src/musicscanner.cpp +++ b/src/musicscanner.cpp @@ -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( new DatabaseCommand_DeleteFiles( dir, SourceList::instance()->getLocal() ) ) ); + dir.setFilter( QDir::Files | QDir::Readable | QDir::NoDotAndDotDot ); dir.setSorting( QDir::Name ); dirs = dir.entryInfoList(); @@ -138,6 +149,7 @@ void MusicScanner::listerFinished( const QMap& newmtimes ) { qDebug() << Q_FUNC_INFO; + // any remaining stuff that wasnt emitted as a batch: if( m_scannedfiles.length() ) { @@ -145,13 +157,23 @@ MusicScanner::listerFinished( const QMap& 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( 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(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 ) @@ -222,7 +244,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 @@ -235,7 +259,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(); @@ -272,14 +296,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; @@ -288,7 +311,8 @@ MusicScanner::readFile( const QFileInfo& fi ) m["track"] = track; m["albumpos"] = tag->track(); m["year"] = tag->year(); - + m["hash"] = ""; // TODO + m_scanned++; return m; } diff --git a/src/musicscanner.h b/src/musicscanner.h index d76c2d06d..86aedfbb7 100644 --- a/src/musicscanner.h +++ b/src/musicscanner.h @@ -36,12 +36,7 @@ signals: void finished( const QMap& ); 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 m_dirmtimes; QMap m_newdirmtimes; - + QList m_scannedfiles; quint32 m_batchsize; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 95f277025..282665429 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -23,7 +23,7 @@ - 0 + 1 @@ -382,10 +382,10 @@ Qt::RightToLeft - Playdar HTTP API - NO AUTH + Playdar HTTP API - false + true diff --git a/src/sip/SipHandler.cpp b/src/sip/SipHandler.cpp index 12a2f3c10..061720a5e 100644 --- a/src/sip/SipHandler.cpp +++ b/src/sip/SipHandler.cpp @@ -27,6 +27,7 @@ SipHandler::~SipHandler() disconnectPlugins(); } + QList< SipPlugin* > SipHandler::plugins() const { @@ -189,7 +190,13 @@ SipHandler::onPeerOnline( const QString& jid ) ControlConnection* conn = new ControlConnection( Servent::instance() ); const QString& nodeid = Database::instance()->dbid(); - conn->setName( jid.left( jid.indexOf( "/" ) ) ); + + //TODO: this is a terrible assumption, help me clean this up, mighty muesli! + if ( jid.contains( "@conference.") ) + conn->setName( jid ); + else + conn->setName( jid.left( jid.indexOf( "/" ) ) ); + conn->setId( nodeid ); Servent::instance()->registerOffer( key, conn ); diff --git a/src/sip/jreen/jabber_p.cpp b/src/sip/jreen/jabber_p.cpp index 3e809404a..ef7a9a080 100644 --- a/src/sip/jreen/jabber_p.cpp +++ b/src/sip/jreen/jabber_p.cpp @@ -150,8 +150,9 @@ Jabber_p::addContact( const QString& jid, const QString& msg ) return; } - //FIXME: implement it when I dont suck that much :-) - //handleSubscription(Subscription()); + // Add contact to the Tomahawk group on the roster + m_roster->add( jid, jid, QStringList() << "Tomahawk" ); + return; } @@ -175,45 +176,77 @@ Jabber_p::onConnect() m_client->setPresence(jreen::Presence::Available, "Tomahawk-JREEN available", 1); m_client->disco()->setSoftwareVersion( "Tomahawk JREEN", "0.0.0.0", "Foobar" ); m_client->setPingInterval(60000); - jreen::AbstractRoster *roster = new jreen::AbstractRoster( m_client ); - roster->load(); + m_roster = new jreen::SimpleRoster( m_client ); + m_roster->load(); + + // join MUC with bare jid as nickname + //TODO: make the room a list of rooms and make that configurable + QString bare(m_jid.bare()); + m_room = new jreen::MUCRoom(m_client, jreen::JID(QString("tomahawk@conference.qutim.org/").append(bare.replace("@", "-")))); + m_room->setHistorySeconds(0); + m_room->join(); + + // treat muc participiants like contacts + connect(m_room, SIGNAL(messageReceived(jreen::Message, bool)), this, SLOT(onNewMessage(jreen::Message))); + connect(m_room, SIGNAL(presenceReceived(jreen::Presence,const jreen::MUCRoom::Participant*)), this, SLOT(onNewPresence(jreen::Presence))); } void Jabber_p::onDisconnect( jreen::Client::DisconnectReason reason ) { - qDebug() << Q_FUNC_INFO << reason; - QString error; + bool reconnect = false; + int reconnectInSeconds = 0; switch( reason ) { case jreen::Client::User: + error = "User Interaction"; break; case jreen::Client::HostUnknown: + error = "Host is unknown"; break; case jreen::Client::ItemNotFound: + error = "Item not found"; break; case jreen::Client::AuthorizationError: + error = "Authorization Error"; break; case jreen::Client::RemoteStreamError: + error = "Remote Stream Error"; + reconnect = true; break; case jreen::Client::RemoteConnectionFailed: + error = "Remote Connection failed"; break; case jreen::Client::InternalServerError: + error = "Internal Server Error"; + reconnect = true; break; case jreen::Client::SystemShutdown: + error = "System shutdown"; + reconnect = true; + reconnectInSeconds = 60; break; case jreen::Client::Conflict: + error = "Conflict"; break; case jreen::Client::Unknown: + error = "Unknown"; + break; + default: + qDebug() << "Not all Client::DisconnectReasons checked"; + Q_ASSERT(false); break; } - qDebug() << "Connection error msg:" << error; + qDebug() << "Disconnected from server:" << error; + + if(reconnect) + QTimer::singleShot(reconnectInSeconds*1000, m_client, SLOT(connectToServer())); emit disconnected(); } diff --git a/src/sip/jreen/jabber_p.h b/src/sip/jreen/jabber_p.h index 645e0d039..b69369b6e 100644 --- a/src/sip/jreen/jabber_p.h +++ b/src/sip/jreen/jabber_p.h @@ -31,6 +31,7 @@ #include "../sipdllmacro.h" #include +#include class SIPDLLEXPORT Jabber_p : public QObject @@ -72,6 +73,8 @@ private slots: private: bool presenceMeansOnline( jreen::Presence::Type p ); jreen::Client *m_client; + jreen::MUCRoom *m_room; + jreen::SimpleRoster *m_roster; jreen::JID m_jid; QMap m_presences; QMap m_peers; diff --git a/src/sip/zeroconf/tomahawkzeroconf.h b/src/sip/zeroconf/tomahawkzeroconf.h index 6630b865d..d80f1103a 100644 --- a/src/sip/zeroconf/tomahawkzeroconf.h +++ b/src/sip/zeroconf/tomahawkzeroconf.h @@ -61,10 +61,16 @@ public: TomahawkZeroconf( int port, QObject* parent = 0 ) : QObject( parent ), m_sock( this ), m_port( port ) { + qDebug() << Q_FUNC_INFO; m_sock.bind( ZCONF_PORT, QUdpSocket::ShareAddress ); connect( &m_sock, SIGNAL( readyRead() ), this, SLOT( readPacket() ) ); } + virtual ~TomahawkZeroconf() + { + qDebug() << Q_FUNC_INFO; + } + public slots: void advertise() { @@ -107,8 +113,8 @@ private slots: { qDebug() << "ADVERT received:" << sender << port; Node *n = new Node( sender.toString(), parts.at( 2 ), port ); - connect( n, SIGNAL( tomahawkHostFound( const QString&, int, const QString&, const QString& ) ), - this, SIGNAL( tomahawkHostFound( const QString&, int, const QString&, const QString& ) ) ); + connect( n, SIGNAL( tomahawkHostFound( QString, int, QString, QString ) ), + this, SIGNAL( tomahawkHostFound( QString, int, QString, QString ) ) ); n->resolve(); } } diff --git a/src/sip/zeroconf/zeroconf.cpp b/src/sip/zeroconf/zeroconf.cpp index 239cb33ce..3a567ea48 100644 --- a/src/sip/zeroconf/zeroconf.cpp +++ b/src/sip/zeroconf/zeroconf.cpp @@ -25,21 +25,20 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ ) { delete m_zeroconf; m_zeroconf = new TomahawkZeroconf( Servent::instance()->port(), this ); - QObject::connect( m_zeroconf, SIGNAL( tomahawkHostFound( const QString&, int, const QString&, const QString& ) ), - SLOT( lanHostFound( const QString&, int, const QString&, const QString& ) ) ); + QObject::connect( m_zeroconf, SIGNAL( tomahawkHostFound( QString, int, QString, QString ) ), + SLOT( lanHostFound( QString, int, QString, QString ) ) ); m_zeroconf->advertise(); - m_isOnline = true; - + foreach( QStringList *currNode, m_cachedNodes ) { QStringList nodeSet = *currNode; if ( !Servent::instance()->connectedToSession( nodeSet[3] ) ) Servent::instance()->connectToPeer( nodeSet[0], nodeSet[1].toInt(), "whitelist", nodeSet[2], nodeSet[3] ); + delete currNode; } - m_cachedNodes.empty(); return true; } @@ -48,6 +47,7 @@ void ZeroconfPlugin::disconnectPlugin() { m_isOnline = false; + delete m_zeroconf; m_zeroconf = 0; } @@ -55,20 +55,24 @@ ZeroconfPlugin::disconnectPlugin() void ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name, const QString& nodeid ) { + if ( sender() != m_zeroconf ) + return; + qDebug() << "Found LAN host:" << host << port << nodeid; - - //FIXME: This doesn't work...why? I never see Found LAN host in debug either, but somehow nodes are being connected... + if ( !m_isOnline ) { - qDebug() << "Not online, so not connecting"; + qDebug() << "Not online, so not connecting."; QStringList *nodeSet = new QStringList(); *nodeSet << host << QString::number( port ) << name << nodeid; m_cachedNodes.insert( nodeSet ); return; } - + if ( !Servent::instance()->connectedToSession( nodeid ) ) Servent::instance()->connectToPeer( host, port, "whitelist", name, nodeid ); + else + qDebug() << "Already connected to" << host; } Q_EXPORT_PLUGIN2( sip, ZeroconfPlugin ) diff --git a/src/sip/zeroconf/zeroconf.h b/src/sip/zeroconf/zeroconf.h index 79eee4101..aa4926908 100644 --- a/src/sip/zeroconf/zeroconf.h +++ b/src/sip/zeroconf/zeroconf.h @@ -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(); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 62fb28086..be34d4564 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -51,7 +51,7 @@ #include #include -#define LOGFILE TomahawkUtils::appDataDir().filePath( "tomahawk.log" ).toLocal8Bit() +#define LOGFILE TomahawkUtils::appLogDir().filePath( "Tomahawk.log" ).toLocal8Bit() #define LOGFILE_SIZE 1024 * 512 using namespace std; @@ -146,10 +146,10 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) #endif qDebug() << "TomahawkApp thread:" << this->thread(); - setOrganizationName( "Tomahawk" ); - setOrganizationDomain( "tomahawk.org" ); - setApplicationName( "Player" ); - setApplicationVersion( "0.0.0" ); + setOrganizationName( QLatin1String( ORGANIZATION_NAME ) ); + setOrganizationDomain( QLatin1String( ORGANIZATION_DOMAIN ) ); + setApplicationName( QLatin1String( APPLICATION_NAME ) ); + setApplicationVersion( QLatin1String( VERSION ) ); registerMetaTypes(); setupLogfile(); diff --git a/src/web/api_v1.cpp b/src/web/api_v1.cpp index c5e65472c..36c3587d3 100644 --- a/src/web/api_v1.cpp +++ b/src/web/api_v1.cpp @@ -165,7 +165,7 @@ Api_v1::stat( QxtWebRequestEvent* event ) if( event->url.hasQueryItem( "auth" ) ) { // check for auth status - DatabaseCommand_ClientAuthValid* dbcmd = new DatabaseCommand_ClientAuthValid( event->url.queryItemValue( "auth" ), this ); + DatabaseCommand_ClientAuthValid* dbcmd = new DatabaseCommand_ClientAuthValid( event->url.queryItemValue( "auth" ) ); connect( dbcmd, SIGNAL( authValid( QString, QString, bool ) ), this, SLOT( statResult( QString, QString, bool ) ) ); Database::instance()->enqueue( QSharedPointer(dbcmd) ); } @@ -215,11 +215,17 @@ Api_v1::resolve( QxtWebRequestEvent* event ) void -Api_v1::staticdata( QxtWebRequestEvent* event ) +Api_v1::staticdata( QxtWebRequestEvent* event, const QString& str ) { - if( event->url.path().contains( "playdar_auth_logo.gif" ) ) + qDebug() << "STATIC request:" << event << str; + if( str.contains( "tomahawk_auth_logo.png" ) ) { - // TODO handle + QFile f( RESPATH "www/tomahawk_banner_small.png" ); + f.open( QIODevice::ReadOnly ); + QByteArray data = f.readAll(); + QxtWebPageEvent * e = new QxtWebPageEvent( event->sessionID, event->requestID, data ); + e->contentType = "image/png"; + postEvent( e ); } } diff --git a/src/web/api_v1.h b/src/web/api_v1.h index 28b14678a..73f2c68b6 100644 --- a/src/web/api_v1.h +++ b/src/web/api_v1.h @@ -53,7 +53,7 @@ public slots: void stat( QxtWebRequestEvent* event ); void statResult( const QString& clientToken, const QString& name, bool valid ); void resolve( QxtWebRequestEvent* event ); - void staticdata( QxtWebRequestEvent* event ); + void staticdata( QxtWebRequestEvent* event,const QString& ); void get_results( QxtWebRequestEvent* event ); void sendJSON( const QVariantMap& m, QxtWebRequestEvent* event ); diff --git a/thirdparty/jreen b/thirdparty/jreen index a997c4196..040ca3f3c 160000 --- a/thirdparty/jreen +++ b/thirdparty/jreen @@ -1 +1 @@ -Subproject commit a997c41967823907216255346e179569e4b1cfc9 +Subproject commit 040ca3f3cb9b30b4845fc23054c833fda4717460