void UltimateLyricsProvider::lyricsFetched()
{
    NetworkJob *reply = qobject_cast<NetworkJob*>(sender());
    if (!reply) {
        return;
    }

    int id = requests.take(reply);
    reply->deleteLater();
    Song song=songs.take(id);

    if (!reply->ok()) {
        //emit Finished(id);
        emit lyricsReady(id, QString());
        return;
    }

    const QTextCodec *codec = QTextCodec::codecForName(charset.toLatin1().constData());
    const QString originalContent = codec->toUnicode(reply->readAll()).replace("<br />", "<br/>");

    DBUG << name << "response" << originalContent;
    // Check for invalid indicators
    for (const QString &indicator: invalidIndicators) {
        if (originalContent.contains(indicator)) {
            //emit Finished(id);
            DBUG << name << "invalid";
            emit lyricsReady(id, QString());
            return;
        }
    }

    QString lyrics;

    // Apply extract rules
    for (const Rule& rule: extractRules) {
        QString content = originalContent;
        applyExtractRule(rule, content, song);
        #ifndef Q_OS_WIN
        content.replace(QLatin1String("\r"), QLatin1String(""));
        #endif
        content=content.trimmed();

        if (!content.isEmpty()) {
            lyrics = content;
            break;
        }
    }

    // Apply exclude rules
    for (const Rule& rule: excludeRules) {
        applyExcludeRule(rule, lyrics, song);
    }

    lyrics=lyrics.trimmed();
    lyrics.replace("<br/>\n", "<br/>");
    lyrics.replace("<br>\n", "<br/>");
    DBUG << name << (lyrics.isEmpty() ? "empty" : "succeeded");
    emit lyricsReady(id, lyrics);
}
void UltimateLyricsProvider::wikiMediaLyricsFetched()
{
    NetworkJob *reply = qobject_cast<NetworkJob*>(sender());
    if (!reply) {
        return;
    }

    int id = requests.take(reply);
    reply->deleteLater();

    if (!reply->ok()) {
        emit lyricsReady(id, QString());
        return;
    }

    const QTextCodec *codec = QTextCodec::codecForName(charset.toLatin1().constData());
    QString contents = codec->toUnicode(reply->readAll()).replace("<br />", "<br/>");
    DBUG << name << "response" << contents;
    emit lyricsReady(id, extract(contents, QLatin1String("&lt;lyrics&gt;"), QLatin1String("&lt;/lyrics&gt;")));
}
void UltimateLyricsProvider::wikiMediaSearchResponse()
{
    NetworkJob *reply = qobject_cast<NetworkJob*>(sender());
    if (!reply) {
        return;
    }

    int id = requests.take(reply);
    reply->deleteLater();

    if (!reply->ok()) {
        emit lyricsReady(id, QString());
        return;
    }

    QUrl url;
    QXmlStreamReader doc(reply->actualJob());
    while (!doc.atEnd()) {
        doc.readNext();
        if (doc.isStartElement() && QLatin1String("url")==doc.name()) {
            QString lyricsUrl=doc.readElementText();
            if (!lyricsUrl.contains(QLatin1String("action=edit"))) {
                url=QUrl::fromEncoded(lyricsUrl.toUtf8()).toString();
            }
            break;
        }
    }

    if (url.isValid()) {
        QString path=url.path();
        QByteArray u=url.scheme().toLatin1()+"://"+url.host().toLatin1()+"/api.php?action=query&prop=revisions&rvprop=content&format=xml&titles=";
        QByteArray titles=QUrl::toPercentEncoding(path.startsWith(QLatin1Char('/')) ? path.mid(1) : path).replace('+', "%2b");
        NetworkJob *reply = NetworkAccessManager::self()->get(QUrl::fromEncoded(u+titles));
        requests[reply] = id;
        connect(reply, SIGNAL(finished()), this, SLOT(wikiMediaLyricsFetched()));
    } else {
        emit lyricsReady(id, QString());
    }
}
void UltimateLyricsProvider::fetchInfo(int id, const Song &metadata)
{
    #if QT_VERSION < 0x050000
    const QTextCodec *codec = QTextCodec::codecForName(charset.toAscii().constData());
    #else
    const QTextCodec *codec = QTextCodec::codecForName(charset.toLatin1().constData());
    #endif
    if (!codec) {
        emit lyricsReady(id, QString());
        return;
    }

    QString artistFixed=metadata.basicArtist();
    QString urlText(url);

    if (QLatin1String("lyrics.wikia.com")==name) {
        QUrl url(urlText);
        #if QT_VERSION < 0x050000
        QUrl &query=url;
        #else
        QUrlQuery query;
        #endif

        query.addQueryItem(QLatin1String("artist"), artistFixed);
        query.addQueryItem(QLatin1String("song"), metadata.title);
        query.addQueryItem(QLatin1String("func"), QLatin1String("getSong"));
        query.addQueryItem(QLatin1String("fmt"), QLatin1String("xml"));
        #if QT_VERSION >= 0x050000
        url.setQuery(query);
        #endif

        NetworkJob *reply = NetworkAccessManager::self()->get(url);
        requests[reply] = id;
        connect(reply, SIGNAL(finished()), this, SLOT(wikiMediaSearchResponse()));
        return;
    }

    songs.insert(id, metadata);

    // Fill in fields in the URL
    bool urlContainsDetails=urlText.contains(QLatin1Char('{'));
    if (urlContainsDetails) {
        doUrlReplace(constArtistArg, artistFixed, urlText);
        doUrlReplace(constArtistLowerArg, artistFixed.toLower(), urlText);
        doUrlReplace(constArtistLowerNoSpaceArg, noSpace(artistFixed.toLower()), urlText);
        doUrlReplace(constArtistFirstCharArg, firstChar(artistFixed), urlText);
        doUrlReplace(constAlbumArg, metadata.album, urlText);
        doUrlReplace(constAlbumLowerArg, metadata.album.toLower(), urlText);
        doUrlReplace(constAlbumLowerNoSpaceArg, noSpace(metadata.album.toLower()), urlText);
        doUrlReplace(constTitleArg, metadata.title, urlText);
        doUrlReplace(constTitleLowerArg, metadata.title.toLower(), urlText);
        doUrlReplace(constTitleCaseArg, titleCase(metadata.title), urlText);
        doUrlReplace(constYearArg, QString::number(metadata.year), urlText);
        doUrlReplace(constTrackNoArg, QString::number(metadata.track), urlText);
    }

    // For some reason Qt messes up the ? -> %3F and & -> %26 conversions - by placing 25 after the %
    // So, try and revert this...
    QUrl url(urlText);

    if (urlContainsDetails) {
        QByteArray data=url.toEncoded();
        data.replace("%253F", "%3F");
        data.replace("%253f", "%3f");
        data.replace("%2526", "%26");
        url=QUrl::fromEncoded(data, QUrl::StrictMode);
    }

    QNetworkRequest req(url);
    req.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0");
    NetworkJob *reply = NetworkAccessManager::self()->get(req);
    requests[reply] = id;
    connect(reply, SIGNAL(finished()), this, SLOT(lyricsFetched()));
}