1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-07 06:36:55 +02:00

Listen along -- fix bug where catching up to the same track would stop audio. Also allow option to stop listening.

This commit is contained in:
Jeff Mitchell
2011-06-18 11:12:34 -04:00
parent 0abb46f3e6
commit c760d26b68
5 changed files with 114 additions and 31 deletions

View File

@@ -111,14 +111,14 @@ AudioEngine::play()
{ {
m_mediaObject->play(); m_mediaObject->play();
emit resumed(); emit resumed();
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
trackInfo["title"] = m_currentTrack->track(); trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name(); trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name(); trackInfo["album"] = m_currentTrack->album()->name();
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed, s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
} }
else else
loadNextTrack(); loadNextTrack();
@@ -143,7 +143,8 @@ AudioEngine::stop()
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
m_mediaObject->stop(); m_mediaObject->stop();
m_retryTimer.stop();
setCurrentTrack( Tomahawk::result_ptr() ); setCurrentTrack( Tomahawk::result_ptr() );
emit stopped(); emit stopped();
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
@@ -155,6 +156,10 @@ void
AudioEngine::previous() AudioEngine::previous()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( !m_playlist )
return;
if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip || if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip ||
m_playlist->skipRestrictions() == PlaylistInterface::NoSkipBackwards ) m_playlist->skipRestrictions() == PlaylistInterface::NoSkipBackwards )
return; return;
@@ -167,6 +172,10 @@ void
AudioEngine::next() AudioEngine::next()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( !m_playlist )
return;
if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip || if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip ||
m_playlist->skipRestrictions() == PlaylistInterface::NoSkipForwards ) m_playlist->skipRestrictions() == PlaylistInterface::NoSkipForwards )
return; return;
@@ -178,6 +187,9 @@ AudioEngine::next()
void void
AudioEngine::seek( int ms ) AudioEngine::seek( int ms )
{ {
if ( !m_playlist )
return;
if ( m_playlist->seekRestrictions() == PlaylistInterface::NoSeek ) if ( m_playlist->seekRestrictions() == PlaylistInterface::NoSeek )
return; return;
@@ -345,7 +357,7 @@ AudioEngine::loadNextTrack()
else else
{ {
stop(); stop();
if ( m_playlist->retryMode() == Tomahawk::PlaylistInterface::Retry ) if ( m_playlist && m_playlist->retryMode() == Tomahawk::PlaylistInterface::Retry )
{ {
m_retryTimer.setInterval( m_playlist->retryInterval() ); m_retryTimer.setInterval( m_playlist->retryInterval() );
m_retryTimer.start(); m_retryTimer.start();

View File

@@ -28,6 +28,7 @@ using namespace Tomahawk;
SourcePlaylistInterface::SourcePlaylistInterface( Tomahawk::source_ptr& source ) SourcePlaylistInterface::SourcePlaylistInterface( Tomahawk::source_ptr& source )
: PlaylistInterface( this ) : PlaylistInterface( this )
, m_source( source ) , m_source( source )
, m_currentItem( 0 )
, m_gotNextSong( false ) , m_gotNextSong( false )
{ {
connect( source.data(), SIGNAL( playbackStarted( const Tomahawk::query_ptr& ) ), SLOT( onSourcePlaybackStarted( const Tomahawk::query_ptr& ) ) ); connect( source.data(), SIGNAL( playbackStarted( const Tomahawk::query_ptr& ) ), SLOT( onSourcePlaybackStarted( const Tomahawk::query_ptr& ) ) );
@@ -39,15 +40,21 @@ SourcePlaylistInterface::siblingItem( int itemsAway )
{ {
Q_UNUSED( itemsAway ); Q_UNUSED( itemsAway );
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( !m_gotNextSong || m_source.isNull() || m_source->currentTrack().isNull() || m_source->currentTrack()->results().isEmpty() ) if ( m_source.isNull() || m_source->currentTrack().isNull() || m_source->currentTrack()->results().isEmpty() )
{ {
qDebug() << Q_FUNC_INFO << " Results were empty for current track or source no longer valid"; qDebug() << Q_FUNC_INFO << " Results were empty for current track or source no longer valid";
m_currentItem = Tomahawk::result_ptr();
return m_currentItem;
}
else if ( !m_gotNextSong )
{
qDebug() << Q_FUNC_INFO << " This song was already fetched";
return Tomahawk::result_ptr(); return Tomahawk::result_ptr();
} }
m_gotNextSong = false; m_gotNextSong = false;
m_currentItem = m_source->currentTrack()->results().first();
return m_source->currentTrack()->results().first(); return m_currentItem;
} }
@@ -55,15 +62,21 @@ Tomahawk::result_ptr
SourcePlaylistInterface::nextItem() SourcePlaylistInterface::nextItem()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( !m_gotNextSong || m_source.isNull() || m_source->currentTrack().isNull() || m_source->currentTrack()->results().isEmpty() ) if ( m_source.isNull() || m_source->currentTrack().isNull() || m_source->currentTrack()->results().isEmpty() )
{ {
qDebug() << Q_FUNC_INFO << " Results were empty for current track or source no longer valid"; qDebug() << Q_FUNC_INFO << " Results were empty for current track or source no longer valid";
m_currentItem = Tomahawk::result_ptr();
return m_currentItem;
}
else if ( !m_gotNextSong )
{
qDebug() << Q_FUNC_INFO << " This song was already fetched";
return Tomahawk::result_ptr(); return Tomahawk::result_ptr();
} }
m_gotNextSong = false; m_gotNextSong = false;
m_currentItem = m_source->currentTrack()->results().first();
return m_source->currentTrack()->results().first(); return m_currentItem;
} }
@@ -74,6 +87,16 @@ SourcePlaylistInterface::tracks()
} }
void
SourcePlaylistInterface::reset()
{
if ( !m_currentItem.isNull() )
m_gotNextSong = true;
else
m_gotNextSong = false;
}
void void
SourcePlaylistInterface::onSourcePlaybackStarted( const Tomahawk::query_ptr& query ) SourcePlaylistInterface::onSourcePlaybackStarted( const Tomahawk::query_ptr& query )
{ {

View File

@@ -45,6 +45,7 @@ public:
virtual Tomahawk::result_ptr siblingItem( int itemsAway ); virtual Tomahawk::result_ptr siblingItem( int itemsAway );
virtual Tomahawk::result_ptr nextItem(); virtual Tomahawk::result_ptr nextItem();
virtual Tomahawk::result_ptr currentItem() { return m_currentItem; }
virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; } virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; }
virtual PlaylistInterface::SeekRestrictions seekRestrictions() const { return PlaylistInterface::NoSeek; } virtual PlaylistInterface::SeekRestrictions seekRestrictions() const { return PlaylistInterface::NoSeek; }
@@ -57,6 +58,8 @@ public:
virtual Tomahawk::source_ptr source() const { return m_source; } virtual Tomahawk::source_ptr source() const { return m_source; }
virtual void reset();
public slots: public slots:
virtual void setRepeatMode( PlaylistInterface::RepeatMode ) {} virtual void setRepeatMode( PlaylistInterface::RepeatMode ) {}
virtual void setShuffled( bool ) {} virtual void setShuffled( bool ) {}
@@ -74,6 +77,7 @@ private slots:
private: private:
Tomahawk::source_ptr m_source; Tomahawk::source_ptr m_source;
Tomahawk::result_ptr m_currentItem;
bool m_gotNextSong; bool m_gotNextSong;
}; };

View File

@@ -127,7 +127,7 @@ SourceTreeView::setupMenus()
{ {
m_playlistMenu.clear(); m_playlistMenu.clear();
m_roPlaylistMenu.clear(); m_roPlaylistMenu.clear();
m_followMenu.clear(); m_latchMenu.clear();
bool readonly = true; bool readonly = true;
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
@@ -142,6 +142,8 @@ SourceTreeView::setupMenus()
} }
} }
m_latchOnAction = m_latchMenu.addAction( tr( "&Listen Along" ) );
if ( type == SourcesModel::Collection ) if ( type == SourcesModel::Collection )
{ {
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex ); CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
@@ -153,12 +155,13 @@ SourceTreeView::setupMenus()
{ {
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi ); SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() ) if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
m_followAction = m_followMenu.addAction( tr( "&Catch Up" ) ); {
else m_latchOnAction->setText( tr( "&Catch Up" ) );
m_followAction = m_followMenu.addAction( tr( "&Listen Along" ) ); m_latchMenu.addSeparator();
m_latchOffAction = m_latchMenu.addAction( tr( "&Stop Listening Along" ) );
connect( m_latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
}
} }
else
m_followAction = m_followMenu.addAction( tr( "&Listen Along" ) );
} }
} }
@@ -192,7 +195,7 @@ SourceTreeView::setupMenus()
connect( m_deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) ); connect( m_deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
connect( m_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) ); connect( m_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
connect( m_addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) ); connect( m_addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) );
connect( m_followAction, SIGNAL( triggered() ), SLOT( follow() ) ); connect( m_latchOnAction, SIGNAL( triggered() ), SLOT( latchOn() ) );
} }
@@ -329,7 +332,7 @@ void SourceTreeView::addToLocal()
void void
SourceTreeView::follow() SourceTreeView::latchOn()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
QModelIndex idx = m_contextMenuIndex; QModelIndex idx = m_contextMenuIndex;
@@ -337,12 +340,51 @@ SourceTreeView::follow()
return; return;
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
if( type == SourcesModel::Collection ) if( type != SourcesModel::Collection )
return;
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
source_ptr source = item->source();
PlaylistInterface* pi = AudioEngine::instance()->playlist();
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
{ {
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex ); SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
source_ptr source = item->source(); if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() ); {
//it's a catch-up -- if they're trying to catch-up in the same track, don't do anything
//so that you don't repeat the track and/or cause the retry timer to fire
if ( !AudioEngine::instance()->currentTrack().isNull() &&
AudioEngine::instance()->currentTrack()->id() == sourcepi->currentItem()->id() )
return;
}
} }
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
}
void
SourceTreeView::latchOff()
{
qDebug() << Q_FUNC_INFO;
QModelIndex idx = m_contextMenuIndex;
if ( !idx.isValid() )
return;
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
if( type != SourcesModel::Collection )
return;
PlaylistInterface* pi = AudioEngine::instance()->playlist();
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
{
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
sourcepi->reset();
}
AudioEngine::instance()->stop();
AudioEngine::instance()->setPlaylist( 0 );
} }
@@ -381,7 +423,7 @@ SourceTreeView::onCustomContextMenu( const QPoint& pos )
{ {
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex ); CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
if ( !item->source()->isLocal() ) if ( !item->source()->isLocal() )
m_followMenu.exec( mapToGlobal( pos ) ); m_latchMenu.exec( mapToGlobal( pos ) );
} }
} }

View File

@@ -56,7 +56,8 @@ private slots:
void copyPlaylistLink(); void copyPlaylistLink();
void addToLocal(); void addToLocal();
void follow(); void latchOn();
void latchOff();
void onCustomContextMenu( const QPoint& pos ); void onCustomContextMenu( const QPoint& pos );
protected: protected:
@@ -83,13 +84,14 @@ private:
QMenu m_playlistMenu; QMenu m_playlistMenu;
QMenu m_roPlaylistMenu; QMenu m_roPlaylistMenu;
QMenu m_followMenu; QMenu m_latchMenu;
QAction* m_loadPlaylistAction; QAction* m_loadPlaylistAction;
QAction* m_renamePlaylistAction; QAction* m_renamePlaylistAction;
QAction* m_deletePlaylistAction; QAction* m_deletePlaylistAction;
QAction* m_copyPlaylistAction; QAction* m_copyPlaylistAction;
QAction* m_addToLocalAction; QAction* m_addToLocalAction;
QAction* m_followAction; QAction* m_latchOnAction;
QAction* m_latchOffAction;
bool m_dragging; bool m_dragging;
QRect m_dropRect; QRect m_dropRect;