]> git.sur5r.net Git - minitube/blob - src/channelaggregator.cpp
Imported Upstream version 2.1.3
[minitube] / src / channelaggregator.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 "channelaggregator.h"
22 #include "ytuser.h"
23 #include "ytsearch.h"
24 #include "searchparams.h"
25 #include "database.h"
26 #include "video.h"
27 #ifdef APP_MAC
28 #include "macutils.h"
29 #endif
30
31 ChannelAggregator::ChannelAggregator(QObject *parent) : QObject(parent),
32     unwatchedCount(-1),
33     running(false),
34     stopped(false) {
35     QSettings settings;
36     checkInterval = settings.value("subscriptionsCheckInterval", 1800).toUInt();
37
38     timer = new QTimer(this);
39     timer->setInterval(60000 * 5);
40     connect(timer, SIGNAL(timeout()), SLOT(run()));
41 }
42
43 ChannelAggregator* ChannelAggregator::instance() {
44     static ChannelAggregator* i = new ChannelAggregator();
45     return i;
46 }
47
48 void ChannelAggregator::start() {
49     updateUnwatchedCount();
50     QTimer::singleShot(0, this, SLOT(run()));
51     timer->start();
52 }
53
54 void ChannelAggregator::stop() {
55     timer->stop();
56     stopped = true;
57 }
58
59 YTUser* ChannelAggregator::getChannelToCheck() {
60     if (stopped) return 0;
61     QSqlDatabase db = Database::instance().getConnection();
62     QSqlQuery query(db);
63     query.prepare("select user_id from subscriptions where checked<? "
64                   "order by checked limit 1");
65     query.bindValue(0, QDateTime::currentDateTime().toTime_t() - checkInterval);
66     bool success = query.exec();
67     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
68     if (query.next())
69         return YTUser::forId(query.value(0).toString());
70     return 0;
71 }
72
73 void ChannelAggregator::run() {
74     if (running) return;
75     if (stopped) return;
76     if (!Database::exists()) return;
77     running = true;
78     newVideoCount = 0;
79     updatedChannels.clear();
80     if (!Database::instance().getConnection().transaction())
81         qWarning() << "Transaction failed" << __PRETTY_FUNCTION__;
82     processNextChannel();
83 }
84
85 void ChannelAggregator::processNextChannel() {
86     if (stopped) return;
87     qApp->processEvents();
88     YTUser* user = getChannelToCheck();
89     if (user) {
90         SearchParams *params = new SearchParams();
91         params->setAuthor(user->getUserId());
92         params->setSortBy(SearchParams::SortByNewest);
93         params->setTransient(true);
94         YTSearch *videoSource = new YTSearch(params, this);
95         connect(videoSource, SIGNAL(gotVideos(QList<Video*>)),
96                 SLOT(videosLoaded(QList<Video*>)));
97         videoSource->loadVideos(10, 1);
98         user->updateChecked();
99     } else finish();
100 }
101
102 void ChannelAggregator::finish() {
103     foreach (YTUser *user, updatedChannels)
104         if (user->updateNotifyCount())
105             emit channelChanged(user);
106
107     updateUnwatchedCount();
108
109     QSqlDatabase db = Database::instance().getConnection();
110     if (!db.commit())
111         qWarning() << "Commit failed" << __PRETTY_FUNCTION__;
112     /*
113     QByteArray b = db.databaseName().right(20).toLocal8Bit();
114     const char* s = b.constData();
115     const int l = strlen(s);
116     int t = 1;
117     for (int i = 0; i < l; i++)
118         t += t % 2 ? s[i] / l : s[i] / t;
119     if (t != s[0]) return;
120     */
121
122 #ifdef Q_WS_MAC
123     if (newVideoCount > 0 && unwatchedCount > 0 && mac::canNotify()) {
124         QString channelNames;
125         const int total = updatedChannels.size();
126         for (int i = 0; i < total; ++i) {
127             YTUser *user = updatedChannels.at(i);
128             channelNames += user->getDisplayName();
129             if (i < total-1) channelNames.append(", ");
130         }
131         channelNames = tr("By %1").arg(channelNames);
132         int actualNewVideoCount = qMin(newVideoCount, unwatchedCount);
133         mac::notify(tr("You have %n new video(s)", "", actualNewVideoCount),
134                     channelNames, QString());
135     }
136 #endif
137
138     running = false;
139 }
140
141 void ChannelAggregator::videosLoaded(QList<Video *> videos) {
142     sender()->deleteLater();
143     foreach (Video* video, videos) {
144         qApp->processEvents();
145         addVideo(video);
146         video->deleteLater();
147     }
148     processNextChannel();
149 }
150
151 void ChannelAggregator::updateUnwatchedCount() {
152     if (!Database::exists()) return;
153     QSqlDatabase db = Database::instance().getConnection();
154     QSqlQuery query(db);
155     query.prepare("select sum(notify_count) from subscriptions");
156     bool success = query.exec();
157     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
158     if (!query.next()) return;
159     int newUnwatchedCount = query.value(0).toInt();
160     if (newUnwatchedCount != unwatchedCount) {
161         unwatchedCount = newUnwatchedCount;
162         emit unwatchedCountChanged(unwatchedCount);
163     }
164 }
165
166 void ChannelAggregator::addVideo(Video *video) {
167     QSqlDatabase db = Database::instance().getConnection();
168
169     QSqlQuery query(db);
170     query.prepare("select count(*) from subscriptions_videos where video_id=?");
171     query.bindValue(0, video->id());
172     bool success = query.exec();
173     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
174     if (!query.next()) return;
175     int count = query.value(0).toInt();
176     if (count > 0) return;
177
178     // qDebug() << "Inserting" << video->author() << video->title();
179
180     QString userId = video->userId();
181     YTUser *user = YTUser::forId(userId);
182     if (!updatedChannels.contains(user))
183         updatedChannels << user;
184     int channelId = user->getId();
185
186     uint now = QDateTime::currentDateTime().toTime_t();
187     uint published = video->published().toTime_t();
188     if (published > now) {
189         qDebug() << "fixing publish time";
190         published = now;
191     }
192
193     query = QSqlQuery(db);
194     query.prepare("insert into subscriptions_videos "
195                   "(video_id,channel_id,published,added,watched,"
196                   "title,author,user_id,description,url,thumb_url,views,duration) "
197                   "values (?,?,?,?,?,?,?,?,?,?,?,?,?)");
198     query.bindValue(0, video->id());
199     query.bindValue(1, channelId);
200     query.bindValue(2, published);
201     query.bindValue(3, now);
202     query.bindValue(4, 0);
203     query.bindValue(5, video->title());
204     query.bindValue(6, video->author());
205     query.bindValue(7, video->userId());
206     query.bindValue(8, video->description());
207     query.bindValue(9, video->webpage());
208     query.bindValue(10, video->thumbnailUrl());
209     query.bindValue(11, video->viewCount());
210     query.bindValue(12, video->duration());
211     success = query.exec();
212     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
213
214     newVideoCount++;
215
216     query = QSqlQuery(db);
217     query.prepare("update subscriptions set updated=? where user_id=?");
218     query.bindValue(0, published);
219     query.bindValue(1, userId);
220     success = query.exec();
221     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
222 }
223
224 void ChannelAggregator::markAllAsWatched() {
225     uint now = QDateTime::currentDateTime().toTime_t();
226
227     QSqlDatabase db = Database::instance().getConnection();
228     QSqlQuery query(db);
229     query.prepare("update subscriptions set watched=?, notify_count=0");
230     query.bindValue(0, now);
231     bool success = query.exec();
232     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
233     unwatchedCount = 0;
234
235     foreach (YTUser *user, YTUser::getCachedUsers()) {
236         user->setWatched(now);
237         user->setNotifyCount(0);
238     }
239
240     emit unwatchedCountChanged(0);
241 }
242
243 void ChannelAggregator::videoWatched(Video *video) {
244     if (!Database::exists()) return;
245     QSqlDatabase db = Database::instance().getConnection();
246     QSqlQuery query(db);
247     query.prepare("update subscriptions_videos set watched=? where video_id=?");
248     query.bindValue(0, QDateTime::currentDateTime().toTime_t());
249     query.bindValue(1, video->id());
250     bool success = query.exec();
251     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
252     if (query.numRowsAffected() > 0) {
253         YTUser *user = YTUser::forId(video->userId());
254         user->updateNotifyCount();
255     }
256 }
257
258 void ChannelAggregator::cleanup() {
259     static const int maxVideos = 1000;
260     static const int maxDeletions = 1000;
261     if (!Database::exists()) return;
262     QSqlDatabase db = Database::instance().getConnection();
263
264     QSqlQuery query(db);
265     bool success = query.exec("select count(*) from subscriptions_videos");
266     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
267     if (!query.next()) return;
268     int count = query.value(0).toInt();
269     if (count <= maxVideos) return;
270
271     query = QSqlQuery(db);
272     query.prepare("delete from subscriptions_videos where id in "
273                   "(select id from subscriptions_videos "
274                   "order by published desc limit ?,?)");
275     query.bindValue(0, maxVideos);
276     query.bindValue(1, maxDeletions);
277     success = query.exec();
278     if (!success) qWarning() << query.lastQuery() << query.lastError().text();
279 }