diff --git a/src/accounts/lastfm/LastFmConfig.cpp b/src/accounts/lastfm/LastFmConfig.cpp index d364d7ba4..a0e5caa6b 100644 --- a/src/accounts/lastfm/LastFmConfig.cpp +++ b/src/accounts/lastfm/LastFmConfig.cpp @@ -17,15 +17,20 @@ */ #include "LastFmConfig.h" +#include "ui_LastFmConfig.h" #include "LastFmAccount.h" -#include -#include "ui_LastFmConfig.h" +#include "database/Database.h" +#include "database/DatabaseCommand_LogPlayback.h" +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" #include "lastfm/ws.h" +#include "lastfm/User" #include "lastfm/XmlQuery" using namespace Tomahawk::Accounts; + LastFmConfig::LastFmConfig( LastFmAccount* account ) : QWidget( 0 ) , m_account( account ) @@ -33,18 +38,17 @@ LastFmConfig::LastFmConfig( LastFmAccount* account ) m_ui = new Ui_LastFmConfig; m_ui->setupUi( this ); + m_ui->progressBar->hide(); + m_ui->username->setText( m_account->username() ); m_ui->password->setText( m_account->password() ); m_ui->enable->setChecked( m_account->scrobble() ); - connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), this, SLOT( testLogin( bool ) ) ); + connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) ); + connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); - connect( m_ui->username, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - connect( m_ui->password, SIGNAL( textChanged( QString ) ), this, SLOT( enableButton() ) ); - -// #ifdef Q_WS_MAC // FIXME -// m_ui->testLogin->setVisible( false ); -// #endif + connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); + connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); } @@ -70,10 +74,10 @@ LastFmConfig::username() const void -LastFmConfig::testLogin(bool ) +LastFmConfig::testLogin() { m_ui->testLogin->setEnabled( false ); - m_ui->testLogin->setText( "Testing..." ); + m_ui->testLogin->setText( tr( "Testing..." ) ); QString authToken = TomahawkUtils::md5( ( m_ui->username->text().toLower() + TomahawkUtils::md5( m_ui->password->text().toUtf8() ) ).toUtf8() ); @@ -100,6 +104,79 @@ LastFmConfig::enableButton() } +void +LastFmConfig::loadHistory( int page ) +{ + if ( page == 1 ) + { + m_ui->importHistory->setText( tr( "Importing History..." ) ); + m_ui->importHistory->setEnabled( false ); + + m_ui->progressBar->show(); + } + + QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, page ); + connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) ); +} + + +void +LastFmConfig::onHistoryLoaded() +{ + bool finished = false; + QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); + + try + { + lastfm::XmlQuery lfm = reply->readAll(); + + foreach ( lastfm::XmlQuery e, lfm.children( "track" ) ) + { + tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt(); + Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false ); + uint timeStamp = e["date"].attribute( "uts" ).toUInt(); + + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, timeStamp ); + Database::instance()->enqueue( QSharedPointer(cmd) ); + } + + if ( !lfm.children( "recenttracks" ).isEmpty() ) + { + lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first(); + + int page = stats.attribute( "page" ).toInt(); + int total = stats.attribute( "totalPages" ).toInt(); + tDebug() << "page:" << page << "total:" << total; + + m_ui->progressBar->setMaximum( total ); + m_ui->progressBar->setValue( page ); + + if ( page < total ) + loadHistory( ++page ); + else + finished = true; + } + else + finished = true; + } + catch( lastfm::ws::ParseError e ) + { + tDebug() << "XmlQuery error:" << e.what(); + finished = true; + } + + if ( finished ) + { + if ( m_ui->progressBar->value() != m_ui->progressBar->maximum() ) + m_ui->importHistory->setText( tr( "History Incomplete. Retry" ) ); + else + m_ui->importHistory->setText( tr( "Import Playback History" ) ); + + m_ui->importHistory->setEnabled( true ); + } +} + + void LastFmConfig::onLastFmFinished() { diff --git a/src/accounts/lastfm/LastFmConfig.h b/src/accounts/lastfm/LastFmConfig.h index f6e0d72be..765f4a831 100644 --- a/src/accounts/lastfm/LastFmConfig.h +++ b/src/accounts/lastfm/LastFmConfig.h @@ -24,6 +24,7 @@ class Ui_LastFmConfig; namespace Tomahawk { + namespace Accounts { class LastFmAccount; @@ -39,11 +40,14 @@ public: bool scrobble() const; public slots: - void testLogin( bool ); + void testLogin(); void onLastFmFinished(); private slots: void enableButton(); + + void loadHistory( int page = 1 ); + void onHistoryLoaded(); private: LastFmAccount* m_account; @@ -51,6 +55,7 @@ private: }; } + } #endif // LASTFMCONFIG_H diff --git a/src/accounts/lastfm/LastFmConfig.ui b/src/accounts/lastfm/LastFmConfig.ui index 5cdf0e5e8..1a75ae970 100644 --- a/src/accounts/lastfm/LastFmConfig.ui +++ b/src/accounts/lastfm/LastFmConfig.ui @@ -7,7 +7,7 @@ 0 0 400 - 220 + 253 @@ -77,6 +77,20 @@ + + + + Import Playback History + + + + + + + 0 + + + diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp index 81ee8fbd6..37e089940 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.cpp @@ -37,31 +37,33 @@ using namespace Tomahawk; void DatabaseCommand_LogPlayback::postCommitHook() { + if ( !m_query.isNull() ) + return; + connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr, unsigned int ) ), source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr, unsigned int ) ), Qt::QueuedConnection ); connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ), source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection ); - Tomahawk::query_ptr q; - if ( !m_result.isNull() ) + if ( !m_result.isNull() && m_query.isNull() ) { - q = m_result->toQuery(); + m_query = m_result->toQuery(); } else { // do not auto resolve this track - q = Tomahawk::Query::get( m_artist, m_track, QString() ); + m_query = Tomahawk::Query::get( m_artist, m_track, QString() ); } - q->setPlayedBy( source(), m_playtime ); + m_query->setPlayedBy( source(), m_playtime ); if ( m_action == Finished ) { - emit trackPlayed( q ); + emit trackPlayed( m_query ); } // if the play time is more than 10 minutes in the past, ignore else if ( m_action == Started && QDateTime::fromTime_t( playtime() ).secsTo( QDateTime::currentDateTime() ) < STARTED_THRESHOLD ) { - emit trackPlaying( q, m_trackDuration ); + emit trackPlaying( m_query, m_trackDuration ); } if ( source()->isLocal() ) @@ -78,25 +80,36 @@ DatabaseCommand_LogPlayback::exec( DatabaseImpl* dbi ) if ( m_action != Finished ) return; - if ( m_secsPlayed < FINISHED_THRESHOLD ) + if ( m_secsPlayed < FINISHED_THRESHOLD && m_trackDuration > 0 ) + return; + if ( m_artist.isEmpty() || m_track.isEmpty() ) return; - TomahawkSqlQuery query = dbi->newquery(); - query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) " - "VALUES (?, ?, ?, ?)" ); - QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id(); - qDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid; + TomahawkSqlQuery query = dbi->newquery(); + + if ( !m_query.isNull() ) + { + query.prepare( QString( "SELECT * FROM playback_log WHERE source %1 AND playtime = %2" ).arg( srcid.isNull() ? "IS NULL" : srcid.toString() ).arg( m_playtime ) ); + query.exec(); + if ( query.next() ) + { + tDebug() << "Ignoring dupe playback log for source" << srcid << "with timestamp" << m_playtime; + return; + } + } + +// tDebug() << "Logging playback of" << m_artist << "-" << m_track << "for source" << srcid << "- timestamp:" << m_playtime; + + query.prepare( "INSERT INTO playback_log(source, track, playtime, secs_played) VALUES (?, ?, ?, ?)" ); query.bindValue( 0, srcid ); - // If there's no artist, becuase it's a resolver result with bad metadata for example, don't save it - bool autoCreate = m_artist.isEmpty(); - int artid = dbi->artistId( m_artist, autoCreate ); + // If there's no artist, because it's a resolver result with bad metadata for example, don't save it + int artid = dbi->artistId( m_artist, true ); if( artid < 1 ) return; - autoCreate = true; // artistId overwrites autoCreate (reference) - int trkid = dbi->trackId( artid, m_track, autoCreate ); + int trkid = dbi->trackId( artid, m_track, true ); if( trkid < 1 ) return; diff --git a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h index 384a07579..14912ca55 100644 --- a/src/libtomahawk/database/DatabaseCommand_LogPlayback.h +++ b/src/libtomahawk/database/DatabaseCommand_LogPlayback.h @@ -51,6 +51,17 @@ public: : DatabaseCommandLoggable( parent ), m_playtime( 0 ), m_secsPlayed( 0 ), m_trackDuration( 0 ) {} + explicit DatabaseCommand_LogPlayback( const Tomahawk::query_ptr& query, Action action, uint timeStamp, QObject* parent = 0 ) + : DatabaseCommandLoggable( parent ), m_query( query ), m_secsPlayed( 0 ), m_action( action ) + { + m_playtime = timeStamp; + m_trackDuration = 0; + setSource( SourceList::instance()->getLocal() ); + + setArtist( query->artist() ); + setTrack( query->track() ); + } + explicit DatabaseCommand_LogPlayback( const Tomahawk::result_ptr& result, Action action, unsigned int secsPlayed = 0, QObject* parent = 0 ) : DatabaseCommandLoggable( parent ), m_result( result ), m_secsPlayed( secsPlayed ), m_action( action ) { @@ -96,6 +107,7 @@ signals: private: Tomahawk::result_ptr m_result; + Tomahawk::query_ptr m_query; QString m_artist; QString m_track;