1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-06-04 23:14:56 +02:00

* Import InfoSystem - we now depend on libechonest.

* Import XMPP Bot.
* Add SOCKS proxy support.
This commit is contained in:
Christian Muehlhaeuser 2010-10-26 10:24:54 +02:00
parent a7dbcef462
commit 512fc46d22
24 changed files with 1885 additions and 65 deletions

12
README
View File

@ -30,12 +30,20 @@ QJson (Qt JSON library)
$ ./configure && make
$ sudo make install
libEchonest 0.1
---------------
$ git clone git://git.kde.org/libechonest.git
$ cd libechonest
$ mkdir build && cd build
$ cmake ..
$ make
$ sudo make install
Now compile Tomahawk
-------------------
$ sudo ldconfig -v | grep -Ei 'qjson|gloox'
$ mkdir build
$ cd build
$ mkdir build && cd build
$ cmake ..
$ make
$ ./tomahawk

View File

@ -0,0 +1,148 @@
#ifndef TOMAHAWK_INFOSYSTEM_H
#define TOMAHAWK_INFOSYSTEM_H
#include <QtCore/QObject>
#include <QtCore/QtDebug>
#include <QtCore/qmap.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qset.h>
#include <QtCore/qlinkedlist.h>
#include <QtCore/qvariant.h>
namespace Tomahawk {
namespace InfoSystem {
enum InfoType {
InfoTrackID,
InfoTrackArtist,
InfoTrackAlbum,
InfoTrackGenre,
InfoTrackComposer,
InfoTrackDate,
InfoTrackNumber,
InfoTrackDiscNumber,
InfoTrackBitRate,
InfoTrackLength,
InfoTrackSampleRate,
InfoTrackFileSize,
InfoTrackBPM,
InfoTrackReplayGain,
InfoTrackReplayPeakGain,
InfoTrackLyrics,
InfoTrackLocation,
InfoTrackProfile,
InfoTrackEnergy,
InfoTrackDanceability,
InfoTrackTempo,
InfoTrackLoudness,
InfoArtistID,
InfoArtistName,
InfoArtistBiography,
InfoArtistBlog,
InfoArtistFamiliarity,
InfoArtistHotttness,
InfoArtistImages,
InfoArtistNews,
InfoArtistProfile,
InfoArtistReviews,
InfoArtistSongs,
InfoArtistSimilars,
InfoArtistTerms,
InfoArtistLinks,
InfoArtistVideos,
InfoAlbumID,
InfoAlbumName,
InfoAlbumArtist,
InfoAlbumDate,
InfoAlbumGenre,
InfoAlbumComposer,
InfoMiscTopHotttness,
InfoMiscTopTerms,
InfoNoInfo
};
typedef QMap< InfoType, QVariant > InfoMap;
typedef QMap< QString, QMap< QString, QString > > InfoGenericMap;
typedef QHash<QString, QVariant> InfoCustomDataHash;
typedef QHash<QString, QString> MusixMatchHash;
class InfoPlugin : public QObject
{
Q_OBJECT
public:
InfoPlugin(QObject *parent)
:QObject(parent)
{
qDebug() << Q_FUNC_INFO;
}
~InfoPlugin()
{
qDebug() << Q_FUNC_INFO;
}
virtual void getInfo(const QString &caller, const InfoType type, const QVariant &data, Tomahawk::InfoSystem::InfoCustomDataHash customData) = 0;
signals:
void info(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData);
void finished(QString, Tomahawk::InfoSystem::InfoType);
protected:
InfoType m_type;
};
typedef QWeakPointer< InfoPlugin > InfoPluginPtr;
class InfoSystem : public QObject
{
Q_OBJECT
public:
InfoSystem(QObject *parent);
~InfoSystem()
{
qDebug() << Q_FUNC_INFO;
}
void registerInfoTypes(const InfoPluginPtr &plugin, const QSet< InfoType > &types);
void getInfo(const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData);
void getInfo(const QString &caller, const InfoMap &input, InfoCustomDataHash customData);
signals:
void info(QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData);
void finished(QString target);
public slots:
void infoSlot(QString target, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData);
void finishedSlot(QString target,Tomahawk::InfoSystem::InfoType type);
private:
QLinkedList< InfoPluginPtr > determineOrderedMatches(const InfoType type) const;
QMap< InfoType, QLinkedList<InfoPluginPtr> > m_infoMap;
// For now, statically instantiate plugins; this is just somewhere to keep them
QLinkedList<InfoPluginPtr> m_plugins;
QHash< QString, QHash< Tomahawk::InfoSystem::InfoType, int > > m_dataTracker;
};
}
}
Q_DECLARE_METATYPE(Tomahawk::InfoSystem::InfoGenericMap)
Q_DECLARE_METATYPE(Tomahawk::InfoSystem::InfoCustomDataHash);
Q_DECLARE_METATYPE(Tomahawk::InfoSystem::MusixMatchHash)
#endif // TOMAHAWK_INFOSYSTEM_H

View File

@ -29,9 +29,18 @@
class Database;
class Jabber;
class XMPPBot;
class TomahawkZeroconf;
class TomahawkSettings;
namespace Tomahawk
{
namespace InfoSystem
{
class InfoSystem;
}
}
#ifndef TOMAHAWK_HEADLESS
class AudioEngine;
class TomahawkWindow;
@ -64,6 +73,9 @@ public:
SourceList& sourcelist() { return m_sources; }
Servent& servent() { return m_servent; }
QNetworkAccessManager* nam() { return m_nam; }
QNetworkProxy* proxy() { return m_proxy; }
Tomahawk::InfoSystem::InfoSystem* infoSystem() { return m_infoSystem; }
XMPPBot* xmppBot() { return m_xmppBot; }
const QString& nodeID() const;
#ifndef TOMAHAWK_HEADLESS
@ -114,6 +126,7 @@ private:
SourceList m_sources;
TomahawkZeroconf* m_zeroconf;
QSharedPointer<Jabber> m_jabber;
XMPPBot* m_xmppBot;
#ifndef TOMAHAWK_HEADLESS
TomahawkWindow* m_mainwindow;
@ -129,6 +142,9 @@ private:
TomahawkSettings* m_settings;
QNetworkAccessManager* m_nam;
QNetworkProxy* m_proxy;
Tomahawk::InfoSystem::InfoSystem* m_infoSystem;
QxtHttpServerConnector m_connector;
QxtHttpSessionManager m_session;

View File

