downloadmgr.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include <QtCore>
  2. #include "downloadmgr.h"
  3. Download::Download(Episode& e, QObject* parent)
  4. : QObject(parent), episode(e), totalBytes(0), bytesWritten(0), progress(0), status(NotStarted) {
  5. QString fn = e.downloadPath();
  6. file.setFileName(fn);
  7. if(file.exists()) {
  8. bytesWritten = file.size();
  9. // qDebug() << "Found partial download for " << e.name << " of size: " << bytesWritten;
  10. }
  11. }
  12. Download::~Download() {
  13. file.close();
  14. }
  15. void Download::abort() {
  16. file.close();
  17. status = Aborted;
  18. if (!reply.isNull()) {
  19. reply->abort();
  20. reply->deleteLater();
  21. }
  22. qDebug() << "Download Aborted: " << episode.name;
  23. }
  24. void Download::start(QNetworkReply *r) {
  25. if (!reply.isNull())
  26. reply->deleteLater();
  27. reply=r;
  28. status = Downloading;
  29. }
  30. DownloadMgr::DownloadMgr(QObject *parent) : QObject(parent) {
  31. connect (&m_manager, SIGNAL(finished(QNetworkReply*)),
  32. this, SLOT(downloadEpisodeFinished(QNetworkReply*)), Qt::UniqueConnection);
  33. }
  34. Download* DownloadMgr::start(Episode& ep) {
  35. QNetworkRequest request(ep.downloadLink);
  36. Download* d = 0;
  37. if (m_downloads.contains(ep)) {
  38. d = m_downloads[ep];
  39. }
  40. else {
  41. d = new Download(ep, this);
  42. m_downloads[ep]=d;
  43. }
  44. if (d->status != Download::Downloading) {
  45. QNetworkReply* reply = m_manager.get(request);
  46. reply->setReadBufferSize(2 * BufferSize);
  47. d->start(reply);
  48. m_replyHash[reply] = d;
  49. connect (reply, SIGNAL(downloadProgress(qint64,qint64)),
  50. this, SLOT(updateProgress(qint64, qint64)));
  51. }
  52. // qDebug() << "Get: " << request.url();
  53. return d;
  54. }
  55. void DownloadMgr::abort(Episode &e) {
  56. Download* d = m_downloads[e];
  57. if (d == 0) {
  58. qDebug() << e.name << "Can't find current download to abort!!";
  59. return;
  60. }
  61. d->abort();
  62. emit updateViews(e);
  63. }
  64. Download* DownloadMgr::getDownload(const Episode& e) const {
  65. if (m_downloads.contains(e)) return m_downloads[e];
  66. else return 0;
  67. }
  68. void DownloadMgr::remove(Episode& e) {
  69. Download* d = m_downloads[e];
  70. if (d != 0) d->deleteLater();
  71. m_downloads.remove(e);
  72. //m_replyHash.remove(d->reply);
  73. }
  74. void DownloadMgr::updateProgress(qint64 received, qint64 total) {
  75. // This has the side-effect of ignoring redirect packets which we do not want to touch here.
  76. if (total < BufferSize) return;
  77. QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
  78. Q_ASSERT(reply != 0);
  79. Download* d = m_replyHash[reply];
  80. if (d->bytesWritten >= total) {
  81. // we already have the episode.
  82. d->abort();
  83. d->status = Download::Complete;
  84. d->progress = 100;
  85. emit updateViews(d->episode);
  86. return;
  87. }
  88. d->progress = 100 * d->bytesWritten / total;
  89. if (received < BufferSize) return;
  90. if (received < d->bytesWritten) {
  91. int bytes = d->reply->bytesAvailable();
  92. int newBytes = received + bytes - d->bytesWritten;
  93. if (newBytes > 0) {
  94. bytes = bytes - newBytes;
  95. }
  96. d->reply->read(bytes);
  97. // qDebug() << " Skipping " << bytes << ". received: " << received << " bytesWritten: " << d->bytesWritten;
  98. return;
  99. }
  100. if (savePartial(d)) {
  101. d->totalBytes = total;
  102. emit updateViews(d->episode);
  103. }
  104. }
  105. bool DownloadMgr::savePartial(Download* d) {
  106. int bytesAvailable = d->reply->bytesAvailable();
  107. if (bytesAvailable < BufferSize) return false;
  108. QByteArray ba = d->reply->read(BufferSize);
  109. if (!d->file.isOpen()) {
  110. if (!d->file.open(QIODevice::Append)) {
  111. qDebug() << "Unable to open for append: " << d->episode.downloadPath();
  112. return false;
  113. }
  114. }
  115. d->file.write(ba);
  116. d->bytesWritten += ba.size();
  117. d->status = Download::Downloading;
  118. return true;
  119. }
  120. void DownloadMgr::downloadEpisodeFinished(QNetworkReply * reply) {
  121. // qDebug() << reply->rawHeaderList();
  122. Download* d = m_replyHash[reply];
  123. if (d->status == Download::Aborted) return;
  124. Episode& e = d->episode;
  125. qApp->processEvents();
  126. m_replyHash.remove(reply);
  127. QUrl url = reply->url();
  128. reply->deleteLater();
  129. QVariant redirectVar = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
  130. if (redirectVar != QVariant()) {
  131. QUrl url = redirectVar.toUrl();
  132. if (e.downloadLink == url) {
  133. qDebug() << "Redirect loop.";
  134. return;
  135. }
  136. e.downloadLink = url;
  137. d->progress = 1;
  138. d->status = Download::Downloading;
  139. d->bytesWritten = 0;
  140. qDebug() << "REDIRECT:" << url.toString();
  141. emit updateViews(e);
  142. start(e);
  143. return;
  144. }
  145. if (reply->error()) {
  146. d->abort();
  147. qDebug() << QString("Download of %1 failed: %2\n")
  148. .arg(url.toEncoded().constData())
  149. .arg(qPrintable(reply->errorString()));
  150. emit updateViews(e);
  151. return;
  152. }
  153. QByteArray contentType = reply->rawHeader("Content-Type");
  154. qDebug() << "Content Type: " << contentType;
  155. QByteArray bytes = reply->readAll();
  156. qDebug() << bytes.size() + d->bytesWritten << "bytes read. ";
  157. QString contentStr(contentType);
  158. if (contentStr.startsWith("text/html")) {
  159. QRegExp redirectURLPattern = QRegExp("\"(http://[^\"]+\\.mp3)\"");
  160. // search 'bytes' for a http://*.\.mp3 url
  161. contentStr = QString(bytes);
  162. int idx = redirectURLPattern.indexIn(contentStr);
  163. if (idx > -1) {
  164. QString capturedURL = redirectURLPattern.cap(1);
  165. QUrl url = QUrl::fromUserInput(capturedURL);
  166. e.downloadLink = url;
  167. d->progress = 1;
  168. d->status = Download::Downloading;
  169. d->bytesWritten = 0;
  170. qDebug() << "REDIRECT from HTML content:" << url.toString();
  171. emit updateViews(e);
  172. start(e);
  173. return;
  174. }
  175. }
  176. if (!d->file.isOpen()) {
  177. if (!d->file.open(QIODevice::Append)) {
  178. qDebug() << "Unable to open for append: " << d->file.fileName();
  179. d->status = Download::Aborted;
  180. emit updateViews(e);
  181. return;
  182. }
  183. }
  184. d->file.write(bytes);
  185. d->bytesWritten += bytes.size();
  186. d->file.close();
  187. d->status = Download::Complete;
  188. d->progress = 100;
  189. emit updateViews(e);
  190. }