parent
7c0ef13bb7
commit
55af2b1d3b
|
@ -7,6 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++0x")
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
core/closure.cpp
|
core/closure.cpp
|
||||||
|
core/latch.cpp
|
||||||
core/logging.cpp
|
core/logging.cpp
|
||||||
core/messagehandler.cpp
|
core/messagehandler.cpp
|
||||||
core/messagereply.cpp
|
core/messagereply.cpp
|
||||||
|
@ -16,6 +17,7 @@ set(SOURCES
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
core/closure.h
|
core/closure.h
|
||||||
|
core/latch.h
|
||||||
core/messagehandler.h
|
core/messagehandler.h
|
||||||
core/messagereply.h
|
core/messagereply.h
|
||||||
core/workerpool.h
|
core/workerpool.h
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* This file is part of Clementine.
|
||||||
|
Copyright 2016, John Maguire <john.maguire@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "latch.h"
|
||||||
|
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
|
CountdownLatch::CountdownLatch() : count_(0) {}
|
||||||
|
|
||||||
|
void CountdownLatch::Wait() {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
++count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CountdownLatch::CountDown() {
|
||||||
|
QMutexLocker l(&mutex_);
|
||||||
|
Q_ASSERT(count_ > 0);
|
||||||
|
--count_;
|
||||||
|
qLog(Debug) << "Decrement:" << count_;
|
||||||
|
if (count_ == 0) {
|
||||||
|
emit Done();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* This file is part of Clementine.
|
||||||
|
Copyright 2016, John Maguire <john.maguire@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CORE_LATCH_H
|
||||||
|
#define CORE_LATCH_H
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CountdownLatch : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
CountdownLatch();
|
||||||
|
void Wait();
|
||||||
|
void CountDown();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void Done();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex mutex_;
|
||||||
|
int count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CORE_LATCH_H
|
|
@ -22,11 +22,18 @@
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
#include "core/closure.h"
|
#include "core/closure.h"
|
||||||
|
#include "core/latch.h"
|
||||||
|
#include "core/logging.h"
|
||||||
#include "core/network.h"
|
#include "core/network.h"
|
||||||
#include "songinfo/songinfotextview.h"
|
#include "songinfo/songinfotextview.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char* kArtistBioUrl = "https://data.clementine-player.org/fetchbio";
|
const char* kArtistBioUrl = "https://data.clementine-player.org/fetchbio";
|
||||||
|
const char* kWikipediaImageListUrl =
|
||||||
|
"https://en.wikipedia.org/w/api.php?action=query&prop=images&format=json";
|
||||||
|
const char* kWikipediaImageInfoUrl =
|
||||||
|
"https://en.wikipedia.org/w/"
|
||||||
|
"api.php?action=query&prop=imageinfo&iiprop=url&format=json";
|
||||||
|
|
||||||
QString GetLocale() {
|
QString GetLocale() {
|
||||||
QLocale locale;
|
QLocale locale;
|
||||||
|
@ -75,6 +82,105 @@ void ArtistBiography::FetchInfo(int id, const Song& metadata) {
|
||||||
editor->SetHtml(text);
|
editor->SetHtml(text);
|
||||||
data.contents_ = editor;
|
data.contents_ = editor;
|
||||||
emit InfoReady(id, data);
|
emit InfoReady(id, data);
|
||||||
emit Finished(id);
|
|
||||||
|
if (url.contains("wikipedia.org")) {
|
||||||
|
FetchWikipediaImages(id, url);
|
||||||
|
} else {
|
||||||
|
emit Finished(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QStringList ExtractImageTitles(const QVariantMap& json) {
|
||||||
|
QStringList ret;
|
||||||
|
for (auto it = json.constBegin(); it != json.constEnd(); ++it) {
|
||||||
|
if (it.value().type() == QVariant::Map) {
|
||||||
|
ret.append(ExtractImageTitles(it.value().toMap()));
|
||||||
|
} else if (it.key() == "images" && it.value().type() == QVariant::List) {
|
||||||
|
QVariantList images = it.value().toList();
|
||||||
|
for (QVariant i : images) {
|
||||||
|
QVariantMap image = i.toMap();
|
||||||
|
QString image_title = image["title"].toString();
|
||||||
|
if (!image_title.isEmpty() &&
|
||||||
|
(
|
||||||
|
// SVGs tend to be irrelevant icons.
|
||||||
|
image_title.endsWith(".jpg", Qt::CaseInsensitive) ||
|
||||||
|
image_title.endsWith(".png", Qt::CaseInsensitive))) {
|
||||||
|
ret.append(image_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExtractImageUrl(const QVariantMap& json) {
|
||||||
|
for (auto it = json.constBegin(); it != json.constEnd(); ++it) {
|
||||||
|
if (it.value().type() == QVariant::Map) {
|
||||||
|
QString r = ExtractImageUrl(it.value().toMap());
|
||||||
|
if (!r.isEmpty()) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
} else if (it.key() == "imageinfo") {
|
||||||
|
QVariantList imageinfos = it.value().toList();
|
||||||
|
QVariantMap imageinfo = imageinfos.first().toMap();
|
||||||
|
return imageinfo["url"].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void ArtistBiography::FetchWikipediaImages(int id,
|
||||||
|
const QString& wikipedia_url) {
|
||||||
|
QRegExp regex("/wiki/(.*)");
|
||||||
|
if (regex.indexIn(wikipedia_url) == -1) {
|
||||||
|
emit Finished(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString wiki_title = regex.cap(1);
|
||||||
|
QUrl url(kWikipediaImageListUrl);
|
||||||
|
url.addQueryItem("titles", wiki_title);
|
||||||
|
|
||||||
|
qLog(Debug) << "Wikipedia images:" << url;
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply* reply = network_->get(request);
|
||||||
|
NewClosure(reply, SIGNAL(finished()), [this, id, reply]() {
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
QJson::Parser parser;
|
||||||
|
QVariantMap response = parser.parse(reply).toMap();
|
||||||
|
|
||||||
|
QStringList image_titles = ExtractImageTitles(response);
|
||||||
|
|
||||||
|
CountdownLatch* latch = new CountdownLatch;
|
||||||
|
NewClosure(latch, SIGNAL(Done()), [this, latch, id]() {
|
||||||
|
latch->deleteLater();
|
||||||
|
emit Finished(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const QString& image_title : image_titles) {
|
||||||
|
latch->Wait();
|
||||||
|
QUrl url(kWikipediaImageInfoUrl);
|
||||||
|
url.addQueryItem("titles", image_title);
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply* reply = network_->get(request);
|
||||||
|
NewClosure(reply, SIGNAL(finished()), [this, id, reply, latch]() {
|
||||||
|
reply->deleteLater();
|
||||||
|
QJson::Parser parser;
|
||||||
|
QVariantMap json = parser.parse(reply).toMap();
|
||||||
|
QString url = ExtractImageUrl(json);
|
||||||
|
qLog(Debug) << "Found wikipedia image url:" << url;
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
emit ImageReady(id, QUrl(url));
|
||||||
|
}
|
||||||
|
latch->CountDown();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ class ArtistBiography : public SongInfoProvider {
|
||||||
void FetchInfo(int id, const Song& metadata) override;
|
void FetchInfo(int id, const Song& metadata) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void FetchWikipediaImages(int id, const QString& title);
|
||||||
|
|
||||||
std::unique_ptr<NetworkAccessManager> network_;
|
std::unique_ptr<NetworkAccessManager> network_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,8 @@ void PrettyImage::ImageFetched(RedirectFollower* follower) {
|
||||||
|
|
||||||
QImage image = QImage::fromData(reply->readAll());
|
QImage image = QImage::fromData(reply->readAll());
|
||||||
if (image.isNull()) {
|
if (image.isNull()) {
|
||||||
qLog(Debug) << "Image failed to load" << reply->request().url();
|
qLog(Debug) << "Image failed to load" << reply->request().url()
|
||||||
|
<< reply->error();
|
||||||
deleteLater();
|
deleteLater();
|
||||||
} else {
|
} else {
|
||||||
state_ = State_CreatingThumbnail;
|
state_ = State_CreatingThumbnail;
|
||||||
|
|
Loading…
Reference in New Issue