]> git.sur5r.net Git - minitube/blob - src/ytuser.cpp
Imported Upstream version 2.2
[minitube] / src / ytuser.cpp
1 /* $BEGIN_LICENSE
2
3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
5
6 Minitube is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Minitube is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
18
19 $END_LICENSE */
20
21 #include "ytuser.h"
22 #include "networkaccess.h"
23 #include "database.h"
24 #include <QtSql>
25
26 namespace The {
27 NetworkAccess* http();
28 }
29
30 YTUser::YTUser(QString userId, QObject *parent) : QObject(parent),
31     id(0),
32     userId(userId),
33     loadingThumbnail(false),
34     notifyCount(0),
35     checked(0),
36     watched(0),
37     loaded(0),
38     loading(false) { }
39
40 QHash<QString, YTUser*> YTUser::cache;
41
42 YTUser* YTUser::forId(QString userId) {
43     if (userId.isEmpty()) return 0;
44
45     if (cache.contains(userId))
46         return cache.value(userId);
47
48     QSqlDatabase db = Database::instance().getConnection();
49     QSqlQuery query(db);
50     query.prepare("select id,name,description,thumb_url,notify_count,watched,checked,loaded "
51                   "from subscriptions where user_id=?");
52     query.bindValue(0, userId);
53     bool success = query.exec();
54     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
55
56     YTUser* user = 0;
57     if (query.next()) {
58         user = new YTUser(userId);
59         user->id = query.value(0).toInt();
60         user->displayName = query.value(1).toString();
61         user->description = query.value(2).toString();
62         user->thumbnailUrl = query.value(3).toString();
63         user->notifyCount = query.value(4).toInt();
64         user->watched = query.value(5).toUInt();
65         user->checked = query.value(6).toUInt();
66         user->loaded = query.value(7).toUInt();
67         user->thumbnail = QPixmap(user->getThumbnailLocation());
68         user->maybeLoadfromAPI();
69         cache.insert(userId, user);
70     }
71
72     return user;
73 }
74
75 void YTUser::maybeLoadfromAPI() {
76     if (loading) return;
77     if (userId.isEmpty()) return;
78
79     uint now = QDateTime::currentDateTime().toTime_t();
80     static const int refreshInterval = 60 * 60 * 24 * 10;
81     if (loaded > now - refreshInterval) return;
82
83     loading = true;
84
85     QUrl url("http://gdata.youtube.com/feeds/api/users/" + userId);
86     url.addQueryItem("v", "2");
87     QObject *reply = The::http()->get(url);
88     connect(reply, SIGNAL(data(QByteArray)), SLOT(parseResponse(QByteArray)));
89     connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(requestError(QNetworkReply*)));
90 }
91
92 void YTUser::parseResponse(QByteArray bytes) {
93     QXmlStreamReader xml(bytes);
94     xml.readNextStartElement();
95     if (xml.name() == QLatin1String("entry"))
96         while(xml.readNextStartElement()) {
97             const QStringRef n = xml.name();
98             if (n == QLatin1String("summary"))
99                 description = xml.readElementText().simplified();
100             else if (n == QLatin1String("title"))
101                 displayName = xml.readElementText();
102             else if (n == QLatin1String("thumbnail")) {
103                 thumbnailUrl = xml.attributes().value("url").toString();
104                 xml.skipCurrentElement();
105             } else if (n == QLatin1String("username"))
106                 userName = xml.readElementText();
107             else xml.skipCurrentElement();
108         }
109
110     if (xml.hasError()) {
111         emit error(xml.errorString());
112         qWarning() << xml.errorString();
113     }
114
115     emit infoLoaded();
116     storeInfo();
117     loading = false;
118 }
119
120 void YTUser::loadThumbnail() {
121     if (loadingThumbnail) return;
122     if (thumbnailUrl.isEmpty()) return;
123     loadingThumbnail = true;
124
125 #ifdef Q_WS_WIN
126     thumbnailUrl.replace(QLatin1String("https://"), QLatin1String("http://"));
127 #endif
128
129     QUrl url(thumbnailUrl);
130     QObject *reply = The::http()->get(url);
131     connect(reply, SIGNAL(data(QByteArray)), SLOT(storeThumbnail(QByteArray)));
132     connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(requestError(QNetworkReply*)));
133 }
134
135 const QString & YTUser::getThumbnailDir() {
136     static const QString thumbDir = QDesktopServices::storageLocation(
137                 QDesktopServices::DataLocation) + "/channels/";
138     return thumbDir;
139 }
140
141 QString YTUser::getThumbnailLocation() {
142     return getThumbnailDir() + userId;
143 }
144
145 void YTUser::unsubscribe() {
146     YTUser::unsubscribe(userId);
147 }
148
149 void YTUser::storeThumbnail(QByteArray bytes) {
150     thumbnail.loadFromData(bytes);
151     static const int maxWidth = 88;
152
153     QDir dir;
154     dir.mkpath(getThumbnailDir());
155
156     if (thumbnail.width() > maxWidth) {
157         thumbnail = thumbnail.scaledToWidth(maxWidth, Qt::SmoothTransformation);
158         thumbnail.save(getThumbnailLocation(), "JPG");
159     } else {
160         QFile file(getThumbnailLocation());
161         if (!file.open(QIODevice::WriteOnly))
162             qWarning() << "Error opening file for writing" << file.fileName();
163         QDataStream stream(&file);
164         stream.writeRawData(bytes.constData(), bytes.size());
165     }
166
167     emit thumbnailLoaded();
168     loadingThumbnail = false;
169 }
170
171 void YTUser::requestError(QNetworkReply *reply) {
172     emit error(reply->errorString());
173     qWarning() << reply->errorString();
174     loading = false;
175     loadingThumbnail = false;
176 }
177
178 void YTUser::storeInfo() {
179     if (userId.isEmpty()) return;
180     QSqlDatabase db = Database::instance().getConnection();
181     QSqlQuery query(db);
182     query.prepare("update subscriptions set "
183                   "user_name=?, name=?, description=?, thumb_url=?, loaded=? "
184                   "where user_id=?");
185     qDebug() << userName;
186     query.bindValue(0, userName);
187     query.bindValue(1, displayName);
188     query.bindValue(2, description);
189     query.bindValue(3, thumbnailUrl);
190     query.bindValue(4, QDateTime::currentDateTime().toTime_t());
191     query.bindValue(5, userId);
192     bool success = query.exec();
193     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
194
195     loadThumbnail();
196 }
197
198 void YTUser::subscribe(QString userId) {
199     if (userId.isEmpty()) return;
200
201     uint now = QDateTime::currentDateTime().toTime_t();
202
203     QSqlDatabase db = Database::instance().getConnection();
204     QSqlQuery query(db);
205     query.prepare("insert into subscriptions "
206                   "(user_id,added,watched,checked,views,notify_count)"
207                   " values (?,?,?,0,0,0)");
208     query.bindValue(0, userId);
209     query.bindValue(1, now);
210     query.bindValue(2, now);
211     bool success = query.exec();
212     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
213
214     // This will call maybeLoadFromApi
215     YTUser::forId(userId);
216 }
217
218 void YTUser::unsubscribe(QString userId) {
219     if (userId.isEmpty()) return;
220     QSqlDatabase db = Database::instance().getConnection();
221     QSqlQuery query(db);
222     query.prepare("delete from subscriptions where user_id=?");
223     query.bindValue(0, userId);
224     bool success = query.exec();
225     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
226
227     query = QSqlQuery(db);
228     query.prepare("delete from subscriptions_videos where user_id=?");
229     query.bindValue(0, userId);
230     success = query.exec();
231     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
232
233     YTUser *user = cache.take(userId);
234     if (user) user->deleteLater();
235 }
236
237 bool YTUser::isSubscribed(QString userId) {
238     if (!Database::exists()) return false;
239     if (userId.isEmpty()) return false;
240     QSqlDatabase db = Database::instance().getConnection();
241     QSqlQuery query(db);
242     query.prepare("select count(*) from subscriptions where user_id=?");
243     query.bindValue(0, userId);
244     bool success = query.exec();
245     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
246     if (query.next())
247         return query.value(0).toInt() > 0;
248     return false;
249 }
250
251 void YTUser::updateChecked() {
252     if (userId.isEmpty()) return;
253
254     uint now = QDateTime::currentDateTime().toTime_t();
255     checked = now;
256
257     QSqlDatabase db = Database::instance().getConnection();
258     QSqlQuery query(db);
259     query.prepare("update subscriptions set checked=? where user_id=?");
260     query.bindValue(0, QDateTime::currentDateTime().toTime_t());
261     query.bindValue(1, userId);
262     bool success = query.exec();
263     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
264 }
265
266 void YTUser::updateWatched() {
267     if (userId.isEmpty()) return;
268
269     uint now = QDateTime::currentDateTime().toTime_t();
270     watched = now;
271     notifyCount = 0;
272     emit notifyCountChanged();
273
274     QSqlDatabase db = Database::instance().getConnection();
275     QSqlQuery query(db);
276     query.prepare("update subscriptions set watched=?, notify_count=0, views=views+1 where user_id=?");
277     query.bindValue(0, now);
278     query.bindValue(1, userId);
279     bool success = query.exec();
280     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
281 }
282
283 void YTUser::storeNotifyCount(int count) {
284     if (notifyCount != count)
285         emit notifyCountChanged();
286     notifyCount = count;
287
288     QSqlDatabase db = Database::instance().getConnection();
289     QSqlQuery query(db);
290     query.prepare("update subscriptions set notify_count=? where user_id=?");
291     query.bindValue(0, count);
292     query.bindValue(1, userId);
293     bool success = query.exec();
294     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
295 }
296
297 bool YTUser::updateNotifyCount() {
298     QSqlDatabase db = Database::instance().getConnection();
299     QSqlQuery query(db);
300     query.prepare("select count(*) from subscriptions_videos "
301                   "where channel_id=? and added>? and published>? and watched=0");
302     query.bindValue(0, id);
303     query.bindValue(1, watched);
304     query.bindValue(2, watched);
305     bool success = query.exec();
306     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
307     if (!query.next()) {
308         qWarning() << __PRETTY_FUNCTION__ << "Count failed";
309         return false;
310     }
311     int count = query.value(0).toInt();
312     storeNotifyCount(count);
313     return count != notifyCount;
314 }