123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- #include <QtCore>
- #include "downloadmgr.h"
- Download::Download(Episode& e, QObject* parent)
- : QObject(parent), episode(e), totalBytes(0), bytesWritten(0), progress(0), status(NotStarted) {
- QString fn = e.downloadPath();
- file.setFileName(fn);
- if(file.exists()) {
- bytesWritten = file.size();
- // qDebug() << "Found partial download for " << e.name << " of size: " << bytesWritten;
- }
- }
- Download::~Download() {
- file.close();
- }
- void Download::abort() {
- file.close();
- status = Aborted;
- if (!reply.isNull()) {
- reply->abort();
- reply->deleteLater();
- }
- qDebug() << "Download Aborted: " << episode.name;
- }
- void Download::start(QNetworkReply *r) {
- if (!reply.isNull())
- reply->deleteLater();
- reply=r;
- status = Downloading;
- }
- DownloadMgr::DownloadMgr(QObject *parent) : QObject(parent) {
- connect (&m_manager, SIGNAL(finished(QNetworkReply*)),
- this, SLOT(downloadEpisodeFinished(QNetworkReply*)), Qt::UniqueConnection);
- }
- Download* DownloadMgr::start(Episode& ep) {
- QNetworkRequest request(ep.downloadLink);
- Download* d = 0;
- if (m_downloads.contains(ep)) {
- d = m_downloads[ep];
- }
- else {
- d = new Download(ep, this);
- m_downloads[ep]=d;
- }
- if (d->status != Download::Downloading) {
- QNetworkReply* reply = m_manager.get(request);
- reply->setReadBufferSize(2 * BufferSize);
- d->start(reply);
- m_replyHash[reply] = d;
- connect (reply, SIGNAL(downloadProgress(qint64,qint64)),
- this, SLOT(updateProgress(qint64, qint64)));
- }
- // qDebug() << "Get: " << request.url();
- return d;
- }
- void DownloadMgr::abort(Episode &e) {
- Download* d = m_downloads[e];
- if (d == 0) {
- qDebug() << e.name << "Can't find current download to abort!!";
- return;
- }
- d->abort();
- emit updateViews(e);
- }
- Download* DownloadMgr::getDownload(const Episode& e) const {
- if (m_downloads.contains(e)) return m_downloads[e];
- else return 0;
- }
- void DownloadMgr::remove(Episode& e) {
- Download* d = m_downloads[e];
- if (d != 0) d->deleteLater();
- m_downloads.remove(e);
- //m_replyHash.remove(d->reply);
- }
- void DownloadMgr::updateProgress(qint64 received, qint64 total) {
- // This has the side-effect of ignoring redirect packets which we do not want to touch here.
- if (total < BufferSize) return;
- QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
- Q_ASSERT(reply != 0);
- Download* d = m_replyHash[reply];
- if (d->bytesWritten >= total) {
- // we already have the episode.
- d->abort();
- d->status = Download::Complete;
- d->progress = 100;
- emit updateViews(d->episode);
- return;
- }
- d->progress = 100 * d->bytesWritten / total;
- if (received < BufferSize) return;
- if (received < d->bytesWritten) {
- int bytes = d->reply->bytesAvailable();
- int newBytes = received + bytes - d->bytesWritten;
- if (newBytes > 0) {
- bytes = bytes - newBytes;
- }
- d->reply->read(bytes);
- // qDebug() << " Skipping " << bytes << ". received: " << received << " bytesWritten: " << d->bytesWritten;
- return;
- }
- if (savePartial(d)) {
- d->totalBytes = total;
- emit updateViews(d->episode);
- }
- }
- bool DownloadMgr::savePartial(Download* d) {
- int bytesAvailable = d->reply->bytesAvailable();
- if (bytesAvailable < BufferSize) return false;
- QByteArray ba = d->reply->read(BufferSize);
- if (!d->file.isOpen()) {
- if (!d->file.open(QIODevice::Append)) {
- qDebug() << "Unable to open for append: " << d->episode.downloadPath();
- return false;
- }
- }
- d->file.write(ba);
- d->bytesWritten += ba.size();
- d->status = Download::Downloading;
- return true;
- }
- void DownloadMgr::downloadEpisodeFinished(QNetworkReply * reply) {
- // qDebug() << reply->rawHeaderList();
- Download* d = m_replyHash[reply];
- if (d->status == Download::Aborted) return;
- Episode& e = d->episode;
- qApp->processEvents();
- m_replyHash.remove(reply);
- QUrl url = reply->url();
- reply->deleteLater();
- QVariant redirectVar = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirectVar != QVariant()) {
- QUrl url = redirectVar.toUrl();
- if (e.downloadLink == url) {
- qDebug() << "Redirect loop.";
- return;
- }
- e.downloadLink = url;
- d->progress = 1;
- d->status = Download::Downloading;
- d->bytesWritten = 0;
- qDebug() << "REDIRECT:" << url.toString();
- emit updateViews(e);
- start(e);
- return;
- }
- if (reply->error()) {
- d->abort();
- qDebug() << QString("Download of %1 failed: %2\n")
- .arg(url.toEncoded().constData())
- .arg(qPrintable(reply->errorString()));
- emit updateViews(e);
- return;
- }
- QByteArray contentType = reply->rawHeader("Content-Type");
- qDebug() << "Content Type: " << contentType;
- QByteArray bytes = reply->readAll();
- qDebug() << bytes.size() + d->bytesWritten << "bytes read. ";
- QString contentStr(contentType);
- if (contentStr.startsWith("text/html")) {
- QRegExp redirectURLPattern = QRegExp("\"(http://[^\"]+\\.mp3)\"");
- // search 'bytes' for a http://*.\.mp3 url
- contentStr = QString(bytes);
- int idx = redirectURLPattern.indexIn(contentStr);
- if (idx > -1) {
- QString capturedURL = redirectURLPattern.cap(1);
- QUrl url = QUrl::fromUserInput(capturedURL);
- e.downloadLink = url;
- d->progress = 1;
- d->status = Download::Downloading;
- d->bytesWritten = 0;
- qDebug() << "REDIRECT from HTML content:" << url.toString();
- emit updateViews(e);
- start(e);
- return;
- }
- }
- if (!d->file.isOpen()) {
- if (!d->file.open(QIODevice::Append)) {
- qDebug() << "Unable to open for append: " << d->file.fileName();
- d->status = Download::Aborted;
- emit updateViews(e);
- return;
- }
- }
- d->file.write(bytes);
- d->bytesWritten += bytes.size();
- d->file.close();
- d->status = Download::Complete;
- d->progress = 100;
- emit updateViews(e);
- }
|