File indexing completed on 2024-05-05 16:49:23
0001 /* 0002 * SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com> 0003 * SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 #include "sunrisesource.h" 0008 #include "kweathercore_p.h" 0009 #include <QJsonArray> 0010 #include <QJsonDocument> 0011 #include <QJsonObject> 0012 #include <QNetworkAccessManager> 0013 #include <QNetworkReply> 0014 #include <QUrlQuery> 0015 #include <QTimeZone> 0016 0017 namespace KWeatherCore 0018 { 0019 SunriseSource::SunriseSource(double latitude, 0020 double longitude, 0021 const QString &timezone, 0022 const std::vector<Sunrise> &sunrise, 0023 QObject *parent) 0024 : QObject(parent) 0025 , m_latitude(latitude) 0026 , m_longitude(longitude) 0027 , m_timezone(timezone) 0028 , m_sunriseVec(sunrise) 0029 , m_manager(new QNetworkAccessManager(this)) 0030 { 0031 connect(m_manager, 0032 &QNetworkAccessManager::finished, 0033 this, 0034 &SunriseSource::parseResults); 0035 } 0036 void SunriseSource::requestData() 0037 { 0038 // pop older data 0039 popDay(); 0040 0041 if (m_sunriseVec.size() >= 10) // don't update if we have enough data 0042 { 0043 Q_EMIT finished(); 0044 return; 0045 } 0046 0047 auto m_offset = QDateTime::currentDateTime().toTimeZone(QTimeZone(m_timezone.toUtf8())).offsetFromUtc(); 0048 0049 QUrl url(QStringLiteral("https://api.met.no/weatherapi/sunrise/2.0/.json")); 0050 QUrlQuery query; 0051 query.addQueryItem(QStringLiteral("lat"), QString::number(m_latitude)); 0052 query.addQueryItem(QStringLiteral("lon"), QString::number(m_longitude)); 0053 // if we already have data, request data beyond the last day 0054 query.addQueryItem( 0055 QStringLiteral("date"), 0056 !m_sunriseVec.size() 0057 ? QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd")) 0058 : QDate::currentDate() 0059 .addDays(m_sunriseVec.size()) 0060 .toString(QStringLiteral("yyyy-MM-dd"))); 0061 query.addQueryItem(QStringLiteral("days"), 0062 !m_sunriseVec.size() 0063 ? QString::number(10) 0064 : QString::number(11 - m_sunriseVec.size())); 0065 0066 // calculate offset (form example: -04:00) 0067 QString offset = m_offset < 0 ? QStringLiteral("-") : QStringLiteral("+"); 0068 int hour = std::abs(m_offset) / 3600; 0069 if (hour >= 10) 0070 offset.append(QString::number(hour) + QStringLiteral(":")); 0071 else { 0072 offset.append(QStringLiteral("0") + QString::number(hour) + 0073 QStringLiteral(":")); 0074 } 0075 int min = (std::abs(m_offset) - hour * 3600) / 60; 0076 if (min >= 10) { 0077 offset.append(QString::number(min)); 0078 } else { 0079 offset.append(QStringLiteral("0") + QString::number(min)); 0080 } 0081 query.addQueryItem(QStringLiteral("offset"), offset); 0082 0083 url.setQuery(query); 0084 QNetworkRequest req(url); 0085 0086 // see §Identification on https://api.met.no/conditions_service.html 0087 req.setHeader(QNetworkRequest::UserAgentHeader, 0088 QString(QStringLiteral("KWeatherCore/") + 0089 VERSION_NUMBER + 0090 QStringLiteral(" kde-frameworks-devel@kde.org"))); 0091 0092 m_manager->get(req); 0093 } 0094 void SunriseSource::parseResults(QNetworkReply *reply) 0095 { 0096 reply->deleteLater(); 0097 if (reply->error()) { 0098 qWarning() << "nmisunriseapi network error:" << reply->errorString(); 0099 Q_EMIT networkError(); 0100 return; 0101 } 0102 0103 auto timezone = QTimeZone(m_timezone.toUtf8()); 0104 0105 QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); 0106 QJsonArray array = doc[QStringLiteral("location")] 0107 .toObject()[QStringLiteral("time")] 0108 .toArray(); 0109 0110 m_sunriseVec.reserve(array.size()); 0111 0112 for (int i = 0; i <= array.count() - 2; i++) // we don't want last one 0113 { 0114 Sunrise sr; 0115 sr.setSunSet( 0116 QDateTime::fromString(array.at(i) 0117 .toObject()[QStringLiteral("sunset")] 0118 .toObject()[QStringLiteral("time")] 0119 .toString() 0120 .left(19), 0121 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone)); 0122 sr.setSunRise(QDateTime::fromString(array.at(i) 0123 .toObject()[QStringLiteral("sunrise")] 0124 .toObject()[QStringLiteral("time")] 0125 .toString() 0126 .left(19), 0127 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone)); 0128 sr.setMoonSet( 0129 QDateTime::fromString(array.at(i) 0130 .toObject()[QStringLiteral("moonset")] 0131 .toObject()[QStringLiteral("time")] 0132 .toString() 0133 .left(19), 0134 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone)); 0135 sr.setMoonRise( 0136 QDateTime::fromString(array.at(i) 0137 .toObject()[QStringLiteral("moonrise")] 0138 .toObject()[QStringLiteral("time")] 0139 .toString() 0140 .left(19), 0141 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone)); 0142 sr.setSolarMidnight(QPair<QDateTime, double>( 0143 QDateTime::fromString( 0144 array.at(i) 0145 .toObject()[QStringLiteral("solarmidnight")] 0146 .toObject()[QStringLiteral("time")] 0147 .toString() 0148 .left(19), 0149 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone), 0150 array.at(i) 0151 .toObject()[QStringLiteral("solarmidnight")] 0152 .toObject()[QStringLiteral("elevation")] 0153 .toString() 0154 .toDouble())); 0155 sr.setSolarNoon(QPair<QDateTime, double>( 0156 QDateTime::fromString(array.at(i) 0157 .toObject()[QStringLiteral("solarnoon")] 0158 .toObject()[QStringLiteral("time")] 0159 .toString() 0160 .left(19), 0161 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone), 0162 array.at(i) 0163 .toObject()[QStringLiteral("solarnoon")] 0164 .toObject()[QStringLiteral("elevation")] 0165 .toString() 0166 .toDouble())); 0167 sr.setHighMoon(QPair<QDateTime, double>( 0168 QDateTime::fromString(array.at(i) 0169 .toObject()[QStringLiteral("high_moon")] 0170 .toObject()[QStringLiteral("time")] 0171 .toString() 0172 .left(19), 0173 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone), 0174 array.at(i) 0175 .toObject()[QStringLiteral("high_moon")] 0176 .toObject()[QStringLiteral("elevation")] 0177 .toString() 0178 .toDouble())); 0179 sr.setLowMoon(QPair<QDateTime, double>( 0180 QDateTime::fromString(array.at(i) 0181 .toObject()[QStringLiteral("low_moon")] 0182 .toObject()[QStringLiteral("time")] 0183 .toString() 0184 .left(19), 0185 QStringLiteral("yyyy-MM-ddThh:mm:ss")).toTimeZone(timezone), 0186 array.at(i) 0187 .toObject()[QStringLiteral("low_moon")] 0188 .toObject()[QStringLiteral("elevation")] 0189 .toString() 0190 .toDouble())); 0191 sr.setMoonPhase(array.at(i) 0192 .toObject()[QStringLiteral("moonposition")] 0193 .toObject()[QStringLiteral("phase")] 0194 .toString() 0195 .toDouble()); 0196 0197 m_sunriseVec.emplace_back(std::move(sr)); 0198 } 0199 0200 Q_EMIT finished(); 0201 } 0202 void SunriseSource::setTimezone(const QString &timezone) 0203 { 0204 m_timezone = timezone; 0205 } 0206 0207 void SunriseSource::popDay() 0208 { 0209 auto today = QDateTime::currentDateTime(); 0210 auto popIndex = 0; 0211 for (const auto &day : qAsConst(m_sunriseVec)) { 0212 if (day.sunRise().daysTo(today) > 0) { 0213 popIndex++; 0214 } else { 0215 // since vector is always sorted 0216 break; 0217 } 0218 } 0219 0220 m_sunriseVec.erase(m_sunriseVec.begin(), m_sunriseVec.begin() + popIndex); 0221 } 0222 0223 const std::vector<Sunrise> &SunriseSource::value() const 0224 { 0225 return m_sunriseVec; 0226 } 0227 }