@ -36,6 +36,10 @@ SET( tomahawkSources ${tomahawkSources}
utils/tomahawkutils.cpp
jabber/jabber_p.cpp
infosystem/infosystem.cpp
infosystem/infoplugins/echonestplugin.cpp
infosystem/infoplugins/musixmatchplugin.cpp
bufferiodevice.cpp
connection.cpp
msgprocessor.cpp
@ -73,6 +77,8 @@ SET( tomahawkSources ${tomahawkSources}
database/databasecommand_updatesearchindex.cpp
database/databasecollection.cpp
xmppbot/xmppbot.cpp
web/api_v1.cpp
tomahawksettings.cpp
@ -139,6 +145,8 @@ SET( tomahawkHeaders ${tomahawkHeaders}
"${TOMAHAWK_INC_DIR}/tomahawk/track.h"
"${TOMAHAWK_INC_DIR}/tomahawk/playlist.h"
"${TOMAHAWK_INC_DIR}/tomahawk/infosystem.h"
"${TOMAHAWK_INC_DIR}/tomahawk/functimeout.h"
# "${TOMAHAWK_INC_DIR}/tomahawk/tomahawkplugin.h"
@ -170,6 +178,9 @@ SET( tomahawkHeaders ${tomahawkHeaders}
jabber/jabber.h
jabber/jabber_p.h
infosystem/infoplugins/echonestplugin.h
infosystem/infoplugins/musixmatchplugin.h
bufferiodevice.h
connection.h
msgprocessor.h
@ -183,6 +194,8 @@ SET( tomahawkHeaders ${tomahawkHeaders}
scriptresolver.h
tomahawksettings.h
xmppbot/xmppbot.h
web/api_v1.h
)
@ -231,12 +244,13 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
)
SET( tomahawkUI ${tomahawkUI}
tomahawkwindow.ui
settingsdialog.ui
tomahawkwindow.ui
settingsdialog.ui
proxydialog.ui
audiocontrols.ui
sourcetree/sourcetreeitemwidget.ui
topbar/topbar.ui
audiocontrols.ui
sourcetree/sourcetreeitemwidget.ui
topbar/topbar.ui
)
INCLUDE_DIRECTORIES(
@ -258,6 +272,7 @@ INCLUDE_DIRECTORIES(
/usr/include/taglib
/usr/local/include/taglib
/usr/local/include/echonest
/usr/local/include
)
@ -304,6 +319,7 @@ TARGET_LINK_LIBRARIES( tomahawk
${QT_LIBRARIES}
${MAC_EXTRA_LIBS}
${OS_SPECIFIC_LINK_LIBRARIES}
echonest
portfwd
)

View File

@ -25,4 +25,4 @@ ELSE()
SET( tomahawkSourcesGui ${tomahawkSourcesGui} audio/vorbistranscode.cpp scrobbler.cpp )
SET( tomahawkHeadersGui ${tomahawkHeadersGui} audio/vorbistranscode.h scrobbler.h )
ENDIF()
ENDIF()

View File

@ -13,8 +13,8 @@ SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "rj@tomahawk.org")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../README")
SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE.txt")
SET(CPACK_PACKAGE_VERSION_MAJOR "0")
SET(CPACK_PACKAGE_VERSION_MINOR "1")
SET(CPACK_PACKAGE_VERSION_PATCH "3")
SET(CPACK_PACKAGE_VERSION_MINOR "0")
SET(CPACK_PACKAGE_VERSION_PATCH "1")
SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
#SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386") # Default: Output of dpkg --print-architecture or i386
@ -51,7 +51,7 @@ ENDIF(WIN32 AND NOT UNIX)
# Nsis only? SET(CPACK_PACKAGE_EXECUTABLES "tomahawk" "tomahawk")
#gnutls is in here because gloox needs it, and we link statically to gloox:
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libqtgui4 (>=4:4.6.2-0ubuntu5), libtag1c2a (>=1.6.2-0ubuntu1), liblastfm-dev (>=0.4.0~git20090710-1), libqt4-sql-sqlite (>=4:4.6.2-0ubuntu5), libvorbis0a (>=1.2.3-3ubuntu1), libmad0 (>=0.15.1b-4ubuntu1), libasound2 (>=1.0.22-0ubuntu7), zlib1g (>=1:1.2.3.3.dfsg-15ubuntu1), libqjson-dev (>=0.7.1-1), libgnutls26 (>= 2.7.14-0)")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libqtgui4 (>=4:4.7.0-0ubuntu1), libtag1c2a (>=1.6.2-0ubuntu1), liblastfm-dev (>=0.4.0~really0.3.3-0ubuntu1), libqt4-sql-sqlite (>=4:4.7.0-0ubuntu1), libvorbis0a (>=1.2.3-3ubuntu1), libmad0 (>=0.15.1b-4ubuntu1), libasound2 (>=1.0.22-0ubuntu7), zlib1g (>=1:1.2.3.3.dfsg-15ubuntu1), libqjson-dev (>=0.7.1-1), libgnutls26 (>= 2.7.14-0), libgloox8 (>=1.0-1)")
#SET(CPACK_DEBIAN_PACKAGE_SECTION "music")

View File

@ -0,0 +1,260 @@
#include "tomahawk/infosystem.h"
#include "tomahawk/tomahawkapp.h"
#include "echonestplugin.h"
#include <echonest/Artist.h>
#include <echonest/ArtistTypes.h>
using namespace Tomahawk::InfoSystem;
using namespace Echonest;
// for internal neatness
EchoNestPlugin::EchoNestPlugin(QObject *parent)
: InfoPlugin(parent)
{
qDebug() << Q_FUNC_INFO;
Config::instance()->setAPIKey("JGJCRKWLXLBZIFAZB");
QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
}
EchoNestPlugin::~EchoNestPlugin()
{
qDebug() << Q_FUNC_INFO;
}
void EchoNestPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash customData)
{
switch (type)
{
case Tomahawk::InfoSystem::InfoArtistBiography:
return getArtistBiography(caller, data, customData);
case Tomahawk::InfoSystem::InfoArtistFamiliarity:
return getArtistFamiliarity(caller, data, customData);
case Tomahawk::InfoSystem::InfoArtistHotttness:
return getArtistHotttnesss(caller, data, customData);
case Tomahawk::InfoSystem::InfoArtistTerms:
return getArtistTerms(caller, data, customData);
case Tomahawk::InfoSystem::InfoTrackEnergy:
return getSongProfile(caller, data, customData, "energy");
case Tomahawk::InfoSystem::InfoMiscTopTerms:
return getMiscTopTerms(caller, data, customData);
default:
{
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return;
}
}
}
void EchoNestPlugin::getSongProfile(const QString &caller, const QVariant& data, InfoCustomDataHash &customData, const QString &item)
{
//WARNING: Totally not implemented yet
if( !isValidTrackData( caller, data, customData ) )
return;
// Track track( data.toString() );
// Artist artist( customData.data()->property("artistName").toString() );
// reply->setProperty("artist", QVariant::fromValue<Artist>(artist));
// reply->setProperty( "data", data );
// m_replyMap[reply] = customData;
// connect(reply, SIGNAL(finished()), SLOT(getArtistBiographySlot()));
}
void EchoNestPlugin::getArtistBiography(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if( !isValidArtistData( caller, data, customData ) )
return;
Artist artist( data.toString() );
QNetworkReply *reply = artist.fetchBiographies();
reply->setProperty("artist", QVariant::fromValue<Artist>(artist));
reply->setProperty( "data", data );
m_replyMap[reply] = customData;
m_callerMap[reply] = caller;
connect(reply, SIGNAL(finished()), SLOT(getArtistBiographySlot()));
}
void EchoNestPlugin::getArtistFamiliarity(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if( !isValidArtistData( caller, data, customData ) )
return;
qDebug() << "Fetching artist familiarity!" << data;
Artist artist( data.toString() );
QNetworkReply* reply = artist.fetchFamiliarity();
reply->setProperty( "artist", QVariant::fromValue<Artist>(artist));
reply->setProperty( "data", data );
m_replyMap[reply] = customData;
m_callerMap[reply] = caller;
connect(reply, SIGNAL(finished()), SLOT(getArtistFamiliaritySlot()));
}
void EchoNestPlugin::getArtistHotttnesss(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if( !isValidArtistData( caller, data, customData ) )
return;
Artist artist( data.toString() );
QNetworkReply* reply = artist.fetchHotttnesss();
reply->setProperty( "artist", QVariant::fromValue<Artist>(artist));
reply->setProperty( "data", data );
m_replyMap[reply] = customData;
m_callerMap[reply] = caller;
connect(reply, SIGNAL(finished()), SLOT(getArtistHotttnesssSlot()));
}
void EchoNestPlugin::getArtistTerms(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if( !isValidArtistData( caller, data, customData ) )
return;
Artist artist( data.toString() );
QNetworkReply* reply = artist.fetchTerms( Echonest::Artist::Weight );
reply->setProperty( "artist", QVariant::fromValue<Artist>(artist));
reply->setProperty( "data", data );
m_replyMap[reply] = customData;
m_callerMap[reply] = caller;
connect(reply, SIGNAL(finished()), SLOT(getArtistTermsSlot()));
}
void EchoNestPlugin::getMiscTopTerms(const QString &caller, const QVariant& data, InfoCustomDataHash& customData)
{
QNetworkReply* reply = Artist::topTerms( 20 );
m_replyMap[reply] = customData;
m_callerMap[reply] = caller;
connect( reply,SIGNAL(finished()), SLOT( getMiscTopSlot()));
}
void EchoNestPlugin::getArtistBiographySlot()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Artist artist = artistFromReply( reply );
BiographyList biographies = artist.biographies();
InfoGenericMap biographyMap;
Q_FOREACH(const Biography& biography, biographies)
{
biographyMap[biography.site()]["site"] = biography.site();
biographyMap[biography.site()]["url"] = biography.url().toString();
biographyMap[biography.site()]["text"] = biography.text();
biographyMap[biography.site()]["attribution"] = biography.license().attribution;
biographyMap[biography.site()]["licensetype"] = biography.license().type;
biographyMap[biography.site()]["attribution"] = biography.license().url.toString();
}
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistBiography, reply->property( "data" ), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(biographyMap), m_replyMap[reply] );
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistBiography);
m_replyMap.remove(reply);
m_callerMap.remove(reply);
reply->deleteLater();
}
void EchoNestPlugin::getArtistFamiliaritySlot()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Artist artist = artistFromReply( reply );
qreal familiarity = artist.familiarity();
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistFamiliarity, reply->property( "data" ), familiarity, m_replyMap[reply] );
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistFamiliarity);
m_replyMap.remove(reply);
m_callerMap.remove(reply);
reply->deleteLater();
}
void EchoNestPlugin::getArtistHotttnesssSlot()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Artist artist = artistFromReply( reply );
qreal hotttnesss = artist.hotttnesss();
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistHotttness, reply->property( "data" ), hotttnesss, m_replyMap[reply] );
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistHotttness);
m_replyMap.remove(reply);
m_callerMap.remove(reply);
reply->deleteLater();
}
void EchoNestPlugin::getArtistTermsSlot()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
Artist artist = artistFromReply( reply );
TermList terms = artist.terms();
InfoGenericMap termsMap;
Q_FOREACH( const Echonest::Term& term, terms ) {
QMap< QString, QString > termMap;
termMap[ "weight" ] = QString::number(term.weight());
termMap[ "frequency" ] = QString::number(term.frequency());
termsMap[ term.name() ] = termMap;
}
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistTerms, reply->property( "data" ), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(termsMap), m_replyMap[reply] );
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoArtistTerms);
m_replyMap.remove(reply);
m_callerMap.remove(reply);
reply->deleteLater();
}
void EchoNestPlugin::getMiscTopSlot()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
TermList terms = Artist::parseTopTerms( reply );
InfoGenericMap termsMap;
Q_FOREACH( const Echonest::Term& term, terms ) {
QMap< QString, QString > termMap;
termMap[ "weight" ] = QString::number( term.weight() );
termMap[ "frequency" ] = QString::number( term.frequency() );
termsMap[ term.name().toLower() ] = termMap;
}
emit info( m_callerMap[reply], Tomahawk::InfoSystem::InfoMiscTopTerms, QVariant(), QVariant::fromValue<Tomahawk::InfoSystem::InfoGenericMap>(termsMap), m_replyMap[reply] );
emit finished( m_callerMap[reply], Tomahawk::InfoSystem::InfoMiscTopTerms);
m_replyMap.remove(reply);
m_callerMap.remove(reply);
reply->deleteLater();
}
bool EchoNestPlugin::isValidArtistData(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if (data.isNull() || !data.isValid() || !data.canConvert<QString>())
{
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return false;
}
QString artistName = data.toString();
if (artistName.isEmpty() )
{
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return false;
}
return true;
}
bool EchoNestPlugin::isValidTrackData(const QString &caller, const QVariant& data, InfoCustomDataHash &customData)
{
if (data.isNull() || !data.isValid() || !data.canConvert<QString>())
{
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return false;
}
QString trackName = data.toString();
if (trackName.isEmpty() )
{
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return false;
}
if (!customData.contains("artistName") ||
customData["artistName"].toString().isEmpty())
return false;
return true;
}
Artist EchoNestPlugin::artistFromReply(QNetworkReply* reply)
{
Artist artist = reply->property("artist").value<Artist>();
try {
artist.parseProfile(reply);
} catch( const Echonest::ParseError& e ) {
qWarning() << "Caught parser error from echonest!" << e.what();
}
return artist;
}

