webimagefetcher.cpp 6.42 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/**
 * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
 * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
 * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
18

19
#include "webimagefetcher.h"
20

21 22 23 24 25 26 27 28
#include <KApplication>
#include <KStatusBar>
#include <KXmlGuiWindow>
#include <KLocale>
#include <KInputDialog>
#include <KUrl>
#include <KDebug>
#include <KIO/Job>
29
#include <QPushButton>
30
#include <KDialog>
31

32
#include "covermanager.h"
33
#include "filehandle.h"
34
#include "tag.h"
35
#include "juk.h"
36

Laurent Montel's avatar
Laurent Montel committed
37
#include <QPixmap>
38 39 40
#include <QDomDocument>
#include <QDomElement>
#include <QPointer>
41 42 43
#include <QLayout>
#include <QLabel>
#include <QPainter>
44

45 46
#include <kiconloader.h>

Scott Wheeler's avatar
Scott Wheeler committed
47

48
class WebImageFetcher::Private
49
{
50
    friend class WebImageFetcher;
51

52
    Private() : connection(0), dialog(0)
53 54 55 56
    {
    }

    FileHandle file;
57 58
    QString artist;
    QString albumName;
59
    QPointer<KIO::StoredTransferJob> connection;
60 61
    KDialog *dialog;
    KUrl url;
62
};
Scott Wheeler's avatar
Scott Wheeler committed
63

64
WebImageFetcher::WebImageFetcher(QObject *parent)
65
        : QObject(parent), d(new Private)
66 67 68
{
}

69
WebImageFetcher::~WebImageFetcher()
70 71 72 73
{
    delete d;
}

74
void WebImageFetcher::setFile(const FileHandle &file)
75
{
76
    d->file = file;
77 78
    d->artist = file.tag()->artist();
    d->albumName = file.tag()->album();
79 80
}

81
void WebImageFetcher::abortSearch()
82
{
83
    if (d->connection)
84 85
        d->connection->kill();
}
86
void WebImageFetcher::searchCover()
87
{
88
    QStatusBar *statusBar = JuK::JuKInstance()->statusBar();
89
    statusBar->showMessage(i18n("Searching for cover. Please Wait..."));
90 91


92 93 94 95 96
    KUrl url("http://ws.audioscrobbler.com/2.0/");
    url.addQueryItem("method", "album.getInfo");
    url.addQueryItem("api_key", "3e6ecbd7284883089e8f2b5b53b0aecd");
    url.addQueryItem("artist", d->artist);
    url.addQueryItem("album", d->albumName);
97

98
    kDebug() << "Using request " << url.encodedPathAndQuery();
99

100
    d->connection = KIO::storedGet(url, KIO::Reload /* reload always */, KIO::HideProgressInfo);
Laurent Montel's avatar
Laurent Montel committed
101
    connect(d->connection, SIGNAL(result(KJob*)), SLOT(slotWebRequestFinished(KJob*)));
102 103 104 105

    // Wait for the results...
}

106
void WebImageFetcher::slotWebRequestFinished(KJob *job)
107
{
108
    kDebug() << "Results received.\n";
109

110
    if (job != d->connection)
111
        return;
112

113 114 115 116
    if (!job || job->error()) {
        kError() << "Error reading image results from last.fm!\n";
        kError() << d->connection->errorString() << endl;
        return;
117
    }
118

119
    kDebug() << "Checking for data!!\n";
120 121
    if (d->connection->data().isEmpty()) {
        kError() << "last.fm returned an empty result!\n";
122 123
        return;
    }
124

125
    QDomDocument results("ResultSet");
126

127 128
    QString errorStr;
    int errorCol, errorLine;
129 130 131
    if (!results.setContent(d->connection->data(), &errorStr, &errorLine, &errorCol)) {
        kError() << "Unable to create XML document from results.\n";
        kError() << "Line " << errorLine << ", " << errorStr << endl;
132

133
        return;
134
    }
135
    
136
    QDomNode n = results.documentElement();
137

138 139
    if (n.isNull()) {
        kDebug() << "No document root in XML results??\n";
Scott Wheeler's avatar
Scott Wheeler committed
140 141
        return;
    }
142
    n = n.firstChildElement("album");
143

144 145 146 147 148
    d->url = n.lastChildElement("image").text(); //FIXME: We assume they have a sane sorting (smallest -> largest)
    //TODO: size attribute can have the values mega, extralarge, large, medium and small
    
    kDebug() << "Got cover:" << d->url;

149
    QStatusBar *statusBar = JuK::JuKInstance()->statusBar();
150 151 152 153 154
    statusBar->showMessage(i18n("Downloading cover. Please Wait..."));
    
    KIO::StoredTransferJob *newJob = KIO::storedGet(d->url, KIO::Reload /* reload always */, KIO::HideProgressInfo);
    connect(newJob, SIGNAL(result(KJob*)), SLOT(slotImageFetched(KJob*)));
}
155

156 157
void WebImageFetcher::slotImageFetched(KJob* j)
{
158
    QStatusBar *statusBar = JuK::JuKInstance()->statusBar();
159
    statusBar->clearMessage();
160

161 162 163 164
    KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob*>(j);
    
    if (d->dialog) return;
    d->dialog = new KDialog();
Arnold Dumas's avatar
Arnold Dumas committed
165
    d->dialog->setCaption(i18n("Cover found"));
166 167 168 169 170 171 172 173 174 175 176
    d->dialog->setButtons(KDialog::Apply | KDialog::Cancel);
    d->dialog->button(KDialog::Apply)->setText(i18n("Store"));
    QWidget *mainWidget = new QWidget();
    d->dialog->setMainWidget(mainWidget);
    mainWidget->setLayout(new QVBoxLayout);
    
    if(job->error()) {
        kError() << "Unable to grab image\n";
        d->dialog->setWindowIcon(DesktopIcon("dialog-error"));
        return;
    }
177

178 179 180 181 182 183 184
    QPixmap iconImage, realImage(150, 150);
    iconImage.loadFromData(job->data());
    realImage.fill(Qt::transparent);

    if(iconImage.isNull()) {
        kError() << "Thumbnail image is not of a supported format\n";
        return;
Scott Wheeler's avatar
Scott Wheeler committed
185
    }
186

187 188 189 190 191 192 193 194 195 196 197 198 199 200
    // Scale down if necesssary
    if(iconImage.width() > 150 || iconImage.height() > 150)
        iconImage = iconImage.scaled(150, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation);

    QLabel *cover = new QLabel();
    cover->setPixmap(iconImage);
    mainWidget->layout()->addWidget(cover);
    QLabel *infoLabel = new QLabel(i18n("Cover fetched from <a href='http://last.fm/'>last.fm</a>."));
    infoLabel->setOpenExternalLinks(true);
    infoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
    mainWidget->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
    mainWidget->layout()->addWidget(infoLabel);
    
    d->dialog->setWindowIcon(realImage);
201
    d->dialog->show();
202
    connect(d->dialog, SIGNAL(applyClicked()), SLOT(slotCoverChosen()));
203 204
}

205 206

void WebImageFetcher::slotCoverChosen()
207
{
208
    kDebug() << "Adding new cover for " << d->file.tag()->fileName()
209
    << "from URL" << d->url;
210

211
    coverKey newId = CoverManager::addCover(d->url, d->file.tag()->artist(), d->file.tag()->album());
212

213
    if (newId != CoverManager::NoMatch) {
214 215
        emit signalCoverChanged(newId);
        d->dialog->close();
216 217
        d->dialog->deleteLater();
        d->dialog = 0;
218 219 220
    }
}

221
// vim: set et sw=4 tw=0 sta: