scan: add log view. fix scan pattern.
[abby.git] / src / scandlg.cpp
blobb2dab1cd84cded0755fbe5803f534e15466bbbde
1 /*
2 * abby Copyright (C) 2009 Toni Gundogdu.
3 * This file is part of abby.
5 * abby 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 * abby 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 this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <QDialog>
19 #include <QSettings>
20 //#include <QDebug>
21 #include <QMessageBox>
22 #include <QRegExp>
24 #include "util.h"
25 #include "scandlg.h"
27 ScanDialog::ScanDialog(QWidget *parent)
28 : QDialog(parent), mgr(0), titleMode(false),
29 scannedPages(0), expectedScans(0)
31 setupUi(this);
33 readSettings();
35 mgr = createManager();
37 itemsTree->setColumnHidden(1, true);
40 static void
41 enable_widgets(ScanDialog *d, const bool state=true) {
42 d->linkEdit->setEnabled (state);
43 d->scanButton->setEnabled (state);
44 d->titlesBox->setEnabled (state);
45 d->selectallButton->setEnabled(state);
46 d->invertButton->setEnabled(state);
47 d->buttonBox->setEnabled (state);
50 void
51 ScanDialog::onScan() {
53 QString lnk = linkEdit->text();
55 lnk = lnk.trimmed();
57 if (lnk.isEmpty())
58 return;
60 if (!lnk.startsWith("http://", Qt::CaseInsensitive))
61 lnk.insert(0,"http://");
63 itemsTree->clear();
64 logEdit->clear();
66 scannedPages = 0;
67 expectedScans = 0;
68 titleMode = false;
70 enable_widgets(this, false);
72 Util::appendLog(logEdit, QString(tr("Scan ... %1")).arg(lnk));
74 mgr->get( QNetworkRequest(lnk) );
77 void
78 ScanDialog::replyFinished(QNetworkReply* reply) {
80 if (reply->error() == QNetworkReply::NoError) {
82 handleRedirect(reply);
84 if (!redirectedToURL.isEmpty()) {
85 Util::appendLog(
86 logEdit,
87 QString(tr("Fetch ... %1"))
88 .arg(redirectedToURL.toString())
90 mgr->get( QNetworkRequest(redirectedToURL) );
92 else {
93 if (!titleMode) {
94 Util::appendLog(logEdit, tr("Scan contents for video links."));
95 scanContent(reply);
97 else {
98 Util::appendLog(
99 logEdit,
100 QString(tr("Parse video title ... %1 [%2/%3]"))
101 .arg(reply->url().toString())
102 .arg(++scannedPages)
103 .arg(expectedScans)
105 parseHtmlTitle(reply);
106 if (scannedPages == expectedScans)
107 emit scanComplete();
109 redirectedToURL.clear();
112 else {
113 Util::appendLog(logEdit, tr("Error occurred."));
114 QMessageBox::critical(this, QCoreApplication::applicationName(),
115 QString(tr("Network error: %1")).arg(reply->errorString()));
118 #ifdef _1_
119 if (state) {
120 linkEdit->setEnabled (state);
121 scanButton->setEnabled (state);
122 titlesBox->setEnabled (state);
123 buttonBox->setEnabled (state);
124 selectallButton->setEnabled(state);
125 invertButton->setEnabled(state);
127 #endif
129 reply->deleteLater();
132 static QStringList
133 matchScanContent (const QStringList& lst, QRegExp& re, const QString& content) {
135 re.setCaseSensitivity(Qt::CaseInsensitive);
136 re.setMinimal(true);
138 QStringList matches;
140 int pos = 0;
141 while ((pos = re.indexIn(content, pos)) != -1) {
142 const QString cap = re.cap(1).simplified();
143 if (!matches.contains(cap)
144 && !lst.contains(cap)
145 && !cap.isEmpty())
147 matches << cap;
149 pos += re.matchedLength();
151 return matches;
154 typedef unsigned int _uint;
156 #ifdef _1_
157 static void
158 dumpScanMatches (const QStringList& lst) {
159 const register _uint size = lst.size();
160 for (register _uint i=0; i<size; ++i)
161 qDebug() << lst[i];
162 qDebug() << "total: " << lst.size();
164 #endif
166 static void
167 scanYoutubeEmbed(QStringList& lst, const QString& content) {
168 QRegExp re("\\/v\\/(.*)[\"&\n<]");
169 QStringList matches = matchScanContent(lst, re, content);
170 //dumpScanMatches(matches);
171 lst << matches;
174 static void
175 scanYoutubeRegular(QStringList& lst, const QString& content) {
176 QRegExp re("\\/watch\\?v=(.*)[\"&\n<]");
177 QStringList matches = matchScanContent(lst, re, content);
178 //dumpScanMatches(matches);
179 lst << matches;
182 void
183 ScanDialog::scanContent(QNetworkReply *reply) {
185 const QString content = QString::fromLocal8Bit(reply->readAll());
187 QStringList IDs, links;
189 scanYoutubeEmbed (IDs, content);
190 scanYoutubeRegular (IDs, content);
192 const register _uint ids_size = IDs.size();
193 register _uint i;
195 for (i=0; i<ids_size; ++i)
196 links << "http://www.youtube.com/watch?v="+IDs[i];
198 const register _uint links_size = links.size();
200 Util::appendLog(
201 logEdit,
202 QString(tr("Found %1 video links.")).arg(links_size)
205 if (titlesBox->checkState()) {
206 titleMode = true;
207 for (i=0, expectedScans=links_size; i<links_size; ++i)
208 mgr->get( QNetworkRequest(links[i]) );
210 else {
212 for (i=0; i<links_size; ++i) {
213 QTreeWidgetItem *item = new QTreeWidgetItem;
214 item->setCheckState(0, Qt::Unchecked);
215 item->setText(0, links[i]);
216 item->setText(1, links[i]);
217 itemsTree->addTopLevelItem(item);
220 emit scanComplete();
224 void
225 ScanDialog::parseHtmlTitle(QNetworkReply *reply) {
227 const QString content = QString::fromLocal8Bit(reply->readAll());
228 const QString link = reply->url().toString();
230 QRegExp re("<title>(.*)<"); // TODO: improve.
231 re.setCaseSensitivity(Qt::CaseInsensitive);
232 re.setMinimal(true);
233 re.indexIn(content);
235 QTreeWidgetItem *item = new QTreeWidgetItem;
236 item->setCheckState(0, Qt::Unchecked);
237 item->setText(0, re.cap(1).simplified());
238 item->setText(1, link);
239 itemsTree->addTopLevelItem(item);
242 QNetworkAccessManager*
243 ScanDialog::createManager() {
244 QNetworkAccessManager *p = new QNetworkAccessManager(this);
246 connect(p, SIGNAL(finished(QNetworkReply*)),
247 this, SLOT(replyFinished(QNetworkReply*)));
249 return p;
252 void
253 ScanDialog::handleRedirect(const QNetworkReply *reply) {
255 // QUrl location =
256 // reply->header(QNetworkRequest::LocationHeader).toUrl();
258 QUrl location =
259 reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
261 if (!location.isEmpty() && location != redirectedToURL)
262 redirectedToURL = location;
263 else
264 redirectedToURL.clear();
267 void
268 ScanDialog::writeSettings() {
269 QSettings s;
270 s.beginGroup("ScanDialog");
271 s.setValue("size", size());
272 s.endGroup();
275 void
276 ScanDialog::readSettings() {
277 QSettings s;
278 s.beginGroup("ScanDialog");
279 resize( s.value("size", QSize(514,295)).toSize() );
280 s.endGroup();
283 void
284 ScanDialog::onSelectAll() {
285 Util::checkAllItems(itemsTree, Qt::Checked);
288 void
289 ScanDialog::onInvert() {
290 Util::invertAllCheckableItems(itemsTree);
293 void
294 ScanDialog::scanComplete() {
295 enable_widgets(this);
296 Util::appendLog(logEdit, tr("Scan complete."));