View File

@ -0,0 +1,54 @@
#ifndef ECHONESTPLUGIN_H
#define ECHONESTPLUGIN_H
#include "tomahawk/infosystem.h"
class QNetworkReply;
namespace Echonest {
class Artist;
}
namespace Tomahawk
{
namespace InfoSystem
{
class EchoNestPlugin : public InfoPlugin
{
Q_OBJECT
public:
EchoNestPlugin(QObject *parent);
virtual ~EchoNestPlugin();
void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData );
private:
void getSongProfile( const QString &caller, const QVariant &data, InfoCustomDataHash &customData, const QString &item = QString() );
void getArtistBiography ( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
void getArtistFamiliarity( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
void getArtistHotttnesss( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
void getArtistTerms( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
void getMiscTopTerms( const QString &caller, const QVariant &data, InfoCustomDataHash &customData );
bool isValidArtistData( const QString &caller, const QVariant& data, InfoCustomDataHash& customData );
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomDataHash& customData );
Echonest::Artist artistFromReply( QNetworkReply* );
private slots:
void getArtistBiographySlot();
void getArtistFamiliaritySlot();
void getArtistHotttnesssSlot();
void getArtistTermsSlot();
void getMiscTopSlot();
private:
QHash< QNetworkReply*, InfoCustomDataHash > m_replyMap;
QHash< QNetworkReply*, QString > m_callerMap;
};
}
}
#endif // ECHONESTPLUGIN_H

View File

@ -0,0 +1,134 @@
#include "tomahawk/infosystem.h"
#include "tomahawk/tomahawkapp.h"
#include "musixmatchplugin.h"
#include <QNetworkReply>
using namespace Tomahawk::InfoSystem;
// for internal neatness
MusixMatchPlugin::MusixMatchPlugin(QObject *parent)
: InfoPlugin(parent)
, m_apiKey("61be4ea5aea7dd942d52b2f1311dd9fe")
{
qDebug() << Q_FUNC_INFO;
QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoTrackLyrics;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
}
MusixMatchPlugin::~MusixMatchPlugin()
{
qDebug() << Q_FUNC_INFO;
}
void MusixMatchPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash customData)
{
qDebug() << Q_FUNC_INFO;
if( !isValidTrackData(caller, data, customData) || !data.canConvert<Tomahawk::InfoSystem::MusixMatchHash>())
return;
Tomahawk::InfoSystem::MusixMatchHash hash = data.value<Tomahawk::InfoSystem::MusixMatchHash>();
QString artist = hash["artistName"];
QString track = hash["trackName"];
if( artist.isEmpty() || track.isEmpty() )
{
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
return;
}
qDebug() << "artist is " << artist << ", track is " << track;
QString requestString("http://api.musixmatch.com/ws/1.1/track.search?format=xml&page_size=1&f_has_lyrics=1");
QUrl url(requestString);
url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("q_artist", artist);
url.addQueryItem("q_track", track);
QNetworkReply* reply = TomahawkApp::instance()->nam()->get(QNetworkRequest(url));
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomDataHash>(customData));
reply->setProperty("origData", data);
reply->setProperty("caller", caller);
connect(reply, SIGNAL(finished()), SLOT(trackSearchSlot()));
}
bool MusixMatchPlugin::isValidTrackData(const QString &caller, const QVariant& data, Tomahawk::InfoSystem::InfoCustomDataHash &customData)
{
qDebug() << Q_FUNC_INFO;
if (data.isNull() || !data.isValid() || !data.canConvert<Tomahawk::InfoSystem::MusixMatchHash>())
{
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
qDebug() << "MusixMatchPlugin::isValidTrackData: Data null, invalid, or can't convert";
return false;
}
MusixMatchHash hash = data.value<Tomahawk::InfoSystem::MusixMatchHash>();
if (hash["trackName"].isEmpty() )
{
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
qDebug() << "MusixMatchPlugin::isValidTrackData: Track name is empty";
return false;
}
if (hash["artistName"].isEmpty() )
{
emit info(caller, Tomahawk::InfoSystem::InfoTrackLyrics, data, QVariant(), customData);
emit finished(caller, Tomahawk::InfoSystem::InfoTrackLyrics);
qDebug() << "MusixMatchPlugin::isValidTrackData: No artist name found";
return false;
}
return true;
}
void MusixMatchPlugin::trackSearchSlot()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() );
if (!oldReply)
{
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomDataHash());
return;
}
QDomDocument doc;
doc.setContent(oldReply->readAll());
qDebug() << doc.toString();
QDomNodeList domNodeList = doc.elementsByTagName("track_id");
if (domNodeList.isEmpty())
{
emit info(oldReply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, oldReply->property("origData"), QVariant(), oldReply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
emit finished(oldReply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
return;
}
QString track_id = domNodeList.at(0).toElement().text();
QString requestString("http://api.musixmatch.com/ws/1.1/track.lyrics.get?track_id=%1&format=xml&apikey=%2");
QUrl url(requestString);
url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("track_id", track_id);
QNetworkReply* newReply = TomahawkApp::instance()->nam()->get(QNetworkRequest(url));
newReply->setProperty("origData", oldReply->property("origData"));
newReply->setProperty("customData", oldReply->property("customData"));
newReply->setProperty("caller", oldReply->property("caller"));
connect(newReply, SIGNAL(finished()), SLOT(trackLyricsSlot()));
}
void MusixMatchPlugin::trackLyricsSlot()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
if (!reply)
{
emit info(QString(), Tomahawk::InfoSystem::InfoTrackLyrics, QVariant(), QVariant(), Tomahawk::InfoSystem::InfoCustomDataHash());
return;
}
QDomDocument doc;
doc.setContent(reply->readAll());
QDomNodeList domNodeList = doc.elementsByTagName("lyrics_body");
if (domNodeList.isEmpty())
{
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
emit finished(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
return;
}
QString lyrics = domNodeList.at(0).toElement().text();
qDebug() << "Emitting lyrics: " << lyrics;
emit info(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics, reply->property("origData"), QVariant(lyrics), reply->property("customData").value<Tomahawk::InfoSystem::InfoCustomDataHash>());
emit finished(reply->property("caller").toString(), Tomahawk::InfoSystem::InfoTrackLyrics);
}

View File

@ -0,0 +1,38 @@
#ifndef MUSIXMATCHPLUGIN_H
#define MUSIXMATCHPLUGIN_H
#include "tomahawk/infosystem.h"
class QNetworkReply;
namespace Tomahawk
{
namespace InfoSystem
{
class MusixMatchPlugin : public InfoPlugin
{
Q_OBJECT
public:
MusixMatchPlugin(QObject *parent);
virtual ~MusixMatchPlugin();
void getInfo(const QString &caller, const InfoType type, const QVariant &data, InfoCustomDataHash customData);
private:
bool isValidTrackData( const QString &caller, const QVariant& data, InfoCustomDataHash &customData );
public slots:
void trackSearchSlot();
void trackLyricsSlot();
private:
QString m_apiKey;
};
}
}
#endif // MUSIXMATCHPLUGIN_H

View File

@ -0,0 +1,96 @@
#include "tomahawk/infosystem.h"
#include "infoplugins/echonestplugin.h"
#include "infoplugins/musixmatchplugin.h"
using namespace Tomahawk::InfoSystem;
InfoSystem::InfoSystem(QObject *parent)
: QObject( parent )
{
qDebug() << Q_FUNC_INFO;
qRegisterMetaType<QMap< QString, QMap< QString, QString > > >("Tomahawk::InfoSystem::InfoGenericMap");
qRegisterMetaType<QHash<QString, QVariant > >("Tomahawk::InfoSystem::InfoCustomDataHash");
qRegisterMetaType<QHash<QString, QString > >("Tomahawk::InfoSystem::MusixMatchHash");
InfoPluginPtr enptr(new EchoNestPlugin(this));
m_plugins.append(enptr);
InfoPluginPtr mmptr(new MusixMatchPlugin(this));
m_plugins.append(mmptr);
}
void InfoSystem::registerInfoTypes(const InfoPluginPtr &plugin, const QSet< InfoType >& types)
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH(InfoType type, types)
m_infoMap[type].append(plugin);
}
QLinkedList< InfoPluginPtr > InfoSystem::determineOrderedMatches(const InfoType type) const
{
//Dummy function for now that returns the various items in the QSet; at some point this will
//probably need to support ordering based on the data source
QLinkedList< InfoPluginPtr > providers;
Q_FOREACH(InfoPluginPtr ptr, m_infoMap[type])
providers << ptr;
return providers;
}
void InfoSystem::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomDataHash customData)
{
qDebug() << Q_FUNC_INFO;
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
if (providers.isEmpty())
{
emit info(QString(), Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return;
}
InfoPluginPtr ptr = providers.first();
if (!ptr)
{
emit info(QString(), Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
return;
}
m_dataTracker[caller][type] = m_dataTracker[caller][type] + 1;
qDebug() << "current count in dataTracker for type" << type << "is" << m_dataTracker[caller][type];
connect(ptr.data(), SIGNAL(info(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)),
this, SLOT(infoSlot(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)), Qt::UniqueConnection);
connect(ptr.data(), SIGNAL(finished(QString, Tomahawk::InfoSystem::InfoType)),
this, SLOT(finishedSlot(QString, Tomahawk::InfoSystem::InfoType)), Qt::UniqueConnection);
ptr.data()->getInfo(caller, type, data, customData);
}
void InfoSystem::getInfo(const QString &caller, const InfoMap &input, InfoCustomDataHash customData)
{
Q_FOREACH( InfoType type, input.keys() )
getInfo(caller, type, input[type], customData);
}
void InfoSystem::infoSlot(QString target, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData)
{
qDebug() << Q_FUNC_INFO;
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];
if (m_dataTracker[target][type] == 0)
{
qDebug() << "Caller was not waiting for that type of data!";
return;
}
emit info(target, type, input, output, customData);
}
void InfoSystem::finishedSlot(QString target, Tomahawk::InfoSystem::InfoType type)
{
qDebug() << Q_FUNC_INFO;
m_dataTracker[target][type] = m_dataTracker[target][type] - 1;
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];
Q_FOREACH(Tomahawk::InfoSystem::InfoType testtype, m_dataTracker[target].keys())
{
if (m_dataTracker[target][testtype] != 0)
{
qDebug() << "found outstanding request of type" << testtype;
return;
}
}
qDebug() << "emitting finished with target" << target;
emit finished(target);
}

