mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-06 06:07:37 +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:
@@ -111,14 +111,14 @@ AudioEngine::play()
|
||||
{
|
||||
m_mediaObject->play();
|
||||
emit resumed();
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
trackInfo["artist"] = m_currentTrack->artist()->name();
|
||||
trackInfo["album"] = m_currentTrack->album()->name();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
trackInfo["artist"] = m_currentTrack->artist()->name();
|
||||
trackInfo["album"] = m_currentTrack->album()->name();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
}
|
||||
else
|
||||
loadNextTrack();
|
||||
@@ -143,7 +143,8 @@ AudioEngine::stop()
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_mediaObject->stop();
|
||||
|
||||
m_retryTimer.stop();
|
||||
|
||||
setCurrentTrack( Tomahawk::result_ptr() );
|
||||
emit stopped();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
@@ -155,6 +156,10 @@ void
|
||||
AudioEngine::previous()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !m_playlist )
|
||||
return;
|
||||
|
||||
if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip ||
|
||||
m_playlist->skipRestrictions() == PlaylistInterface::NoSkipBackwards )
|
||||
return;
|
||||
@@ -167,6 +172,10 @@ void
|
||||
AudioEngine::next()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !m_playlist )
|
||||
return;
|
||||
|
||||
if ( m_playlist->skipRestrictions() == PlaylistInterface::NoSkip ||
|
||||
m_playlist->skipRestrictions() == PlaylistInterface::NoSkipForwards )
|
||||
return;
|
||||
@@ -178,6 +187,9 @@ AudioEngine::next()
|
||||
void
|
||||
AudioEngine::seek( int ms )
|
||||
{
|
||||
if ( !m_playlist )
|
||||
return;
|
||||
|
||||
if ( m_playlist->seekRestrictions() == PlaylistInterface::NoSeek )
|
||||
return;
|
||||
|
||||
@@ -345,7 +357,7 @@ AudioEngine::loadNextTrack()
|
||||
else
|
||||
{
|
||||
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.start();
|
||||
|
@@ -28,6 +28,7 @@ using namespace Tomahawk;
|
||||
SourcePlaylistInterface::SourcePlaylistInterface( Tomahawk::source_ptr& source )
|
||||
: PlaylistInterface( this )
|
||||
, m_source( source )
|
||||
, m_currentItem( 0 )
|
||||
, m_gotNextSong( false )
|
||||
{
|
||||
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 );
|
||||
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";
|
||||
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();
|
||||
}
|
||||
|
||||
m_gotNextSong = false;
|
||||
|
||||
return m_source->currentTrack()->results().first();
|
||||
m_currentItem = m_source->currentTrack()->results().first();
|
||||
return m_currentItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,15 +62,21 @@ Tomahawk::result_ptr
|
||||
SourcePlaylistInterface::nextItem()
|
||||
{
|
||||
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";
|
||||
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();
|
||||
}
|
||||
|
||||
m_gotNextSong = false;
|
||||
|
||||
return m_source->currentTrack()->results().first();
|
||||
m_currentItem = 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
|
||||
SourcePlaylistInterface::onSourcePlaybackStarted( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
|
@@ -45,6 +45,7 @@ public:
|
||||
|
||||
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
|
||||
virtual Tomahawk::result_ptr nextItem();
|
||||
virtual Tomahawk::result_ptr currentItem() { return m_currentItem; }
|
||||
|
||||
virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; }
|
||||
virtual PlaylistInterface::SeekRestrictions seekRestrictions() const { return PlaylistInterface::NoSeek; }
|
||||
@@ -57,6 +58,8 @@ public:
|
||||
|
||||
virtual Tomahawk::source_ptr source() const { return m_source; }
|
||||
|
||||
virtual void reset();
|
||||
|
||||
public slots:
|
||||
virtual void setRepeatMode( PlaylistInterface::RepeatMode ) {}
|
||||
virtual void setShuffled( bool ) {}
|
||||
@@ -74,6 +77,7 @@ private slots:
|
||||
|
||||
private:
|
||||
Tomahawk::source_ptr m_source;
|
||||
Tomahawk::result_ptr m_currentItem;
|
||||
bool m_gotNextSong;
|
||||
};
|
||||
|
||||
|
@@ -127,7 +127,7 @@ SourceTreeView::setupMenus()
|
||||
{
|
||||
m_playlistMenu.clear();
|
||||
m_roPlaylistMenu.clear();
|
||||
m_followMenu.clear();
|
||||
m_latchMenu.clear();
|
||||
|
||||
bool readonly = true;
|
||||
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 )
|
||||
{
|
||||
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
|
||||
@@ -153,12 +155,13 @@ SourceTreeView::setupMenus()
|
||||
{
|
||||
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
|
||||
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
|
||||
m_followAction = m_followMenu.addAction( tr( "&Catch Up" ) );
|
||||
else
|
||||
m_followAction = m_followMenu.addAction( tr( "&Listen Along" ) );
|
||||
{
|
||||
m_latchOnAction->setText( tr( "&Catch Up" ) );
|
||||
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_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
|
||||
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
|
||||
SourceTreeView::follow()
|
||||
SourceTreeView::latchOn()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QModelIndex idx = m_contextMenuIndex;
|
||||
@@ -337,12 +340,51 @@ SourceTreeView::follow()
|
||||
return;
|
||||
|
||||
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 );
|
||||
source_ptr source = item->source();
|
||||
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
||||
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
|
||||
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
|
||||
{
|
||||
//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 );
|
||||
if ( !item->source()->isLocal() )
|
||||
m_followMenu.exec( mapToGlobal( pos ) );
|
||||
m_latchMenu.exec( mapToGlobal( pos ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -56,7 +56,8 @@ private slots:
|
||||
void copyPlaylistLink();
|
||||
void addToLocal();
|
||||
|
||||
void follow();
|
||||
void latchOn();
|
||||
void latchOff();
|
||||
|
||||
void onCustomContextMenu( const QPoint& pos );
|
||||
protected:
|
||||
@@ -83,13 +84,14 @@ private:
|
||||
|
||||
QMenu m_playlistMenu;
|
||||
QMenu m_roPlaylistMenu;
|
||||
QMenu m_followMenu;
|
||||
QMenu m_latchMenu;
|
||||
QAction* m_loadPlaylistAction;
|
||||
QAction* m_renamePlaylistAction;
|
||||
QAction* m_deletePlaylistAction;
|
||||
QAction* m_copyPlaylistAction;
|
||||
QAction* m_addToLocalAction;
|
||||
QAction* m_followAction;
|
||||
QAction* m_latchOnAction;
|
||||
QAction* m_latchOffAction;
|
||||
|
||||
bool m_dragging;
|
||||
QRect m_dropRect;
|
||||
|
Reference in New Issue
Block a user