1 // Copyright 2010 Jochen Becher
3 // This file is part of MovieSchedule.
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.
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.
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/>.
18 #include "theatersearchclient.h"
20 #include "data/cinemakey.h"
21 #include "data/cinema.h"
22 #include "data/cinemaschedule.h"
23 #include "utils/assertedlocker.h"
25 #include <QXmlStreamReader>
28 TheaterSearchClient::TheaterSearchClient(CinemaSchedule *cinema_schedule, QObject *parent)
29 : AbstractSearchClient(parent),
30 _cinema_schedule(cinema_schedule)
34 void TheaterSearchClient::SearchTheater(const QString &town)
36 _semaphore.Activate(GetSearchTaskId());
37 setObjectName(QString("TheaterSearchClient:%1").arg(town));
42 void TheaterSearchClient::CancelAllRunningSearchs()
44 _semaphore.CancelAll();
47 void TheaterSearchClient::Search(int start)
49 QUrl url("http://www.google.com/m/movies");
50 url.addQueryItem("action","chgloc");
51 url.addQueryItem("loc", _town);
52 url.addQueryItem("sort", QString::number(0));
53 AbstractSearchClient::Search(url, start);
66 void TheaterSearchClient::ReplyFinished(QNetworkReply *reply)
68 //std::cout << qPrintable(QString::fromUtf8(reply->readAll().data())) << std::endl;
69 QXmlStreamReader xml(reply);
70 State state = PARSE_HTML;
73 QString theater_address;
74 QString theater_movies_url;
75 QString theater_phone;
76 QString next_page_url;
78 while (!xml.atEnd()) {
79 QXmlStreamReader::TokenType token = xml.readNext();
80 if (token == QXmlStreamReader::StartElement) {
81 QString attr_href = xml.attributes().value("href").toString();
82 //std::cout << "name: " << qPrintable(xml.name().toString()) << ", href: " << qPrintable(attr_href) << std::endl;
83 if (state == PARSE_HTML && xml.name() == "a" && attr_href.startsWith("/m/movies")) {
84 QUrl url = QUrl::fromEncoded(QString("http://www.google.com" + attr_href).toAscii(), QUrl::TolerantMode);
85 //std::cout << "LINK " << qPrintable(attr_href) << std::endl;
86 if (url.hasQueryItem("tid")) {
89 theater_movies_url = attr_href;
91 state = PARSE_THEATER_LINK;
92 } else if (url.hasQueryItem("start")) {
93 QString sort = url.queryItemValue("sort");
94 QString start = url.queryItemValue("start");
95 int istart = start.toInt();
96 if (sort == "0" && istart > GetStartIndex()) {
97 //std::cout << "next page LINK " << qPrintable(attr_href) << std::endl;
98 next_page_url = attr_href;
99 next_page_start = istart;
101 state = PARSE_NEXT_PAGE_LINK;
105 } else if (state == PARSE_THEATER_DIV && xml.name() == "br") {
106 state = PARSE_THEATER_BR;
107 } else if (state == PARSE_THEATER_DIV && xml.name() == "span") {
108 state = PARSE_THEATER_SPAN;
109 } else if (state == PARSE_THEATER_DIV && xml.name() == "a" && attr_href.startsWith("wtai:")) {
110 state = PARSE_THEATER_PHONE;
111 } else if (state == PARSE_THEATER_DIV && xml.name() == "a") {
112 state = PARSE_THEATER_BR;
116 } else if (token == QXmlStreamReader::EndElement) {
117 if (state == PARSE_THEATER_LINK) {
118 state = PARSE_THEATER_DIV;
119 } else if (state == PARSE_THEATER_BR) {
120 state = PARSE_THEATER_DIV;
121 } else if (state == PARSE_THEATER_SPAN) {
122 state = PARSE_THEATER_DIV;
123 } else if (state == PARSE_THEATER_PHONE) {
124 state = PARSE_THEATER_DIV;
125 } else if (state == PARSE_THEATER_DIV) {
126 if (!theater_name.isEmpty()) {
127 AssertedWriteLocker locker(_cinema_schedule->GetLock());
128 if (!_semaphore.IsActive(GetSearchTaskId())) {
132 CinemaKey key(theater_name, theater_address);
133 Cinema *cinema = _cinema_schedule->FindCinema(key);
135 cinema = _cinema_schedule->AddCinema(key);
137 if (!theater_movies_url.isEmpty()) {
138 cinema->SetMoviesUrl(theater_movies_url);
140 if (!theater_phone.isEmpty()) {
141 cinema->SetTelephone(theater_phone);
145 } else if (state == PARSE_NEXT_PAGE_LINK) {
148 } else if (token == QXmlStreamReader::Characters) {
149 if (state == PARSE_THEATER_LINK) {
150 theater_name = xml.text().toString();
151 } else if (state == PARSE_THEATER_PHONE) {
152 theater_phone = xml.text().toString();
153 } else if (state == PARSE_THEATER_SPAN) {
154 theater_address = xml.text().toString();
158 if (xml.hasError()) {
159 emit SearchFinished(GetSearchTaskId(), false);
160 std::cout << "xml error (" << xml.lineNumber() << "/" << xml.columnNumber() << "): " << qPrintable(xml.errorString()) << std::endl;
161 emit Error(GetSearchTaskId());
163 } else if (!_semaphore.IsActive(GetSearchTaskId())) {
164 emit Cancelled(GetSearchTaskId());
165 emit SearchFinished(GetSearchTaskId(), false);
168 if (!next_page_url.isEmpty()) {
169 emit Reply(GetSearchTaskId(), true);
170 SearchEncodedUrl(next_page_url, next_page_start);
172 emit Reply(GetSearchTaskId(), false);
173 emit SearchFinished(GetSearchTaskId(), true);
177 reply->deleteLater();
180 SearchClientSemaphore TheaterSearchClient::_semaphore;