View File

@ -11,11 +11,8 @@ class Jabber : public QObject
Q_OBJECT
public:
Jabber(const QString &jid,
const QString password,
const QString server = "",
const int port=-1)
: p( jid, password, server, port )
Jabber( const QString &jid, const QString password, const QString server = "", const int port=-1 )
: p( jid, password, server, port )
{
}
@ -24,6 +21,11 @@ public:
// p.disconnect();
}
void setProxy( QNetworkProxy* proxy )
{
p.setProxy( proxy );
}
public slots:
void start()

View File

@ -2,6 +2,8 @@
#include <QDebug>
#include <QTime>
#include <QString>
#include <QRegExp>
using namespace gloox;
using namespace std;
@ -62,6 +64,40 @@ Jabber_p::~Jabber_p()
}
}
void
Jabber_p::setProxy( QNetworkProxy* proxy )
{
qDebug() << Q_FUNC_INFO;
if( !m_client || !proxy )
{
qDebug() << "No client or no proxy";
return;
}
QNetworkProxy appProx = QNetworkProxy::applicationProxy();
QNetworkProxy* prox = proxy->type() == QNetworkProxy::DefaultProxy ? &appProx : proxy;
if( prox->type() == QNetworkProxy::NoProxy )
{
qDebug() << "Setting proxy to none";
m_client->setConnectionImpl( new gloox::ConnectionTCPClient( m_client.data(), m_client->logInstance(), m_client->server(), m_client->port() ) );
}
else if( proxy->type() == QNetworkProxy::Socks5Proxy )
{
qDebug() << "Setting proxy to SOCKS5";
m_client->setConnectionImpl( new gloox::ConnectionSOCKS5Proxy( m_client.data(),
new gloox::ConnectionTCPClient( m_client->logInstance(), proxy->hostName().toStdString(), proxy->port() ),
m_client->logInstance(), m_client->server(), m_client->port() ) );
}
else
{
qDebug() << "Proxy type unknown";
}
}
void
Jabber_p::go()
{
@ -79,8 +115,10 @@ Jabber_p::go()
m_client->setPresence( Presence::Available, 1, "Tomahawk available" );
// m_client->connect();
// return;
// m_client->connect();
// return;
// Handle proxy
if( m_client->connect( false ) )
{
@ -400,14 +438,21 @@ Jabber_p::handleRosterPresence( const RosterItem& item, const std::string& resou
return;
// ignore anyone not running tomahawk:
if( jid.full().find( "/tomahawk" ) == string::npos )
// convert to QString to get proper regex support
QString res( jid.resource().c_str() );
QRegExp regex( "tomahawk\\d+" );
if( res != "tomahawk-tomahawk" && !res.contains( regex ) )
{
qDebug() << "not considering resource of " << res;
// Disco them to check if they are tomahawk-capable
//qDebug() << "No tomahawk resource, DISCOing... " << jid.full().c_str();
//m_client->disco()->getDiscoInfo( jid, "", this, 0 );
return;
}
qDebug() << "handling presence for resource of " << res;
//qDebug() << Q_FUNC_INFO << "jid: " << QString::fromStdString(item.jid())
// << " resource: " << QString::fromStdString(resource)
// << " presencetype " << presence;

View File

@ -9,6 +9,7 @@
#include <QObject>
#include <QSharedPointer>
#include <QMap>
#include <QNetworkProxy>
#include <QThread>
#include <QTimer>
@ -64,6 +65,8 @@ public:
explicit Jabber_p( const QString& jid, const QString& password, const QString& server = "", const int port = -1 );
virtual ~Jabber_p();
void setProxy( QNetworkProxy* proxy );
void disconnect();
/// GLOOX IMPLEMENTATION STUFF FOLLOWS

View File

@ -21,7 +21,7 @@ PlaylistManager::PlaylistManager( QObject* parent )
, m_currentMode( 0 )
, m_superCollectionVisible( true )
{
m_widget->setMinimumWidth( 600 );
m_widget->setMinimumWidth( 620 );
m_superCollectionViews << new CollectionView();
m_superCollectionViews.first()->setModel( m_superCollectionFlatModel );

174
src/proxydialog.ui Normal file
View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProxyDialog</class>
<widget class="QDialog" name="ProxyDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>200</height>
</rect>
</property>
<property name="windowTitle">
<string>Proxy Settings</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>30</x>
<y>160</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>141</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>16</number>
</property>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="typeBox"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="hostLineEdit">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="hostLabel">
<property name="text">
<string>Host</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="portLabel">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="portLineEdit"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="userLineEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="userLabel">
<property name="text">
<string>User</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="passwordLable">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="passwordLineEdit">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="typeLabel">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ProxyDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ProxyDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,5 +1,6 @@
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
#include "ui_proxydialog.h"
#include <QCryptographicHash>
#include <QDebug>
@ -17,7 +18,8 @@
#include <QDesktopServices>
static QString md5( const QByteArray& src )
static QString
md5( const QByteArray& src )
{
QByteArray const digest = QCryptographicHash::hash( src, QCryptographicHash::Md5 );
return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' );
@ -27,6 +29,7 @@ static QString md5( const QByteArray& src )
SettingsDialog::SettingsDialog( QWidget *parent )
: QDialog( parent )
, ui( new Ui::SettingsDialog )
, m_proxySettings( this )
, m_rejected( false )
, m_testLastFmQuery( 0 )
{
@ -39,9 +42,10 @@ SettingsDialog::SettingsDialog( QWidget *parent )
// JABBER
ui->checkBoxJabberAutoConnect->setChecked( s->jabberAutoConnect() );
ui->jabberUsername->setText( s->jabberUsername() );
ui->jabberPassword->setText(s->jabberPassword() );
ui->jabberServer->setText( s->jabberServer() );
ui->jabberPassword->setText( s->jabberPassword() );
ui->jabberServer->setText( s->jabberServer() );
ui->jabberPort->setValue( s->jabberPort() );
ui->proxyButton->setVisible( false );
if ( ui->jabberPort->text().toInt() != 5222 || !ui->jabberServer->text().isEmpty() )
{
@ -67,6 +71,7 @@ SettingsDialog::SettingsDialog( QWidget *parent )
connect( ui->pushButtonTestLastfmLogin, SIGNAL( clicked( bool) ), this, SLOT( testLastFmLogin() ) );
connect( ui->buttonBrowse, SIGNAL( clicked() ), SLOT( showPathSelector() ) );
connect( ui->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) );
connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
}
@ -117,7 +122,6 @@ SettingsDialog::~SettingsDialog()
{
APP->reconnectJabber();
}
}
else
qDebug() << "Settings dialog cancelled, NOT saving prefs.";
@ -126,7 +130,8 @@ SettingsDialog::~SettingsDialog()
}
void SettingsDialog::showPathSelector()
void
SettingsDialog::showPathSelector()
{
QString path = QFileDialog::getExistingDirectory(
this,
@ -141,7 +146,8 @@ void SettingsDialog::showPathSelector()
}
void SettingsDialog::doScan()
void
SettingsDialog::doScan()
{
// TODO this doesnt really belong here..
QString path = ui->lineEditMusicPath->text();
@ -155,13 +161,15 @@ void SettingsDialog::doScan()
}
void SettingsDialog::onRejected()
void
SettingsDialog::onRejected()
{
m_rejected = true;
}
void SettingsDialog::changeEvent( QEvent *e )
void
SettingsDialog::changeEvent( QEvent *e )
{
QDialog::changeEvent( e );
switch ( e->type() )
@ -176,7 +184,17 @@ void SettingsDialog::changeEvent( QEvent *e )
}
void SettingsDialog::testLastFmLogin()
void
SettingsDialog::showProxySettings()
{
m_proxySettings.exec();
if ( m_proxySettings.result() == QDialog::Accepted )
m_proxySettings.saveSettings();
}
void
SettingsDialog::testLastFmLogin()
{
#ifndef NO_LIBLASTFM
ui->pushButtonTestLastfmLogin->setEnabled( false );
@ -196,7 +214,8 @@ void SettingsDialog::testLastFmLogin()
}
void SettingsDialog::onLastFmFinished()
void
SettingsDialog::onLastFmFinished()
{
#ifndef NO_LIBLASTFM
lastfm::XmlQuery lfm = lastfm::XmlQuery( m_testLastFmQuery->readAll() );
@ -233,3 +252,61 @@ void SettingsDialog::onLastFmFinished()
#endif
}
ProxyDialog::ProxyDialog( QWidget *parent )
: QDialog( parent )
, ui( new Ui::ProxyDialog )
{
ui->setupUi( this );
// ugly, I know, but...
QHash<int,int> enumMap;
int i = 0;
ui->typeBox->insertItem( i, "No Proxy", QNetworkProxy::NoProxy );
enumMap[QNetworkProxy::NoProxy] = i++;
ui->typeBox->insertItem( i, "SOCKS 5", QNetworkProxy::Socks5Proxy );
enumMap[QNetworkProxy::Socks5Proxy] = i++;
TomahawkSettings* s = TomahawkApp::instance()->settings();
ui->typeBox->setCurrentIndex( enumMap[s->proxyType()] );
ui->hostLineEdit->setText( s->proxyHost() );
ui->portLineEdit->setText( QString::number( s->proxyPort() ) );
ui->userLineEdit->setText( s->proxyUsername() );
ui->passwordLineEdit->setText( s->proxyPassword() );
}
void
ProxyDialog::saveSettings()
{
qDebug() << Q_FUNC_INFO;
//First set settings
TomahawkSettings* s = TomahawkApp::instance()->settings();
s->setProxyHost( ui->hostLineEdit->text() );
bool ok;
qulonglong port = ui->portLineEdit->text().toULongLong( &ok );
if( ok )
s->setProxyPort( port );
s->setProxyUsername( ui->userLineEdit->text() );
s->setProxyPassword( ui->passwordLineEdit->text() );
s->setProxyType( ui->typeBox->itemData( ui->typeBox->currentIndex() ).toInt() );
// Now, if a proxy is defined, set QNAM
if( s->proxyType() == QNetworkProxy::NoProxy || s->proxyHost().isEmpty() )
return;
QNetworkProxy proxy( static_cast<QNetworkProxy::ProxyType>(s->proxyType()), s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() );
QNetworkAccessManager* nam = TomahawkApp::instance()->nam();
nam->setProxy( proxy );
QNetworkProxy* globalProxy = TomahawkApp::instance()->proxy();
QNetworkProxy* oldProxy = globalProxy;
globalProxy = new QNetworkProxy( proxy );
if( oldProxy )
delete oldProxy;
QNetworkProxy::setApplicationProxy( proxy );
}

View File

@ -8,8 +8,23 @@ class QNetworkReply;
namespace Ui
{
class SettingsDialog;
class ProxyDialog;
}
class ProxyDialog : public QDialog
{
Q_OBJECT
public:
explicit ProxyDialog( QWidget *parent = 0 );
~ProxyDialog() {};
void saveSettings();
private:
Ui::ProxyDialog *ui;
};
class SettingsDialog : public QDialog
{
Q_OBJECT
@ -31,12 +46,15 @@ private slots:
void showPathSelector();
void doScan();
void showProxySettings();
void testLastFmLogin();
void onLastFmFinished();
private:
Ui::SettingsDialog *ui;
ProxyDialog m_proxySettings;
bool m_rejected;
QNetworkReply* m_testLastFmQuery;
};

View File

@ -224,6 +224,43 @@
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="proxyButton">
<property name="text">
<string>Proxy Settings...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
@ -234,7 +271,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>146</height>
<height>73</height>
</size>
</property>
</spacer>
@ -531,5 +568,21 @@
</hint>
</hints>
</connection>
<connection>
<sender>checkBoxJabberAdvanced</sender>
<signal>toggled(bool)</signal>
<receiver>proxyButton</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>310</x>
<y>110</y>
</hint>
<hint type="destinationlabel">
<x>368</x>
<y>194</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -7,12 +7,14 @@
#include <QNetworkReply>
#include "tomahawk/collection.h"
#include "tomahawk/infosystem.h"
#include "database/database.h"
#include "database/databasecollection.h"
#include "database/databasecommand_collectionstats.h"
#include "database/databaseresolver.h"
#include "jabber/jabber.h"
#include "utils/tomahawkutils.h"
#include "xmppbot/xmppbot.h"
#include "web/api_v1.h"
#include "scriptresolver.h"
@ -101,6 +103,8 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
, m_zeroconf( 0 )
, m_settings( 0 )
, m_nam( 0 )
, m_proxy( 0 )
, m_infoSystem( 0 )
{
qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) );
@ -157,6 +161,24 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
}
#endif
// Set up proxy
if( m_settings->proxyType() != QNetworkProxy::NoProxy && !m_settings->proxyHost().isEmpty() )
{
qDebug() << "Setting proxy to saved values";
m_proxy = new QNetworkProxy( static_cast<QNetworkProxy::ProxyType>(m_settings->proxyType()), m_settings->proxyHost(), m_settings->proxyPort(), m_settings->proxyUsername(), m_settings->proxyPassword() );
qDebug() << "Proxy type = " << QString::number( static_cast<int>(m_proxy->type()) );
qDebug() << "Proxy host = " << m_proxy->hostName();
QNetworkAccessManager* nam = TomahawkApp::instance()->nam();
nam->setProxy( *m_proxy );
}
else
m_proxy = new QNetworkProxy( QNetworkProxy::NoProxy );
QNetworkProxy::setApplicationProxy( *m_proxy );
m_infoSystem = new Tomahawk::InfoSystem::InfoSystem( this );
m_xmppBot = new XMPPBot( this );
boost::function<QSharedPointer<QIODevice>(result_ptr)> fac =
boost::bind( &TomahawkApp::httpIODeviceFactory, this, _1 );
this->registerIODeviceFactory( "http", fac );
@ -449,6 +471,7 @@ TomahawkApp::setupJabber() //const QString& jid, const QString& pass, const QStr
connect( m_jabber.data(), SIGNAL( connected() ), SLOT( jabberConnected() ) );
connect( m_jabber.data(), SIGNAL( authError(int, const QString&) ), SLOT( jabberAuthError(int,const QString&) ) );
m_jabber->setProxy( m_proxy );
m_jabber->start();
}

View File

@ -21,8 +21,8 @@ TomahawkSettings::TomahawkSettings( QObject* parent )
else if( value( "configversion" ).toUInt() != SettingsDialog::VERSION )
{
qDebug() << "Config version outdated, old:" << value( "configversion" ).toUInt()
<< "new:" << SettingsDialog::VERSION
<< "Doing upgrade, if any...";
<< "new:" << SettingsDialog::VERSION
<< "Doing upgrade, if any...";
// insert upgrade code here as required
setValue( "configversion", SettingsDialog::VERSION );
@ -36,7 +36,8 @@ TomahawkSettings::~TomahawkSettings()
}
QString TomahawkSettings::scannerPath() const
QString
TomahawkSettings::scannerPath() const
{
#ifndef TOMAHAWK_HEADLESS
return value( "scannerpath", QDesktopServices::storageLocation( QDesktopServices::MusicLocation ) ).toString();
@ -46,181 +47,337 @@ QString TomahawkSettings::scannerPath() const
}
void TomahawkSettings::setScannerPath(const QString& path)
void
TomahawkSettings::setScannerPath( const QString& path )
{
setValue( "scannerpath", path );
}
bool TomahawkSettings::hasScannerPath() const
bool
TomahawkSettings::hasScannerPath() const
{
return contains( "scannerpath" );
}
bool TomahawkSettings::httpEnabled() const
bool
TomahawkSettings::httpEnabled() const
{
return value( "network/http", true ).toBool();
}
void TomahawkSettings::setHttpEnabled(bool enable)
void
TomahawkSettings::setHttpEnabled( bool enable )
{
setValue( "network/http", enable );
}
QByteArray TomahawkSettings::mainWindowGeometry() const
QString
TomahawkSettings::proxyHost() const
{
return value( "network/proxy/host", QString() ).toString();
}
void
TomahawkSettings::setProxyHost( const QString& host )
{
setValue( "network/proxy/host", host );
}
qulonglong
TomahawkSettings::proxyPort() const
{
return value( "network/proxy/port", 1080 ).toULongLong();
}
void
TomahawkSettings::setProxyPort( const qulonglong port )
{
setValue( "network/proxy/port", port );
}
QString
TomahawkSettings::proxyUsername() const
{
return value( "network/proxy/username", QString() ).toString();
}
void
TomahawkSettings::setProxyUsername( const QString& username )
{
setValue( "network/proxy/username", username );
}
QString
TomahawkSettings::proxyPassword() const
{
return value( "network/proxy/password", QString() ).toString();
}
void
TomahawkSettings::setProxyPassword( const QString& password )
{
setValue( "network/proxy/password", password );
}
int
TomahawkSettings::proxyType() const
{
return value( "network/proxy/type", 0 ).toInt();
}
void
TomahawkSettings::setProxyType( const int type )
{
setValue( "network/proxy/type", type );
}
QByteArray
TomahawkSettings::mainWindowGeometry() const
{
return value( "ui/mainwindow/geometry" ).toByteArray();
}
void TomahawkSettings::setMainWindowGeometry(const QByteArray& geom)
void
TomahawkSettings::setMainWindowGeometry( const QByteArray& geom )
{
setValue( "ui/mainwindow/geometry", geom );
}
QByteArray TomahawkSettings::mainWindowState() const
QByteArray
TomahawkSettings::mainWindowState() const
{
return value( "ui/mainwindow/state" ).toByteArray();
}
void TomahawkSettings::setMainWindowState(const QByteArray& state)
void
TomahawkSettings::setMainWindowState( const QByteArray& state )
{
setValue( "ui/mainwindow/state", state );
}
QList<QVariant> TomahawkSettings::playlistColumnSizes() const
QList<QVariant>
TomahawkSettings::playlistColumnSizes() const
{
return value( "ui/playlist/columnSize" ).toList();
}
void TomahawkSettings::setPlaylistColumnSizes(const QList<QVariant>& cols)
void
TomahawkSettings::setPlaylistColumnSizes( const QList<QVariant>& cols )
{
setValue( "ui/playlist/geometry", cols );
}
bool TomahawkSettings::jabberAutoConnect() const
bool
TomahawkSettings::jabberAutoConnect() const
{
return value( "jabber/autoconnect", true ).toBool();
}
void TomahawkSettings::setJabberAutoConnect(bool autoconnect)
void
TomahawkSettings::setJabberAutoConnect( bool autoconnect )
{
setValue( "jabber/autoconnect", autoconnect );
}
int TomahawkSettings::jabberPort() const
int
TomahawkSettings::jabberPort() const
{
return value( "jabber/port", 5222 ).toInt();
}
void TomahawkSettings::setJabberPort(int port)
void
TomahawkSettings::setJabberPort( int port )
{
setValue( "jabber/port", port );
}
QString TomahawkSettings::jabberServer() const
QString
TomahawkSettings::jabberServer() const
{
return value( "jabber/server" ).toString();
}
void TomahawkSettings::setJabberServer(const QString& server)
void
TomahawkSettings::setJabberServer( const QString& server )
{
setValue( "jabber/server", server );
}
QString TomahawkSettings::jabberUsername() const
QString
TomahawkSettings::jabberUsername() const
{
return value( "jabber/username" ).toString();
}
void TomahawkSettings::setJabberUsername(const QString& username)
void
TomahawkSettings::setJabberUsername( const QString& username )
{
setValue( "jabber/username", username );
}
QString TomahawkSettings::jabberPassword() const
QString
TomahawkSettings::jabberPassword() const
{
return value( "jabber/password" ).toString();
}
void TomahawkSettings::setJabberPassword(const QString& pw)
void
TomahawkSettings::setJabberPassword( const QString& pw )
{
setValue( "jabber/password", pw );
}
bool TomahawkSettings::upnpEnabled() const
bool
TomahawkSettings::upnpEnabled() const
{
return value( "network/upnp", true ).toBool();
}
void TomahawkSettings::setUPnPEnabled(bool enable)
void
TomahawkSettings::setUPnPEnabled( bool enable )
{
setValue( "network/upnp", enable );
}
QString TomahawkSettings::lastFmPassword() const
QString
TomahawkSettings::lastFmPassword() const
{
return value( "lastfm/password" ).toString();
}
void TomahawkSettings::setLastFmPassword(const QString& password)
void
TomahawkSettings::setLastFmPassword( const QString& password )
{
setValue( "lastfm/password", password );
}
QByteArray TomahawkSettings::lastFmSessionKey() const
QByteArray
TomahawkSettings::lastFmSessionKey() const
{
return value( "lastfm/sessionkey" ).toByteArray();
}
void TomahawkSettings::setLastFmSessionKey(const QByteArray& key)
void
TomahawkSettings::setLastFmSessionKey( const QByteArray& key )
{
setValue( "lastfm/sessionkey", key );
}
QString TomahawkSettings::lastFmUsername() const
QString
TomahawkSettings::lastFmUsername() const
{
return value( "lastfm/username" ).toString();
}
void TomahawkSettings::setLastFmUsername(const QString& username )
void
TomahawkSettings::setLastFmUsername( const QString& username )
{
setValue( "lastfm/username", username );
}
bool TomahawkSettings::scrobblingEnabled() const
bool
TomahawkSettings::scrobblingEnabled() const
{
return value( "lastfm/enablescrobbling", false ).toBool();
}
void TomahawkSettings::setScrobblingEnabled(bool enable)
void
TomahawkSettings::setScrobblingEnabled( bool enable )
{
setValue( "lastfm/enablescrobbling", enable );
}
QString
TomahawkSettings::xmppBotServer() const
{
return value( "xmppBot/server", QString() ).toString();
}
void
TomahawkSettings::setXmppBotServer( const QString& server )
{
setValue( "xmppBot/server", server );
}
QString
TomahawkSettings::xmppBotJid() const
{
return value( "xmppBot/jid", QString() ).toString();
}
void
TomahawkSettings::setXmppBotJid( const QString& component )
{
setValue( "xmppBot/jid", component );
}
QString
TomahawkSettings::xmppBotPassword() const
{
return value( "xmppBot/password", QString() ).toString();
}
void
TomahawkSettings::setXmppBotPassword( const QString& password )
{
setValue( "xmppBot/password", password );
}
int
TomahawkSettings::xmppBotPort() const
{
return value( "xmppBot/port", -1 ).toInt();
}
void
TomahawkSettings::setXmppBotPort( const int port )
{
setValue( "xmppBot/port", -1 );
}

View File

@ -50,7 +50,22 @@ public:
bool upnpEnabled() const; /// true by default
void setUPnPEnabled( bool enable );
QString proxyHost() const;
void setProxyHost( const QString &host );
qulonglong proxyPort() const;
void setProxyPort( const qulonglong port );
QString proxyUsername() const;
void setProxyUsername( const QString &username );
QString proxyPassword() const;
void setProxyPassword( const QString &password );
int proxyType() const;
void setProxyType( const int type );
/// Last.fm settings
bool scrobblingEnabled() const; /// false by default
void setScrobblingEnabled( bool enable );
@ -63,6 +78,19 @@ public:
QByteArray lastFmSessionKey() const;
void setLastFmSessionKey( const QByteArray& key );
/// XMPP Component Settings
QString xmppBotServer() const;
void setXmppBotServer( const QString &server );
QString xmppBotJid() const;
void setXmppBotJid( const QString &component );
QString xmppBotPassword() const;
void setXmppBotPassword( const QString &password );
int xmppBotPort() const;
void setXmppBotPort( const int port );
};
#endif

