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
25 #include "medarddownloader.h"
27 #define DOWNLOAD_CACHE_DIR ".cache/medard-downloader"
29 #define MEDARD_URL "http://www.medard-online.cz"
30 #define MEDARD_IMAGE_URL "http://www.medard-online.cz/scripts/getimage.php?initDate=%1&domain=%2&variable=%3&offset=%4"
32 #define FC_SEA_LEVEL_PRESSURE "slp"
33 #define FC_PRECIPITATION "precip"
34 #define FC_WIND_VELOCITY "wv"
35 #define FC_CLOUDINESS "cloud"
36 #define FC_TEMPERATURE "temp"
39 #define FD_CZECH_REPUBLIC "2"
44 #define IMAGE_WIDTH 556
45 #define IMAGE_HEIGHT 408
47 #define MAX_DOWNLOAD_RETRIES 3
48 #define RETRY_TIMEOUT 5000
50 MedardDownloader::MedardDownloader() : QObject()
52 m_forecastType = FC_SEA_LEVEL_PRESSURE;
53 m_forecastDomain = FD_EUROPE;
54 m_forecastInitialDateCode.clear();
55 m_forecastDateOffset = 0;
57 m_network = new QNetworkAccessManager();
61 m_retryTimer = new QTimer();
62 connect(m_retryTimer, SIGNAL(timeout()), this, SLOT(retryTimerEvent()));
64 m_cachePath = QString("%1/%2")
65 .arg(QDir().homePath())
66 .arg(DOWNLOAD_CACHE_DIR);
68 createCacheDirectory();
71 MedardDownloader::~MedardDownloader()
73 if (m_retryTimer->isActive())
82 QSize MedardDownloader::imageSize()
84 return QSize(IMAGE_WIDTH, IMAGE_HEIGHT);
87 void MedardDownloader::setForecastType(ForecastType type)
90 case SeaLevelPressure:
91 m_forecastType = FC_SEA_LEVEL_PRESSURE;
95 m_forecastType = FC_PRECIPITATION;
99 m_forecastType = FC_WIND_VELOCITY;
103 m_forecastType = FC_CLOUDINESS;
107 m_forecastType = FC_TEMPERATURE;
112 void MedardDownloader::setForecastDomain(ForecastDomain domain)
116 m_forecastDomain = FD_EUROPE;
120 m_forecastDomain = FD_CZECH_REPUBLIC;
125 void MedardDownloader::setForecastInitialDate(QDateTime date)
129 m_forecastInitialDate = date.toUTC();
131 if (date.toUTC().time().hour() >= 18) {
132 m_forecastInitialDate.setTime(QTime(18, 0, 0));
134 } else if (date.toUTC().time().hour() >= 12) {
135 m_forecastInitialDate.setTime(QTime(12, 0, 0));
137 } else if (date.toUTC().time().hour() >= 6) {
138 m_forecastInitialDate.setTime(QTime(6, 0, 0));
141 m_forecastInitialDate.setTime(QTime(0, 0, 0));
145 if (offset == "18") {
146 /* use previous day */
147 m_forecastInitialDateCode = QString("%1_%2")
148 .arg(date.addDays(-1).toUTC().toString("yyMMdd"))
151 /* use current day */
152 m_forecastInitialDateCode = QString("%1_%2")
153 .arg(date.toUTC().toString("yyMMdd"))
157 cleanCacheDirectory();
160 QDateTime MedardDownloader::forecastInitialDate()
162 return m_forecastInitialDate.toLocalTime();
165 QDateTime MedardDownloader::forecastDate()
167 return m_forecastInitialDate.addSecs(3600 * m_forecastDateOffset).toLocalTime();
170 void MedardDownloader::setForecastDateOffset(int offset)
172 m_forecastDateOffset = offset;
173 if (m_forecastDateOffset > MAX_OFFSET)
174 m_forecastDateOffset = MAX_OFFSET;
176 if (m_forecastDateOffset < MIN_OFFSET)
177 m_forecastDateOffset = MIN_OFFSET;
180 void MedardDownloader::retryTimerEvent()
182 if (m_retryTimer->isActive())
183 m_retryTimer->stop();
188 void MedardDownloader::tryDownloadImageAgain()
192 if (m_retryCounter < MAX_DOWNLOAD_RETRIES) {
193 m_retryTimer->setInterval(RETRY_TIMEOUT * (m_retryCounter + 1));
194 m_retryTimer->start();
197 emit downloadFailed();
201 void MedardDownloader::clearDownloadRequest()
207 void MedardDownloader::downloadImageFinished()
209 QByteArray picture = m_reply->readAll();
211 if (picture.isNull() || picture.size() <= 0)
217 if (!image.loadFromData(picture, "png"))
220 QString filename = QString("%1/%2_%3_%4_%5.png")
223 .arg(m_forecastDomain)
224 .arg(m_forecastInitialDateCode)
225 .arg(QString().number(m_forecastDateOffset));
227 if ((image.width() == 512) && (image.height() == 512)) {
228 QImage croped(512, 400, QImage::Format_ARGB32_Premultiplied);
229 croped = image.copy(0, 52, 512, IMAGE_HEIGHT);
230 croped.save(filename, "png");
232 QImage croped(560, 400, QImage::Format_ARGB32_Premultiplied);
233 croped = image.copy(10, 96, IMAGE_WIDTH, IMAGE_HEIGHT);
234 croped.save(filename, "png");
237 emit downloadFinished(filename, forecastDate());
239 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
242 void MedardDownloader::downloadImageError(QNetworkReply::NetworkError /* code */)
244 tryDownloadImageAgain();
245 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
248 void MedardDownloader::downloadImage()
250 if (m_forecastInitialDateCode.isNull()) {
251 retrieveForecastInitialDate();
252 tryDownloadImageAgain();
256 QString filename = QString("%1/%2_%3_%4_%5.png")
259 .arg(m_forecastDomain)
260 .arg(m_forecastInitialDateCode)
261 .arg(QString().number(m_forecastDateOffset));
263 if (isDownloaded(filename)) {
264 emit downloadFinished(filename, forecastDate());
268 QString imageUrl = QString(MEDARD_IMAGE_URL)
269 .arg(m_forecastInitialDateCode)
270 .arg(m_forecastDomain)
272 .arg(QString().number(m_forecastDateOffset));
275 QNetworkRequest request(url);
278 clearDownloadRequest();
279 m_reply = m_network->get(request);
281 connect(m_reply, SIGNAL(finished()), this, SLOT(downloadImageFinished()));
282 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
283 SLOT(downloadImageError(QNetworkReply::NetworkError)));
286 bool MedardDownloader::isDownloaded(const QString filename)
288 return QFile(filename).exists();
291 int MedardDownloader::forecastDateOffset()
293 return m_forecastDateOffset;
296 int MedardDownloader::minForecastDateOffset()
301 int MedardDownloader::maxForecastDateOffset()
306 void MedardDownloader::retrieveForecastInitialDateFinished()
308 QByteArray data = m_reply->readAll();
310 int index1 = data.indexOf("var fcst_initDatestamp=\"", 0);
311 int index2 = data.indexOf("\";", index1);
314 for (int i = index1 + 24; i < index2; i++) {
315 temp.append(data.at(i));
317 QDateTime date = QDateTime::fromTime_t(temp.toULong() + 6 * 3600);
318 if (!date.isNull()) {
319 setForecastInitialDate(date.toLocalTime());
321 int forecastDateOffset = date.toLocalTime().secsTo(QDateTime().currentDateTime()) / 3600;
322 setForecastDateOffset(forecastDateOffset);
327 QTimer::singleShot(0, this, SLOT(clearDownloadRequest()));
330 void MedardDownloader::retrieveForecastInitialDateError(QNetworkReply::NetworkError /* code */)
334 void MedardDownloader::retrieveForecastInitialDate()
336 QString serverUrl = QString(MEDARD_URL);
339 QNetworkRequest request(url);
342 clearDownloadRequest();
343 m_reply = m_network->get(request);
345 connect(m_reply, SIGNAL(finished()), this, SLOT(retrieveForecastInitialDateFinished()));
346 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
347 SLOT(retrieveForecastInitialDateError(QNetworkReply::NetworkError)));
350 void MedardDownloader::createCacheDirectory()
352 QDir cacheDir(m_cachePath);
353 if (!cacheDir.exists())
354 cacheDir.mkpath(cacheDir.path());
357 void MedardDownloader::cleanCacheDirectory()
359 QDir cacheDir(m_cachePath);
360 QStringList list = cacheDir.entryList();
361 for (int i = 0; i < list.size(); i++) {
362 if (!list.at(i).contains(m_forecastInitialDateCode)) {
363 QFile(m_cachePath + "/" + list.at(i)).remove();