Lazy load lyrics.xml
This commit is contained in:
committed by
craig.p.drummond
parent
674efaacff
commit
b2fb415aed
@@ -160,8 +160,7 @@ SET( CANTATA_SRCS
|
||||
lyrics/lyricspage.cpp
|
||||
lyrics/lyricsettings.cpp
|
||||
lyrics/ultimatelyricsprovider.cpp
|
||||
lyrics/ultimatelyricsreader.cpp
|
||||
lyrics/songinfoprovider.cpp
|
||||
lyrics/ultimatelyrics.cpp
|
||||
lyrics/lyricsdialog.cpp
|
||||
network/networkaccessmanager.cpp
|
||||
online/onlineservicespage.cpp
|
||||
@@ -229,8 +228,8 @@ SET( CANTATA_MOC_HDRS
|
||||
widgets/toolbar.h
|
||||
lyrics/lyricspage.h
|
||||
lyrics/lyricsettings.h
|
||||
lyrics/ultimatelyrics.h
|
||||
lyrics/ultimatelyricsprovider.h
|
||||
lyrics/songinfoprovider.h
|
||||
lyrics/lyricsdialog.h
|
||||
network/networkaccessmanager.h
|
||||
online/onlineservice.h
|
||||
|
||||
@@ -961,7 +961,7 @@ void MainWindow::mpdConnectionStateChanged(bool connected)
|
||||
emit playListInfo();
|
||||
emit outputs();
|
||||
if (CS_Init!=connectedState) {
|
||||
loaded=loaded&TAB_STREAMS ? TAB_STREAMS : 0;
|
||||
loaded=(loaded&TAB_STREAMS);
|
||||
currentTabChanged(tabWidget->current_index());
|
||||
}
|
||||
connectedState=CS_Connected;
|
||||
@@ -971,7 +971,7 @@ void MainWindow::mpdConnectionStateChanged(bool connected)
|
||||
updateWindowTitle();
|
||||
}
|
||||
} else {
|
||||
loaded=loaded&TAB_STREAMS ? TAB_STREAMS : 0;
|
||||
loaded=(loaded&TAB_STREAMS);
|
||||
libraryPage->clear();
|
||||
albumsPage->clear();
|
||||
folderPage->clear();
|
||||
@@ -1101,7 +1101,7 @@ void MainWindow::showPreferencesDialog()
|
||||
}
|
||||
#endif
|
||||
|
||||
PreferencesDialog *pref=new PreferencesDialog(this, lyricsPage);
|
||||
PreferencesDialog *pref=new PreferencesDialog(this);
|
||||
controlConnectionsMenu(false);
|
||||
connect(pref, SIGNAL(settingsSaved()), this, SLOT(updateSettings()));
|
||||
connect(pref, SIGNAL(connectTo(const MPDConnectionDetails &)), this, SLOT(connectToMpd(const MPDConnectionDetails &)));
|
||||
@@ -1270,7 +1270,6 @@ void MainWindow::readSettings()
|
||||
#ifdef ENABLE_DEVICES_SUPPORT
|
||||
StdActions::self()->deleteSongsAction->setVisible(Settings::self()->showDeleteAction());
|
||||
#endif
|
||||
lyricsPage->setEnabledProviders(Settings::self()->lyricProviders());
|
||||
MPDParseUtils::setGroupSingle(Settings::self()->groupSingle());
|
||||
MPDParseUtils::setGroupMultiple(Settings::self()->groupMultiple());
|
||||
albumsPage->setView(Settings::self()->albumsView());
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "httpserversettings.h"
|
||||
#endif
|
||||
#include "lyricsettings.h"
|
||||
#include "lyricspage.h"
|
||||
#include "cachesettings.h"
|
||||
#include "localize.h"
|
||||
#include "mpdconnection.h"
|
||||
@@ -55,7 +54,7 @@ int PreferencesDialog::instanceCount()
|
||||
return iCount;
|
||||
}
|
||||
|
||||
PreferencesDialog::PreferencesDialog(QWidget *parent, LyricsPage *lp)
|
||||
PreferencesDialog::PreferencesDialog(QWidget *parent)
|
||||
: Dialog(parent)
|
||||
{
|
||||
iCount++;
|
||||
@@ -74,8 +73,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent, LyricsPage *lp)
|
||||
playback->load();
|
||||
files->load();
|
||||
interface->load();
|
||||
const QList<UltimateLyricsProvider *> &lprov=lp->getProviders();
|
||||
lyrics->Load(lprov);
|
||||
lyrics->load();
|
||||
widget->addPage(server, i18n("Connection"), Icons::libraryIcon, i18n("Connection Settings"));
|
||||
widget->addPage(serverplayback, i18n("Output"), Icons::speakerIcon, i18n("Output Settings"));
|
||||
widget->addPage(playback, i18n("Playback"), Icon("media-playback-start"), i18n("Playback Settings"));
|
||||
@@ -134,7 +132,7 @@ void PreferencesDialog::writeSettings()
|
||||
#if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND
|
||||
audiocd->save();
|
||||
#endif
|
||||
Settings::self()->saveLyricProviders(lyrics->EnabledProviders());
|
||||
lyrics->save();
|
||||
Settings::self()->save();
|
||||
emit settingsSaved();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ class PlaybackSettings;
|
||||
class FileSettings;
|
||||
class InterfaceSettings;
|
||||
class LyricSettings;
|
||||
class LyricsPage;
|
||||
#ifdef TAGLIB_FOUND
|
||||
class HttpServerSettings;
|
||||
#endif
|
||||
@@ -54,7 +53,7 @@ class PreferencesDialog : public Dialog
|
||||
public:
|
||||
static int instanceCount();
|
||||
|
||||
PreferencesDialog(QWidget *parent, LyricsPage *lp);
|
||||
PreferencesDialog(QWidget *parent);
|
||||
virtual ~PreferencesDialog();
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,86 +22,80 @@
|
||||
*/
|
||||
|
||||
#include "lyricsettings.h"
|
||||
//#include "songinfoview.h"
|
||||
#include "ultimatelyricsprovider.h"
|
||||
#include "ultimatelyrics.h"
|
||||
#include "ui_lyricsettings.h"
|
||||
#include "localize.h"
|
||||
#include "icon.h"
|
||||
#include "config.h"
|
||||
#include "settings.h"
|
||||
|
||||
LyricSettings::LyricSettings(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
ui_(new Ui_LyricSettings)
|
||||
LyricSettings::LyricSettings(QWidget *p)
|
||||
: QWidget(p)
|
||||
{
|
||||
ui_->setupUi(this);
|
||||
|
||||
connect(ui_->up, SIGNAL(clicked()), SLOT(MoveUp()));
|
||||
connect(ui_->down, SIGNAL(clicked()), SLOT(MoveDown()));
|
||||
connect(ui_->providers, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
||||
SLOT(CurrentItemChanged(QListWidgetItem*)));
|
||||
// connect(ui_->providers, SIGNAL(itemChanged(QListWidgetItem*)),
|
||||
// SLOT(ItemChanged(QListWidgetItem*)));
|
||||
ui_->up->setIcon(Icon("arrow-up"));
|
||||
ui_->down->setIcon(Icon("arrow-down"));
|
||||
setupUi(this);
|
||||
connect(up, SIGNAL(clicked()), SLOT(moveUp()));
|
||||
connect(down, SIGNAL(clicked()), SLOT(moveDown()));
|
||||
connect(providers, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
||||
SLOT(currentItemChanged(QListWidgetItem*)));
|
||||
up->setIcon(Icon("arrow-up"));
|
||||
down->setIcon(Icon("arrow-down"));
|
||||
}
|
||||
|
||||
LyricSettings::~LyricSettings() {
|
||||
delete ui_;
|
||||
void LyricSettings::load()
|
||||
{
|
||||
const QList<UltimateLyricsProvider *> &lprov=UltimateLyrics::self()->getProviders();
|
||||
|
||||
providers->clear();
|
||||
foreach (const UltimateLyricsProvider *provider, lprov) {
|
||||
QListWidgetItem *item = new QListWidgetItem(providers);
|
||||
QString name(provider->getName());
|
||||
name.replace("(POLISH)", i18n("(Polish Translations)"));
|
||||
name.replace("(PORTUGUESE)", i18n("(Portuguese Translations)"));
|
||||
item->setText(name);
|
||||
item->setData(Qt::UserRole, provider->getName());
|
||||
item->setCheckState(provider->isEnabled() ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void LyricSettings::Load(const QList<UltimateLyricsProvider*> &providers) {
|
||||
ui_->providers->clear();
|
||||
foreach (const UltimateLyricsProvider* provider, providers) {
|
||||
QListWidgetItem* item = new QListWidgetItem(ui_->providers);
|
||||
QString name(provider->name());
|
||||
name.replace("(POLISH)", i18n("(Polish Translations)"));
|
||||
name.replace("(PORTUGUESE)", i18n("(Portuguese Translations)"));
|
||||
item->setText(name);
|
||||
item->setData(Qt::UserRole, provider->name());
|
||||
item->setCheckState(provider->is_enabled() ? Qt::Checked : Qt::Unchecked);
|
||||
// item->setForeground(provider->is_enabled() ? palette().color(QPalette::Active, QPalette::Text)
|
||||
// : palette().color(QPalette::Disabled, QPalette::Text));
|
||||
}
|
||||
void LyricSettings::save()
|
||||
{
|
||||
QStringList enabled;
|
||||
for (int i=0 ; i<providers->count() ; ++i) {
|
||||
const QListWidgetItem* item = providers->item(i);
|
||||
if (Qt::Checked==item->checkState()) {
|
||||
enabled << item->data(Qt::UserRole).toString();
|
||||
}
|
||||
}
|
||||
UltimateLyrics::self()->setEnabled(enabled);
|
||||
}
|
||||
|
||||
QStringList LyricSettings::EnabledProviders() {
|
||||
QStringList providers;
|
||||
for (int i=0 ; i<ui_->providers->count() ; ++i) {
|
||||
const QListWidgetItem* item = ui_->providers->item(i);
|
||||
if (item->checkState() == Qt::Checked)
|
||||
providers << item->data(Qt::UserRole).toString();
|
||||
}
|
||||
return providers;
|
||||
void LyricSettings::currentItemChanged(QListWidgetItem *item)
|
||||
{
|
||||
if (!item) {
|
||||
up->setEnabled(false);
|
||||
down->setEnabled(false);
|
||||
} else {
|
||||
const int row = providers->row(item);
|
||||
up->setEnabled(row != 0);
|
||||
down->setEnabled(row != providers->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void LyricSettings::CurrentItemChanged(QListWidgetItem* item) {
|
||||
if (!item) {
|
||||
ui_->up->setEnabled(false);
|
||||
ui_->down->setEnabled(false);
|
||||
} else {
|
||||
const int row = ui_->providers->row(item);
|
||||
ui_->up->setEnabled(row != 0);
|
||||
ui_->down->setEnabled(row != ui_->providers->count() - 1);
|
||||
}
|
||||
void LyricSettings::moveUp()
|
||||
{
|
||||
move(-1);
|
||||
}
|
||||
|
||||
void LyricSettings::MoveUp() {
|
||||
Move(-1);
|
||||
void LyricSettings::moveDown()
|
||||
{
|
||||
move(+1);
|
||||
}
|
||||
|
||||
void LyricSettings::MoveDown() {
|
||||
Move(+1);
|
||||
void LyricSettings::move(int d)
|
||||
{
|
||||
const int row = providers->currentRow();
|
||||
QListWidgetItem* item = providers->takeItem(row);
|
||||
providers->insertItem(row + d, item);
|
||||
providers->setCurrentRow(row + d);
|
||||
}
|
||||
|
||||
void LyricSettings::Move(int d) {
|
||||
const int row = ui_->providers->currentRow();
|
||||
QListWidgetItem* item = ui_->providers->takeItem(row);
|
||||
ui_->providers->insertItem(row + d, item);
|
||||
ui_->providers->setCurrentRow(row + d);
|
||||
}
|
||||
|
||||
// void LyricSettings::ItemChanged(QListWidgetItem* item) {
|
||||
// const bool checked = item->checkState() == Qt::Checked;
|
||||
// item->setForeground(checked ? palette().color(QPalette::Active, QPalette::Text)
|
||||
// : palette().color(QPalette::Disabled, QPalette::Text));
|
||||
// }
|
||||
|
||||
@@ -27,34 +27,27 @@
|
||||
#include <QWidget>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include "ui_lyricsettings.h"
|
||||
|
||||
class Ui_LyricSettings;
|
||||
class QListWidgetItem;
|
||||
class UltimateLyricsProvider;
|
||||
|
||||
class LyricSettings : public QWidget
|
||||
class LyricSettings : public QWidget, private Ui::LyricSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LyricSettings(QWidget *parent = 0);
|
||||
~LyricSettings();
|
||||
LyricSettings(QWidget *p);
|
||||
virtual ~LyricSettings() { }
|
||||
|
||||
QStringList EnabledProviders();
|
||||
|
||||
public Q_SLOTS:
|
||||
void Load(const QList<UltimateLyricsProvider*> &providers);
|
||||
void load();
|
||||
void save();
|
||||
|
||||
private Q_SLOTS:
|
||||
void MoveUp();
|
||||
void MoveDown();
|
||||
void Move(int d);
|
||||
|
||||
void CurrentItemChanged(QListWidgetItem* item);
|
||||
// void ItemChanged(QListWidgetItem* item);
|
||||
|
||||
private:
|
||||
Ui_LyricSettings* ui_;
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
void move(int d);
|
||||
void currentItemChanged(QListWidgetItem *item);
|
||||
};
|
||||
|
||||
#endif // LYRICSETTINGS_H
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "songinfoprovider.h"
|
||||
#include "lyricspage.h"
|
||||
#include "lyricsdialog.h"
|
||||
#include "ultimatelyricsprovider.h"
|
||||
#include "ultimatelyricsreader.h"
|
||||
#include "ultimatelyrics.h"
|
||||
#include "settings.h"
|
||||
#include "squeezedtextlabel.h"
|
||||
#include "utils.h"
|
||||
@@ -62,32 +61,14 @@ static QString cacheFile(QString artist, QString title, bool createDir=false)
|
||||
return QDir::toNativeSeparators(Utils::cacheDir(LyricsPage::constLyricsDir+artist+'/', createDir))+title+LyricsPage::constExtension;
|
||||
}
|
||||
|
||||
typedef QList<UltimateLyricsProvider *> ProviderList;
|
||||
|
||||
bool CompareLyricProviders(const UltimateLyricsProvider* a, const UltimateLyricsProvider* b) {
|
||||
return a->relevance() < b->relevance();
|
||||
}
|
||||
|
||||
LyricsPage::LyricsPage(QWidget *p)
|
||||
: QWidget(p)
|
||||
// , reader(new UltimateLyricsReader(this))
|
||||
, currentProvider(-1)
|
||||
, currentRequest(0)
|
||||
, mode(Mode_Display)
|
||||
, job(0)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
providers=UltimateLyricsReader().Parse(QString(":lyrics.xml"));
|
||||
foreach (UltimateLyricsProvider* provider, providers) {
|
||||
connect(provider, SIGNAL(InfoReady(int, const QString &)), SLOT(resultReady(int, const QString &)));
|
||||
}
|
||||
|
||||
// Parse the ultimate lyrics xml file in the background
|
||||
// QFuture<ProviderList> future = QtConcurrent::run(reader.data(), &UltimateLyricsReader::Parse,
|
||||
// QString(":lyrics.xml"));
|
||||
// QFutureWatcher<ProviderList> *watcher = new QFutureWatcher<ProviderList>(this);
|
||||
// watcher->setFuture(future);
|
||||
// connect(watcher, SIGNAL(finished()), SLOT(ultimateLyricsParsed()));
|
||||
refreshAction = ActionCollection::get()->createAction("refreshlyrics", i18n("Refresh"), "view-refresh");
|
||||
searchAction = ActionCollection::get()->createAction("searchlyrics", i18n("Search For Lyrics"), "edit-find");
|
||||
editAction = ActionCollection::get()->createAction("editlyrics", i18n("Edit Lyrics"), Icons::editIcon);
|
||||
@@ -101,6 +82,7 @@ LyricsPage::LyricsPage(QWidget *p)
|
||||
connect(saveAction, SIGNAL(triggered()), SLOT(save()));
|
||||
connect(cancelAction, SIGNAL(triggered()), SLOT(cancel()));
|
||||
connect(delAction, SIGNAL(triggered()), SLOT(del()));
|
||||
connect(UltimateLyrics::self(), SIGNAL(lyricsReady(int, const QString &)), SLOT(lyricsReady(int, const QString &)));
|
||||
Icon::init(refreshBtn);
|
||||
Icon::init(searchBtn);
|
||||
Icon::init(editBtn);
|
||||
@@ -120,9 +102,7 @@ LyricsPage::LyricsPage(QWidget *p)
|
||||
|
||||
LyricsPage::~LyricsPage()
|
||||
{
|
||||
foreach (UltimateLyricsProvider* provider, providers) {
|
||||
delete provider;
|
||||
}
|
||||
UltimateLyrics::self()->release();
|
||||
}
|
||||
|
||||
void LyricsPage::saveSettings()
|
||||
@@ -130,25 +110,6 @@ void LyricsPage::saveSettings()
|
||||
Settings::self()->saveLyricsZoom(text->zoom());
|
||||
}
|
||||
|
||||
void LyricsPage::setEnabledProviders(const QStringList &providerList)
|
||||
{
|
||||
foreach (UltimateLyricsProvider* provider, providers) {
|
||||
provider->set_enabled(false);
|
||||
provider->set_relevance(0xFFFF);
|
||||
}
|
||||
|
||||
int relevance=0;
|
||||
foreach (const QString &p, providerList) {
|
||||
UltimateLyricsProvider *provider=providerByName(p);
|
||||
if (provider) {
|
||||
provider->set_enabled(true);
|
||||
provider->set_relevance(relevance++);
|
||||
}
|
||||
}
|
||||
|
||||
qSort(providers.begin(), providers.end(), CompareLyricProviders);
|
||||
}
|
||||
|
||||
void LyricsPage::update()
|
||||
{
|
||||
QString mpdName=mpdFileName();
|
||||
@@ -367,7 +328,7 @@ void LyricsPage::downloadFinished()
|
||||
getLyrics();
|
||||
}
|
||||
|
||||
void LyricsPage::resultReady(int id, const QString &lyrics)
|
||||
void LyricsPage::lyricsReady(int id, const QString &lyrics)
|
||||
{
|
||||
if (id != currentRequest)
|
||||
return;
|
||||
@@ -412,38 +373,21 @@ QString LyricsPage::cacheFileName() const
|
||||
return currentSong.artist.isEmpty() || currentSong.title.isEmpty() ? QString() : cacheFile(currentSong.artist, currentSong.title);
|
||||
}
|
||||
|
||||
UltimateLyricsProvider* LyricsPage::providerByName(const QString &name) const
|
||||
{
|
||||
foreach (UltimateLyricsProvider* provider, providers) {
|
||||
if (provider->name() == name) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LyricsPage::getLyrics()
|
||||
{
|
||||
for(;;) {
|
||||
currentProvider++;
|
||||
if (currentProvider<providers.count()) {
|
||||
UltimateLyricsProvider *prov=providers.at(currentProvider++);
|
||||
if (prov && prov->is_enabled()) {
|
||||
text->setText(i18nc("<title> by <artist>\nFetching lyrics via <url>", "%1 by %2\nFetching lyrics via %3")
|
||||
.arg(currentSong.title).arg(currentSong.artist, prov->name()));
|
||||
prov->FetchInfo(currentRequest, currentSong);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
text->setText(i18nc("<title> by <artist>\nFailed\n", "%1 by %2\nFailed to fetch lyrics").arg(currentSong.title).arg(currentSong.artist));
|
||||
currentProvider=-1;
|
||||
// Set lyrics file anyway - so that editing is enabled!
|
||||
lyricsFile=Settings::self()->storeLyricsInMpdDir()
|
||||
? Utils::changeExtension(MPDConnection::self()->getDetails().dir+currentSong.file, constExtension)
|
||||
: cacheFile(currentSong.artist, currentSong.title);
|
||||
setMode(Mode_Display);
|
||||
return;
|
||||
}
|
||||
UltimateLyricsProvider *prov=UltimateLyrics::self()->getNext(currentProvider);
|
||||
if (prov) {
|
||||
text->setText(i18nc("<title> by <artist>\nFetching lyrics via <url>", "%1 by %2\nFetching lyrics via %3")
|
||||
.arg(currentSong.title).arg(currentSong.artist, prov->getName()));
|
||||
prov->fetchInfo(currentRequest, currentSong);
|
||||
} else {
|
||||
text->setText(i18nc("<title> by <artist>\nFailed\n", "%1 by %2\nFailed to fetch lyrics").arg(currentSong.title).arg(currentSong.artist));
|
||||
currentProvider=-1;
|
||||
// Set lyrics file anyway - so that editing is enabled!
|
||||
lyricsFile=Settings::self()->storeLyricsInMpdDir()
|
||||
? Utils::changeExtension(MPDConnection::self()->getDetails().dir+currentSong.file, constExtension)
|
||||
: cacheFile(currentSong.artist, currentSong.title);
|
||||
setMode(Mode_Display);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,18 +426,3 @@ bool LyricsPage::setLyricsFromFile(const QString &filePath) const
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// void LyricsPage::ultimateLyricsParsed()
|
||||
// {
|
||||
// QFutureWatcher<ProviderList>* watcher = static_cast<QFutureWatcher<ProviderList>*>(sender());
|
||||
// QStringList names;
|
||||
//
|
||||
// foreach (UltimateLyricsProvider* provider, watcher->result()) {
|
||||
// providers.append(provider);
|
||||
// connect(provider, SIGNAL(InfoReady(int, const QString &)), SLOT(resultReady(int, const QString &)));
|
||||
// }
|
||||
//
|
||||
// watcher->deleteLater();
|
||||
// reader.reset();
|
||||
// emit providersUpdated();
|
||||
// }
|
||||
|
||||
@@ -25,13 +25,11 @@
|
||||
#define LYRICSPAGE_H
|
||||
|
||||
#include <QWidget>
|
||||
// #include <QScopedPointer>
|
||||
#include "song.h"
|
||||
#include "ui_lyricspage.h"
|
||||
#include "textbrowser.h"
|
||||
|
||||
class UltimateLyricsProvider;
|
||||
// class UltimateLyricsReader;
|
||||
class UltimateLyricsProvider;
|
||||
class QImage;
|
||||
class Action;
|
||||
@@ -55,9 +53,7 @@ public:
|
||||
~LyricsPage();
|
||||
|
||||
void saveSettings();
|
||||
void setEnabledProviders(const QStringList &providerList);
|
||||
void update(const Song &song, bool force=false);
|
||||
const QList<UltimateLyricsProvider *> & getProviders() { return providers; }
|
||||
void setBgndImageEnabled(bool e) { text->enableImage(e); }
|
||||
bool bgndImageEnabled() { return text->imageEnabled(); }
|
||||
|
||||
@@ -69,7 +65,7 @@ public Q_SLOTS:
|
||||
|
||||
protected Q_SLOTS:
|
||||
void downloadFinished();
|
||||
void resultReady(int id, const QString &lyrics);
|
||||
void lyricsReady(int, const QString &lyrics);
|
||||
void update();
|
||||
void search();
|
||||
void edit();
|
||||
@@ -80,7 +76,6 @@ protected Q_SLOTS:
|
||||
private:
|
||||
QString mpdFileName() const;
|
||||
QString cacheFileName() const;
|
||||
UltimateLyricsProvider * providerByName(const QString &name) const;
|
||||
void getLyrics();
|
||||
void setMode(Mode m);
|
||||
bool saveFile(const QString &fileName);
|
||||
@@ -95,12 +90,7 @@ private:
|
||||
*/
|
||||
bool setLyricsFromFile(const QString &filePath) const;
|
||||
|
||||
// private Q_SLOTS:
|
||||
// void ultimateLyricsParsed();
|
||||
|
||||
private:
|
||||
// QScopedPointer<UltimateLyricsReader> reader;
|
||||
QList<UltimateLyricsProvider *> providers;
|
||||
int currentProvider;
|
||||
int currentRequest;
|
||||
Song currentSong;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
*/
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "songinfoprovider.h"
|
||||
|
||||
SongInfoProvider::SongInfoProvider()
|
||||
: enabled_(true)
|
||||
{
|
||||
}
|
||||
|
||||
QString SongInfoProvider::name() const {
|
||||
return metaObject()->className();
|
||||
}
|
||||
202
lyrics/ultimatelyrics.cpp
Normal file
202
lyrics/ultimatelyrics.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
*/
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ultimatelyrics.h"
|
||||
#include "ultimatelyricsprovider.h"
|
||||
#include "settings.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QXmlStreamReader>
|
||||
#ifdef ENABLE_KDE_SUPPORT
|
||||
#include <KDE/KGlobal>
|
||||
K_GLOBAL_STATIC(UltimateLyrics, instance)
|
||||
#endif
|
||||
|
||||
static bool compareLyricProviders(const UltimateLyricsProvider *a, const UltimateLyricsProvider *b)
|
||||
{
|
||||
return a->getRelevance() < b->getRelevance();
|
||||
}
|
||||
|
||||
static QString parseInvalidIndicator(QXmlStreamReader *reader)
|
||||
{
|
||||
QString ret = reader->attributes().value("value").toString();
|
||||
reader->skipCurrentElement();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UltimateLyricsProvider::Rule parseRule(QXmlStreamReader *reader)
|
||||
{
|
||||
UltimateLyricsProvider::Rule ret;
|
||||
|
||||
while (!reader->atEnd()) {
|
||||
reader->readNext();
|
||||
|
||||
if (QXmlStreamReader::EndElement==reader->tokenType()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (QXmlStreamReader::StartElement==reader->tokenType()) {
|
||||
if (QLatin1String("item")==reader->name()) {
|
||||
QXmlStreamAttributes attr = reader->attributes();
|
||||
if (attr.hasAttribute("tag")) {
|
||||
ret << UltimateLyricsProvider::RuleItem(attr.value("tag").toString(), QString());
|
||||
} else if (attr.hasAttribute("begin")) {
|
||||
ret << UltimateLyricsProvider::RuleItem(attr.value("begin").toString(), attr.value("end").toString());
|
||||
}
|
||||
}
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UltimateLyricsProvider * parseProvider(QXmlStreamReader *reader)
|
||||
{
|
||||
QXmlStreamAttributes attributes = reader->attributes();
|
||||
|
||||
UltimateLyricsProvider* scraper = new UltimateLyricsProvider;
|
||||
scraper->setName(attributes.value("name").toString());
|
||||
scraper->setTitle(attributes.value("title").toString());
|
||||
scraper->setCharset(attributes.value("charset").toString());
|
||||
scraper->setUrl(attributes.value("url").toString());
|
||||
|
||||
while (!reader->atEnd()) {
|
||||
reader->readNext();
|
||||
|
||||
if (QXmlStreamReader::EndElement==reader->tokenType()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (QXmlStreamReader::StartElement==reader->tokenType()) {
|
||||
if (QLatin1String("extract")==reader->name()) {
|
||||
scraper->addExtractRule(parseRule(reader));
|
||||
} else if (QLatin1String("exclude")==reader->name()) {
|
||||
scraper->addExcludeRule(parseRule(reader));
|
||||
} else if (QLatin1String("invalidIndicator")==reader->name()) {
|
||||
scraper->addInvalidIndicator(parseInvalidIndicator(reader));
|
||||
} else if (QLatin1String("urlFormat")==reader->name()) {
|
||||
scraper->addUrlFormat(reader->attributes().value("replace").toString(), reader->attributes().value("with").toString());
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
return scraper;
|
||||
}
|
||||
|
||||
UltimateLyrics * UltimateLyrics::self()
|
||||
{
|
||||
#ifdef ENABLE_KDE_SUPPORT
|
||||
return instance;
|
||||
#else
|
||||
static UltimateLyrics *instance=0;
|
||||
if(!instance) {
|
||||
instance=new UltimateLyrics;
|
||||
}
|
||||
return instance;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UltimateLyrics::release()
|
||||
{
|
||||
foreach (UltimateLyricsProvider *provider, providers) {
|
||||
delete provider;
|
||||
}
|
||||
providers.clear();
|
||||
}
|
||||
|
||||
const QList<UltimateLyricsProvider *> UltimateLyrics::getProviders()
|
||||
{
|
||||
load();
|
||||
return providers;
|
||||
}
|
||||
|
||||
UltimateLyricsProvider * UltimateLyrics::providerByName(const QString &name) const
|
||||
{
|
||||
foreach (UltimateLyricsProvider *provider, providers) {
|
||||
if (provider->getName() == name) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
UltimateLyricsProvider * UltimateLyrics::getNext(int &index)
|
||||
{
|
||||
load();
|
||||
index++;
|
||||
if (index>-1 && index<providers.count()) {
|
||||
for (int i=index; i<providers.count(); ++i) {
|
||||
if (providers.at(i)->isEnabled()) {
|
||||
index=i;
|
||||
return providers.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UltimateLyrics::load()
|
||||
{
|
||||
if (!providers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(":lyrics.xml");
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QXmlStreamReader reader(&file);
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
|
||||
if (QLatin1String("provider")==reader.name()) {
|
||||
UltimateLyricsProvider *provider = parseProvider(&reader);
|
||||
if (provider) {
|
||||
providers << provider;
|
||||
connect(provider, SIGNAL(lyricsReady(int,QString)), this, SIGNAL(lyricsReady(int,QString)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setEnabled(Settings::self()->lyricProviders());
|
||||
}
|
||||
|
||||
void UltimateLyrics::setEnabled(const QStringList &enabled)
|
||||
{
|
||||
foreach (UltimateLyricsProvider *provider, providers) {
|
||||
provider->setEnabled(false);
|
||||
provider->setRelevance(0xFFFF);
|
||||
}
|
||||
|
||||
int relevance=0;
|
||||
foreach (const QString &p, enabled) {
|
||||
UltimateLyricsProvider *provider=providerByName(p);
|
||||
if (provider) {
|
||||
provider->setEnabled(true);
|
||||
provider->setRelevance(relevance++);
|
||||
}
|
||||
}
|
||||
qSort(providers.begin(), providers.end(), compareLyricProviders);
|
||||
Settings::self()->saveLyricProviders(enabled);
|
||||
}
|
||||
@@ -21,38 +21,35 @@
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SONGINFOPROVIDER_H
|
||||
#define SONGINFOPROVIDER_H
|
||||
#ifndef ULTIMATELYRICS_H
|
||||
#define ULTIMATELYRICS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
|
||||
//#include "collapsibleinfopane.h"
|
||||
//#include "core/song.h"
|
||||
class UltimateLyricsProvider;
|
||||
|
||||
class Song;
|
||||
|
||||
class SongInfoProvider : public QObject {
|
||||
Q_OBJECT
|
||||
class UltimateLyrics : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SongInfoProvider();
|
||||
static UltimateLyrics * self();
|
||||
UltimateLyrics() { }
|
||||
|
||||
virtual void FetchInfo(int id, const Song& metadata) = 0;
|
||||
// virtual void Cancel(int id) {}
|
||||
UltimateLyricsProvider * getNext(int &index);
|
||||
const QList<UltimateLyricsProvider *> getProviders();
|
||||
void release();
|
||||
void setEnabled(const QStringList &enabled);
|
||||
|
||||
virtual QString name() const;
|
||||
|
||||
bool is_enabled() const { return enabled_; }
|
||||
void set_enabled(bool enabled) { enabled_ = enabled; }
|
||||
|
||||
signals:
|
||||
void ImageReady(int id, const QUrl& url);
|
||||
void InfoReady(int id, const QString& data);
|
||||
void Finished(int id);
|
||||
Q_SIGNALS:
|
||||
void lyricsReady(int id, const QString &data);
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
UltimateLyricsProvider * providerByName(const QString &name) const;
|
||||
void load();
|
||||
|
||||
private:
|
||||
QList<UltimateLyricsProvider *> providers;
|
||||
};
|
||||
|
||||
#endif // SONGINFOPROVIDER_H
|
||||
#endif // ULTIMATELYRICS_H
|
||||
@@ -21,37 +21,121 @@
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include "songinfotextview.h"
|
||||
#include "ultimatelyricsprovider.h"
|
||||
#include "networkaccessmanager.h"
|
||||
//#include "core/network.h"
|
||||
#include "song.h"
|
||||
#include <QNetworkReply>
|
||||
#include <QTextCodec>
|
||||
//#include <boost/scoped_ptr.hpp>
|
||||
|
||||
const int UltimateLyricsProvider::kRedirectLimit = 5;
|
||||
static const int constRedirectLimit=5;
|
||||
|
||||
static QString extract(const QString &source, const QString &begin, const QString &end)
|
||||
{
|
||||
int beginIdx = source.indexOf(begin);
|
||||
if (-1==beginIdx) {
|
||||
return QString();
|
||||
}
|
||||
beginIdx += begin.length();
|
||||
|
||||
int endIdx = source.indexOf(end, beginIdx);
|
||||
if (-1==endIdx) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return source.mid(beginIdx, endIdx - beginIdx - 1);
|
||||
}
|
||||
|
||||
static QString extractXmlTag(const QString &source, const QString &tag)
|
||||
{
|
||||
QRegExp re("<(\\w+).*>"); // ಠ_ಠ
|
||||
if (-1==re.indexIn(tag)) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return extract(source, tag, "</" + re.cap(1) + ">");
|
||||
}
|
||||
|
||||
static QString exclude(const QString &source, const QString &begin, const QString &end)
|
||||
{
|
||||
int beginIdx = source.indexOf(begin);
|
||||
if (-1==beginIdx) {
|
||||
return source;
|
||||
}
|
||||
|
||||
int endIdx = source.indexOf(end, beginIdx + begin.length());
|
||||
if (-1==endIdx) {
|
||||
return source;
|
||||
}
|
||||
|
||||
return source.left(beginIdx) + source.right(source.length() - endIdx - end.length());
|
||||
}
|
||||
|
||||
static QString excludeXmlTag(const QString &source, const QString &tag)
|
||||
{
|
||||
QRegExp re("<(\\w+).*>"); // ಠ_ಠ
|
||||
if (-1==re.indexIn(tag)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
return exclude(source, tag, "</" + re.cap(1) + ">");
|
||||
}
|
||||
|
||||
static void applyExtractRule(const UltimateLyricsProvider::Rule &rule, QString *content)
|
||||
{
|
||||
foreach (const UltimateLyricsProvider::RuleItem& item, rule) {
|
||||
if (item.second.isNull()) {
|
||||
*content = extractXmlTag(*content, item.first);
|
||||
} else {
|
||||
*content = extract(*content, item.first, item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void applyExcludeRule(const UltimateLyricsProvider::Rule &rule, QString *content)
|
||||
{
|
||||
foreach (const UltimateLyricsProvider::RuleItem& item, rule) {
|
||||
if (item.second.isNull()) {
|
||||
*content = excludeXmlTag(*content, item.first);
|
||||
} else {
|
||||
*content = exclude(*content, item.first, item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QString firstChar(const QString &text)
|
||||
{
|
||||
return text.isEmpty() ? text : text[0].toLower();
|
||||
}
|
||||
|
||||
static QString titleCase(const QString &text)
|
||||
{
|
||||
if (0==text.length()) {
|
||||
return QString();
|
||||
}
|
||||
if (1==text.length()) {
|
||||
return text[0].toUpper();
|
||||
}
|
||||
return text[0].toUpper() + text.right(text.length() - 1).toLower();
|
||||
}
|
||||
|
||||
UltimateLyricsProvider::UltimateLyricsProvider()
|
||||
: relevance_(0),
|
||||
redirect_count_(0)
|
||||
: enabled(true)
|
||||
, relevance(0)
|
||||
, redirectCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void UltimateLyricsProvider::FetchInfo(int id, const Song& metadata) {
|
||||
// Get the text codec
|
||||
#if QT_VERSION < 0x050000
|
||||
const QTextCodec* codec = QTextCodec::codecForName(charset_.toAscii().constData());
|
||||
#else
|
||||
const QTextCodec* codec = QTextCodec::codecForName(charset_.toLatin1().constData());
|
||||
#endif
|
||||
if (!codec) {
|
||||
//qWarning() << "Invalid codec" << charset_;
|
||||
//emit Finished(id);
|
||||
emit InfoReady(id, QString());
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// strip "featuring <someone else>" from the song.artist
|
||||
QString artistFixed=metadata.artist;
|
||||
@@ -59,207 +143,116 @@ void UltimateLyricsProvider::FetchInfo(int id, const Song& metadata) {
|
||||
toStrip << QLatin1String(" ft. ") << QLatin1String(" feat. ") << QLatin1String(" featuring ");
|
||||
foreach (const QString s, toStrip) {
|
||||
int strip = artistFixed.toLower().indexOf( " ft. ");
|
||||
if ( strip != -1 ) {
|
||||
if (-1!=strip) {
|
||||
artistFixed = artistFixed.mid( 0, strip );
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in fields in the URL
|
||||
QString url_text(url_);
|
||||
DoUrlReplace("{artist}", artistFixed.toLower(), &url_text);
|
||||
DoUrlReplace("{album}", metadata.album.toLower(), &url_text);
|
||||
DoUrlReplace("{title}", metadata.title.toLower(), &url_text);
|
||||
DoUrlReplace("{Artist}", artistFixed, &url_text);
|
||||
DoUrlReplace("{Album}", metadata.album, &url_text);
|
||||
DoUrlReplace("{Title}", metadata.title, &url_text);
|
||||
DoUrlReplace("{Title2}", TitleCase(metadata.title), &url_text);
|
||||
DoUrlReplace("{a}", FirstChar(artistFixed), &url_text);
|
||||
// Fill in fields in the URL
|
||||
QString urlText(url);
|
||||
doUrlReplace("{artist}", artistFixed.toLower(), &urlText);
|
||||
doUrlReplace("{album}", metadata.album.toLower(), &urlText);
|
||||
doUrlReplace("{title}", metadata.title.toLower(), &urlText);
|
||||
doUrlReplace("{Artist}", artistFixed, &urlText);
|
||||
doUrlReplace("{Album}", metadata.album, &urlText);
|
||||
doUrlReplace("{Title}", metadata.title, &urlText);
|
||||
doUrlReplace("{Title2}", titleCase(metadata.title), &urlText);
|
||||
doUrlReplace("{a}", firstChar(artistFixed), &urlText);
|
||||
|
||||
QUrl url(url_text);
|
||||
|
||||
// Fetch the URL, follow redirects
|
||||
redirect_count_ = 0;
|
||||
QNetworkReply* reply = NetworkAccessManager::self()->get(QNetworkRequest(url));
|
||||
requests_[reply] = id;
|
||||
connect(reply, SIGNAL(finished()), SLOT(LyricsFetched()));
|
||||
// Fetch the URL, follow redirects
|
||||
redirectCount = 0;
|
||||
QNetworkReply *reply = NetworkAccessManager::self()->get(QNetworkRequest(QUrl(urlText)));
|
||||
requests[reply] = id;
|
||||
connect(reply, SIGNAL(finished()), SLOT(lyricsFetched()));
|
||||
}
|
||||
|
||||
void UltimateLyricsProvider::LyricsFetched() {
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
void UltimateLyricsProvider::lyricsFetched()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
int id = requests_.take(reply);
|
||||
reply->deleteLater();
|
||||
int id = requests.take(reply);
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
//emit Finished(id);
|
||||
emit InfoReady(id, QString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle redirects
|
||||
QVariant redirect_target = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (redirect_target.isValid()) {
|
||||
if (redirect_count_ >= kRedirectLimit) {
|
||||
//emit Finished(id);
|
||||
emit InfoReady(id, QString());
|
||||
return;
|
||||
if (QNetworkReply::NoError!=reply->error()) {
|
||||
//emit Finished(id);
|
||||
emit lyricsReady(id, QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl target = redirect_target.toUrl();
|
||||
if (target.scheme().isEmpty() || target.host().isEmpty()) {
|
||||
QString path = target.path();
|
||||
target = reply->url();
|
||||
target.setPath(path);
|
||||
// Handle redirects
|
||||
QVariant redirect_target = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (redirect_target.isValid()) {
|
||||
if (redirectCount >= constRedirectLimit) {
|
||||
//emit Finished(id);
|
||||
emit lyricsReady(id, QString());
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl target = redirect_target.toUrl();
|
||||
if (target.scheme().isEmpty() || target.host().isEmpty()) {
|
||||
QString path = target.path();
|
||||
target = reply->url();
|
||||
target.setPath(path);
|
||||
}
|
||||
|
||||
redirectCount ++;
|
||||
QNetworkReply* reply = NetworkAccessManager::self()->get(QNetworkRequest(target));
|
||||
requests[reply] = id;
|
||||
connect(reply, SIGNAL(finished()), SLOT(lyricsFetched()));
|
||||
return;
|
||||
}
|
||||
|
||||
redirect_count_ ++;
|
||||
QNetworkReply* reply = NetworkAccessManager::self()->get(QNetworkRequest(target));
|
||||
requests_[reply] = id;
|
||||
connect(reply, SIGNAL(finished()), SLOT(LyricsFetched()));
|
||||
return;
|
||||
}
|
||||
#if QT_VERSION < 0x050000
|
||||
const QTextCodec *codec = QTextCodec::codecForName(charset.toAscii().constData());
|
||||
#else
|
||||
const QTextCodec *codec = QTextCodec::codecForName(charset.toLatin1().constData());
|
||||
#endif
|
||||
const QString original_content = codec->toUnicode(reply->readAll());
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
const QTextCodec* codec = QTextCodec::codecForName(charset_.toAscii().constData());
|
||||
#else
|
||||
const QTextCodec* codec = QTextCodec::codecForName(charset_.toLatin1().constData());
|
||||
#endif
|
||||
const QString original_content = codec->toUnicode(reply->readAll());
|
||||
|
||||
// Check for invalid indicators
|
||||
foreach (const QString& indicator, invalid_indicators_) {
|
||||
if (original_content.contains(indicator)) {
|
||||
//emit Finished(id);
|
||||
emit InfoReady(id, QString());
|
||||
return;
|
||||
// Check for invalid indicators
|
||||
foreach (const QString &indicator, invalidIndicators) {
|
||||
if (original_content.contains(indicator)) {
|
||||
//emit Finished(id);
|
||||
emit lyricsReady(id, QString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString lyrics;
|
||||
QString lyrics;
|
||||
|
||||
// Apply extract rules
|
||||
foreach (const Rule& rule, extract_rules_) {
|
||||
QString content = original_content;
|
||||
ApplyExtractRule(rule, &content);
|
||||
// Apply extract rules
|
||||
foreach (const Rule& rule, extractRules) {
|
||||
QString content = original_content;
|
||||
applyExtractRule(rule, &content);
|
||||
|
||||
if (!content.isEmpty())
|
||||
lyrics = content;
|
||||
}
|
||||
|
||||
// Apply exclude rules
|
||||
foreach (const Rule& rule, exclude_rules_) {
|
||||
ApplyExcludeRule(rule, &lyrics);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!lyrics.isEmpty()) {
|
||||
CollapsibleInfoPane::Data data;
|
||||
data.id_ = "ultimatelyrics/" + name_;
|
||||
data.title_ = tr("Lyrics from %1").arg(name_);
|
||||
data.type_ = CollapsibleInfoPane::Data::Type_Lyrics;
|
||||
data.relevance_ = relevance();
|
||||
|
||||
SongInfoTextView* editor = new SongInfoTextView;
|
||||
editor->SetHtml(lyrics);
|
||||
data.contents_ = editor;
|
||||
|
||||
emit InfoReady(id, data);
|
||||
}
|
||||
emit Finished(id);
|
||||
#endif
|
||||
|
||||
lyrics=lyrics.trimmed();
|
||||
emit InfoReady(id, lyrics);
|
||||
}
|
||||
|
||||
void UltimateLyricsProvider::ApplyExtractRule(const Rule& rule, QString* content) const {
|
||||
foreach (const RuleItem& item, rule) {
|
||||
if (item.second.isNull()) {
|
||||
*content = ExtractXmlTag(*content, item.first);
|
||||
} else {
|
||||
*content = Extract(*content, item.first, item.second);
|
||||
if (!content.isEmpty()) {
|
||||
lyrics = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::ExtractXmlTag(const QString& source, const QString& tag) {
|
||||
QRegExp re("<(\\w+).*>"); // ಠ_ಠ
|
||||
if (re.indexIn(tag) == -1)
|
||||
return QString();
|
||||
|
||||
return Extract(source, tag, "</" + re.cap(1) + ">");
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::Extract(const QString& source, const QString& begin, const QString& end) {
|
||||
int begin_idx = source.indexOf(begin);
|
||||
if (begin_idx == -1)
|
||||
return QString();
|
||||
begin_idx += begin.length();
|
||||
|
||||
int end_idx = source.indexOf(end, begin_idx);
|
||||
if (end_idx == -1)
|
||||
return QString();
|
||||
|
||||
return source.mid(begin_idx, end_idx - begin_idx - 1);
|
||||
}
|
||||
|
||||
void UltimateLyricsProvider::ApplyExcludeRule(const Rule& rule, QString* content) const {
|
||||
foreach (const RuleItem& item, rule) {
|
||||
if (item.second.isNull()) {
|
||||
*content = ExcludeXmlTag(*content, item.first);
|
||||
} else {
|
||||
*content = Exclude(*content, item.first, item.second);
|
||||
// Apply exclude rules
|
||||
foreach (const Rule& rule, excludeRules) {
|
||||
applyExcludeRule(rule, &lyrics);
|
||||
}
|
||||
}
|
||||
|
||||
lyrics=lyrics.trimmed();
|
||||
emit lyricsReady(id, lyrics);
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::ExcludeXmlTag(const QString& source, const QString& tag) {
|
||||
QRegExp re("<(\\w+).*>"); // ಠ_ಠ
|
||||
if (re.indexIn(tag) == -1)
|
||||
return source;
|
||||
void UltimateLyricsProvider::doUrlReplace(const QString &tag, const QString &value, QString *u) const
|
||||
{
|
||||
if (!u->contains(tag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Exclude(source, tag, "</" + re.cap(1) + ">");
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::Exclude(const QString& source, const QString& begin, const QString& end) {
|
||||
int begin_idx = source.indexOf(begin);
|
||||
if (begin_idx == -1)
|
||||
return source;
|
||||
|
||||
int end_idx = source.indexOf(end, begin_idx + begin.length());
|
||||
if (end_idx == -1)
|
||||
return source;
|
||||
|
||||
return source.left(begin_idx) + source.right(source.length() - end_idx - end.length());
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::FirstChar(const QString& text) {
|
||||
if (text.isEmpty())
|
||||
return QString();
|
||||
return text[0].toLower();
|
||||
}
|
||||
|
||||
QString UltimateLyricsProvider::TitleCase(const QString& text) {
|
||||
if (text.length() == 0)
|
||||
return QString();
|
||||
if (text.length() == 1)
|
||||
return text[0].toUpper();
|
||||
return text[0].toUpper() + text.right(text.length() - 1).toLower();
|
||||
}
|
||||
|
||||
void UltimateLyricsProvider::DoUrlReplace(const QString& tag, const QString& value,
|
||||
QString* url) const {
|
||||
if (!url->contains(tag))
|
||||
return;
|
||||
|
||||
// Apply URL character replacement
|
||||
QString value_copy(value);
|
||||
foreach (const UrlFormat& format, url_formats_) {
|
||||
QRegExp re("[" + QRegExp::escape(format.first) + "]");
|
||||
value_copy.replace(re, format.second);
|
||||
}
|
||||
|
||||
url->replace(tag, value_copy, Qt::CaseInsensitive);
|
||||
// Apply URL character replacement
|
||||
QString valueCopy(value);
|
||||
foreach (const UltimateLyricsProvider::UrlFormat& format, urlFormats) {
|
||||
QRegExp re("[" + QRegExp::escape(format.first) + "]");
|
||||
valueCopy.replace(re, format.second);
|
||||
}
|
||||
|
||||
u->replace(tag, valueCopy, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
@@ -28,71 +28,57 @@
|
||||
#include <QPair>
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include "songinfoprovider.h"
|
||||
|
||||
class Song;
|
||||
class QNetworkReply;
|
||||
|
||||
class UltimateLyricsProvider : public SongInfoProvider {
|
||||
Q_OBJECT
|
||||
class UltimateLyricsProvider : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UltimateLyricsProvider();
|
||||
UltimateLyricsProvider();
|
||||
|
||||
static const int kRedirectLimit;
|
||||
typedef QPair<QString, QString> RuleItem;
|
||||
typedef QList<RuleItem> Rule;
|
||||
typedef QPair<QString, QString> UrlFormat;
|
||||
|
||||
typedef QPair<QString, QString> RuleItem;
|
||||
typedef QList<RuleItem> Rule;
|
||||
typedef QPair<QString, QString> UrlFormat;
|
||||
void setName(const QString &n) { name = n; }
|
||||
void setTitle(const QString &t) { title = t; }
|
||||
void setUrl(const QString &u) { url = u; }
|
||||
void setCharset(const QString &c) { charset = c; }
|
||||
void setRelevance(int r) { relevance = r; }
|
||||
void addUrlFormat(const QString &replace, const QString &with) { urlFormats << UrlFormat(replace, with); }
|
||||
void addExtractRule(const Rule &rule) { extractRules << rule; }
|
||||
void addExcludeRule(const Rule &rule) { excludeRules << rule; }
|
||||
void addInvalidIndicator(const QString &indicator) { invalidIndicators << indicator; }
|
||||
QString getName() const { return name; }
|
||||
int getRelevance() const { return relevance; }
|
||||
void fetchInfo(int id, const Song &metadata);
|
||||
bool isEnabled() const { return enabled; }
|
||||
void setEnabled(bool e) { enabled = e; }
|
||||
|
||||
void set_name(const QString& name) { name_ = name; }
|
||||
void set_title(const QString& title) { title_ = title; }
|
||||
void set_url(const QString& url) { url_ = url; }
|
||||
void set_charset(const QString& charset) { charset_ = charset; }
|
||||
void set_relevance(int relevance) { relevance_ = relevance; }
|
||||
Q_SIGNALS:
|
||||
void lyricsReady(int id, const QString &data);
|
||||
|
||||
void add_url_format(const QString& replace, const QString& with) {
|
||||
url_formats_ << UrlFormat(replace, with); }
|
||||
|
||||
void add_extract_rule(const Rule& rule) { extract_rules_ << rule; }
|
||||
void add_exclude_rule(const Rule& rule) { exclude_rules_ << rule; }
|
||||
void add_invalid_indicator(const QString& indicator) { invalid_indicators_ << indicator; }
|
||||
|
||||
QString name() const { return name_; }
|
||||
int relevance() const { return relevance_; }
|
||||
|
||||
void FetchInfo(int id, const Song& metadata);
|
||||
|
||||
private slots:
|
||||
void LyricsFetched();
|
||||
private Q_SLOTS:
|
||||
void lyricsFetched();
|
||||
|
||||
private:
|
||||
void ApplyExtractRule(const Rule& rule, QString* content) const;
|
||||
void ApplyExcludeRule(const Rule& rule, QString* content) const;
|
||||
|
||||
static QString ExtractXmlTag(const QString& source, const QString& tag);
|
||||
static QString Extract(const QString& source, const QString& begin, const QString& end);
|
||||
static QString ExcludeXmlTag(const QString& source, const QString& tag);
|
||||
static QString Exclude(const QString& source, const QString& begin, const QString& end);
|
||||
static QString FirstChar(const QString& text);
|
||||
static QString TitleCase(const QString& text);
|
||||
void DoUrlReplace(const QString& tag, const QString& value, QString* url) const;
|
||||
void doUrlReplace(const QString &tag, const QString &value, QString *u) const;
|
||||
|
||||
private:
|
||||
QHash<QNetworkReply*, int> requests_;
|
||||
|
||||
QString name_;
|
||||
QString title_;
|
||||
QString url_;
|
||||
QString charset_;
|
||||
int relevance_;
|
||||
|
||||
QList<UrlFormat> url_formats_;
|
||||
QList<Rule> extract_rules_;
|
||||
QList<Rule> exclude_rules_;
|
||||
QStringList invalid_indicators_;
|
||||
|
||||
int redirect_count_;
|
||||
bool enabled;
|
||||
QHash<QNetworkReply*, int> requests;
|
||||
QString name;
|
||||
QString title;
|
||||
QString url;
|
||||
QString charset;
|
||||
int relevance;
|
||||
QList<UrlFormat> urlFormats;
|
||||
QList<Rule> extractRules;
|
||||
QList<Rule> excludeRules;
|
||||
QStringList invalidIndicators;
|
||||
int redirectCount;
|
||||
};
|
||||
|
||||
#endif // ULTIMATELYRICSPROVIDER_H
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
*/
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ultimatelyricsprovider.h"
|
||||
#include "ultimatelyricsreader.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
UltimateLyricsReader::UltimateLyricsReader(/*QObject* parent*/)
|
||||
// : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QList<UltimateLyricsProvider*> UltimateLyricsReader::Parse(const QString& filename) const {
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
// qWarning() << "Error opening" << filename;
|
||||
return QList<UltimateLyricsProvider*>();
|
||||
}
|
||||
|
||||
return ParseDevice(&file);
|
||||
}
|
||||
|
||||
QList<UltimateLyricsProvider*> UltimateLyricsReader::ParseDevice(QIODevice* device) const {
|
||||
QList<UltimateLyricsProvider*> ret;
|
||||
|
||||
QXmlStreamReader reader(device);
|
||||
while (!reader.atEnd()) {
|
||||
reader.readNext();
|
||||
|
||||
if (reader.name() == "provider") {
|
||||
UltimateLyricsProvider* provider = ParseProvider(&reader);
|
||||
if (provider) {
|
||||
provider->moveToThread(qApp->thread());
|
||||
ret << provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UltimateLyricsProvider* UltimateLyricsReader::ParseProvider(QXmlStreamReader* reader) const {
|
||||
QXmlStreamAttributes attributes = reader->attributes();
|
||||
|
||||
UltimateLyricsProvider* scraper = new UltimateLyricsProvider;
|
||||
scraper->set_name(attributes.value("name").toString());
|
||||
scraper->set_title(attributes.value("title").toString());
|
||||
scraper->set_charset(attributes.value("charset").toString());
|
||||
scraper->set_url(attributes.value("url").toString());
|
||||
|
||||
while (!reader->atEnd()) {
|
||||
reader->readNext();
|
||||
|
||||
if (reader->tokenType() == QXmlStreamReader::EndElement)
|
||||
break;
|
||||
|
||||
if (reader->tokenType() == QXmlStreamReader::StartElement) {
|
||||
if (reader->name() == "extract")
|
||||
scraper->add_extract_rule(ParseRule(reader));
|
||||
else if (reader->name() == "exclude")
|
||||
scraper->add_exclude_rule(ParseRule(reader));
|
||||
else if (reader->name() == "invalidIndicator")
|
||||
scraper->add_invalid_indicator(ParseInvalidIndicator(reader));
|
||||
else if (reader->name() == "urlFormat") {
|
||||
scraper->add_url_format(reader->attributes().value("replace").toString(),
|
||||
reader->attributes().value("with").toString());
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
else
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
return scraper;
|
||||
}
|
||||
|
||||
UltimateLyricsProvider::Rule UltimateLyricsReader::ParseRule(QXmlStreamReader* reader) const {
|
||||
UltimateLyricsProvider::Rule ret;
|
||||
|
||||
while (!reader->atEnd()) {
|
||||
reader->readNext();
|
||||
|
||||
if (reader->tokenType() == QXmlStreamReader::EndElement)
|
||||
break;
|
||||
|
||||
if (reader->tokenType() == QXmlStreamReader::StartElement) {
|
||||
if (reader->name() == "item") {
|
||||
QXmlStreamAttributes attr = reader->attributes();
|
||||
if (attr.hasAttribute("tag"))
|
||||
ret << UltimateLyricsProvider::RuleItem(attr.value("tag").toString(), QString());
|
||||
else if (attr.hasAttribute("begin"))
|
||||
ret << UltimateLyricsProvider::RuleItem(attr.value("begin").toString(),
|
||||
attr.value("end").toString());
|
||||
}
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString UltimateLyricsReader::ParseInvalidIndicator(QXmlStreamReader* reader) const {
|
||||
QString ret = reader->attributes().value("value").toString();
|
||||
reader->skipCurrentElement();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Cantata
|
||||
*
|
||||
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
|
||||
*
|
||||
*/
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ULTIMATELYRICSREADER_H
|
||||
#define ULTIMATELYRICSREADER_H
|
||||
|
||||
#include "ultimatelyricsprovider.h"
|
||||
|
||||
// #include <QObject>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
class QIODevice;
|
||||
|
||||
class UltimateLyricsReader/* : public QObject*/ {
|
||||
// Q_OBJECT
|
||||
|
||||
public:
|
||||
UltimateLyricsReader(/*QObject* parent = 0*/);
|
||||
|
||||
QList<UltimateLyricsProvider*> Parse(const QString& filename) const;
|
||||
QList<UltimateLyricsProvider*> ParseDevice(QIODevice* device) const;
|
||||
|
||||
private:
|
||||
UltimateLyricsProvider* ParseProvider(QXmlStreamReader* reader) const;
|
||||
UltimateLyricsProvider::Rule ParseRule(QXmlStreamReader* reader) const;
|
||||
QString ParseInvalidIndicator(QXmlStreamReader* reader) const;
|
||||
};
|
||||
|
||||
#endif // ULTIMATELYRICSREADER_H
|
||||
Reference in New Issue
Block a user