396
src/xmppbot/xmppbot.cpp Normal file
View File

@ -0,0 +1,396 @@
#include "xmppbot.h"
#include "tomahawk/tomahawkapp.h"
#include "tomahawk/infosystem.h"
#include <tomahawksettings.h>
#include <audio/audioengine.h>
#include <gloox/client.h>
#include <gloox/rostermanager.h>
#include <gloox/message.h>
#include <QtCore/QStringList>
using namespace gloox;
using namespace Tomahawk::InfoSystem;
static QString s_infoIdentifier = QString("XMPPBot");
XMPPBot::XMPPBot(QObject *parent)
: QObject(parent)
, m_currReturnMessage("\n")
{
qDebug() << Q_FUNC_INFO;
TomahawkSettings *settings = TomahawkApp::instance()->settings();
QString server = settings->xmppBotServer();
QString jidstring = settings->xmppBotJid();
QString password = settings->xmppBotPassword();
int port = settings->xmppBotPort();
if (jidstring.isEmpty() || password.isEmpty())
return;
JID jid(jidstring.toStdString());
m_client = new XMPPBotClient(this, jid, password.toStdString(), port);
if (!server.isEmpty())
m_client.data()->setServer(server.toStdString());
m_client.data()->registerConnectionListener(this);
m_client.data()->registerSubscriptionHandler(this);
m_client.data()->registerMessageHandler(this);
connect(TomahawkApp::instance()->audioEngine(), SIGNAL(started(const Tomahawk::result_ptr &)),
SLOT(newTrackSlot(const Tomahawk::result_ptr &)));
connect(TomahawkApp::instance()->infoSystem(),
SIGNAL(info(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)),
SLOT(infoReturnedSlot(QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomDataHash)));
connect(TomahawkApp::instance()->infoSystem(), SIGNAL(finished(QString)), SLOT(infoFinishedSlot(QString)));
bool success = m_client.data()->gloox::Client::connect(false);
if (success)
m_client.data()->run();
else
qDebug() << "XMPPBot failed to connect with Client";
}
XMPPBot::~XMPPBot()
{
qDebug() << Q_FUNC_INFO;
if (!m_client.isNull())
m_client.data()->gloox::Client::disconnect();
}
void XMPPBot::newTrackSlot(const Tomahawk::result_ptr &track)
{
m_currTrack = track;
if (!track)
return;
QString status = QString("%1 - %2 (%3)")
.arg(track->artist())
.arg(track->track())
.arg(track->album());
m_client.data()->setPresence(Presence::Chat, 1, status.toStdString());
}
void XMPPBot::onConnect()
{
qDebug() << Q_FUNC_INFO;
qDebug() << "XMPPBot Connected";
}
void XMPPBot::onDisconnect(ConnectionError e)
{
qDebug() << Q_FUNC_INFO;
qDebug() << "XMPPBot Disconnected";
if (e != gloox::ConnNoError && e != gloox::ConnUserDisconnected)
qDebug() << "ERROR: in XMPPBot, disconnected";
}
bool XMPPBot::onTLSConnect(const gloox::CertInfo& info)
{
//WARNING: Blindly accepts all certificates, at the moment
qDebug() << Q_FUNC_INFO;
return true;
}
void XMPPBot::handleSubscription(const gloox::Subscription& subscription)
{
qDebug() << Q_FUNC_INFO;
if (subscription.subtype() == Subscription::Subscribed)
{
qDebug() << "XMPPBot is now subscribed to " << subscription.from().bare().c_str();
return;
}
else if(subscription.subtype() == Subscription::Unsubscribed)
{
qDebug() << "XMPPBot is now unsubscribed from " << subscription.from().bare().c_str();
return;
}
else if(subscription.subtype() == Subscription::Subscribe)
{
m_client.data()->rosterManager()->ackSubscriptionRequest(subscription.from().bareJID(), true);
m_client.data()->rosterManager()->subscribe(subscription.from().bareJID(), EmptyString, StringList(), "Let me in?");
}
else if(subscription.subtype() == Subscription::Unsubscribe)
{
m_client.data()->rosterManager()->ackSubscriptionRequest(subscription.from().bareJID(), true);
m_client.data()->rosterManager()->unsubscribe(subscription.from().bareJID(), "Sorry to see you go.");
}
}
void XMPPBot::handleMessage(const Message& msg, MessageSession* session)
{
//TODO: implement "properly" with MessageSessions, if the bot is to be multi-user
if (msg.subtype() != Message::Chat || msg.from().full().empty() || msg.to().full().empty())
return;
qDebug() << "jid from: " << QString::fromStdString(msg.from().full()) << ", jid to: " << QString::fromStdString(msg.to().full());
QString body = QString::fromStdString(msg.body());
QString originatingJid = QString::fromStdString(msg.from().full());
QStringList tokens(body.split(QString(" and "), QString::SkipEmptyParts));
qDebug() << "Operating on tokens: " << tokens;
if (m_currTrack.isNull() || m_currTrack->artist().isEmpty() || m_currTrack->track().isEmpty())
{
qDebug() << "XMPPBot can't figure out track";
QString m_currReturnMessage("\n\nSorry, I can't figure out what track is playing.\n\n");
Message retMsg(Message::Chat, JID(originatingJid.toStdString()), m_currReturnMessage.toStdString());
m_client.data()->send(retMsg);
return;
}
InfoMap infoMap;
Q_FOREACH(QString token, tokens)
{
if (token == "biography")
infoMap[InfoArtistBiography] = m_currTrack.data()->artist();
if (token == "terms")
infoMap[InfoArtistTerms] = m_currTrack.data()->artist();
if (token == "hotttness")
infoMap[InfoArtistHotttness] = m_currTrack.data()->artist();
if (token == "familiarity")
infoMap[InfoArtistFamiliarity] = m_currTrack.data()->artist();
if (token == "lyrics")
{
MusixMatchHash myhash;
myhash["trackName"] = m_currTrack.data()->track();
myhash["artistName"] = m_currTrack.data()->artist();
infoMap[InfoTrackLyrics] = QVariant::fromValue<Tomahawk::InfoSystem::MusixMatchHash>(myhash);
}
}
if (infoMap.isEmpty())
{
qDebug() << "XMPPBot can't figure out track";
QString m_currReturnMessage("\n\nSorry, I couldn't recognize any commands.\n\n");
Message retMsg(Message::Chat, JID(originatingJid.toStdString()), m_currReturnMessage.toStdString());
m_client.data()->send(retMsg);
return;
}
m_currInfoMap.unite(infoMap);
QString waitMsg("Please wait...");
Message retMsg(Message::Chat, JID(originatingJid.toStdString()), waitMsg.toStdString());
m_client.data()->send(retMsg);
Tomahawk::InfoSystem::InfoCustomDataHash hash;
hash["XMPPBotSendToJID"] = originatingJid;
TomahawkApp::instance()->infoSystem()->getInfo(s_infoIdentifier, infoMap, hash);
}
void XMPPBot::infoReturnedSlot(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData)
{
qDebug() << Q_FUNC_INFO;
if (caller != s_infoIdentifier ||
input.isNull() || !input.isValid() ||
!customData.contains("XMPPBotSendToJID")
)
{
qDebug() << "Not the right object, custom data is null, or don't have a set JID";
return;
}
if (!m_currInfoMap.contains(type))
{
qDebug() << "not in currInfoMap";
return;
}
else
m_currInfoMap.remove(type);
QString jid = customData["XMPPBotSendToJID"].toString();
if (!m_currReturnJid.isEmpty() && m_currReturnJid != jid && !m_currReturnMessage.isEmpty())
{
gloox::Message msg(Message::Chat, JID(jid.toStdString()), m_currReturnMessage.toStdString());
m_client.data()->send(msg);
m_currReturnMessage = QString("\n");
}
m_currReturnJid = jid;
switch(type)
{
case InfoArtistBiography:
{
qDebug() << "Artist bio requested";
if (!output.canConvert<Tomahawk::InfoSystem::InfoGenericMap>() ||
!input.canConvert<QString>()
)
{
qDebug() << "Variants failed to be valid";
break;
}
InfoGenericMap bmap = output.value<Tomahawk::InfoSystem::InfoGenericMap>();
QString artist = input.toString();
m_currReturnMessage += QString("\nBiographies for %1\n").arg(artist);
Q_FOREACH(QString source, bmap.keys())
{
m_currReturnMessage += (bmap[source]["attribution"].isEmpty() ?
QString("From %1:\n").arg(bmap[source]["site"]) :
QString("From %1 at %2:\n").arg(bmap[source]["attribution"]).arg(bmap[source]["site"]));
m_currReturnMessage += bmap[source]["text"] + QString("\n");
}
break;
}
case InfoArtistTerms:
{
qDebug() << "Artist terms requested";
if (!output.canConvert<Tomahawk::InfoSystem::InfoGenericMap>() ||
!input.canConvert<QString>()
)
{
qDebug() << "Variants failed to be valid";
break;
}
InfoGenericMap tmap = output.value<Tomahawk::InfoSystem::InfoGenericMap>();
QString artist = input.toString();
m_currReturnMessage += QString("\nTerms for %1:\n").arg(artist);
if (tmap.isEmpty())
m_currReturnMessage += QString("No terms found, sorry.");
else
{
bool first = true;
Q_FOREACH(QString term, tmap.keys())
{
if (first)
m_currReturnMessage += (first ?
QString("%1 (weight %2, frequency %3)")
.arg(term).arg(tmap[term]["weight"]).arg(tmap[term]["frequency"])
:
QString("\n%1 (weight %2, frequency %3)")
.arg(term).arg(tmap[term]["weight"]).arg(tmap[term]["frequency"])
);
first = false;
}
m_currReturnMessage += QString("\n");
}
break;
}
case InfoArtistHotttness:
{
qDebug() << "Artist hotttness requested";
if (!output.canConvert<qreal>() ||
!input.canConvert<QString>()
)
{
qDebug() << "Variants failed to be valid";
break;
}
QString artist = input.toString();
qreal retVal = output.toReal();
QString retValString = (retVal == 0.0 ? "(none)" : QString::number(retVal));
m_currReturnMessage += QString("\nHotttness for %1: %2\n").arg(artist).arg(retValString);
break;
}
case InfoArtistFamiliarity:
{
qDebug() << "Artist familiarity requested";
if (!output.canConvert<qreal>() ||
!input.canConvert<QString>()
)
{
qDebug() << "Variants failed to be valid";
break;
}
QString artist = input.toString();
qreal retVal = output.toReal();
QString retValString = (retVal == 0.0 ? "(none)" : QString::number(retVal));
m_currReturnMessage += QString("\nFamiliartiy for %1: %2\n").arg(artist).arg(retValString);
break;
}
case InfoTrackLyrics:
{
qDebug() << "Lyrics requested";
if (!output.canConvert<QString>() ||
!input.canConvert<Tomahawk::InfoSystem::MusixMatchHash>()
)
{
qDebug() << "Variants failed to be valid";
break;
}
MusixMatchHash inHash = input.value<MusixMatchHash>();
QString artist = inHash["artistName"];
QString track = inHash["trackName"];
QString lyrics = output.toString();
qDebug() << "lyrics = " << lyrics;
m_currReturnMessage += QString("\nLyrics for \"%1\" by %2:\n\n%3\n").arg(track).arg(artist).arg(lyrics);
break;
}
default:
break;
}
if (m_currReturnMessage.isEmpty())
{
qDebug() << "Empty message, not sending anything back";
return;
}
qDebug() << "Going to send message: " << m_currReturnMessage << " to " << jid;
//gloox::Message msg(Message::Chat, JID(jid.toStdString()), m_currReturnMessage.toStdString());
//m_client.data()->send(msg);
}
void XMPPBot::infoFinishedSlot(QString caller)
{
qDebug() << Q_FUNC_INFO;
qDebug() << "current return message is" << m_currReturnMessage;
qDebug() << "id is" << caller << "and our id is" << s_infoIdentifier;
if (m_currReturnMessage.isEmpty() || caller != s_infoIdentifier)
return;
qDebug() << "Sending message to JID" << m_currReturnJid;
gloox::Message msg(Message::Chat, JID(m_currReturnJid.toStdString()), m_currReturnMessage.toStdString());
m_client.data()->send(msg);
m_currReturnMessage = QString("\n");
m_currReturnJid.clear();
}
///////////////////////////////////////////////////////////////////////////////////////
XMPPBotClient::XMPPBotClient(QObject *parent, JID &jid, std::string password, int port)
: QObject(parent)
, Client(jid, password, port)
, m_timer(this)
{
qDebug() << Q_FUNC_INFO;
setResource(QString( "tomahawkbot%1" ).arg( qrand() ).toStdString() );
// the google hack, because they filter disco features they don't know.
if( server().find( "googlemail." ) != std::string::npos
|| server().find( "gmail." ) != std::string::npos
|| server().find( "gtalk." ) != std::string::npos )
{
if( resource().find( "tomahawkbot" ) == std::string::npos )
{
qDebug() << "Forcing your /resource to contain 'tomahawk' (the google workaround)";
setResource( "tomahawkbot-tomahawkbot" );
}
}
}
XMPPBotClient::~XMPPBotClient()
{
qDebug() << Q_FUNC_INFO;
}
void XMPPBotClient::run()
{
qDebug() << Q_FUNC_INFO;
setPresence(Presence::Chat, 1, "Hi!");
QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(recvSlot()));
m_timer.start(200);
qDebug() << "XMPPBot running";
}
void XMPPBotClient::recvSlot()
{
gloox::ConnectionError error = recv(100);
if (error != gloox::ConnNoError)
qDebug() << "ERROR: in XMPPBotClient::recvSlot";
}

