parent
7c0ef13bb7
commit
55af2b1d3b
@ -7,6 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++0x")
|
||||
|
||||
set(SOURCES
|
||||
core/closure.cpp
|
||||
core/latch.cpp
|
||||
core/logging.cpp
|
||||
core/messagehandler.cpp
|
||||
core/messagereply.cpp
|
||||
@ -16,6 +17,7 @@ set(SOURCES
|
||||
|
||||
set(HEADERS
|
||||
core/closure.h
|
||||
core/latch.h
|
||||
core/messagehandler.h
|
||||
core/messagereply.h
|
||||
core/workerpool.h
|
||||
|
36
ext/libclementine-common/core/latch.cpp
Normal file
36
ext/libclementine-common/core/latch.cpp
Normal file
@ -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();
|
||||
}
|
||||
}
|
38
ext/libclementine-common/core/latch.h
Normal file
38
ext/libclementine-common/core/latch.h
Normal file
@ -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 "core/closure.h"
|
||||
#include "core/latch.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
#include "songinfo/songinfotextview.h"
|
||||
|
||||
namespace {
|
||||
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() {
|
||||
QLocale locale;
|
||||
@ -75,6 +82,105 @@ void ArtistBiography::FetchInfo(int id, const Song& metadata) {
|
||||
editor->SetHtml(text);
|
||||
data.contents_ = editor;
|
||||
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;
|
||||
|
||||
private:
|
||||
void FetchWikipediaImages(int id, const QString& title);
|
||||
|
||||
std::unique_ptr<NetworkAccessManager> network_;
|
||||
};
|
||||
|
||||
|
@ -88,7 +88,8 @@ void PrettyImage::ImageFetched(RedirectFollower* follower) {
|
||||
|
||||
QImage image = QImage::fromData(reply->readAll());
|
||||
if (image.isNull()) {
|
||||
qLog(Debug) << "Image failed to load" << reply->request().url();
|
||||
qLog(Debug) << "Image failed to load" << reply->request().url()
|
||||
<< reply->error();
|
||||
deleteLater();
|
||||
} else {
|
||||
state_ = State_CreatingThumbnail;
|
||||
|
Loading…
x
Reference in New Issue
Block a user