diff --git a/src/internet/geolocator.cpp b/src/internet/geolocator.cpp index d8d8d09a5..d6e981cba 100644 --- a/src/internet/geolocator.cpp +++ b/src/internet/geolocator.cpp @@ -1,5 +1,6 @@ #include "geolocator.h" +#include #include #include @@ -7,8 +8,9 @@ #include #include "core/closure.h" +#include "core/logging.h" -const char* Geolocator::kUrl = "https://data.clementine-player.org/geolocate"; +const char* Geolocator::kUrl = "http://data.clementine-player.org/geolocate"; using std::numeric_limits; @@ -22,6 +24,43 @@ Geolocator::LatLng::LatLng(int lat_e6, int lng_e6) lng_e6_(lng_e6) { } +Geolocator::LatLng::LatLng(const QString& latlng) + : lat_e6_(numeric_limits::min()), + lng_e6_(numeric_limits::min()) { + QStringList split = latlng.split(","); + if (split.length() != 2) { + return; + } + + const double lat = split[0].toDouble(); + const double lng = split[1].toDouble(); + lat_e6_ = static_cast(lat * 1e6); + lng_e6_ = static_cast(lng * 1e6); +} + +Geolocator::LatLng::LatLng(const QString& lat, const QString& lng) { + lat_e6_ = static_cast(lat.toDouble() * 1e6); + lng_e6_ = static_cast(lng.toDouble() * 1e6); +} + +int Geolocator::LatLng::Distance(const Geolocator::LatLng& other) const { + static const int kEarthRadiusMetres = 6372800; + + double lat_a = lat_e6() / 1000000.0 * (M_PI / 180.0); + double lng_a = lng_e6() / 1000000.0 * (M_PI / 180.0); + + double lat_b = other.lat_e6() / 1000000.0 * (M_PI / 180.0); + double lng_b = other.lng_e6() / 1000000.0 * (M_PI / 180.0); + + double delta_longitude = lng_b - lng_a; + + double sines = sin(lat_a) * sin(lat_b); + double cosines = cos(lat_a) * cos(lat_b) * cos(delta_longitude); + double central_angle = acos(sines + cosines); + double distance_metres = kEarthRadiusMetres * central_angle; + return static_cast(distance_metres); +} + bool Geolocator::LatLng::IsValid() const { return lat_e6_ != numeric_limits::min() && lng_e6_ != numeric_limits::min(); @@ -34,7 +73,7 @@ Geolocator::Geolocator(QObject* parent) void Geolocator::Geolocate() { QNetworkRequest req = QNetworkRequest(QUrl(kUrl)); QNetworkReply* reply = network_.get(req); - NewClosure(reply, SIGNAL(finished()), this, SLOT(RequestFinished())); + NewClosure(reply, SIGNAL(finished()), this, SLOT(RequestFinished(QNetworkReply*)), reply); } void Geolocator::RequestFinished(QNetworkReply* reply) { @@ -54,16 +93,13 @@ void Geolocator::RequestFinished(QNetworkReply* reply) { QVariantMap map = result.toMap(); QString latlng = map["latlng"].toString(); - QStringList split = latlng.split(","); - if (split.length() != 2) { - emit Finished(LatLng()); - return; - } - double lat = split[0].toDouble(); - double lng = split[1].toDouble(); - - emit Finished( - LatLng(static_cast(lat * 1e6), - static_cast(lng * 1e6))); + LatLng ll(latlng); + qLog(Debug) << "Gelocated to:" << ll; + emit Finished(ll); +} + +QDebug operator<<(QDebug dbg, const Geolocator::LatLng& ll) { + dbg.nospace() << "(" << ll.lat_e6() << "," << ll.lng_e6() << ")"; + return dbg.space(); } diff --git a/src/internet/geolocator.h b/src/internet/geolocator.h index 340f97ba7..195045af3 100644 --- a/src/internet/geolocator.h +++ b/src/internet/geolocator.h @@ -16,19 +16,22 @@ class Geolocator : public QObject { public: LatLng(); LatLng(int lat_e6, int lng_e6); + explicit LatLng(const QString& latlng); + LatLng(const QString& lat, const QString& lng); int lat_e6() const { return lat_e6_; } int lng_e6() const { return lng_e6_; } bool IsValid() const; + int Distance(const LatLng& other) const; private: - const int lat_e6_; - const int lng_e6_; + int lat_e6_; + int lng_e6_; }; signals: - void Finished(LatLng latlng); + void Finished(Geolocator::LatLng latlng); private slots: void RequestFinished(QNetworkReply* reply); @@ -39,4 +42,7 @@ class Geolocator : public QObject { static const char* kUrl; }; +QDebug operator<<(QDebug dbg, const Geolocator::LatLng& ll); +Q_DECLARE_METATYPE(Geolocator::LatLng); + #endif // GEOLOCATOR_H diff --git a/src/main.cpp b/src/main.cpp index 4aca0421b..37df38c47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,6 +44,7 @@ #include "engines/enginebase.h" #include "globalsearch/searchprovider.h" #include "internet/digitallyimportedclient.h" +#include "internet/geolocator.h" #include "internet/somafmservice.h" #include "library/directory.h" #include "playlist/playlist.h" @@ -293,6 +294,7 @@ int main(int argc, char *argv[]) { qRegisterMetaType >("QList"); qRegisterMetaType("PodcastList"); qRegisterMetaType("PodcastEpisodeList"); + qRegisterMetaType("Geolocator::LatLng"); qRegisterMetaType("GstBuffer*"); qRegisterMetaType("GstElement*"); diff --git a/src/songinfo/songkickconcerts.cpp b/src/songinfo/songkickconcerts.cpp index 28607445a..dc02057f5 100644 --- a/src/songinfo/songkickconcerts.cpp +++ b/src/songinfo/songkickconcerts.cpp @@ -34,7 +34,10 @@ const char* SongkickConcerts::kSongkickArtistCalendarUrl = "apikey=8rgKfy1WU6IlJFfN"; SongkickConcerts::SongkickConcerts() { - + Geolocator* geolocator = new Geolocator; + geolocator->Geolocate(); + connect(geolocator, SIGNAL(Finished(Geolocator::LatLng)), SLOT(GeolocateFinished(Geolocator::LatLng))); + NewClosure(geolocator, SIGNAL(Finished(Geolocator::LatLng)), geolocator, SLOT(deleteLater())); } void SongkickConcerts::FetchInfo(int id, const Song& metadata) { @@ -120,15 +123,35 @@ void SongkickConcerts::CalendarRequestFinished(QNetworkReply* reply, int id) { foreach (const QVariant& v, events) { QVariantMap event = v.toMap(); { + QString display_name = event["displayName"].toString(); + QVariantMap venue = event["venue"].toMap(); + const bool valid_latlng = + venue["lng"].isValid() && venue["lat"].isValid(); + + if (valid_latlng && latlng_.IsValid()) { + static const int kFilterDistanceMetres = 250 * 1e3; // 250km + Geolocator::LatLng latlng( + venue["lat"].toString(), venue["lng"].toString()); + if (latlng_.IsValid() && latlng.IsValid()) { + int distance_metres = latlng_.Distance(latlng); + if (distance_metres > kFilterDistanceMetres) { + qLog(Debug) << "Filtered concert:" + << display_name + << "as too far away:" + << distance_metres; + continue; + } + } + } + writer.writeStartElement("div"); { writer.writeStartElement("a"); writer.writeAttribute("href", event["uri"].toString()); - writer.writeCharacters(event["displayName"].toString()); + writer.writeCharacters(display_name); writer.writeEndElement(); } - QVariantMap venue = event["venue"].toMap(); - if (venue["lng"].isValid() && venue["lat"].isValid()) { + if (valid_latlng) { writer.writeStartElement("img"); QString maps_url = QString(kStaticMapUrl).arg( venue["lat"].toString(), @@ -171,3 +194,7 @@ void SongkickConcerts::InjectImage( reply->request().url(), QVariant(image)); } + +void SongkickConcerts::GeolocateFinished(Geolocator::LatLng latlng) { + latlng_ = latlng; +} diff --git a/src/songinfo/songkickconcerts.h b/src/songinfo/songkickconcerts.h index 79206d488..84d99d019 100644 --- a/src/songinfo/songkickconcerts.h +++ b/src/songinfo/songkickconcerts.h @@ -21,6 +21,7 @@ #include "songinfoprovider.h" #include "core/network.h" +#include "internet/geolocator.h" class QNetworkReply; class SongInfoTextView; @@ -36,11 +37,13 @@ class SongkickConcerts : public SongInfoProvider { void ArtistSearchFinished(QNetworkReply* reply, int id); void CalendarRequestFinished(QNetworkReply* reply, int id); void InjectImage(QNetworkReply* reply, SongInfoTextView* text_view); + void GeolocateFinished(Geolocator::LatLng latlng); private: void FetchSongkickCalendar(const QString& artist_id, int id); NetworkAccessManager network_; + Geolocator::LatLng latlng_; static const char* kSongkickArtistBucket; static const char* kSongkickArtistCalendarUrl;