74
src/xmppbot/xmppbot.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef XMPPBOT_H
#define XMPPBOT_H
#include <tomahawk/result.h>
#include <tomahawk/infosystem.h>
#include <QtCore/QObject>
#include <QtCore/qsharedpointer.h>
#include <QTimer>
#include <gloox/messagehandler.h>
#include <gloox/messagesessionhandler.h>
#include <gloox/client.h>
#include <gloox/connectionlistener.h>
#include <gloox/subscriptionhandler.h>
#include <gloox/messagehandler.h>
class XMPPBotClient
: public QObject
, public gloox::Client
{
Q_OBJECT
public:
XMPPBotClient(QObject* parent, gloox::JID &jid, std::string password, int port);
virtual ~XMPPBotClient();
void run();
private slots:
void recvSlot();
private:
QTimer m_timer;
};
class XMPPBot
: public QObject
, public gloox::ConnectionListener
, public gloox::SubscriptionHandler
, public gloox::MessageHandler
{
Q_OBJECT
public:
XMPPBot(QObject *parent);
virtual ~XMPPBot();
public slots:
virtual void newTrackSlot(const Tomahawk::result_ptr &track);
virtual void infoReturnedSlot(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomDataHash customData);
virtual void infoFinishedSlot(QString caller);
protected:
// ConnectionListener
virtual void onConnect();
virtual void onDisconnect(gloox::ConnectionError e);
virtual bool onTLSConnect(const gloox::CertInfo &info);
// SubscriptionHandler
virtual void handleSubscription(const gloox::Subscription &subscription);
// MessageHandler
virtual void handleMessage(const gloox::Message &msg, gloox::MessageSession *session = 0);
private:
QWeakPointer<XMPPBotClient> m_client;
Tomahawk::result_ptr m_currTrack;
Tomahawk::InfoSystem::InfoMap m_currInfoMap;
QString m_currReturnMessage;
QString m_currReturnJid;
};
#endif // XMPPBOT_H