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 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*)));
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();
110 if (xml.hasError()) {
111 emit error(xml.errorString());
112 qWarning() << xml.errorString();
120 void YTUser::loadThumbnail() {
121 if (loadingThumbnail) return;
122 if (thumbnailUrl.isEmpty()) return;
123 loadingThumbnail = true;
126 thumbnailUrl.replace(QLatin1String("https://"), QLatin1String("http://"));
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*)));
135 const QString & YTUser::getThumbnailDir() {
136 static const QString thumbDir = QDesktopServices::storageLocation(
137 QDesktopServices::DataLocation) + "/channels/";
141 QString YTUser::getThumbnailLocation() {
142 return getThumbnailDir() + userId;
145 void YTUser::unsubscribe() {
146 YTUser::unsubscribe(userId);
149 void YTUser::storeThumbnail(QByteArray bytes) {
150 thumbnail.loadFromData(bytes);
151 static const int maxWidth = 88;
154 dir.mkpath(getThumbnailDir());
156 if (thumbnail.width() > maxWidth) {
157 thumbnail = thumbnail.scaledToWidth(maxWidth, Qt::SmoothTransformation);
158 thumbnail.save(getThumbnailLocation(), "JPG");
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());
167 emit thumbnailLoaded();
168 loadingThumbnail = false;
171 void YTUser::requestError(QNetworkReply *reply) {
172 emit error(reply->errorString());
173 qWarning() << reply->errorString();
175 loadingThumbnail = false;
178 void YTUser::storeInfo() {
179 if (userId.isEmpty()) return;
180 QSqlDatabase db = Database::instance().getConnection();
182 query.prepare("update subscriptions set "
183 "user_name=?, name=?, description=?, thumb_url=?, loaded=? "
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();
198 void YTUser::subscribe(QString userId) {
199 if (userId.isEmpty()) return;
201 uint now = QDateTime::currentDateTime().toTime_t();
203 QSqlDatabase db = Database::instance().getConnection();
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();
214 // This will call maybeLoadFromApi
215 YTUser::forId(userId);
218 void YTUser::unsubscribe(QString userId) {
219 if (userId.isEmpty()) return;
220 QSqlDatabase db = Database::instance().getConnection();
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();
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();
233 YTUser *user = cache.take(userId);
234 if (user) user->deleteLater();
237 bool YTUser::isSubscribed(QString userId) {
238 if (!Database::exists()) return false;
239 if (userId.isEmpty()) return false;
240 QSqlDatabase db = Database::instance().getConnection();
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();
247 return query.value(0).toInt() > 0;
251 void YTUser::updateChecked() {
252 if (userId.isEmpty()) return;
254 uint now = QDateTime::currentDateTime().toTime_t();
257 QSqlDatabase db = Database::instance().getConnection();
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();
266 void YTUser::updateWatched() {
267 if (userId.isEmpty()) return;
269 uint now = QDateTime::currentDateTime().toTime_t();
272 emit notifyCountChanged();
274 QSqlDatabase db = Database::instance().getConnection();
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();
283 void YTUser::storeNotifyCount(int count) {
284 if (notifyCount != count)
285 emit notifyCountChanged();
288 QSqlDatabase db = Database::instance().getConnection();
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();
297 bool YTUser::updateNotifyCount() {
298 QSqlDatabase db = Database::instance().getConnection();
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();
308 qWarning() << __PRETTY_FUNCTION__ << "Count failed";
311 int count = query.value(0).toInt();
312 storeNotifyCount(count);
313 return count != notifyCount;