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:
@@ -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();
|
||||||
|
@@ -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 )
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user