mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-07-31 11:20:22 +02:00
Added DownloadManager and DownloadJob.
This commit is contained in:
@@ -15,6 +15,8 @@ set( libGuiSources
|
|||||||
ActionCollection.cpp
|
ActionCollection.cpp
|
||||||
|
|
||||||
ContextMenu.cpp
|
ContextMenu.cpp
|
||||||
|
DownloadManager.cpp
|
||||||
|
DownloadJob.cpp
|
||||||
DropJob.cpp
|
DropJob.cpp
|
||||||
GlobalActionManager.cpp
|
GlobalActionManager.cpp
|
||||||
ViewPage.cpp
|
ViewPage.cpp
|
||||||
|
446
src/libtomahawk/DownloadJob.cpp
Normal file
446
src/libtomahawk/DownloadJob.cpp
Normal file
@@ -0,0 +1,446 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DownloadJob.h"
|
||||||
|
|
||||||
|
#include "Track.h"
|
||||||
|
#include "TomahawkSettings.h"
|
||||||
|
#include "utils/NetworkAccessManager.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
|
||||||
|
DownloadJob::DownloadJob( const Tomahawk::track_ptr& track, DownloadFormat format, bool tryResuming, DownloadJob::TrackState state )
|
||||||
|
: m_state( state )
|
||||||
|
, m_retries( 0 )
|
||||||
|
, m_tryResuming( tryResuming )
|
||||||
|
, m_reply( 0 )
|
||||||
|
, m_file( 0 )
|
||||||
|
, m_rcvdStamp( 0 )
|
||||||
|
, m_rcvdEmit( 0 )
|
||||||
|
, m_rcvdSize( 0 )
|
||||||
|
, m_fileSize( 0 )
|
||||||
|
, m_format( format )
|
||||||
|
, m_track( track )
|
||||||
|
{
|
||||||
|
m_finished = ( state == Finished );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadJob::~DownloadJob()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
DownloadJob::progressPercentage() const
|
||||||
|
{
|
||||||
|
if ( m_fileSize == 0 )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ( (double)m_rcvdSize / (double)m_fileSize ) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::setState( TrackState state )
|
||||||
|
{
|
||||||
|
TrackState oldState = m_state;
|
||||||
|
m_state = state;
|
||||||
|
|
||||||
|
emit stateChanged( state, oldState );
|
||||||
|
|
||||||
|
if ( m_state == Finished )
|
||||||
|
{
|
||||||
|
m_rcvdSize = m_fileSize;
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
DownloadJob::localFile() const
|
||||||
|
{
|
||||||
|
return m_localFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
DownloadJob::localPath() const
|
||||||
|
{
|
||||||
|
QDir dir = TomahawkSettings::instance()->downloadsPath();
|
||||||
|
|
||||||
|
if ( !dir.exists() )
|
||||||
|
{
|
||||||
|
dir.mkpath( "." );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = QString( "%1/%2" ).arg( safeEncode( m_track->artist(), true ) ).arg( safeEncode( m_track->album(), true ) );
|
||||||
|
dir.mkpath( path );
|
||||||
|
|
||||||
|
return QString( dir.path() + "/" + path ).replace( "//", "/" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QUrl
|
||||||
|
DownloadJob::prepareFilename()
|
||||||
|
{
|
||||||
|
QString filename = QString( "%1. %2.%3" ).arg( m_track->albumpos() ).arg( safeEncode( m_track->track() ) ).arg( m_format.extension );
|
||||||
|
QString path = localPath();
|
||||||
|
QString localFile = QString( path + "/" + filename );
|
||||||
|
|
||||||
|
if ( !m_tryResuming )
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo( localFile );
|
||||||
|
unsigned int dupe = 1;
|
||||||
|
while ( dupe < 100 )
|
||||||
|
{
|
||||||
|
QFileInfo fi( localFile );
|
||||||
|
if ( fi.exists() )
|
||||||
|
{
|
||||||
|
QString dupeToken = QString( " (%1)" ).arg( dupe++ );
|
||||||
|
localFile = path + "/" + fileInfo.completeBaseName() + dupeToken + "." + fileInfo.suffix();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo( localFile );
|
||||||
|
unsigned int dupe = 1;
|
||||||
|
QString lastFound = localFile;
|
||||||
|
while ( dupe < 100 )
|
||||||
|
{
|
||||||
|
QFileInfo fi( localFile );
|
||||||
|
if ( fi.exists() )
|
||||||
|
{
|
||||||
|
lastFound = localFile;
|
||||||
|
QString dupeToken = QString( " (%1)" ).arg( dupe++ );
|
||||||
|
localFile = path + "/" + fileInfo.completeBaseName() + dupeToken + "." + fileInfo.suffix();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
localFile = lastFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << "Storing file as" << localFile << m_tryResuming;
|
||||||
|
return QUrl( localFile );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::retry()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
m_retries = 0;
|
||||||
|
m_reply = 0;
|
||||||
|
m_file = 0;
|
||||||
|
m_rcvdSize = 0;
|
||||||
|
m_fileSize = 0;
|
||||||
|
m_finished = false;
|
||||||
|
m_tryResuming = true;
|
||||||
|
|
||||||
|
setState( Waiting );
|
||||||
|
emit updated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadJob::download()
|
||||||
|
{
|
||||||
|
QUrl localFile = prepareFilename();
|
||||||
|
|
||||||
|
if ( m_file )
|
||||||
|
{
|
||||||
|
tLog() << "Recovering from failed download for track:" << toString() << "-" << m_retries << "retries so far.";
|
||||||
|
m_finished = false;
|
||||||
|
delete m_file;
|
||||||
|
m_file = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << "Saving download to file:" << localFile << localFile.toLocalFile();
|
||||||
|
|
||||||
|
m_file = new QFile( localFile.toString() );
|
||||||
|
m_localFile = localFile.toString();
|
||||||
|
|
||||||
|
if ( m_tryResuming && checkForResumedFile() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
m_reply = Tomahawk::Utils::nam()->get( QNetworkRequest( m_format.url ) );
|
||||||
|
|
||||||
|
connect( m_reply, SIGNAL( error( QNetworkReply::NetworkError ) ), SLOT( onDownloadError( QNetworkReply::NetworkError ) ) );
|
||||||
|
connect( m_reply, SIGNAL( downloadProgress( qint64, qint64 ) ), SLOT( onDownloadProgress( qint64, qint64 ) ) );
|
||||||
|
connect( m_reply, SIGNAL( finished() ), SLOT( onDownloadNetworkFinished() ) );
|
||||||
|
|
||||||
|
setState( Running );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::pause()
|
||||||
|
{
|
||||||
|
if ( !m_reply )
|
||||||
|
return;
|
||||||
|
|
||||||
|
setState( Paused );
|
||||||
|
// m_reply->setReadBufferSize( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::resume()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << m_finished << m_rcvdSize << m_fileSize;
|
||||||
|
if ( !m_reply )
|
||||||
|
{
|
||||||
|
tLog() << "Initiating paused download from previous session:" << toString();
|
||||||
|
download();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState( Running );
|
||||||
|
// m_reply->setReadBufferSize( 65536 );
|
||||||
|
|
||||||
|
onDownloadProgress( m_fileSize, m_fileSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::abort()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << toString();
|
||||||
|
setState( Aborted );
|
||||||
|
|
||||||
|
if ( m_reply )
|
||||||
|
{
|
||||||
|
m_reply->abort();
|
||||||
|
m_reply->deleteLater();
|
||||||
|
m_reply = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::onDownloadError( QNetworkReply::NetworkError code )
|
||||||
|
{
|
||||||
|
if ( code == QNetworkReply::NoError )
|
||||||
|
return;
|
||||||
|
if ( m_state == Aborted )
|
||||||
|
return;
|
||||||
|
|
||||||
|
tLog() << "Download error for track:" << toString() << "-" << code;
|
||||||
|
|
||||||
|
if ( ++m_retries > 3 )
|
||||||
|
{
|
||||||
|
setState( Failed );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_tryResuming = true;
|
||||||
|
download();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::onDownloadProgress( qint64 rcvd, qint64 total )
|
||||||
|
{
|
||||||
|
if ( m_reply == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( rcvd >= m_fileSize && m_fileSize > 0 )
|
||||||
|
{
|
||||||
|
m_finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( state() == Paused )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_rcvdSize = rcvd;
|
||||||
|
m_fileSize = total;
|
||||||
|
|
||||||
|
qint64 now = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||||
|
if ( ( now - 50 > m_rcvdStamp ) || ( rcvd == total ) )
|
||||||
|
{
|
||||||
|
m_rcvdStamp = now;
|
||||||
|
if ( ( m_rcvdSize - 16384 > m_rcvdEmit ) || ( rcvd == total ) )
|
||||||
|
{
|
||||||
|
m_rcvdEmit = m_rcvdSize;
|
||||||
|
emit progress( progressPercentage() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_file )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !m_file->isOpen() )
|
||||||
|
{
|
||||||
|
if ( m_tryResuming && checkForResumedFile() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !m_file->open( QIODevice::WriteOnly ) )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed opening file:" << m_file->fileName();
|
||||||
|
setState( Failed );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = m_reply->readAll();
|
||||||
|
if ( data.length() == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_file->write( data ) < 0 )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Failed writing to file:" << data.length();
|
||||||
|
onDownloadError( QNetworkReply::UnknownContentError );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_rcvdSize >= m_fileSize && m_fileSize > 0 )
|
||||||
|
{
|
||||||
|
onDownloadFinished();
|
||||||
|
}
|
||||||
|
else if ( m_reply->isFinished() && m_reply->bytesAvailable() == 0 )
|
||||||
|
{
|
||||||
|
if ( ( m_fileSize > 0 && m_rcvdSize < m_fileSize ) || m_rcvdSize == 0 )
|
||||||
|
{
|
||||||
|
onDownloadError( QNetworkReply::UnknownContentError );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::onDownloadNetworkFinished()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << m_rcvdSize << m_fileSize;
|
||||||
|
if ( m_reply && m_reply->bytesAvailable() > 0 )
|
||||||
|
{
|
||||||
|
tLog() << "Expecting more data!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( m_fileSize > 0 && m_rcvdSize < m_fileSize ) || m_rcvdSize == 0 )
|
||||||
|
{
|
||||||
|
if ( m_reply )
|
||||||
|
onDownloadError( QNetworkReply::UnknownContentError );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadJob::onDownloadFinished()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << m_rcvdSize << m_fileSize;
|
||||||
|
if ( state() == Paused )
|
||||||
|
{
|
||||||
|
m_finished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( m_fileSize > 0 && m_rcvdSize < m_fileSize ) || m_rcvdSize == 0 )
|
||||||
|
{
|
||||||
|
onDownloadError( QNetworkReply::UnknownContentError );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect( m_reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( onDownloadError( QNetworkReply::NetworkError ) ) );
|
||||||
|
disconnect( m_reply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( onDownloadProgress( qint64, qint64 ) ) );
|
||||||
|
disconnect( m_reply, SIGNAL( finished() ), this, SLOT( onDownloadNetworkFinished() ) );
|
||||||
|
m_reply->abort();
|
||||||
|
|
||||||
|
if ( m_file && m_file->isOpen() )
|
||||||
|
{
|
||||||
|
m_file->flush();
|
||||||
|
m_file->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_file;
|
||||||
|
m_file = 0;
|
||||||
|
|
||||||
|
m_finishedTimestamp = QDateTime::currentDateTimeUtc();
|
||||||
|
setState( Finished );
|
||||||
|
tLog() << Q_FUNC_INFO << "Finished downloading:" << toString();
|
||||||
|
tLog() << Q_FUNC_INFO << m_finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadJob::checkForResumedFile()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
if ( !m_tryResuming )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QUrl localFile = prepareFilename();
|
||||||
|
QFileInfo fi( localFile.toString() );
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << m_fileSize << fi.size();
|
||||||
|
|
||||||
|
if ( fi.size() > 0 && fi.exists() && fi.size() == m_fileSize )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Detected previously finished download.";
|
||||||
|
m_rcvdSize = fi.size();
|
||||||
|
m_finished = true;
|
||||||
|
onDownloadFinished();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
DownloadJob::safeEncode( const QString& filename, bool removeTrailingDots ) const
|
||||||
|
{
|
||||||
|
//FIXME: make it a regexp
|
||||||
|
QString res = QString( filename ).toLatin1().replace( "/", "_" ).replace( "\\", "_" )
|
||||||
|
.replace( "*", "_" ).replace( "?", "_" ).replace( "%", "_" )
|
||||||
|
.replace( "'", "_" ).replace( "\"", "_" )
|
||||||
|
.replace( ":", "_" ).replace( "#", "_" )
|
||||||
|
.replace( "<", "_" ).replace( ">", "_" );
|
||||||
|
|
||||||
|
if ( removeTrailingDots )
|
||||||
|
{
|
||||||
|
while ( res.endsWith( "." ) )
|
||||||
|
res = res.left( res.count() - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.left( 127 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
DownloadJob::toString() const
|
||||||
|
{
|
||||||
|
return m_track->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadFormat
|
||||||
|
DownloadJob::format() const
|
||||||
|
{
|
||||||
|
return m_format;
|
||||||
|
}
|
117
src/libtomahawk/DownloadJob.h
Normal file
117
src/libtomahawk/DownloadJob.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DOWNLOADJOB_H
|
||||||
|
#define DOWNLOADJOB_H
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QDomElement>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "Track.h"
|
||||||
|
|
||||||
|
struct DownloadFormat
|
||||||
|
{
|
||||||
|
QUrl url;
|
||||||
|
QString extension;
|
||||||
|
QString mimetype;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DownloadJob : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum TrackState
|
||||||
|
{ Waiting = 0, Running, Paused, Failed, Finished, Aborted, Any };
|
||||||
|
|
||||||
|
DownloadJob( const Tomahawk::track_ptr& track, DownloadFormat format, bool tryResuming = false, DownloadJob::TrackState state = Waiting );
|
||||||
|
~DownloadJob();
|
||||||
|
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
TrackState state() const { return m_state; }
|
||||||
|
unsigned int retries() const { return m_retries; }
|
||||||
|
|
||||||
|
int progressPercentage() const;
|
||||||
|
long receivedSize() const { return m_rcvdSize; }
|
||||||
|
long fileSize() const { return m_fileSize; }
|
||||||
|
|
||||||
|
QString localPath() const;
|
||||||
|
QString localFile() const;
|
||||||
|
DownloadFormat format() const;
|
||||||
|
|
||||||
|
QDateTime finishedTimestamp() const { return m_finishedTimestamp; }
|
||||||
|
void setFinishedTimestamp( const QDateTime& timestamp ) { m_finishedTimestamp = timestamp; }
|
||||||
|
|
||||||
|
void setState( TrackState state );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool download();
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
void retry();
|
||||||
|
void abort();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void updated();
|
||||||
|
void progress( int percentage );
|
||||||
|
void stateChanged( DownloadJob::TrackState newState, DownloadJob::TrackState oldState );
|
||||||
|
void finished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onDownloadNetworkFinished();
|
||||||
|
void onDownloadError( QNetworkReply::NetworkError code );
|
||||||
|
void onDownloadProgress( qint64, qint64 );
|
||||||
|
void onDownloadFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void storeState();
|
||||||
|
QString safeEncode( const QString& filename, bool removeTrailingDots = false ) const;
|
||||||
|
bool checkForResumedFile();
|
||||||
|
QUrl prepareFilename();
|
||||||
|
|
||||||
|
TrackState m_state;
|
||||||
|
unsigned int m_retries;
|
||||||
|
bool m_tryResuming;
|
||||||
|
|
||||||
|
QNetworkReply* m_reply;
|
||||||
|
QFile* m_file;
|
||||||
|
|
||||||
|
qint64 m_rcvdStamp;
|
||||||
|
long m_rcvdEmit;
|
||||||
|
long m_rcvdSize;
|
||||||
|
long m_fileSize;
|
||||||
|
bool m_finished;
|
||||||
|
|
||||||
|
QString m_localFile;
|
||||||
|
|
||||||
|
QDateTime m_finishedTimestamp;
|
||||||
|
|
||||||
|
DownloadFormat m_format;
|
||||||
|
Tomahawk::track_ptr m_track;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QSharedPointer<DownloadJob> downloadjob_ptr;
|
||||||
|
|
||||||
|
#endif // DOWNLOADJOB_H
|
239
src/libtomahawk/DownloadManager.cpp
Normal file
239
src/libtomahawk/DownloadManager.cpp
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DownloadManager.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
DownloadManager* DownloadManager::s_instance = 0;
|
||||||
|
|
||||||
|
|
||||||
|
DownloadManager*
|
||||||
|
DownloadManager::instance()
|
||||||
|
{
|
||||||
|
if ( !s_instance )
|
||||||
|
{
|
||||||
|
s_instance = new DownloadManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadManager::DownloadManager()
|
||||||
|
: m_globalState( true )
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Initializing DownloadManager.";
|
||||||
|
|
||||||
|
QTimer::singleShot( 0, this, SLOT( resumeJobs() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadManager::~DownloadManager()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO << "Shutting down DownloadManager.";
|
||||||
|
|
||||||
|
QList< downloadjob_ptr > jl;
|
||||||
|
foreach ( const downloadjob_ptr& job, jobs() )
|
||||||
|
{
|
||||||
|
jl << job;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TomahawkSettings::instance()->storeJobs( jl );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadManager::resumeJobs()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
/* QList<downloadjob_ptr> jobs = TomahawkSettings::instance()->storedJobs();
|
||||||
|
for ( int i = jobs.count() - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
downloadjob_ptr job = jobs.at( i );
|
||||||
|
addJob( job );
|
||||||
|
}
|
||||||
|
|
||||||
|
tLog() << Q_FUNC_INFO << "Restored" << jobs.count() << "existing jobs.";*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QList<downloadjob_ptr>
|
||||||
|
DownloadManager::jobs( DownloadJob::TrackState state ) const
|
||||||
|
{
|
||||||
|
if ( state < 0 )
|
||||||
|
return m_jobs;
|
||||||
|
|
||||||
|
QList<downloadjob_ptr> jobs;
|
||||||
|
foreach ( const downloadjob_ptr& job, m_jobs )
|
||||||
|
{
|
||||||
|
if ( job.isNull() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( state == DownloadJob::TrackState::Any || job->state() == state )
|
||||||
|
jobs << job;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadManager::addJob( const downloadjob_ptr& job )
|
||||||
|
{
|
||||||
|
if ( job.isNull() )
|
||||||
|
{
|
||||||
|
tLog() << "Found invalid download job - ignoring!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( containsJob( job ) )
|
||||||
|
{
|
||||||
|
tLog() << "Found duplicate download job - ignoring:" << job->toString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_jobs << job;
|
||||||
|
emit jobAdded( job );
|
||||||
|
|
||||||
|
connect( job.data(), SIGNAL( finished() ), SLOT( checkJobs() ) );
|
||||||
|
connect( job.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ), SLOT( checkJobs() ) ) ;
|
||||||
|
// connect( job.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ) );
|
||||||
|
|
||||||
|
checkJobs();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadManager::removeJob( const downloadjob_ptr& job )
|
||||||
|
{
|
||||||
|
tLog() << "Removing job:" << job->toString();
|
||||||
|
job->abort();
|
||||||
|
m_jobs.removeAll( job );
|
||||||
|
emit jobRemoved( job );
|
||||||
|
|
||||||
|
checkJobs();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadManager::containsJob( const downloadjob_ptr& job ) const
|
||||||
|
{
|
||||||
|
return m_jobs.contains( job );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
downloadjob_ptr
|
||||||
|
DownloadManager::currentJob() const
|
||||||
|
{
|
||||||
|
QList<downloadjob_ptr> j = jobs( DownloadJob::TrackState::Running );
|
||||||
|
if ( j.count() )
|
||||||
|
return j.first();
|
||||||
|
|
||||||
|
j = jobs( DownloadJob::TrackState::Paused );
|
||||||
|
if ( j.count() )
|
||||||
|
return j.first();
|
||||||
|
|
||||||
|
j = jobs( DownloadJob::TrackState::Waiting );
|
||||||
|
if ( j.count() )
|
||||||
|
return j.first();
|
||||||
|
|
||||||
|
return downloadjob_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DownloadManager::DownloadManagerState
|
||||||
|
DownloadManager::state() const
|
||||||
|
{
|
||||||
|
if ( !currentJob().isNull() )
|
||||||
|
{
|
||||||
|
switch ( currentJob()->state() )
|
||||||
|
{
|
||||||
|
case DownloadJob::TrackState::Waiting:
|
||||||
|
return DownloadManager::DownloadManagerState::Waiting;
|
||||||
|
|
||||||
|
case DownloadJob::TrackState::Paused:
|
||||||
|
return DownloadManager::DownloadManagerState::Paused;
|
||||||
|
|
||||||
|
case DownloadJob::TrackState::Running:
|
||||||
|
return DownloadManager::DownloadManagerState::Running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DownloadManager::DownloadManagerState::Waiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadManager::checkJobs()
|
||||||
|
{
|
||||||
|
if ( !m_globalState )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( state() == DownloadManager::DownloadManagerState::Waiting && !currentJob().isNull() )
|
||||||
|
{
|
||||||
|
downloadjob_ptr job = currentJob();
|
||||||
|
/* connect( job.data(), SIGNAL( finished() ), SLOT( checkJobs() ) );
|
||||||
|
connect( job.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ), SLOT( checkJobs() ) ) ;
|
||||||
|
connect( job.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ), SIGNAL( stateChanged( Track::TrackState, Track::TrackState ) ) );*/
|
||||||
|
|
||||||
|
job->download();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadManager::pause()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
m_globalState = false;
|
||||||
|
foreach ( const downloadjob_ptr& job, jobs( DownloadJob::TrackState::Running ) )
|
||||||
|
{
|
||||||
|
job->pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadManager::resume()
|
||||||
|
{
|
||||||
|
tLog() << Q_FUNC_INFO;
|
||||||
|
|
||||||
|
m_globalState = true;
|
||||||
|
|
||||||
|
if ( jobs( DownloadJob::TrackState::Paused ).count() )
|
||||||
|
{
|
||||||
|
foreach ( const downloadjob_ptr& job, jobs( DownloadJob::TrackState::Paused ) )
|
||||||
|
{
|
||||||
|
tLog() << "Resuming job:" << job->toString();
|
||||||
|
job->resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkJobs();
|
||||||
|
}
|
70
src/libtomahawk/DownloadManager.h
Normal file
70
src/libtomahawk/DownloadManager.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
|
*
|
||||||
|
* Copyright 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
*
|
||||||
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tomahawk is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DOWNLOADMANAGER_H
|
||||||
|
#define DOWNLOADMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "DownloadJob.h"
|
||||||
|
|
||||||
|
class DownloadManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum DownloadManagerState { None, Running, Paused, Waiting };
|
||||||
|
static DownloadManager* instance();
|
||||||
|
|
||||||
|
DownloadManager();
|
||||||
|
~DownloadManager();
|
||||||
|
|
||||||
|
DownloadManagerState state() const;
|
||||||
|
|
||||||
|
QList<downloadjob_ptr> jobs( DownloadJob::TrackState state = DownloadJob::TrackState::Any ) const;
|
||||||
|
bool containsJob( const downloadjob_ptr& job ) const;
|
||||||
|
downloadjob_ptr currentJob() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool addJob( const downloadjob_ptr& job );
|
||||||
|
bool removeJob( const downloadjob_ptr& job );
|
||||||
|
void checkJobs();
|
||||||
|
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
void resumeJobs();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void jobAdded( const downloadjob_ptr& job );
|
||||||
|
void jobRemoved( const downloadjob_ptr& job );
|
||||||
|
|
||||||
|
void stateChanged( DownloadManagerState newState, DownloadManagerState oldState );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList< downloadjob_ptr > m_jobs;
|
||||||
|
bool m_globalState;
|
||||||
|
|
||||||
|
static DownloadManager* s_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DOWNLOADMANAGER_H
|
Reference in New Issue
Block a user