3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
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.
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.
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/>.
22 #include "networkaccess.h"
27 NetworkAccess* http();
30 YTUser::YTUser(QString userId, QObject *parent) : QObject(parent),
33 loadingThumbnail(false),
40 QHash<QString, YTUser*> YTUser::cache;
42 YTUser* YTUser::forId(QString userId) {
43 if (userId.isEmpty()) return 0;
45 if (cache.contains(userId))
46 return cache.value(userId);
48 QSqlDatabase db = Database::instance().getConnection();
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();
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);
75 void YTUser::maybeLoadfromAPI() {
77 if (userId.isEmpty()) return;
79 uint now = QDateTime::currentDateTime().toTime_t();
80 static const int refreshInterval = 60 * 60 * 24 * 10;
81 if (loaded > now - refreshInterval) return;
85 QUrl url("http://gdata.youtube.com/feeds/api/users/" + userId);
86 #if QT_VERSION >= 0x050000
91 url.addQueryItem("v", "2");
92 #if QT_VERSION >= 0x050000
96 QObject *reply = The::http()->get(url);
97 connect(reply, SIGNAL(data(QByteArray)), SLOT(parseResponse(QByteArray)));
98 connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(requestError(QNetworkReply*)));
101 void YTUser::parseResponse(QByteArray bytes) {
102 QXmlStreamReader xml(bytes);
103 xml.readNextStartElement();
104 if (xml.name() == QLatin1String("entry"))
105 while(xml.readNextStartElement()) {
106 const QStringRef n = xml.name();
107 if (n == QLatin1String("summary"))
108 description = xml.readElementText().simplified();
109 else if (n == QLatin1String("title"))
110 displayName = xml.readElementText();
111 else if (n == QLatin1String("thumbnail")) {
112 thumbnailUrl = xml.attributes().value("url").toString();
113 xml.skipCurrentElement();
114 } else if (n == QLatin1String("username"))
115 userName = xml.readElementText();
116 else xml.skipCurrentElement();
119 if (xml.hasError()) {
120 emit error(xml.errorString());
121 qWarning() << xml.errorString();
129 void YTUser::loadThumbnail() {
130 if (loadingThumbnail) return;
131 if (thumbnailUrl.isEmpty()) return;
132 loadingThumbnail = true;
135 thumbnailUrl.replace(QLatin1String("https://"), QLatin1String("http://"));
138 QUrl url(thumbnailUrl);
139 QObject *reply = The::http()->get(url);
140 connect(reply, SIGNAL(data(QByteArray)), SLOT(storeThumbnail(QByteArray)));
141 connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(requestError(QNetworkReply*)));
144 const QString & YTUser::getThumbnailDir() {
145 static const QString thumbDir =
146 #if QT_VERSION >= 0x050000
147 QStandardPaths::writableLocation(QStandardPaths::DataLocation)
149 QDesktopServices::storageLocation(QDesktopServices::DataLocation)
155 QString YTUser::getThumbnailLocation() {
156 return getThumbnailDir() + userId;
159 void YTUser::unsubscribe() {
160 YTUser::unsubscribe(userId);
163 void YTUser::storeThumbnail(QByteArray bytes) {
164 thumbnail.loadFromData(bytes);
165 static const int maxWidth = 88;
168 dir.mkpath(getThumbnailDir());
170 if (thumbnail.width() > maxWidth) {
171 thumbnail = thumbnail.scaledToWidth(maxWidth, Qt::SmoothTransformation);
172 thumbnail.save(getThumbnailLocation(), "JPG");
174 QFile file(getThumbnailLocation());
175 if (!file.open(QIODevice::WriteOnly))
176 qWarning() << "Error opening file for writing" << file.fileName();
177 QDataStream stream(&file);
178 stream.writeRawData(bytes.constData(), bytes.size());
181 emit thumbnailLoaded();
182 loadingThumbnail = false;
185 void YTUser::requestError(QNetworkReply *reply) {
186 emit error(reply->errorString());
187 qWarning() << reply->errorString();
189 loadingThumbnail = false;
192 void YTUser::storeInfo() {
193 if (userId.isEmpty()) return;
194 QSqlDatabase db = Database::instance().getConnection();
196 query.prepare("update subscriptions set "
197 "user_name=?, name=?, description=?, thumb_url=?, loaded=? "
199 qDebug() << userName;
200 query.bindValue(0, userName);
201 query.bindValue(1, displayName);
202 query.bindValue(2, description);
203 query.bindValue(3, thumbnailUrl);
204 query.bindValue(4, QDateTime::currentDateTime().toTime_t());
205 query.bindValue(5, userId);
206 bool success = query.exec();
207 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
212 void YTUser::subscribe(QString userId) {
213 if (userId.isEmpty()) return;
215 uint now = QDateTime::currentDateTime().toTime_t();
217 QSqlDatabase db = Database::instance().getConnection();
219 query.prepare("insert into subscriptions "
220 "(user_id,added,watched,checked,views,notify_count)"
221 " values (?,?,?,0,0,0)");
222 query.bindValue(0, userId);
223 query.bindValue(1, now);
224 query.bindValue(2, now);
225 bool success = query.exec();
226 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
228 // This will call maybeLoadFromApi
229 YTUser::forId(userId);
232 void YTUser::unsubscribe(QString userId) {
233 if (userId.isEmpty()) return;
234 QSqlDatabase db = Database::instance().getConnection();
236 query.prepare("delete from subscriptions where user_id=?");
237 query.bindValue(0, userId);
238 bool success = query.exec();
239 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
241 query = QSqlQuery(db);
242 query.prepare("delete from subscriptions_videos where user_id=?");
243 query.bindValue(0, userId);
244 success = query.exec();
245 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
247 YTUser *user = cache.take(userId);
248 if (user) user->deleteLater();
251 bool YTUser::isSubscribed(QString userId) {
252 if (!Database::exists()) return false;
253 if (userId.isEmpty()) return false;
254 QSqlDatabase db = Database::instance().getConnection();
256 query.prepare("select count(*) from subscriptions where user_id=?");
257 query.bindValue(0, userId);
258 bool success = query.exec();
259 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
261 return query.value(0).toInt() > 0;
265 void YTUser::updateChecked() {
266 if (userId.isEmpty()) return;
268 uint now = QDateTime::currentDateTime().toTime_t();
271 QSqlDatabase db = Database::instance().getConnection();
273 query.prepare("update subscriptions set checked=? where user_id=?");
274 query.bindValue(0, QDateTime::currentDateTime().toTime_t());
275 query.bindValue(1, userId);
276 bool success = query.exec();
277 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
280 void YTUser::updateWatched() {
281 if (userId.isEmpty()) return;
283 uint now = QDateTime::currentDateTime().toTime_t();
286 emit notifyCountChanged();
288 QSqlDatabase db = Database::instance().getConnection();
290 query.prepare("update subscriptions set watched=?, notify_count=0, views=views+1 where user_id=?");
291 query.bindValue(0, now);
292 query.bindValue(1, userId);
293 bool success = query.exec();
294 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
297 void YTUser::storeNotifyCount(int count) {
298 if (notifyCount != count)
299 emit notifyCountChanged();
302 QSqlDatabase db = Database::instance().getConnection();
304 query.prepare("update subscriptions set notify_count=? where user_id=?");
305 query.bindValue(0, count);
306 query.bindValue(1, userId);
307 bool success = query.exec();
308 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
311 bool YTUser::updateNotifyCount() {
312 QSqlDatabase db = Database::instance().getConnection();
314 query.prepare("select count(*) from subscriptions_videos "
315 "where channel_id=? and added>? and published>? and watched=0");
316 query.bindValue(0, id);
317 query.bindValue(1, watched);
318 query.bindValue(2, watched);
319 bool success = query.exec();
320 if (!success) qWarning() << query.lastQuery() << query.lastError().text();
322 qWarning() << __PRETTY_FUNCTION__ << "Count failed";
325 int count = query.value(0).toInt();
326 storeNotifyCount(count);
327 return count != notifyCount;