1
/* smplayer, GUI front-end for mplayer.
2
Copyright (C) 2006-2009 Ricardo Villalba <rvm@escomposlinux.org>
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
#include "findsubtitleswindow.h"
20
#include "findsubtitlesconfigdialog.h"
21
#include "simplehttp.h"
23
#include "languages.h"
24
#include <QStandardItemModel>
25
#include <QSortFilterProxyModel>
26
#include <QHeaderView>
27
#include <QMessageBox>
28
#include <QDesktopServices>
37
#include "filedownloader.h"
38
#include "subchooserdialog.h"
40
#include "quazipfile.h"
41
#include <QTemporaryFile>
52
FindSubtitlesWindow::FindSubtitlesWindow( QWidget * parent, Qt::WindowFlags f )
59
subtitles_for_label->setBuddy(file_chooser->lineEdit());
63
connect( file_chooser, SIGNAL(fileChanged(QString)),
64
this, SLOT(setMovie(QString)) );
65
connect( file_chooser->lineEdit(), SIGNAL(textChanged(const QString &)),
66
this, SLOT(updateRefreshButton()) );
68
connect( refresh_button, SIGNAL(clicked()),
69
this, SLOT(refresh()) );
71
connect( download_button, SIGNAL(clicked()),
72
this, SLOT(download()) );
75
connect( language_filter, SIGNAL(editTextChanged(const QString &)),
76
this, SLOT(applyFilter(const QString &)) );
78
connect( language_filter, SIGNAL(activated(int)),
79
this, SLOT(applyCurrentFilter()) );
81
table = new QStandardItemModel(this);
82
table->setColumnCount(COL_USER + 1);
84
proxy_model = new QSortFilterProxyModel(this);
85
proxy_model->setSourceModel(table);
86
proxy_model->setFilterKeyColumn(COL_LANG);
87
proxy_model->setFilterRole(Qt::UserRole);
89
view->setModel(proxy_model);
90
view->setRootIsDecorated(false);
91
view->setSortingEnabled(true);
92
view->setAlternatingRowColors(true);
93
view->header()->setSortIndicator(COL_LANG, Qt::AscendingOrder);
94
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
95
view->setContextMenuPolicy( Qt::CustomContextMenu );
97
connect(view, SIGNAL(activated(const QModelIndex &)),
98
this, SLOT(itemActivated(const QModelIndex &)) );
99
connect(view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)),
100
this, SLOT(currentItemChanged(const QModelIndex &,const QModelIndex &)) );
102
connect(view, SIGNAL(customContextMenuRequested(const QPoint &)),
103
this, SLOT(showContextMenu(const QPoint &)) );
105
downloader = new SimpleHttp(this);
107
connect( downloader, SIGNAL(downloadFailed(QString)),
108
this, SLOT(showError(QString)) );
109
connect( downloader, SIGNAL(downloadFinished(QByteArray)),
110
this, SLOT(downloadFinished()) );
111
connect( downloader, SIGNAL(downloadFinished(QByteArray)),
112
this, SLOT(parseInfo(QByteArray)) );
113
connect( downloader, SIGNAL(stateChanged(int)),
114
this, SLOT(updateRefreshButton()) );
116
connect( downloader, SIGNAL(connecting(QString)),
117
this, SLOT(connecting(QString)) );
118
connect( downloader, SIGNAL(dataReadProgress(int, int)),
119
this, SLOT(updateDataReadProgress(int, int)) );
122
include_lang_on_filename = true;
124
file_downloader = new FileDownloader(this);
125
file_downloader->setModal(true);
126
connect( file_downloader, SIGNAL(downloadFailed(QString)),
127
this, SLOT(showError(QString)), Qt::QueuedConnection );
128
connect( file_downloader, SIGNAL(downloadFinished(const QByteArray &)),
129
this, SLOT(archiveDownloaded(const QByteArray &)), Qt::QueuedConnection );
133
downloadAct = new QAction(this);
134
downloadAct->setEnabled(false);
135
connect( downloadAct, SIGNAL(triggered()), this, SLOT(download()) );
137
copyLinkAct = new QAction(this);
138
copyLinkAct->setEnabled(false);
139
connect( copyLinkAct, SIGNAL(triggered()), this, SLOT(copyLink()) );
141
context_menu = new QMenu(this);
142
context_menu->addAction(downloadAct);
143
context_menu->addAction(copyLinkAct);
145
retranslateStrings();
147
language_filter->setCurrentIndex(0);
151
proxy_type = QNetworkProxy::HttpProxy;
160
FindSubtitlesWindow::~FindSubtitlesWindow() {
161
if (set) saveSettings();
164
void FindSubtitlesWindow::setSettings(QSettings * settings) {
170
void FindSubtitlesWindow::setProxy(QNetworkProxy proxy) {
172
downloader->setProxy(proxy);
175
file_downloader->setProxy(proxy);
178
qDebug("FindSubtitlesWindow::setProxy: host: '%s' port: %d type: %d",
179
proxy.hostName().toUtf8().constData(), proxy.port(), proxy.type());
182
void FindSubtitlesWindow::retranslateStrings() {
186
labels << tr("Language") << tr("Name") << tr("Format")
187
<< tr("Files") << tr("Date") << tr("Uploaded by");
189
table->setHorizontalHeaderLabels( labels );
192
//int language_index = language_filter->currentIndex();
193
QString current_language = language_filter->itemData(language_filter->currentIndex()).toString();
194
language_filter->clear();
196
QMap<QString,QString> l = Languages::list();
197
QMapIterator<QString, QString> i(l);
198
while (i.hasNext()) {
200
language_filter->addItem( i.value() + " (" + i.key() + ")", i.key() );
202
language_filter->model()->sort(0);
203
language_filter->insertItem( 0, tr("All"), "*" );
204
//language_filter->setCurrentIndex(language_index);
205
language_filter->setCurrentIndex(language_filter->findData(current_language));
207
#if QT_VERSION < 0x040300
208
QPushButton * close_button = buttonBox->button(QDialogButtonBox::Close);
209
close_button->setText( tr("Close") );
213
downloadAct->setText( tr("&Download") );
214
copyLinkAct->setText( tr("&Copy link to clipboard") );
217
void FindSubtitlesWindow::setMovie(QString filename) {
218
qDebug("FindSubtitlesWindow::setMovie: '%s'", filename.toLatin1().constData());
220
if (filename == last_file) {
224
file_chooser->setText(filename);
225
table->setRowCount(0);
227
QString hash = OSParser::calculateHash(filename);
228
if (hash.isEmpty()) {
229
qWarning("FindSubtitlesWindow::setMovie: hash invalid. Doing nothing.");
231
QString link = "http://www.opensubtitles.org/search/sublanguageid-all/moviehash-" + hash + "/simplexml";
232
qDebug("FindSubtitlesWindow::setMovie: link: '%s'", link.toLatin1().constData());
233
downloader->download(link);
234
last_file = filename;
238
void FindSubtitlesWindow::refresh() {
240
setMovie(file_chooser->text());
243
void FindSubtitlesWindow::updateRefreshButton() {
244
QString file = file_chooser->lineEdit()->text();
245
bool enabled = ( (!file.isEmpty()) && (QFile::exists(file)) &&
246
(downloader->state()==QHttp::Unconnected) );
247
refresh_button->setEnabled(enabled);
250
void FindSubtitlesWindow::currentItemChanged(const QModelIndex & current, const QModelIndex & /*previous*/) {
251
qDebug("FindSubtitlesWindow::currentItemChanged: row: %d, col: %d", current.row(), current.column());
252
download_button->setEnabled(current.isValid());
253
downloadAct->setEnabled(current.isValid());
254
copyLinkAct->setEnabled(current.isValid());
257
void FindSubtitlesWindow::applyFilter(const QString & filter) {
258
proxy_model->setFilterWildcard(filter);
261
void FindSubtitlesWindow::applyCurrentFilter() {
262
//proxy_model->setFilterWildcard(language_filter->currentText());
263
QString filter = language_filter->itemData( language_filter->currentIndex() ).toString();
267
void FindSubtitlesWindow::setLanguage(const QString & lang) {
268
int idx = language_filter->findData(lang);
269
if (idx < 0) idx = 0;
270
language_filter->setCurrentIndex(idx);
273
QString FindSubtitlesWindow::language() {
274
int idx = language_filter->currentIndex();
275
return language_filter->itemData(idx).toString();
278
void FindSubtitlesWindow::showError(QString error) {
279
QMessageBox::information(this, tr("Error"),
280
tr("Download failed: %1.")
284
void FindSubtitlesWindow::connecting(QString host) {
285
status->setText( tr("Connecting to %1...").arg(host) );
288
void FindSubtitlesWindow::updateDataReadProgress(int done, int total) {
289
qDebug("FindSubtitlesWindow::updateDataReadProgress: %d, %d", done, total);
291
status->setText( tr("Downloading...") );
293
if (!progress->isVisible()) progress->show();
294
progress->setMaximum(total);
295
progress->setValue(done);
298
void FindSubtitlesWindow::downloadFinished() {
299
status->setText( tr("Done.") );
300
progress->setMaximum(1);
301
progress->setValue(0);
305
void FindSubtitlesWindow::parseInfo(QByteArray xml_text) {
307
bool ok = osparser.parseXml(xml_text);
309
table->setRowCount(0);
311
QMap <QString,QString> language_list = Languages::list();
314
QList<OSSubtitle> l = osparser.subtitleList();
315
for (int n=0; n < l.count(); n++) {
317
QString title_name = l[n].movie;
318
if (!l[n].releasename.isEmpty()) {
319
title_name += " - " + l[n].releasename;
322
QStandardItem * i_name = new QStandardItem(title_name);
323
i_name->setData( l[n].link );
324
#if QT_VERSION < 0x040400
325
i_name->setToolTip( l[n].link );
328
QStandardItem * i_lang = new QStandardItem(l[n].language);
329
i_lang->setData(l[n].iso639, Qt::UserRole);
330
#if QT_VERSION < 0x040400
331
i_lang->setToolTip(l[n].iso639);
333
if (language_list.contains(l[n].iso639)) {
334
i_lang->setText( language_list[ l[n].iso639 ] );
337
table->setItem(n, COL_LANG, i_lang);
338
table->setItem(n, COL_NAME, i_name);
339
table->setItem(n, COL_FORMAT, new QStandardItem(l[n].format));
340
table->setItem(n, COL_FILES, new QStandardItem(l[n].files));
341
table->setItem(n, COL_DATE, new QStandardItem(l[n].date));
342
table->setItem(n, COL_USER, new QStandardItem(l[n].user));
345
status->setText( tr("%1 files available").arg(l.count()) );
346
applyCurrentFilter();
348
qDebug("sort column: %d", view->header()->sortIndicatorSection());
349
qDebug("sort indicator: %d", view->header()->sortIndicatorOrder());
351
table->sort( view->header()->sortIndicatorSection(),
352
view->header()->sortIndicatorOrder() );
354
status->setText( tr("Failed to parse the received data.") );
357
view->resizeColumnToContents(COL_NAME);
360
void FindSubtitlesWindow::itemActivated(const QModelIndex & index ) {
361
qDebug("FindSubtitlesWindow::itemActivated: row: %d, col %d", proxy_model->mapToSource(index).row(), proxy_model->mapToSource(index).column());
363
QString download_link = table->item(proxy_model->mapToSource(index).row(), COL_NAME)->data().toString();
365
qDebug("FindSubtitlesWindow::itemActivated: download link: '%s'", download_link.toLatin1().constData());
368
file_downloader->download( QUrl(download_link) );
369
file_downloader->show();
371
QDesktopServices::openUrl( QUrl(download_link) );
375
void FindSubtitlesWindow::download() {
376
qDebug("FindSubtitlesWindow::download");
377
if (view->currentIndex().isValid()) {
378
itemActivated(view->currentIndex());
382
void FindSubtitlesWindow::copyLink() {
383
qDebug("FindSubtitlesWindow::copyLink");
384
if (view->currentIndex().isValid()) {
385
const QModelIndex & index = view->currentIndex();
386
QString download_link = table->item(proxy_model->mapToSource(index).row(), COL_NAME)->data().toString();
387
qDebug("FindSubtitlesWindow::copyLink: link: '%s'", download_link.toLatin1().constData());
388
qApp->clipboard()->setText(download_link);
392
void FindSubtitlesWindow::showContextMenu(const QPoint & pos) {
393
qDebug("FindSubtitlesWindow::showContextMenu");
395
context_menu->move( view->viewport()->mapToGlobal(pos) );
396
context_menu->show();
399
// Language change stuff
400
void FindSubtitlesWindow::changeEvent(QEvent *e) {
401
if (e->type() == QEvent::LanguageChange) {
402
retranslateStrings();
404
QWidget::changeEvent(e);
409
void FindSubtitlesWindow::archiveDownloaded(const QByteArray & buffer) {
410
qDebug("FindSubtitlesWindow::archiveDownloaded");
412
QString temp_dir = QDir::tempPath();
413
if (!temp_dir.endsWith("/")) temp_dir += "/";
415
QTemporaryFile file(temp_dir + "archive_XXXXXX.zip");
416
file.setAutoRemove(false);
418
qDebug("FindSubtitlesWindow::archiveDownloaded: a temporary file will be saved in folder '%s'", temp_dir.toUtf8().constData());
421
QString filename = file.fileName();
422
file.write( buffer );
425
qDebug("FindSubtitlesWindow::archiveDownloaded: file saved as: %s", filename.toUtf8().constData());
428
QMessageBox::information(this, tr("Downloaded"), tr("File saved as %1").arg(filename));
432
status->setText(tr("Temporary file %1").arg(filename));
434
QString lang = "unknown";
435
QString extension = "unknown";
436
if (view->currentIndex().isValid()) {
437
const QModelIndex & index = view->currentIndex();
438
lang = table->item(proxy_model->mapToSource(index).row(), COL_LANG)->data(Qt::UserRole).toString();
439
extension = table->item(proxy_model->mapToSource(index).row(), COL_FORMAT)->text();
442
QFileInfo fi(file_chooser->text());
443
QString output_name = fi.completeBaseName();
444
if (include_lang_on_filename) output_name += "_"+ lang;
445
output_name += "." + extension;
447
if (!uncompressZip(filename, fi.absolutePath(), output_name)) {
448
status->setText(tr("Download failed"));
453
qWarning("FindSubtitlesWindow::archiveDownloaded: can't write temporary file");
454
QMessageBox::warning(this, tr("Error saving file"),
455
tr("It wasn't possible to save the downloaded\n"
456
"file in folder %1\n"
457
"Please check the permissions of that folder.").arg(temp_dir));
462
bool FindSubtitlesWindow::uncompressZip(const QString & filename, const QString & output_path, const QString & preferred_output_name) {
463
qDebug("FindSubtitlesWindow::uncompressZip: zip file '%s', output_path '%s', save subtitle as '%s'",
464
filename.toUtf8().constData(), output_path.toUtf8().constData(),
465
preferred_output_name.toUtf8().constData());
467
QuaZip zip(filename);
469
if (!zip.open(QuaZip::mdUnzip)) {
470
qWarning("FindSubtitlesWindow::uncompressZip: open zip failed: %d", zip.getZipError());
474
zip.setFileNameCodec("IBM866");
475
qDebug("FindSubtitlesWindow::uncompressZip: %d entries", zip.getEntriesCount());
476
qDebug("FindSubtitlesWindow::uncompressZip: global comment: '%s'", zip.getComment().toUtf8().constData());
478
QStringList sub_files;
481
for (bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
482
if (!zip.getCurrentFileInfo(&info)) {
483
qWarning("FindSubtitlesWindow::uncompressZip: getCurrentFileInfo(): %d\n", zip.getZipError());
486
qDebug("FindSubtitlesWindow::uncompressZip: file '%s'", info.name.toUtf8().constData());
487
if (QFileInfo(info.name).suffix() != "nfo") sub_files.append(info.name);
490
qDebug("FindSubtitlesWindow::uncompressZip: list of subtitle files:");
491
for (int n=0; n < sub_files.count(); n++) {
492
qDebug("FindSubtitlesWindow::uncompressZip: subtitle file %d '%s'", n, sub_files[n].toUtf8().constData());
495
if (sub_files.count() == 1) {
496
// If only one file, just extract it
497
QString output_name = output_path +"/"+ preferred_output_name;
498
if (extractFile(zip, sub_files[0], output_name )) {
499
status->setText(tr("Subtitle saved as %1").arg(preferred_output_name));
500
emit subtitleDownloaded(output_name);
505
// More than one file
506
SubChooserDialog d(this);
508
for (int n=0; n < sub_files.count(); n++) {
509
d.addFile(sub_files[n]);
512
if (d.exec() == QDialog::Rejected) return false;
514
QStringList files_to_extract = d.selectedFiles();
515
int extracted_count = 0;
516
for (int n=0; n < files_to_extract.count(); n++) {
517
QString file = files_to_extract[n];
518
bool ok = extractFile(zip, file, output_path +"/"+ file);
519
qDebug("FindSubtitlesWindow::uncompressZip: extracted %s ok: %d", file.toUtf8().constData(), ok);
520
if (ok) extracted_count++;
522
status->setText(tr("%1 subtitle(s) extracted","", extracted_count).arg(extracted_count));
523
if (extracted_count > 0) {
524
emit subtitleDownloaded( output_path +"/"+ files_to_extract[0] );
532
bool FindSubtitlesWindow::extractFile(QuaZip & zip, const QString & filename, const QString & output_name) {
533
qDebug("FindSubtitlesWindow::extractFile: '%s', save as '%s'", filename.toUtf8().constData(), output_name.toUtf8().constData());
535
if (QFile::exists(output_name)) {
536
if (QMessageBox::question(this, tr("Overwrite?"),
537
tr("The file %1 already exits, overwrite?").arg(output_name), QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
543
if (!zip.setCurrentFile(filename)) {
544
qDebug("FindSubtitlesWindow::extractFile: can't select file %s", filename.toUtf8().constData());
550
QuaZipFile file(&zip);
551
QFile out(output_name);
553
if (!file.open(QIODevice::ReadOnly)) {
554
qWarning("FindSubtitlesWindow::extractFile: can't open file for reading: %d", file.getZipError());
558
if (out.open(QIODevice::WriteOnly)) {
559
// Slow like hell (on GNU/Linux at least), but it is not my fault.
560
// Not ZIP/UNZIP package's fault either.
561
// The slowest thing here is out.putChar(c).
562
while(file.getChar(&c)) out.putChar(c);
567
qWarning("FindSubtitlesWindow::extractFile: can't open %s for writing", output_name.toUtf8().constData());
576
void FindSubtitlesWindow::on_configure_button_clicked() {
577
qDebug("FindSubtitlesWindow::on_configure_button_clicked");
579
FindSubtitlesConfigDialog d(this);
581
d.setUseProxy( use_proxy );
582
d.setProxyHostname( proxy_host );
583
d.setProxyPort( proxy_port );
584
d.setProxyUsername( proxy_username );
585
d.setProxyPassword( proxy_password );
586
d.setProxyType( proxy_type );
588
if (d.exec() == QDialog::Accepted) {
589
use_proxy = d.useProxy();
590
proxy_host = d.proxyHostname();
591
proxy_port = d.proxyPort();
592
proxy_username = d.proxyUsername();
593
proxy_password = d.proxyPassword();
594
proxy_type = d.proxyType();
600
void FindSubtitlesWindow::setupProxy() {
603
if ( (use_proxy) && (!proxy_host.isEmpty()) ) {
604
proxy.setType((QNetworkProxy::ProxyType) proxy_type);
605
proxy.setHostName(proxy_host);
606
proxy.setPort(proxy_port);
607
if ( (!proxy_username.isEmpty()) && (!proxy_password.isEmpty()) ) {
608
proxy.setUser(proxy_username);
609
proxy.setPassword(proxy_password);
611
qDebug("FindSubtitlesWindow::userProxy: using proxy: host: %s, port: %d, type: %d",
612
proxy_host.toUtf8().constData(), proxy_port, proxy_type);
615
proxy.setType(QNetworkProxy::NoProxy);
616
qDebug("FindSubtitlesDialog::userProxy: no proxy");
622
void FindSubtitlesWindow::saveSettings() {
623
qDebug("FindSubtitlesWindow::saveSettings");
625
set->beginGroup("findsubtitles");
627
set->setValue("language", language());
629
set->setValue("include_lang_on_filename", includeLangOnFilename());
631
set->setValue("proxy/use_proxy", use_proxy);
632
set->setValue("proxy/type", proxy_type);
633
set->setValue("proxy/host", proxy_host);
634
set->setValue("proxy/port", proxy_port);
635
set->setValue("proxy/username", proxy_username);
636
set->setValue("proxy/password", proxy_password);
641
void FindSubtitlesWindow::loadSettings() {
642
qDebug("FindSubtitlesWindow::loadSettings");
644
set->beginGroup("findsubtitles");
646
setLanguage( set->value("language", language()).toString() );
648
setIncludeLangOnFilename( set->value("include_lang_on_filename", includeLangOnFilename()).toBool() );
650
use_proxy = set->value("proxy/use_proxy", use_proxy).toBool();
651
proxy_type = set->value("proxy/type", proxy_type).toInt();
652
proxy_host = set->value("proxy/host", proxy_host).toString();
653
proxy_port = set->value("proxy/port", proxy_port).toInt();
654
proxy_username = set->value("proxy/username", proxy_username).toString();
655
proxy_password = set->value("proxy/password", proxy_password).toString();
660
#include "moc_findsubtitleswindow.cpp"