mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 11:35:24 +01:00
Precache the first and last parts of Google Drive MP3s to reduce the
number of requests when using accurate tagging.
This commit is contained in:
parent
fd1d70c644
commit
08286102da
@ -1,16 +1,16 @@
|
|||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2012, David Sansome <me@davidsansome.com>
|
Copyright 2012, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
Clementine is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -25,7 +25,11 @@
|
|||||||
|
|
||||||
#include <taglib/id3v2framefactory.h>
|
#include <taglib/id3v2framefactory.h>
|
||||||
#include <taglib/mpegfile.h>
|
#include <taglib/mpegfile.h>
|
||||||
using TagLib::ByteVector;
|
|
||||||
|
namespace {
|
||||||
|
static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough.
|
||||||
|
static const int kTaglibSuffixCacheBytes = 2 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
GoogleDriveStream::GoogleDriveStream(
|
GoogleDriveStream::GoogleDriveStream(
|
||||||
const QUrl& url, const QString& filename, const long length,
|
const QUrl& url, const QString& filename, const long length,
|
||||||
@ -37,7 +41,8 @@ GoogleDriveStream::GoogleDriveStream(
|
|||||||
auth_(auth),
|
auth_(auth),
|
||||||
cursor_(0),
|
cursor_(0),
|
||||||
network_(network),
|
network_(network),
|
||||||
cache_(length) {
|
cache_(length),
|
||||||
|
num_requests_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TagLib::FileName GoogleDriveStream::name() const {
|
TagLib::FileName GoogleDriveStream::name() const {
|
||||||
@ -68,6 +73,25 @@ TagLib::ByteVector GoogleDriveStream::GetCached(int start, int end) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GoogleDriveStream::Precache() {
|
||||||
|
// For reading the tags of an MP3, TagLib tends to request:
|
||||||
|
// 1. The first 1024 bytes
|
||||||
|
// 2. Somewhere between the first 2KB and first 60KB
|
||||||
|
// 3. The last KB or two.
|
||||||
|
// 4. Somewhere in the first 64KB again
|
||||||
|
//
|
||||||
|
// So, if we precache the first 64KB and the last 2KB we should be sorted :-)
|
||||||
|
// Ideally, we would use bytes=0-655364,-2048 but Google Drive does not seem
|
||||||
|
// to support multipart byte ranges yet so we have to make do with two
|
||||||
|
// requests.
|
||||||
|
|
||||||
|
seek(0, TagLib::IOStream::Beginning);
|
||||||
|
readBlock(kTaglibPrefixCacheBytes);
|
||||||
|
seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End);
|
||||||
|
readBlock(kTaglibSuffixCacheBytes);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
|
TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
|
||||||
const uint start = cursor_;
|
const uint start = cursor_;
|
||||||
const uint end = qMin(cursor_ + length - 1, length_ - 1);
|
const uint end = qMin(cursor_ + length - 1, length_ - 1);
|
||||||
@ -89,6 +113,7 @@ TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
|
|||||||
"Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
|
"Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8());
|
||||||
|
|
||||||
QNetworkReply* reply = network_->get(request);
|
QNetworkReply* reply = network_->get(request);
|
||||||
|
++num_requests_;
|
||||||
|
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
@ -103,11 +128,11 @@ TagLib::ByteVector GoogleDriveStream::readBlock(ulong length) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoogleDriveStream::writeBlock(const ByteVector&) {
|
void GoogleDriveStream::writeBlock(const TagLib::ByteVector&) {
|
||||||
qLog(Debug) << Q_FUNC_INFO << "not implemented";
|
qLog(Debug) << Q_FUNC_INFO << "not implemented";
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoogleDriveStream::insert(const ByteVector&, ulong, ulong) {
|
void GoogleDriveStream::insert(const TagLib::ByteVector&, ulong, ulong) {
|
||||||
qLog(Debug) << Q_FUNC_INFO << "not implemented";
|
qLog(Debug) << Q_FUNC_INFO << "not implemented";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,17 @@ class GoogleDriveStream : public TagLib::IOStream {
|
|||||||
virtual long length();
|
virtual long length();
|
||||||
virtual void truncate(long);
|
virtual void truncate(long);
|
||||||
|
|
||||||
|
google::sparsetable<char>::size_type cached_bytes() const {
|
||||||
|
return cache_.num_nonempty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_requests() const {
|
||||||
|
return num_requests_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use educated guess to request the bytes that TagLib will probably want.
|
||||||
|
void Precache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CheckCache(int start, int end);
|
bool CheckCache(int start, int end);
|
||||||
void FillCache(int start, TagLib::ByteVector data);
|
void FillCache(int start, TagLib::ByteVector data);
|
||||||
@ -63,6 +74,7 @@ class GoogleDriveStream : public TagLib::IOStream {
|
|||||||
QNetworkAccessManager* network_;
|
QNetworkAccessManager* network_;
|
||||||
|
|
||||||
google::sparsetable<char> cache_;
|
google::sparsetable<char> cache_;
|
||||||
|
int num_requests_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GOOGLEDRIVESTREAM_H
|
#endif // GOOGLEDRIVESTREAM_H
|
||||||
|
@ -616,10 +616,11 @@ void TagReaderWorker::ReadGoogleDrive(const QUrl& download_url,
|
|||||||
|
|
||||||
GoogleDriveStream* stream = new GoogleDriveStream(
|
GoogleDriveStream* stream = new GoogleDriveStream(
|
||||||
download_url, title, size, access_token, network_);
|
download_url, title, size, access_token, network_);
|
||||||
|
stream->Precache();
|
||||||
TagLib::MPEG::File tag(
|
TagLib::MPEG::File tag(
|
||||||
stream, // Takes ownership.
|
stream, // Takes ownership.
|
||||||
TagLib::ID3v2::FrameFactory::instance(),
|
TagLib::ID3v2::FrameFactory::instance(),
|
||||||
TagLib::AudioProperties::Fast);
|
TagLib::AudioProperties::Accurate);
|
||||||
if (tag.tag()) {
|
if (tag.tag()) {
|
||||||
song->set_title(tag.tag()->title().toCString(true));
|
song->set_title(tag.tag()->title().toCString(true));
|
||||||
song->set_artist(tag.tag()->artist().toCString(true));
|
song->set_artist(tag.tag()->artist().toCString(true));
|
||||||
@ -631,6 +632,10 @@ void TagReaderWorker::ReadGoogleDrive(const QUrl& download_url,
|
|||||||
if (tag.audioProperties()) {
|
if (tag.audioProperties()) {
|
||||||
song->set_length_nanosec(tag.audioProperties()->length() * kNsecPerSec);
|
song->set_length_nanosec(tag.audioProperties()->length() * kNsecPerSec);
|
||||||
}
|
}
|
||||||
|
qLog(Debug) << "Google Drive Tagging Stats for:"
|
||||||
|
<< song->title().c_str();
|
||||||
|
qLog(Debug) << "Downloaded bytes:" << stream->cached_bytes()
|
||||||
|
<< "Number of requests:" << stream->num_requests();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // HAVE_GOOGLE_DRIVE
|
#endif // HAVE_GOOGLE_DRIVE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user