c19b7bcbc7df25434bbb33966b204f14fbbd1a8d
[movie-schedule] / src / searchclients / abstractsearchclient.cpp
1 // Copyright 2010 Jochen Becher
2 //
3 // This file is part of MovieSchedule.
4 //
5 // MovieSchedule 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 3 of the License, or
8 // (at your option) any later version.
9 //
10 // MovieSchedule 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.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "abstractsearchclient.h"
19
20 #include "utils/timeutils.h"
21
22 #include <QMutexLocker>
23 #include <iostream>
24
25 AbstractSearchClient::AbstractSearchClient(QObject *parent)
26     : QObject(parent),
27     _network(new QNetworkAccessManager(this)),
28     _search_task_id(INVALID_SEARCH_TASK_ID),
29     _start(0)
30 {
31     connect(_network, SIGNAL(finished(QNetworkReply *)),
32             this, SLOT(ReplyFinished(QNetworkReply*)));
33     {
34         QMutexLocker locker(&_next_search_task_id_mutex);
35         _search_task_id = _next_search_task_id++;
36     }
37 }
38
39 AbstractSearchClient::~AbstractSearchClient()
40 {
41 }
42
43 void AbstractSearchClient::Search(const QUrl &url, int start)
44 {
45     _start = start;
46     if (start == 0) {
47         emit SearchStarted(_search_task_id);
48     }
49     QNetworkRequest request;
50     QUrl xurl(url);
51     if (_start != 0) {
52         xurl.addQueryItem("start", QString::number(_start));
53     }
54     FixLocation(&xurl);
55     //std::cout << "URL: " << qPrintable(QString(xurl.toEncoded())) << std::endl;
56     request.setUrl(xurl);
57     //request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9");
58     request.setRawHeader("User-Agent", "Mozilla/5.0");
59     //request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
60     request.setRawHeader("Accept", "application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
61     request.setRawHeader("Accept-Language", "en-gb;q=1.0,en;q=0.9,de-de;q=0.5,de;q=0.3");
62     //request.setRawHeader("Accept-Encoding", "gzip,deflate");
63     request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
64     request.setRawHeader("Keep-Alive", "300");
65     request.setRawHeader("Connection", "keep-alive");
66     request.setRawHeader("Cache-Control", "max-age=0");
67     QNetworkReply *reply = _network->get(request);
68     connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(DownloadProgress(qint64,qint64)));
69     connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(NetworkError(QNetworkReply::NetworkError)));
70 }
71
72 void AbstractSearchClient::DownloadProgress(qint64 a,qint64 b)
73 {
74     //std::cout << "Search Progress of " << qPrintable(objectName()) << " - " << a << ", " << b << std::endl;
75     //sleep(1);
76     emit Progress(_search_task_id, a, b);
77 }
78
79 void AbstractSearchClient::NetworkError(QNetworkReply::NetworkError error)
80 {
81     emit SearchFinished(_search_task_id, false);
82     std::cout << "ERROR: " << error << std::endl;
83     emit Error(_search_task_id);
84     sender()->deleteLater();
85     deleteLater();
86 }
87
88 QList<QTime> AbstractSearchClient::TimesFromString(const QList<QString> &time_strings)
89 {
90     QList<QTime> schedule_times;
91     bool am_pm = false;
92     Q_FOREACH(const QString time_str, time_strings) {
93         if (time_str.endsWith("am", Qt::CaseInsensitive) || time_str.endsWith("pm", Qt::CaseInsensitive)) {
94             am_pm = true;
95         }
96     }
97     if (am_pm) {
98         int i = 0;
99         bool am = true;
100         while (i < time_strings.length()) {
101             int j = i;
102             while (i < time_strings.length()) {
103                 if (time_strings[i].endsWith("am", Qt::CaseInsensitive)) {
104                     am = true;
105                     break;
106                 } else if (time_strings[i].endsWith("pm", Qt::CaseInsensitive)) {
107                     am = false;
108                     break;
109                 }
110                 ++i;
111             }
112             while (j < i) {
113                 QString time_str = time_strings[j] + (am ? "am" : "pm");
114                 QTime time = TimeUtils::FromTimeString(time_str);
115                 if (time.isValid()) {
116                     schedule_times.append(time);
117                 } else {
118                     std::cout << "ERROR: time " << qPrintable(time_str) << " is invalid." << std::endl;
119                 }
120                 ++j;
121             }
122             if (i < time_strings.length()) {
123                 QString time_str = time_strings[i];
124                 QTime time = TimeUtils::FromTimeString(time_str);
125                 if (time.isValid()) {
126                     schedule_times.append(time);
127                 } else {
128                     std::cout << "ERROR: time " << qPrintable(time_str) << " is invalid." << std::endl;
129                 }
130                 schedule_times.append(time);
131             }
132             ++i;
133         }
134     } else {
135         Q_FOREACH(const QString time_str, time_strings) {
136             QTime time = TimeUtils::FromTimeString(time_str);
137             if (time.isValid()) {
138                 schedule_times.append(time);
139             } else {
140                 std::cout << "ERROR: time " << qPrintable(time_str) << " is invalid." << std::endl;
141             }
142         }
143     }
144     return schedule_times;
145 }
146
147 void AbstractSearchClient::FixLocation(QUrl *url)
148 {
149     // Try to fix the Google url which returns
150     // wrong locations in some links
151     if (_location.isNull()) {
152         // Fetch location from url on first call (which is still correct)
153         if (url->hasQueryItem("loc")) {
154             _location = url->queryItemValue("loc");
155         } else if (url->hasQueryItem("near")) {
156             _location = url->queryItemValue("near");
157         } else if (url->hasQueryItem("defaultloc")) {
158             _location = url->queryItemValue("defaultloc");
159         }
160     } else {
161         // Replace with fetched location in later calls
162         if (url->hasQueryItem("loc")) {
163             url->removeAllQueryItems("loc");
164             url->addQueryItem("loc", _location);
165         }
166         if (url->hasQueryItem("near")) {
167             url->removeAllQueryItems("near");
168             url->addQueryItem("near", _location);
169         }
170         if (url->hasQueryItem("defaultloc")) {
171             url->removeAllQueryItems("defaultloc");
172             url->addQueryItem("defaultloc", _location);
173         }
174     }
175 }
176
177 QMutex AbstractSearchClient::_next_search_task_id_mutex;
178 int AbstractSearchClient::_next_search_task_id = 1;