3 * Copyright (C) 2011 Roman Moravcik
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "medarddownloader.h"
28 #define DOWNLOAD_CACHE_DIR ".cache/medard-downloader"
30 #define MEDARD_URL "http://www.medard-online.cz"
31 #define MEDARD_IMAGE_URL "http://www.medard-online.cz/scripts/getimage.php?initDate=%1&domain=%2&variable=%3&offset=%4"
33 #define FC_SEA_LEVEL_PRESSURE "slp"
34 #define FC_PRECIPITATION "precip"
35 #define FC_WIND_VELOCITY "wv"
36 #define FC_CLOUDINESS "cloud"
37 #define FC_TEMPERATURE "temp"
40 #define FD_CZECH_REPUBLIC "2"
45 #define IMAGE_WIDTH 556
46 #define IMAGE_HEIGHT 408
48 #define MAX_DOWNLOAD_RETRIES 3
49 #define RETRY_TIMEOUT 5000
51 MedardDownloader::MedardDownloader() : QObject()
53 m_forecastType = FC_SEA_LEVEL_PRESSURE;
54 m_forecastDomain = FD_EUROPE;
55 m_forecastInitialDateCode.clear();
56 m_forecastDateOffset = 0;
58 m_network = new QNetworkAccessManager();
62 m_retryTimer = new QTimer();
63 connect(m_retryTimer, SIGNAL(timeout()), this, SLOT(retryTimerEvent()));
65 m_cachePath = QString("%1/%2")
66 .arg(QDir().homePath())
67 .arg(DOWNLOAD_CACHE_DIR);
69 createCacheDirectory();
72 MedardDownloader::~MedardDownloader()
74 if (m_retryTimer->isActive())
83 QSize MedardDownloader::imageSize()
85 return QSize(IMAGE_WIDTH, IMAGE_HEIGHT);
88 void MedardDownloader::setForecastType(ForecastType type)
91 case SeaLevelPressure:
92 m_forecastType = FC_SEA_LEVEL_PRESSURE;
96 m_forecastType = FC_PRECIPITATION;
100 m_forecastType = FC_WIND_VELOCITY;
104 m_forecastType = FC_CLOUDINESS;
108 m_forecastType = FC_TEMPERATURE;
113 void MedardDownloader::setForecastDomain(ForecastDomain domain)
117 m_forecastDomain = FD_EUROPE;
121 m_forecastDomain = FD_CZECH_REPUBLIC;
126 void MedardDownloader::setForecastInitialDate(QDateTime date)
130 m_forecastInitialDate = date.toUTC();
132 if (date.toUTC().time().hour() >= 18) {
133 m_forecastInitialDate.setTime(QTime(18, 0, 0));
135 } else if (date.toUTC().time().hour() >= 12) {
136 m_forecastInitialDate.setTime(QTime(12, 0, 0));
138 } else if (date.toUTC().time().hour() >= 6) {
139 m_forecastInitialDate.setTime(QTime(6, 0, 0));
142 m_forecastInitialDate.setTime(QTime(0, 0, 0));
146 if (offset == "18") {
147 /* use previous day */
148 m_forecastInitialDateCode = QString("%1_%2")
149 .arg(date.addDays(-1).toUTC().toString("yyMMdd"))
152 /* use current day */
153 m_forecastInitialDateCode = QString("%1_%2")
154 .arg(date.toUTC().toString("yyMMdd"))
158 cleanCacheDirectory();
161 QDateTime MedardDownloader::forecastInitialDate()
163 return m_forecastInitialDate.toLocalTime();
166 QDateTime MedardDownloader::forecastDate()
168 return m_forecastInitialDate.addSecs(3600 * m_forecastDateOffset).toLocalTime();
171 void MedardDownloader::setForecastDateOffset(int offset)
173 m_forecastDateOffset = offset;
174 if (m_forecastDateOffset > MAX_OFFSET)
175 m_forecastDateOffset = MAX_OFFSET;
177 if (m_forecastDateOffset < MIN_OFFSET)
178 m_forecastDateOffset = MIN_OFFSET;
181 void MedardDownloader::retryTimerEvent()
183 if (m_retryTimer->isActive())
184 m_retryTimer->stop();
189 void MedardDownloader::tryDownloadImageAgain()
193 if (m_retryCounter < MAX_DOWNLOAD_RETRIES) {
194 m_retryTimer->setInterval(RETRY_TIMEOUT * (m_retryCounter + 1));
195 m_retryTimer->start();
198 emit downloadFailed();
202 void MedardDownloader::clearDownloadRequest()
204 qDebug() << "clearDownloadRequest: m_reply=" << m_reply;
210 void MedardDownloader::downloadImageFinished()
212 qDebug() << "downloadImageFinished: m_reply=" << m_reply;
214 QByteArray picture = m_reply->readAll();
216 if (picture.isNull() || picture.size() <= 0)
222 if (!image.loadFromData(picture, "png"))
225 QString filename = QString("%1/%2_%3_%4_%5.png")
228 .arg(m_forecastDomain)
229 .arg(m_forecastInitialDateCode)
230 .arg(QString().number(m_forecastDateOffset));
232 if ((image.width() == 512) && (image.height() == 512)) {
233 QImage croped(512, 400, QImage::Format_ARGB32_Premultiplied);
234 croped = image.copy(0, 52, 512, IMAGE_HEIGHT);
235 croped.save(filename, "png");
237 QImage croped(560, 400, QImage::Format_ARGB32_Premultiplied);
238 croped = image.copy(10, 96, IMAGE_WIDTH, IMAGE_HEIGHT);
239 croped.save(filename, "png");
242 qDebug() << "downloadImageFinished: downloadFinished=" << filename;
243 emit downloadFinished(filename, forecastDate());
245 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
248 void MedardDownloader::downloadImageError(QNetworkReply::NetworkError /* code */)
250 tryDownloadImageAgain();
251 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
254 void MedardDownloader::downloadImage()
256 qDebug() << "downloadImage: retry=" << m_retryCounter << "date:" << m_forecastInitialDate.toString("dd.MM.yyyy hh:mm");
258 if (m_forecastInitialDateCode.isNull()) {
259 retrieveForecastInitialDate();
260 tryDownloadImageAgain();
264 QString filename = QString("%1/%2_%3_%4_%5.png")
267 .arg(m_forecastDomain)
268 .arg(m_forecastInitialDateCode)
269 .arg(QString().number(m_forecastDateOffset));
271 if (isDownloaded(filename)) {
272 qDebug() << "downloadImage: downloadFinished=" << filename;
274 emit downloadFinished(filename, forecastDate());
278 QString imageUrl = QString(MEDARD_IMAGE_URL)
279 .arg(m_forecastInitialDateCode)
280 .arg(m_forecastDomain)
282 .arg(QString().number(m_forecastDateOffset));
285 QNetworkRequest request(url);
288 clearDownloadRequest();
289 m_reply = m_network->get(request);
291 connect(m_reply, SIGNAL(finished()), this, SLOT(downloadImageFinished()));
292 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
293 SLOT(downloadImageError(QNetworkReply::NetworkError)));
296 bool MedardDownloader::isDownloaded(const QString filename)
298 return QFile(filename).exists();
301 int MedardDownloader::forecastDateOffset()
303 return m_forecastDateOffset;
306 int MedardDownloader::minForecastDateOffset()
311 int MedardDownloader::maxForecastDateOffset()
316 void MedardDownloader::retrieveForecastInitialDateFinished()
318 qDebug() << "retrieveForecastInitialDateFinished: m_reply=" << m_reply;
320 QByteArray data = m_reply->readAll();
322 int index1 = data.indexOf("var fcst_initDatestamp=\"", 0);
323 int index2 = data.indexOf("\";", index1);
326 for (int i = index1 + 24; i < index2; i++) {
327 temp.append(data.at(i));
329 QDateTime date = QDateTime::fromTime_t(temp.toULong() + 6 * 3600);
330 if (!date.isNull()) {
331 setForecastInitialDate(date.toLocalTime());
333 int forecastDateOffset = date.toLocalTime().secsTo(QDateTime().currentDateTime()) / 3600;
334 setForecastDateOffset(forecastDateOffset);
339 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
342 void MedardDownloader::retrieveForecastInitialDateError(QNetworkReply::NetworkError /* code */)
344 qDebug() << "retrieveForecastInitialDateError: m_reply=" << m_reply;
347 void MedardDownloader::retrieveForecastInitialDate()
349 qDebug() << "retrieveForecastInitialDate: m_reply=" << m_reply;
351 QString serverUrl = QString(MEDARD_URL);
354 QNetworkRequest request(url);
357 clearDownloadRequest();
358 m_reply = m_network->get(request);
360 connect(m_reply, SIGNAL(finished()), this, SLOT(retrieveForecastInitialDateFinished()));
361 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
362 SLOT(retrieveForecastInitialDateError(QNetworkReply::NetworkError)));
365 void MedardDownloader::createCacheDirectory()
367 QDir cacheDir(m_cachePath);
368 if (!cacheDir.exists())
369 cacheDir.mkpath(cacheDir.path());
372 void MedardDownloader::cleanCacheDirectory()
374 QDir cacheDir(m_cachePath);
375 QStringList list = cacheDir.entryList();
376 for (int i = 0; i < list.size(); i++) {
377 if (!list.at(i).contains(m_forecastInitialDateCode)) {
378 QFile(m_cachePath + "/" + list.at(i)).remove();