1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-20 21:02:26 +02:00

Merge branch 'master' of github.com:tomahawk-player/tomahawk

Conflicts:
	src/libtomahawk/tomahawksettings.cpp
	src/libtomahawk/tomahawksettings.h
	src/sip/jreen/jabber.cpp
	src/sip/jreen/jabber.h
	src/tomahawkapp.cpp
	src/tomahawkwindow.h
	thirdparty/jreen
This commit is contained in:
Leo Franchi
2011-05-03 15:56:08 -04:00
58 changed files with 2102 additions and 1186 deletions

View File

@@ -39,6 +39,11 @@ INCLUDE( MacroLogFeature )
set(LIBLASTFM_FOUND true) set(LIBLASTFM_FOUND true)
find_package(Phonon REQUIRED) find_package(Phonon REQUIRED)
if(PHONON_VERSION STRLESS "4.5.0")
message(FATAL_ERROR "Phonon version 4.5.0 or higher is required, you have version ${PHONON_VERSION}")
else()
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
endif()
macro_optional_find_package(LibEchonest 1.1.1) macro_optional_find_package(LibEchonest 1.1.1)
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest is needed for dynamic playlists and the infosystem") macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest is needed for dynamic playlists and the infosystem")

View File

@@ -31,11 +31,11 @@ else(PHONON_FOUND)
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY) endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
# As discussed on kde-buildsystem: first look at CMAKE_PREFIX_PATH, then at the suggested PATHS (kde4 install dir) # As discussed on kde-buildsystem: first look at CMAKE_PREFIX_PATH, then at the suggested PATHS (kde4 install dir)
find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
# then at the default system locations (CMAKE_SYSTEM_PREFIX_PATH, i.e. /usr etc.) # then at the default system locations (CMAKE_SYSTEM_PREFIX_PATH, i.e. /usr etc.)
find_library(PHONON_LIBRARY NAMES phonon phonon4) find_library(PHONON_LIBRARY NAMES phonon phonon4)
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h) find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h)
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY) if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)

View File

@@ -39,6 +39,7 @@ SET( tomahawkSources ${tomahawkSources}
musicscanner.cpp musicscanner.cpp
shortcuthandler.cpp shortcuthandler.cpp
globalactionmanager.cpp
scanmanager.cpp scanmanager.cpp
tomahawkapp.cpp tomahawkapp.cpp
main.cpp main.cpp
@@ -83,6 +84,7 @@ SET( tomahawkHeaders ${tomahawkHeaders}
musicscanner.h musicscanner.h
scanmanager.h scanmanager.h
shortcuthandler.h shortcuthandler.h
globalactionmanager.h
) )
IF(LIBLASTFM_FOUND) IF(LIBLASTFM_FOUND)

360
src/globalactionmanager.cpp Normal file
View File

@@ -0,0 +1,360 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "globalactionmanager.h"
#include "audio/audioengine.h"
#include "utils/xspfloader.h"
#include "sourcelist.h"
#include "playlist/dynamic/GeneratorInterface.h"
#include "viewmanager.h"
#include "playlist/topbar/topbar.h"
#include "pipeline.h"
#include "database/localcollection.h"
#include "playlist/playlistview.h"
#include "echonest/Playlist.h"
#include <QUrl>
#include <Playlist.h>
GlobalActionManager* GlobalActionManager::s_instance = 0;
GlobalActionManager*
GlobalActionManager::instance()
{
if( !s_instance )
s_instance = new GlobalActionManager;
return s_instance;
}
GlobalActionManager::GlobalActionManager( QObject* parent )
: QObject( parent )
{
}
GlobalActionManager::~GlobalActionManager()
{}
bool
GlobalActionManager::parseTomahawkLink( const QString& url )
{
if( url.contains( "tomahawk://" ) ) {
QString cmd = url.mid( 11 );
qDebug() << "Parsing tomahawk link command" << cmd;
QString cmdType = cmd.split( "/" ).first();
QUrl u( cmd );
// for backwards compatibility
if( cmdType == "load" ) {
if( u.hasQueryItem( "xspf" ) ) {
QUrl xspf = QUrl::fromUserInput( u.queryItemValue( "xspf" ) );
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << xspf.toString();
l->load( xspf );
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
return true;
}
}
if( cmdType == "playlist" ) {
return handlePlaylistCommand( u );
} else if( cmdType == "collection" ) {
return handleCollectionCommand( u );
} else if( cmdType == "queue" ) {
return handleQueueCommand( u );
} else if( cmdType == "station" ) {
return handleStationCommand( u );
} else if( cmdType == "search" ) {
return handleSearchCommand( u );
} else if( cmdType == "play" ) {
return handlePlayCommand( u );
} else {
qDebug() << "Tomahawk link not supported, command not known!" << cmdType << u.path();
return false;
}
} else {
qDebug() << "Not a tomahawk:// link!";
return false;
}
}
bool
GlobalActionManager::handlePlaylistCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific playlist command:" << url.toString();
return false;
}
if( parts[ 0 ] == "import" ) {
if( !url.hasQueryItem( "xspf" ) ) {
qDebug() << "No xspf to load..";
return false;
}
QUrl xspf = QUrl( url.queryItemValue( "xspf" ) );
QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString();
XSPFLoader* l= new XSPFLoader( true, this );
l->setOverrideTitle( title );
l->load( xspf );
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
} else if( parts [ 0 ] == "new" ) {
if( !url.hasQueryItem( "title" ) ) {
qDebug() << "New playlist command needs a title...";
return false;
}
Tomahawk::playlist_ptr pl = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), url.queryItemValue( "title" ), QString(), QString(), false );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >() );
ViewManager::instance()->show( pl );
} else if( parts[ 0 ] == "add" ) {
if( !url.hasQueryItem( "playlistid" ) || !url.hasQueryItem( "track" ) || !url.hasQueryItem( "artist" ) ) {
qDebug() << "Add to playlist command needs playlistid, track, and artist..." << url.toString();
return false;
}
// TODO implement. Let the user select what playlist to add to
return false;
}
return false;
}
bool
GlobalActionManager::handleCollectionCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific collection command:" << url.toString();
return false;
}
if( parts[ 0 ] == "add" ) {
// TODO implement
}
return false;
}
bool
GlobalActionManager::handleQueueCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific queue command:" << url.toString();
return false;
}
if( parts[ 0 ] == "add" ) {
if( parts.size() > 1 && parts[ 1 ] == "track" ) {
QPair< QString, QString > pair;
foreach( pair, url.queryItems() ) {
if( pair.first != "url" )
continue;
QUrl track = QUrl::fromUserInput( pair.second );
//FIXME: isLocalFile is Qt 4.8
if( track.toString().startsWith( "file://" ) ) { // it's local, so we see if it's in the DB and load it if so
// TODO
} else { // give it a web result hint
// TODO actually read the tags
QFileInfo info( track.path() );
Tomahawk::query_ptr q = Tomahawk::Query::get( QString(), info.baseName(), QString() );
q->setResultHint( track.toString() );
Tomahawk::Pipeline::instance()->resolve( q, true );
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->showQueue();
}
return true;
}
} else {
qDebug() << "Only queue/add/track is support at the moment, got:" << parts;
return false;
}
}
return false;
}
bool
GlobalActionManager::handleSearchCommand( const QUrl& url )
{
// open the super collection and set this as the search filter
QStringList query;
if( url.hasQueryItem( "artist" ) )
query << url.queryItemValue( "artist" );
if( url.hasQueryItem( "album" ) )
query << url.queryItemValue( "album" );
if( url.hasQueryItem( "track" ) )
query << url.queryItemValue( "track" );
QString queryStr = query.join( " " );
if( queryStr.isEmpty() )
return false;
ViewManager::instance()->showSuperCollection();
ViewManager::instance()->topbar()->setFilter( queryStr );
return true;
}
bool
GlobalActionManager::handleStationCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific station command:" << url.toString();
return false;
}
if( parts[ 0 ] == "create" ) {
if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) {
qDebug() << "Station create command needs title and type..." << url.toString();
return false;
}
QString title = url.queryItemValue( "title" );
QString type = url.queryItemValue( "type" );
Tomahawk::dynplaylist_ptr pl = Tomahawk::DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), title, QString(), QString(), Tomahawk::OnDemand, false, type );
QList< Tomahawk::dyncontrol_ptr > controls;
QPair< QString, QString > param;
foreach( param, url.queryItems() ) {
if( param.first == "artist" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistRadioType ) );
controls << c;
} /*else if( param.first == "hotttnesss" ) { TODO
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
c->setInput( param.second );
c->setMatch( 0 );
controls << c;
} */
}
pl->createNewRevision( uuid(), pl->currentrevision(), type, controls );
return true;
}
return false;
}
bool
GlobalActionManager::handlePlayCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific play command:" << url.toString();
return false;
}
if( parts[ 0 ] == "track" ) {
QPair< QString, QString > pair;
QString title, artist, album, urlStr;
foreach( pair, url.queryItems() ) {
if( pair.first == "track" )
title = pair.second;
else if( pair.first == "artist" )
artist = pair.second;
else if( pair.first == "album" )
album = pair.second;
else if( pair.first == "url" )
urlStr = pair.second;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album );
if( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Tomahawk::Pipeline::instance()->resolve( q, true );
// now we add it to the special "bookmarks" playlist, creating it if it doesn't exist. if nothing is playing, start playing the track
QSharedPointer< LocalCollection > col = SourceList::instance()->getLocal()->collection().dynamicCast< LocalCollection >();
Tomahawk::playlist_ptr bookmarkpl = col->bookmarksPlaylist();
if( bookmarkpl.isNull() ) { // create it and do the deed then
m_waitingToBookmark = q;
col->createBookmarksPlaylist();
connect( col.data(), SIGNAL( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), this, SLOT( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), Qt::UniqueConnection );
} else {
doBookmark( bookmarkpl, q );
}
return true;
}
return false;
}
void
GlobalActionManager::bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl )
{
Q_ASSERT( !m_waitingToBookmark.isNull() );
doBookmark( pl, m_waitingToBookmark );
}
void
GlobalActionManager::doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q )
{
Tomahawk::plentry_ptr e( new Tomahawk::PlaylistEntry );
e->setGuid( uuid() );
if ( q->results().count() )
e->setDuration( q->results().at( 0 )->duration() );
else
e->setDuration( 0 );
e->setLastmodified( 0 );
e->setAnnotation( "" ); // FIXME
e->setQuery( q );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >( pl->entries() ) << e );
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( showPlaylist() ) );
m_toShow = pl;
// if nothing is playing, lets start this
// TODO
if( !AudioEngine::instance()->isPlaying() ) {
connect( q.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( waitingForResolved( bool ) ) );
m_waitingToPlay = q;
}
m_waitingToBookmark.clear();
}
void
GlobalActionManager::showPlaylist()
{
if( m_toShow.isNull() )
return;
ViewManager::instance()->show( m_toShow );
m_toShow.clear();
}
void
GlobalActionManager::waitingForResolved( bool success )
{
if( success && !m_waitingToPlay.isNull() && !m_waitingToPlay->results().isEmpty() ) { // play it!
AudioEngine::instance()->playItem( AudioEngine::instance()->playlist(), m_waitingToPlay->results().first() );
}
m_waitingToPlay.clear();
}

61
src/globalactionmanager.h Normal file
View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef GLOBALACTIONMANAGER_H
#define GLOBALACTIONMANAGER_H
#include "playlist.h"
#include <QObject>
#include <QUrl>
class GlobalActionManager : public QObject
{
Q_OBJECT
public:
static GlobalActionManager* instance();
virtual ~GlobalActionManager();
public slots:
bool parseTomahawkLink( const QString& link );
void waitingForResolved( bool );
private slots:
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl );
void showPlaylist();
private:
explicit GlobalActionManager( QObject* parent = 0 );
void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q );
bool handlePlaylistCommand( const QUrl& url );
bool handleCollectionCommand(const QUrl& url );
bool handleQueueCommand(const QUrl& url );
bool handleStationCommand(const QUrl& url );
bool handleSearchCommand(const QUrl& url );
bool handlePlayCommand(const QUrl& url );
Tomahawk::playlist_ptr m_toShow;
Tomahawk::query_ptr m_waitingToBookmark;
Tomahawk::query_ptr m_waitingToPlay;
static GlobalActionManager* s_instance;
};
#endif // GLOBALACTIONMANAGER_H

View File

@@ -21,6 +21,7 @@ set( libSources
artist.cpp artist.cpp
album.cpp album.cpp
collection.cpp collection.cpp
webcollection.cpp
playlist.cpp playlist.cpp
resolver.cpp resolver.cpp
query.cpp query.cpp
@@ -38,6 +39,7 @@ set( libSources
database/database.cpp database/database.cpp
database/fuzzyindex.cpp database/fuzzyindex.cpp
database/databasecollection.cpp database/databasecollection.cpp
database/localcollection.cpp
database/databaseworker.cpp database/databaseworker.cpp
database/databaseimpl.cpp database/databaseimpl.cpp
database/databaseresolver.cpp database/databaseresolver.cpp
@@ -66,7 +68,6 @@ set( libSources
database/databasecommand_renameplaylist.cpp database/databasecommand_renameplaylist.cpp
database/databasecommand_loadops.cpp database/databasecommand_loadops.cpp
database/databasecommand_updatesearchindex.cpp database/databasecommand_updatesearchindex.cpp
database/databasecollection.cpp
database/databasecommand_setdynamicplaylistrevision.cpp database/databasecommand_setdynamicplaylistrevision.cpp
database/databasecommand_createdynamicplaylist.cpp database/databasecommand_createdynamicplaylist.cpp
database/databasecommand_loaddynamicplaylist.cpp database/databasecommand_loaddynamicplaylist.cpp
@@ -79,6 +80,7 @@ set( libSources
infosystem/infosystemcache.cpp infosystem/infosystemcache.cpp
infosystem/infosystem.cpp infosystem/infosystem.cpp
infosystem/infosystemworker.cpp
infosystem/infoplugins/echonestplugin.cpp infosystem/infoplugins/echonestplugin.cpp
infosystem/infoplugins/lastfmplugin.cpp infosystem/infoplugins/lastfmplugin.cpp
infosystem/infoplugins/musixmatchplugin.cpp infosystem/infoplugins/musixmatchplugin.cpp
@@ -174,6 +176,7 @@ set( libHeaders
aclsystem.h aclsystem.h
collection.h collection.h
webcollection.h
query.h query.h
resolver.h resolver.h
result.h result.h
@@ -223,6 +226,7 @@ set( libHeaders
database/databasecommand_loadops.h database/databasecommand_loadops.h
database/databasecommand_updatesearchindex.h database/databasecommand_updatesearchindex.h
database/databasecollection.h database/databasecollection.h
database/localcollection.h
database/databasecommand_setdynamicplaylistrevision.h database/databasecommand_setdynamicplaylistrevision.h
database/databasecommand_createdynamicplaylist.h database/databasecommand_createdynamicplaylist.h
database/databasecommand_loaddynamicplaylist.h database/databasecommand_loaddynamicplaylist.h
@@ -233,6 +237,7 @@ set( libHeaders
database/databasecommand_clientauthvalid.h database/databasecommand_clientauthvalid.h
infosystem/infosystem.h infosystem/infosystem.h
infosystem/infosystemworker.h
infosystem/infosystemcache.h infosystem/infosystemcache.h
infosystem/infoplugins/echonestplugin.h infosystem/infoplugins/echonestplugin.h
infosystem/infoplugins/lastfmplugin.h infosystem/infoplugins/lastfmplugin.h

View File

@@ -113,12 +113,6 @@ AudioEngine::stop()
m_expectStop = true; m_expectStop = true;
m_mediaObject->stop(); m_mediaObject->stop();
if ( !m_input.isNull() )
{
m_input->close();
m_input.clear();
}
setCurrentTrack( Tomahawk::result_ptr() ); setCurrentTrack( Tomahawk::result_ptr() );
emit stopped(); emit stopped();
} }
@@ -198,8 +192,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
m_expectStop = true; m_expectStop = true;
} }
m_input = io;
if ( !m_currentTrack->url().startsWith( "http://" ) ) if ( !m_currentTrack->url().startsWith( "http://" ) )
{ {
m_mediaObject->setCurrentSource( io.data() ); m_mediaObject->setCurrentSource( io.data() );
@@ -215,6 +207,9 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
} }
m_mediaObject->setCurrentSource( furl ); m_mediaObject->setCurrentSource( furl );
} }
m_input = io;
m_mediaObject->currentSource().setAutoDelete( true ); m_mediaObject->currentSource().setAutoDelete( true );
m_mediaObject->play(); m_mediaObject->play();

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
* *
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* *
* Tomahawk is free software: you can redistribute it and/or modify * Tomahawk is free software: you can redistribute it and/or modify
@@ -41,7 +41,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
{ {
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint(); qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
Tomahawk::result_ptr result = lib->result( m_query->resultHint() ); Tomahawk::result_ptr result = lib->resultFromHint( m_query );
if ( !result.isNull() && result->collection()->source()->isOnline() ) if ( !result.isNull() && result->collection()->source()->isOnline() )
{ {
res << result; res << result;
@@ -119,7 +119,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
s = SourceList::instance()->get( files_query.value( 13 ).toUInt() ); s = SourceList::instance()->get( files_query.value( 13 ).toUInt() );
if( s.isNull() ) if( s.isNull() )
{ {
Q_ASSERT( false ); qDebug() << "WTF: Could not find source" << files_query.value( 13 ).toUInt();
continue; continue;
} }

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
* *
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* *
* Tomahawk is free software: you can redistribute it and/or modify * Tomahawk is free software: you can redistribute it and/or modify
@@ -60,7 +60,7 @@ DatabaseCommand_SetPlaylistRevision::postCommitHook()
qDebug() << "Source has gone offline, not emitting to GUI."; qDebug() << "Source has gone offline, not emitting to GUI.";
return; return;
} }
if ( m_localOnly ) if ( m_localOnly )
return; return;
@@ -149,6 +149,8 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
QString resultHint; QString resultHint;
if ( !e->query()->results().isEmpty() ) if ( !e->query()->results().isEmpty() )
resultHint = e->query()->results().first()->url(); resultHint = e->query()->results().first()->url();
else if ( !e->query()->resultHint().isEmpty() )
resultHint = e->query()->resultHint();
adde.bindValue( 0, e->guid() ); adde.bindValue( 0, e->guid() );
adde.bindValue( 1, m_playlistguid ); adde.bindValue( 1, m_playlistguid );

View File

@@ -528,8 +528,9 @@ DatabaseImpl::album( int id )
Tomahawk::result_ptr Tomahawk::result_ptr
DatabaseImpl::result( const QString& url ) DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery )
{ {
QString url = origquery->resultHint();
TomahawkSqlQuery query = newquery(); TomahawkSqlQuery query = newquery();
Tomahawk::source_ptr s; Tomahawk::source_ptr s;
Tomahawk::result_ptr res; Tomahawk::result_ptr res;
@@ -552,7 +553,18 @@ DatabaseImpl::result( const QString& url )
else else
{ {
// Q_ASSERT( false ); // Q_ASSERT( false );
qDebug() << "We don't support non-servent / non-file result-hints yet."; // qDebug() << "We don't support non-servent / non-file result-hints yet.";
res = Tomahawk::result_ptr( new Tomahawk::Result() );
s = SourceList::instance()->webSource();
res->setUrl( url );
res->setCollection( s->collection() );
res->setRID( uuid() );
res->setScore( 1.0 );
res->setArtist( Tomahawk::artist_ptr( new Tomahawk::Artist( 0, origquery->artist() ) ) );
res->setAlbum( Tomahawk::album_ptr( new Tomahawk::Album( 0, origquery->album(), res->artist() ) ) );
res->setTrack( origquery->track() );
res->setDuration( origquery->duration() );
res->setFriendlySource( url );
return res; return res;
} }

View File

@@ -64,7 +64,7 @@ public:
QVariantMap album( int id ); QVariantMap album( int id );
QVariantMap track( int id ); QVariantMap track( int id );
Tomahawk::result_ptr file( int fid ); Tomahawk::result_ptr file( int fid );
Tomahawk::result_ptr result( const QString& url ); Tomahawk::result_ptr resultFromHint( const Tomahawk::query_ptr& query );
static bool scorepairSorter( const QPair<int,float>& left, const QPair<int,float>& right ) static bool scorepairSorter( const QPair<int,float>& left, const QPair<int,float>& right )
{ {

View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "localcollection.h"
#include "sourcelist.h"
#include "viewmanager.h"
#include <tomahawksettings.h>
LocalCollection::LocalCollection( const Tomahawk::source_ptr& source, QObject* parent )
: DatabaseCollection( source, parent )
{
}
Tomahawk::playlist_ptr
LocalCollection::bookmarksPlaylist()
{
if( TomahawkSettings::instance()->bookmarkPlaylist().isEmpty() )
return Tomahawk::playlist_ptr();
return playlist( TomahawkSettings::instance()->bookmarkPlaylist() );
}
void
LocalCollection::createBookmarksPlaylist()
{
if( bookmarksPlaylist().isNull() ) {
QString guid = uuid();
Tomahawk::playlist_ptr p = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), guid, tr( "Bookmarks" ), tr( "Saved tracks" ), QString(), false );
ViewManager::instance()->createPageForPlaylist( p );
// connect( p.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( loaded( Tomahawk::PlaylistRevision ) ), Qt::QueuedConnection );
connect( p.data(), SIGNAL( created() ), this, SLOT( created() ) );
TomahawkSettings::instance()->setBookmarkPlaylist( guid );
// p->createNewRevision( uuid(), p->currentrevision(), QList< Tomahawk::plentry_ptr >() );
}
}
void
LocalCollection::created()
{
emit bookmarkPlaylistCreated( bookmarksPlaylist() );
}

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef LOCALCOLLECTION_H
#define LOCALCOLLECTION_H
#include "databasecollection.h"
#include "dllmacro.h"
#include "playlist.h"
class DLLEXPORT LocalCollection : public DatabaseCollection
{
Q_OBJECT
public:
explicit LocalCollection( const Tomahawk::source_ptr& source, QObject* parent = 0 );
// gets the playlist used for storing stuff from the web, if it already exists. if the returned playlist
// is invalid ask to create and listen to the signal
Tomahawk::playlist_ptr bookmarksPlaylist();
void createBookmarksPlaylist();
signals:
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& p );
private slots:
void created();
};
#endif // LOCALCOLLECTION_H

View File

@@ -25,13 +25,16 @@ using namespace Echonest;
// for internal neatness // for internal neatness
EchoNestPlugin::EchoNestPlugin(QObject *parent) EchoNestPlugin::EchoNestPlugin(InfoSystemWorker *parent)
: InfoPlugin(parent) : InfoPlugin(parent)
, m_infoSystemWorker( parent )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
QSet< InfoType > supportedTypes; QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms; supportedTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); parent->registerInfoTypes( this, supportedTypes, QSet< InfoType>() );
connect( parent, SIGNAL( namChanged() ), SLOT( namChangedSlot() ) );
} }
EchoNestPlugin::~EchoNestPlugin() EchoNestPlugin::~EchoNestPlugin()
@@ -39,6 +42,13 @@ EchoNestPlugin::~EchoNestPlugin()
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
} }
void
EchoNestPlugin::namChangedSlot()
{
qDebug() << Q_FUNC_INFO;
Echonest::Config::instance()->setNetworkAccessManager( m_infoSystemWorker->nam() );
}
void void
EchoNestPlugin::getInfo(const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData) EchoNestPlugin::getInfo(const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData)
{ {

View File

@@ -20,6 +20,7 @@
#define ECHONESTPLUGIN_H #define ECHONESTPLUGIN_H
#include "infosystem/infosystem.h" #include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include <QObject> #include <QObject>
@@ -39,12 +40,31 @@ class EchoNestPlugin : public InfoPlugin
Q_OBJECT Q_OBJECT
public: public:
EchoNestPlugin(QObject *parent); EchoNestPlugin( InfoSystemWorker *parent );
virtual ~EchoNestPlugin(); virtual ~EchoNestPlugin();
protected slots: protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ); virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data )
{
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( data );
}
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
public slots:
void namChangedSlot();
private: private:
void getSongProfile( const QString &caller, const QVariant &input, const InfoCustomData &customData, const QString &item = QString() ); void getSongProfile( const QString &caller, const QVariant &input, const InfoCustomData &customData, const QString &item = QString() );
void getArtistBiography ( const QString &caller, const QVariant &input, const InfoCustomData &customData ); void getArtistBiography ( const QString &caller, const QVariant &input, const InfoCustomData &customData );
@@ -67,6 +87,7 @@ private slots:
private: private:
QHash< QNetworkReply*, InfoCustomData > m_replyMap; QHash< QNetworkReply*, InfoCustomData > m_replyMap;
QHash< QNetworkReply*, QString > m_callerMap; QHash< QNetworkReply*, QString > m_callerMap;
InfoSystemWorker* m_infoSystemWorker;
}; };
} }

View File

@@ -41,14 +41,18 @@ md5( const QByteArray& src )
} }
LastFmPlugin::LastFmPlugin( QObject* parent ) LastFmPlugin::LastFmPlugin( InfoSystemWorker* parent )
: InfoPlugin(parent) : InfoPlugin(parent)
, m_scrobbler( 0 ) , m_scrobbler( 0 )
, m_authJob( 0 ) , m_authJob( 0 )
, m_infoSystemWorker( parent )
{ {
QSet< InfoType > supportedTypes; QSet< InfoType > supportedGetTypes, supportedPushTypes;
supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt << InfoArtistImages; supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); supportedPushTypes << InfoSubmitScrobble << InfoSubmitNowPlaying;
parent->registerInfoTypes( this, supportedGetTypes, supportedPushTypes );
connect( parent, SIGNAL( namChanged() ), SLOT( namChangedSlot() ) );
/* /*
Your API Key is 7194b85b6d1f424fe1668173a78c0c4a Your API Key is 7194b85b6d1f424fe1668173a78c0c4a
@@ -94,6 +98,14 @@ LastFmPlugin::~LastFmPlugin()
} }
void
LastFmPlugin::namChangedSlot()
{
qDebug() << Q_FUNC_INFO;
lastfm::setNetworkAccessManager( m_infoSystemWorker->nam() );
}
void void
LastFmPlugin::dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ) LastFmPlugin::dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
{ {
@@ -109,14 +121,6 @@ LastFmPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp
switch ( type ) switch ( type )
{ {
case InfoMiscSubmitNowPlaying:
nowPlaying( caller, type, input, customData );
break;
case InfoMiscSubmitScrobble:
scrobble( caller, type, input, customData );
break;
case InfoArtistImages: case InfoArtistImages:
fetchArtistImages( caller, type, input, customData ); fetchArtistImages( caller, type, input, customData );
break; break;
@@ -132,19 +136,34 @@ LastFmPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp
void void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ) LastFmPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
{
qDebug() << Q_FUNC_INFO;
switch ( type )
{
case InfoSubmitNowPlaying:
nowPlaying( caller, type, input );
break;
case InfoSubmitScrobble:
scrobble( caller, type, input );
break;
default:
return;
}
}
void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant &input )
{ {
if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() || !m_scrobbler ) if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() || !m_scrobbler )
{
dataError( caller, type, input, customData );
return; return;
}
InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) ) if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) )
{
dataError( caller, type, input, customData );
return; return;
}
m_track = lastfm::MutableTrack(); m_track = lastfm::MutableTrack();
m_track.stamp(); m_track.stamp();
@@ -157,26 +176,20 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar
m_track.setSource( lastfm::Track::Player ); m_track.setSource( lastfm::Track::Player );
m_scrobbler->nowPlaying( m_track ); m_scrobbler->nowPlaying( m_track );
emit info( caller, type, input, QVariant(), customData );
} }
void void
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ) LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant &input )
{ {
Q_ASSERT( QThread::currentThread() == thread() ); Q_ASSERT( QThread::currentThread() == thread() );
if ( !m_scrobbler || m_track.isNull() ) if ( !m_scrobbler || m_track.isNull() )
{
dataError( caller, type, input, customData );
return; return;
}
qDebug() << Q_FUNC_INFO << m_track.toString(); qDebug() << Q_FUNC_INFO << m_track.toString();
m_scrobbler->cache( m_track ); m_scrobbler->cache( m_track );
m_scrobbler->submit(); m_scrobbler->submit();
emit info( caller, type, input, QVariant(), customData );
} }
@@ -241,7 +254,7 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) ); QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
QNetworkReply* reply = TomahawkUtils::nam()->get( req ); QNetworkReply* reply = m_infoSystemWorker->nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) ); reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input ); reply->setProperty( "origData", input );
reply->setProperty( "caller", caller ); reply->setProperty( "caller", caller );
@@ -257,7 +270,7 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b"; QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ) ); QNetworkRequest req( imgurl.arg( artistName ) );
QNetworkReply* reply = TomahawkUtils::nam()->get( req ); QNetworkReply* reply = m_infoSystemWorker->nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) ); reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input ); reply->setProperty( "origData", input );
reply->setProperty( "caller", caller ); reply->setProperty( "caller", caller );
@@ -312,7 +325,7 @@ LastFmPlugin::coverArtReturned()
{ {
// Follow HTTP redirect // Follow HTTP redirect
QNetworkRequest req( redir ); QNetworkRequest req( redir );
QNetworkReply* newReply = TomahawkUtils::nam()->get( req ); QNetworkReply* newReply = m_infoSystemWorker->nam()->get( req );
newReply->setProperty( "origData", reply->property( "origData" ) ); newReply->setProperty( "origData", reply->property( "origData" ) );
newReply->setProperty( "customData", reply->property( "customData" ) ); newReply->setProperty( "customData", reply->property( "customData" ) );
newReply->setProperty( "caller", reply->property( "caller" ) ); newReply->setProperty( "caller", reply->property( "caller" ) );
@@ -362,7 +375,7 @@ LastFmPlugin::artistImagesReturned()
{ {
// Follow HTTP redirect // Follow HTTP redirect
QNetworkRequest req( redir ); QNetworkRequest req( redir );
QNetworkReply* newReply = TomahawkUtils::nam()->get( req ); QNetworkReply* newReply = m_infoSystemWorker->nam()->get( req );
newReply->setProperty( "origData", reply->property( "origData" ) ); newReply->setProperty( "origData", reply->property( "origData" ) );
newReply->setProperty( "customData", reply->property( "customData" ) ); newReply->setProperty( "customData", reply->property( "customData" ) );
newReply->setProperty( "caller", reply->property( "caller" ) ); newReply->setProperty( "caller", reply->property( "caller" ) );

View File

@@ -19,6 +19,7 @@
#ifndef LASTFMPLUGIN_H #ifndef LASTFMPLUGIN_H
#define LASTFMPLUGIN_H #define LASTFMPLUGIN_H
#include "infosystem/infosystem.h" #include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include "result.h" #include "result.h"
#include <lastfm/Track> #include <lastfm/Track>
@@ -40,7 +41,7 @@ class LastFmPlugin : public InfoPlugin
Q_OBJECT Q_OBJECT
public: public:
LastFmPlugin( QObject *parent ); LastFmPlugin( InfoSystemWorker *parent );
virtual ~LastFmPlugin(); virtual ~LastFmPlugin();
public slots: public slots:
@@ -50,17 +51,21 @@ public slots:
void coverArtReturned(); void coverArtReturned();
void artistImagesReturned(); void artistImagesReturned();
void namChangedSlot();
protected slots: protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ); virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ); virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data );
private: private:
void fetchCoverArt( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ); void fetchCoverArt( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void fetchArtistImages( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ); void fetchArtistImages( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void createScrobbler(); void createScrobbler();
void scrobble( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ); void scrobble( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input );
void nowPlaying( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ); void nowPlaying( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input );
void dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData ); void dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
@@ -71,6 +76,8 @@ private:
QList< QUrl > m_badUrls; QList< QUrl > m_badUrls;
QNetworkReply* m_authJob; QNetworkReply* m_authJob;
InfoSystemWorker* m_infoSystemWorker;
}; };
} }

View File

@@ -27,14 +27,15 @@ using namespace Tomahawk::InfoSystem;
// for internal neatness // for internal neatness
MusixMatchPlugin::MusixMatchPlugin(QObject *parent) MusixMatchPlugin::MusixMatchPlugin(InfoSystemWorker *parent)
: InfoPlugin(parent) : InfoPlugin(parent)
, m_apiKey("61be4ea5aea7dd942d52b2f1311dd9fe") , m_apiKey("61be4ea5aea7dd942d52b2f1311dd9fe")
, m_infoSystemWorker( parent )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
QSet< InfoType > supportedTypes; QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoTrackLyrics; supportedTypes << Tomahawk::InfoSystem::InfoTrackLyrics;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes); parent->registerInfoTypes( this, supportedTypes, QSet< InfoType>() );
} }
MusixMatchPlugin::~MusixMatchPlugin() MusixMatchPlugin::~MusixMatchPlugin()
@@ -62,7 +63,7 @@ MusixMatchPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::Inf
url.addQueryItem("apikey", m_apiKey); url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("q_artist", artist); url.addQueryItem("q_artist", artist);
url.addQueryItem("q_track", track); url.addQueryItem("q_track", track);
QNetworkReply* reply = TomahawkUtils::nam()->get(QNetworkRequest(url)); QNetworkReply* reply = m_infoSystemWorker->nam()->get(QNetworkRequest(url));
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>(customData)); reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>(customData));
reply->setProperty("origData", input); reply->setProperty("origData", input);
reply->setProperty("caller", caller); reply->setProperty("caller", caller);
@@ -120,7 +121,7 @@ MusixMatchPlugin::trackSearchSlot()
QUrl url(requestString); QUrl url(requestString);
url.addQueryItem("apikey", m_apiKey); url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("track_id", track_id); url.addQueryItem("track_id", track_id);
QNetworkReply* newReply = TomahawkUtils::nam()->get(QNetworkRequest(url)); QNetworkReply* newReply = m_infoSystemWorker->nam()->get(QNetworkRequest(url));
newReply->setProperty("origData", oldReply->property("origData")); newReply->setProperty("origData", oldReply->property("origData"));
newReply->setProperty("customData", oldReply->property("customData")); newReply->setProperty("customData", oldReply->property("customData"));
newReply->setProperty("caller", oldReply->property("caller")); newReply->setProperty("caller", oldReply->property("caller"));

View File

@@ -20,6 +20,7 @@
#define MUSIXMATCHPLUGIN_H #define MUSIXMATCHPLUGIN_H
#include "infosystem/infosystem.h" #include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
class QNetworkReply; class QNetworkReply;
@@ -34,7 +35,7 @@ class MusixMatchPlugin : public InfoPlugin
Q_OBJECT Q_OBJECT
public: public:
MusixMatchPlugin( QObject *parent ); MusixMatchPlugin( InfoSystemWorker *parent );
virtual ~MusixMatchPlugin(); virtual ~MusixMatchPlugin();
public slots: public slots:
@@ -43,11 +44,29 @@ public slots:
protected slots: protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ); virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data )
{
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( data );
}
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
private: private:
bool isValidTrackData( const QString &caller, const QVariant &input, const InfoCustomData &customData ); bool isValidTrackData( const QString &caller, const QVariant &input, const InfoCustomData &customData );
QString m_apiKey; QString m_apiKey;
InfoSystemWorker* m_infoSystemWorker;
}; };
} }

View File

@@ -19,6 +19,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "infosystem.h" #include "infosystem.h"
#include "tomahawksettings.h"
#include "utils/tomahawkutils.h" #include "utils/tomahawkutils.h"
#include "infosystemcache.h" #include "infosystemcache.h"
#include "infoplugins/echonestplugin.h" #include "infoplugins/echonestplugin.h"
@@ -31,11 +32,11 @@ namespace Tomahawk
namespace InfoSystem namespace InfoSystem
{ {
InfoPlugin::InfoPlugin(QObject *parent) InfoPlugin::InfoPlugin( InfoSystemWorker *parent )
:QObject( parent ) :QObject( parent )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
} }
InfoSystem* InfoSystem::s_instance = 0; InfoSystem* InfoSystem::s_instance = 0;
@@ -59,59 +60,33 @@ InfoSystem::InfoSystem(QObject *parent)
m_cache->moveToThread( m_infoSystemCacheThreadController ); m_cache->moveToThread( m_infoSystemCacheThreadController );
m_infoSystemCacheThreadController->start( QThread::IdlePriority ); m_infoSystemCacheThreadController->start( QThread::IdlePriority );
InfoPluginPtr enptr( new EchoNestPlugin( this ) ); m_infoSystemWorkerThreadController = new QThread( this );
m_plugins.append( enptr ); m_worker = new InfoSystemWorker();
InfoPluginPtr mmptr( new MusixMatchPlugin( this ) ); m_worker->moveToThread( m_infoSystemWorkerThreadController );
m_plugins.append( mmptr ); m_infoSystemWorkerThreadController->start();
InfoPluginPtr lfmptr( new LastFmPlugin( this ) );
m_plugins.append( lfmptr );
Q_FOREACH( InfoPluginPtr plugin, m_plugins ) QMetaObject::invokeMethod( m_worker, "init", Qt::QueuedConnection );
{
connect( connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( newNam() ) );
plugin.data(),
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this,
SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
Qt::UniqueConnection
);
connect(
plugin.data(),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
m_cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
m_cache,
SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
plugin.data(),
SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
plugin.data(),
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
m_cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
connect( m_cache, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), connect( m_cache, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection ); this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection );
connect( m_worker, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection );
} }
InfoSystem::~InfoSystem() InfoSystem::~InfoSystem()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
if( plugin )
delete plugin.data();
}
if ( m_infoSystemCacheThreadController )
m_infoSystemCacheThreadController->quit();
if ( m_infoSystemWorkerThreadController )
m_infoSystemWorkerThreadController->quit();
if( m_infoSystemCacheThreadController ) if( m_infoSystemCacheThreadController )
{ {
m_infoSystemCacheThreadController->quit();
while( !m_infoSystemCacheThreadController->isFinished() ) while( !m_infoSystemCacheThreadController->isFinished() )
{ {
QCoreApplication::processEvents( QEventLoop::AllEvents, 200 ); QCoreApplication::processEvents( QEventLoop::AllEvents, 200 );
@@ -127,56 +102,73 @@ InfoSystem::~InfoSystem()
delete m_infoSystemCacheThreadController; delete m_infoSystemCacheThreadController;
m_infoSystemCacheThreadController = 0; m_infoSystemCacheThreadController = 0;
} }
if( m_infoSystemWorkerThreadController )
{
while( !m_infoSystemWorkerThreadController->isFinished() )
{
QCoreApplication::processEvents( QEventLoop::AllEvents, 200 );
TomahawkUtils::Sleep::msleep( 100 );
}
if( m_worker )
{
delete m_worker;
m_worker = 0;
}
delete m_infoSystemWorkerThreadController;
m_infoSystemWorkerThreadController = 0;
}
} }
void InfoSystem::registerInfoTypes(const InfoPluginPtr &plugin, const QSet< InfoType >& types)
void
InfoSystem::newNam() const
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
Q_FOREACH(InfoType type, types) QMetaObject::invokeMethod( m_worker, "newNam", Qt::QueuedConnection );
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& input, InfoCustomData customData) void
InfoSystem::getInfo( const QString &caller, const InfoType type, const QVariant& input, InfoCustomData customData )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
if (providers.isEmpty())
{
emit info(caller, InfoNoInfo, QVariant(), QVariant(), customData);
emit finished(caller);
return;
}
InfoPluginPtr ptr = providers.first();
if (!ptr)
{
emit info(caller, InfoNoInfo, QVariant(), QVariant(), customData);
emit finished(caller);
return;
}
m_dataTracker[caller][type] = m_dataTracker[caller][type] + 1; m_dataTracker[caller][type] = m_dataTracker[caller][type] + 1;
qDebug() << "current count in dataTracker for type" << type << "is" << m_dataTracker[caller][type]; qDebug() << "current count in dataTracker for type" << type << "is" << m_dataTracker[caller][type];
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) ); QMetaObject::invokeMethod( m_worker, "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
} }
void InfoSystem::getInfo(const QString &caller, const InfoMap &input, InfoCustomData customData)
void
InfoSystem::getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData )
{ {
Q_FOREACH( InfoType type, input.keys() ) Q_FOREACH( InfoType type, input.keys() )
getInfo(caller, type, input[type], customData); getInfo( caller, type, input[type], customData );
} }
void InfoSystem::infoSlot(QString target, InfoType type, QVariant input, QVariant output, InfoCustomData customData)
void
InfoSystem::pushInfo( const QString &caller, const InfoType type, const QVariant& input )
{
qDebug() << Q_FUNC_INFO;
QMetaObject::invokeMethod( m_worker, "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
}
void
InfoSystem::pushInfo( const QString &caller, const InfoMap &input )
{
Q_FOREACH( InfoType type, input.keys() )
pushInfo( caller, type, input[type] );
}
void
InfoSystem::infoSlot( QString target, InfoType type, QVariant input, QVariant output, InfoCustomData customData )
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type]; qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];

View File

@@ -36,62 +36,63 @@ namespace Tomahawk {
namespace InfoSystem { namespace InfoSystem {
class InfoSystemCache; class InfoSystemCache;
class InfoSystemWorker;
enum InfoType { enum InfoType { // as items are saved in cache, mark them here to not change them
InfoTrackID = 0, InfoTrackID = 0,
InfoTrackArtist, InfoTrackArtist = 1,
InfoTrackAlbum, InfoTrackAlbum = 2,
InfoTrackGenre, InfoTrackGenre = 3,
InfoTrackComposer, InfoTrackComposer = 4,
InfoTrackDate, InfoTrackDate = 5,
InfoTrackNumber, InfoTrackNumber = 6,
InfoTrackDiscNumber, InfoTrackDiscNumber = 7,
InfoTrackBitRate, InfoTrackBitRate = 8,
InfoTrackLength, InfoTrackLength = 9,
InfoTrackSampleRate, InfoTrackSampleRate = 10,
InfoTrackFileSize, InfoTrackFileSize = 11,
InfoTrackBPM, InfoTrackBPM = 12,
InfoTrackReplayGain, InfoTrackReplayGain = 13,
InfoTrackReplayPeakGain, InfoTrackReplayPeakGain = 14,
InfoTrackLyrics, InfoTrackLyrics = 15,
InfoTrackLocation, InfoTrackLocation = 16,
InfoTrackProfile, InfoTrackProfile = 17,
InfoTrackEnergy, InfoTrackEnergy = 18,
InfoTrackDanceability, InfoTrackDanceability = 19,
InfoTrackTempo, InfoTrackTempo = 20,
InfoTrackLoudness, InfoTrackLoudness = 21,
InfoArtistID, InfoArtistID = 22,
InfoArtistName, InfoArtistName = 23,
InfoArtistBiography, InfoArtistBiography = 24,
InfoArtistBlog, InfoArtistBlog = 25,
InfoArtistFamiliarity, InfoArtistFamiliarity = 26,
InfoArtistHotttness, InfoArtistHotttness = 27,
InfoArtistImages, InfoArtistImages = 28,
InfoArtistNews, InfoArtistNews = 29,
InfoArtistProfile, InfoArtistProfile = 30,
InfoArtistReviews, InfoArtistReviews = 31,
InfoArtistSongs, InfoArtistSongs = 32,
InfoArtistSimilars, InfoArtistSimilars = 33,
InfoArtistTerms, InfoArtistTerms = 34,
InfoArtistLinks, InfoArtistLinks = 35,
InfoArtistVideos, InfoArtistVideos = 36,
InfoAlbumID, InfoAlbumID = 37,
InfoAlbumName, InfoAlbumName = 38,
InfoAlbumArtist, InfoAlbumArtist = 39,
InfoAlbumDate, InfoAlbumDate = 40,
InfoAlbumGenre, InfoAlbumGenre = 41,
InfoAlbumComposer, InfoAlbumComposer = 42,
InfoAlbumCoverArt, InfoAlbumCoverArt = 43, //cached -- do not change
InfoMiscTopHotttness, InfoMiscTopHotttness = 44,
InfoMiscTopTerms, InfoMiscTopTerms = 45,
InfoMiscSubmitNowPlaying, InfoSubmitNowPlaying = 46,
InfoMiscSubmitScrobble, InfoSubmitScrobble = 47,
InfoNoInfo InfoNoInfo = 48
}; };
typedef QMap< InfoType, QVariant > InfoMap; typedef QMap< InfoType, QVariant > InfoMap;
@@ -104,12 +105,9 @@ class DLLEXPORT InfoPlugin : public QObject
Q_OBJECT Q_OBJECT
public: public:
InfoPlugin( QObject *parent ); InfoPlugin( InfoSystemWorker *parent );
virtual ~InfoPlugin() virtual ~InfoPlugin() {}
{
qDebug() << Q_FUNC_INFO;
}
signals: signals:
void getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData ); void getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
@@ -119,16 +117,8 @@ signals:
protected slots: protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data, const Tomahawk::InfoSystem::InfoCustomData customData ) = 0; virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data, const Tomahawk::InfoSystem::InfoCustomData customData ) = 0;
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data ) = 0;
//FIXME: Make pure virtual when everything supports it virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) = 0;
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
protected: protected:
InfoType m_type; InfoType m_type;
@@ -139,13 +129,6 @@ private:
typedef QWeakPointer< InfoPlugin > InfoPluginPtr; typedef QWeakPointer< InfoPlugin > InfoPluginPtr;
class DLLEXPORT InfoSystemWorker : public QObject
{
Q_OBJECT
InfoSystemWorker() {};
~InfoSystemWorker() {};
};
class DLLEXPORT InfoSystem : public QObject class DLLEXPORT InfoSystem : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -156,12 +139,12 @@ public:
InfoSystem( QObject *parent ); InfoSystem( QObject *parent );
~InfoSystem(); ~InfoSystem();
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &types );
void getInfo( const QString &caller, const InfoType type, const QVariant &input, InfoCustomData customData ); void getInfo( const QString &caller, const InfoType type, const QVariant &input, InfoCustomData customData );
void getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData ); void getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData );
void pushInfo( const QString &caller, const InfoType type, const QVariant &input );
void pushInfo( const QString &caller, const InfoMap &input );
InfoSystemCache* getCache() { return m_cache; } InfoSystemCache* getCache() const { return m_cache; }
signals: signals:
void info( QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData ); void info( QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
@@ -170,14 +153,9 @@ signals:
public slots: public slots:
void infoSlot( const QString target, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const QVariant output, const Tomahawk::InfoSystem::InfoCustomData customData ); void infoSlot( const QString target, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const QVariant output, const Tomahawk::InfoSystem::InfoCustomData customData );
void newNam() const;
private: 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< InfoType, int > > m_dataTracker; QHash< QString, QHash< InfoType, int > > m_dataTracker;
InfoSystemCache* m_cache; InfoSystemCache* m_cache;

View File

@@ -0,0 +1,190 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QCoreApplication>
#include <QNetworkConfiguration>
#include <QNetworkProxy>
#include "infosystemworker.h"
#include "utils/tomahawkutils.h"
#include "infosystemcache.h"
#include "infoplugins/echonestplugin.h"
#include "infoplugins/musixmatchplugin.h"
#include "infoplugins/lastfmplugin.h"
namespace Tomahawk
{
namespace InfoSystem
{
InfoSystemWorker::InfoSystemWorker()
: m_nam( 0 )
{
qDebug() << Q_FUNC_INFO;
}
InfoSystemWorker::~InfoSystemWorker()
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
if( plugin )
delete plugin.data();
}
}
void InfoSystemWorker::init()
{
InfoPluginPtr enptr( new EchoNestPlugin( this ) );
m_plugins.append( enptr );
InfoPluginPtr mmptr( new MusixMatchPlugin( this ) );
m_plugins.append( mmptr );
InfoPluginPtr lfmptr( new LastFmPlugin( this ) );
m_plugins.append( lfmptr );
InfoSystemCache *cache = InfoSystem::instance()->getCache();
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
connect(
plugin.data(),
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
InfoSystem::instance(),
SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
Qt::UniqueConnection
);
connect(
plugin.data(),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
cache,
SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
plugin.data(),
SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
plugin.data(),
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
QMetaObject::invokeMethod( this, "newNam" );
}
void
InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoType type, getTypes )
m_infoGetMap[type].append( plugin );
Q_FOREACH( InfoType type, pushTypes )
m_infoPushMap[type].append( plugin );
}
QLinkedList< InfoPluginPtr >
InfoSystemWorker::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_infoGetMap[type] )
providers << ptr;
return providers;
}
void
InfoSystemWorker::getInfo( QString caller, InfoType type, QVariant input, InfoCustomData customData )
{
qDebug() << Q_FUNC_INFO;
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
if ( providers.isEmpty() )
{
emit info( caller, type, QVariant(), QVariant(), customData );
return;
}
InfoPluginPtr ptr = providers.first();
if ( !ptr )
{
emit info( caller, type, QVariant(), QVariant(), customData );
return;
}
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
}
void
InfoSystemWorker::pushInfo( const QString caller, const InfoType type, const QVariant input )
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr ptr, m_infoPushMap[type] )
{
if( ptr )
QMetaObject::invokeMethod( ptr.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
}
}
QNetworkAccessManager*
InfoSystemWorker::nam() const
{
return m_nam;
}
void
InfoSystemWorker::newNam()
{
qDebug() << Q_FUNC_INFO;
QNetworkAccessManager *newNam = new QNetworkAccessManager();
if ( m_nam )
{
delete m_nam;
}
QNetworkAccessManager *oldNam = TomahawkUtils::nam();
if ( !oldNam )
{
m_nam = newNam;
return;
}
newNam->setConfiguration( oldNam->configuration() );
newNam->setNetworkAccessible( oldNam->networkAccessible() );
newNam->setProxy( oldNam->proxy() );
m_nam = newNam;
emit namChanged();
}
} //namespace InfoSystem
} //namespace Tomahawk

View File

@@ -0,0 +1,76 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOMAHAWK_INFOSYSTEMWORKER_H
#define TOMAHAWK_INFOSYSTEMWORKER_H
#include "infosystem/infosystem.h"
#include <QNetworkAccessManager>
#include <QtCore/QObject>
#include <QtCore/QtDebug>
#include <QtCore/QMap>
#include <QtCore/QWeakPointer>
#include <QtCore/QSet>
#include <QtCore/QLinkedList>
#include <QtCore/QVariant>
#include "dllmacro.h"
namespace Tomahawk {
namespace InfoSystem {
class DLLEXPORT InfoSystemWorker : public QObject
{
Q_OBJECT
public:
InfoSystemWorker();
~InfoSystemWorker();
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes );
QNetworkAccessManager* nam() const;
signals:
void info( QString target, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
void namChanged();
public slots:
void init();
void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input );
void newNam();
private:
QLinkedList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
// For now, statically instantiate plugins; this is just somewhere to keep them
QLinkedList< InfoPluginPtr > m_plugins;
QMap< InfoType, QLinkedList< InfoPluginPtr > > m_infoGetMap;
QMap< InfoType, QLinkedList< InfoPluginPtr > > m_infoPushMap;
QNetworkAccessManager *m_nam;
};
}
}
#endif // TOMAHAWK_INFOSYSTEMWORKER_H

View File

@@ -496,13 +496,13 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, const Q
void void
Servent::connectToPeer( const QString& ha, int port, const QString &key, Connection* conn ) Servent::connectToPeer( const QString& ha, int port, const QString &key, Connection* conn )
{ {
qDebug() << "Servent::connectToPeer:" << ha << ":" << port
<< thread() << QThread::currentThread();
Q_ASSERT( port > 0 ); Q_ASSERT( port > 0 );
Q_ASSERT( conn ); Q_ASSERT( conn );
// Q_ASSERT( this->thread() == QThread::currentThread() ); // Q_ASSERT( this->thread() == QThread::currentThread() );
qDebug() << "Servent::connectToPeer:" << ha << ":" << port
<< thread() << QThread::currentThread();
if ( ( ha == m_externalAddress.toString() || ha == m_externalHostname ) && if ( ( ha == m_externalAddress.toString() || ha == m_externalHostname ) &&
( port == m_externalPort ) ) ( port == m_externalPort ) )
{ {

View File

@@ -30,7 +30,7 @@
using namespace Tomahawk; using namespace Tomahawk;
DynamicPlaylist::DynamicPlaylist(const Tomahawk::source_ptr& author, const QString& type ) DynamicPlaylist::DynamicPlaylist(const Tomahawk::source_ptr& author, const QString& type )
: Playlist(author) : Playlist(author)
{ {
qDebug() << Q_FUNC_INFO << "JSON"; qDebug() << Q_FUNC_INFO << "JSON";
m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
@@ -54,7 +54,7 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src,
bool shared, bool shared,
int lastmod, int lastmod,
const QString& guid ) const QString& guid )
: Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid ) : Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid )
{ {
qDebug() << "Creating Dynamic Playlist 1"; qDebug() << "Creating Dynamic Playlist 1";
// TODO instantiate generator // TODO instantiate generator
@@ -72,7 +72,7 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author,
const QString& type, const QString& type,
GeneratorMode mode, GeneratorMode mode,
bool shared ) bool shared )
: Playlist ( author, guid, title, info, creator, shared ) : Playlist ( author, guid, title, info, creator, shared )
{ {
qDebug() << "Creating Dynamic Playlist 2"; qDebug() << "Creating Dynamic Playlist 2";
m_generator = geninterface_ptr( GeneratorFactory::create( type ) ); m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
@@ -113,15 +113,15 @@ DynamicPlaylist::setMode( int mode )
dynplaylist_ptr dynplaylist_ptr
DynamicPlaylist::create( const Tomahawk::source_ptr& author, DynamicPlaylist::create( const Tomahawk::source_ptr& author,
const QString& guid, const QString& guid,
const QString& title, const QString& title,
const QString& info, const QString& info,
const QString& creator, const QString& creator,
GeneratorMode mode, GeneratorMode mode,
bool shared ) bool shared,
const QString& type
)
{ {
// default generator
QString type = "";
dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared ) ); dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared ) );
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist ); DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist );
@@ -148,10 +148,10 @@ DynamicPlaylist::createNewRevision( const QString& newUuid )
// create a new revision that will be a static playlist, as it has entries // create a new revision that will be a static playlist, as it has entries
void void
DynamicPlaylist::createNewRevision( const QString& newrev, DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev, const QString& oldrev,
const QString& type, const QString& type,
const QList< dyncontrol_ptr>& controls, const QList< dyncontrol_ptr>& controls,
const QList< plentry_ptr >& entries ) const QList< plentry_ptr >& entries )
{ {
// get the newly added tracks // get the newly added tracks
QList< plentry_ptr > added = newEntries( entries ); QList< plentry_ptr > added = newEntries( entries );
@@ -162,29 +162,29 @@ DynamicPlaylist::createNewRevision( const QString& newrev,
// no conflict resolution or partial updating for controls. all or nothing baby // no conflict resolution or partial updating for controls. all or nothing baby
// source making the change (local user in this case) // source making the change (local user in this case)
source_ptr author = SourceList::instance()->getLocal(); source_ptr author = SourceList::instance()->getLocal();
// command writes new rev to DB and calls setRevision, which emits our signal // command writes new rev to DB and calls setRevision, which emits our signal
DatabaseCommand_SetDynamicPlaylistRevision* cmd = DatabaseCommand_SetDynamicPlaylistRevision* cmd =
new DatabaseCommand_SetDynamicPlaylistRevision( author, new DatabaseCommand_SetDynamicPlaylistRevision( author,
guid(), guid(),
newrev, newrev,
oldrev, oldrev,
orderedguids, orderedguids,
added, added,
entries, entries,
type, type,
Static, Static,
controls ); controls );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) ); Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
} }
// create a new revision that will be an ondemand playlist, as it has no entries // create a new revision that will be an ondemand playlist, as it has no entries
void void
DynamicPlaylist::createNewRevision( const QString& newrev, DynamicPlaylist::createNewRevision( const QString& newrev,
const QString& oldrev, const QString& oldrev,
const QString& type, const QString& type,
const QList< dyncontrol_ptr>& controls ) const QList< dyncontrol_ptr>& controls )
{ {
// can skip the entry stuff. just overwrite with new info // can skip the entry stuff. just overwrite with new info
source_ptr author = SourceList::instance()->getLocal(); source_ptr author = SourceList::instance()->getLocal();
@@ -237,7 +237,7 @@ DynamicPlaylist::loadRevision( const QString& rev )
bool ) ) ); bool ) ) );
} }
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) ); Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
} }
bool bool
@@ -257,8 +257,8 @@ DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
Q_ASSERT( !author().isNull() ); Q_ASSERT( !author().isNull() );
Q_ASSERT( !author()->collection().isNull() ); Q_ASSERT( !author()->collection().isNull() );
// will emit Collection::playlistCreated(...) // will emit Collection::playlistCreated(...)
// qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull(); // qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull();
// qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName(); // qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName();
if( self->mode() == Static ) if( self->mode() == Static )
author()->collection()->addAutoPlaylist( self ); author()->collection()->addAutoPlaylist( self );
else else
@@ -339,33 +339,33 @@ void DynamicPlaylist::setRevision( const QString& rev,
setCurrentrevision( rev ); setCurrentrevision( rev );
} }
// qDebug() << "EMITTING REVISION LOADED 1!"; // qDebug() << "EMITTING REVISION LOADED 1!";
emit dynamicRevisionLoaded( dpr ); emit dynamicRevisionLoaded( dpr );
} }
void void
DynamicPlaylist::setRevision( const QString& rev, DynamicPlaylist::setRevision( const QString& rev,
const QList< QString >& neworderedguids, const QList< QString >& neworderedguids,
const QList< QString >& oldorderedguids, const QList< QString >& oldorderedguids,
const QString& type, const QString& type,
const QList< QVariantMap>& controlsV, const QList< QVariantMap>& controlsV,
bool is_newest_rev, bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap, const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied ) bool applied )
{ {
if( QThread::currentThread() != thread() ) if( QThread::currentThread() != thread() )
{ {
QMetaObject::invokeMethod( this, QMetaObject::invokeMethod( this,
"setRevision", "setRevision",
Qt::BlockingQueuedConnection, Qt::BlockingQueuedConnection,
Q_ARG( QString, rev ), Q_ARG( QString, rev ),
Q_ARG( QList<QString> , neworderedguids ), Q_ARG( QList<QString> , neworderedguids ),
Q_ARG( QList<QString> , oldorderedguids ), Q_ARG( QList<QString> , oldorderedguids ),
Q_ARG( QString , type ), Q_ARG( QString , type ),
QGenericArgument( "QList< QVariantMap > " , (const void*)&controlsV ), QGenericArgument( "QList< QVariantMap > " , (const void*)&controlsV ),
Q_ARG( bool, is_newest_rev ), Q_ARG( bool, is_newest_rev ),
QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ), QGenericArgument( "QMap< QString,Tomahawk::plentry_ptr > " , (const void*)&addedmap ),
Q_ARG( bool, applied ) ); Q_ARG( bool, applied ) );
return; return;
} }
@@ -416,10 +416,10 @@ void DynamicPlaylist::setRevision( const QString& rev,
void void
DynamicPlaylist::setRevision( const QString& rev, DynamicPlaylist::setRevision( const QString& rev,
bool is_newest_rev, bool is_newest_rev,
const QString& type, const QString& type,
const QList< QVariantMap >& controlsV, const QList< QVariantMap >& controlsV,
bool applied ) bool applied )
{ {
if( QThread::currentThread() != thread() ) if( QThread::currentThread() != thread() )
{ {

View File

@@ -82,7 +82,8 @@ public:
const QString& info, const QString& info,
const QString& creator, const QString& creator,
GeneratorMode mode, GeneratorMode mode,
bool shared bool shared,
const QString& type = QString()
); );
static bool remove( const dynplaylist_ptr& playlist ); static bool remove( const dynplaylist_ptr& playlist );

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
* *
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* *
* Tomahawk is free software: you can redistribute it and/or modify * Tomahawk is free software: you can redistribute it and/or modify
@@ -55,6 +55,18 @@ SourceList::getLocal()
return m_local; return m_local;
} }
void
SourceList::setWebSource( const source_ptr& websrc )
{
m_dummy = websrc;
}
const
source_ptr SourceList::webSource() const
{
return m_dummy;
}
void void
SourceList::loadSources() SourceList::loadSources()

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
* *
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* *
* Tomahawk is free software: you can redistribute it and/or modify * Tomahawk is free software: you can redistribute it and/or modify
@@ -40,6 +40,9 @@ public:
const Tomahawk::source_ptr& getLocal(); const Tomahawk::source_ptr& getLocal();
void setLocal( const Tomahawk::source_ptr& localSrc ); void setLocal( const Tomahawk::source_ptr& localSrc );
void setWebSource( const Tomahawk::source_ptr& websrc );
const Tomahawk::source_ptr webSource() const;
void removeAllRemote(); void removeAllRemote();
QList<Tomahawk::source_ptr> sources( bool onlyOnline = false ) const; QList<Tomahawk::source_ptr> sources( bool onlyOnline = false ) const;
@@ -57,7 +60,7 @@ signals:
private slots: private slots:
void setSources( const QList<Tomahawk::source_ptr>& sources ); void setSources( const QList<Tomahawk::source_ptr>& sources );
void sourceSynced(); void sourceSynced();
private: private:
void loadSources(); void loadSources();
void add( const Tomahawk::source_ptr& source ); void add( const Tomahawk::source_ptr& source );
@@ -66,8 +69,9 @@ private:
QMap< int, QString > m_sources_id2name; QMap< int, QString > m_sources_id2name;
Tomahawk::source_ptr m_local; Tomahawk::source_ptr m_local;
Tomahawk::source_ptr m_dummy;
mutable QMutex m_mut; // mutable so const methods can use a lock mutable QMutex m_mut; // mutable so const methods can use a lock
static SourceList* s_instance; static SourceList* s_instance;
}; };

View File

@@ -377,6 +377,18 @@ TomahawkSettings::appendRecentlyPlayedPlaylist( const Tomahawk::playlist_ptr& pl
setValue( "playlists/recentlyPlayed", playlist_guids ); setValue( "playlists/recentlyPlayed", playlist_guids );
} }
QString
TomahawkSettings::bookmarkPlaylist() const
{
return value( "playlists/bookmark", QString() ).toString();
}
void
TomahawkSettings::setBookmarkPlaylist( const QString& guid )
{
setValue( "playlists/bookmark", guid );
}
QStringList QStringList
TomahawkSettings::sipPlugins() const TomahawkSettings::sipPlugins() const
{ {

View File

@@ -73,6 +73,9 @@ public:
void setSipPlugins( const QStringList& plugins ); void setSipPlugins( const QStringList& plugins );
QStringList sipPlugins() const; QStringList sipPlugins() const;
void setBookmarkPlaylist( const QString& guid );
QString bookmarkPlaylist() const;
// just the enabled sip plugins. // just the enabled sip plugins.
void setEnabledSipPlugins( const QStringList& list ); void setEnabledSipPlugins( const QStringList& list );
QStringList enabledSipPlugins() const; QStringList enabledSipPlugins() const;

View File

@@ -29,6 +29,12 @@
using namespace Tomahawk; using namespace Tomahawk;
void
XSPFLoader::setOverrideTitle( const QString& newTitle )
{
m_overrideTitle = newTitle;
}
void void
XSPFLoader::load( const QUrl& url ) XSPFLoader::load( const QUrl& url )
@@ -116,13 +122,15 @@ XSPFLoader::gotBody()
m_title = origTitle; m_title = origTitle;
if ( m_title.isEmpty() ) if ( m_title.isEmpty() )
m_title = tr( "New Playlist" ); m_title = tr( "New Playlist" );
if( !m_overrideTitle.isEmpty() )
m_title = m_overrideTitle;
bool shownError = false; bool shownError = false;
for ( unsigned int i = 0; i < tracklist.length(); i++ ) for ( unsigned int i = 0; i < tracklist.length(); i++ )
{ {
QDomNode e = tracklist.at( i ); QDomNode e = tracklist.at( i );
QString artist, album, track, duration, annotation; QString artist, album, track, duration, annotation, url;
QDomElement n = e.firstChildElement(); QDomElement n = e.firstChildElement();
for ( ; !n.isNull(); n = n.nextSiblingElement() ) { for ( ; !n.isNull(); n = n.nextSiblingElement() ) {
if (n.namespaceURI() == m_NS && n.localName() == "duration") { if (n.namespaceURI() == m_NS && n.localName() == "duration") {
@@ -135,6 +143,8 @@ XSPFLoader::gotBody()
album = n.text(); album = n.text();
} else if (n.namespaceURI() == m_NS && n.localName() == "title") { } else if (n.namespaceURI() == m_NS && n.localName() == "title") {
track = n.text(); track = n.text();
} else if (n.namespaceURI() == m_NS && n.localName() == "url") {
url = n.text();
} }
} }
@@ -154,6 +164,8 @@ XSPFLoader::gotBody()
p->setQuery( Tomahawk::Query::get( artist, track, album, uuid() ) ); p->setQuery( Tomahawk::Query::get( artist, track, album, uuid() ) );
p->query()->setDuration( duration.toInt() / 1000 ); p->query()->setDuration( duration.toInt() / 1000 );
if( !url.isEmpty() )
p->query()->setResultHint( url );
m_entries << p; m_entries << p;
} }

View File

@@ -53,6 +53,7 @@ public:
QList< Tomahawk::plentry_ptr > entries() const { return m_entries; } QList< Tomahawk::plentry_ptr > entries() const { return m_entries; }
void setOverrideTitle( const QString& newTitle );
signals: signals:
void failed(); void failed();
void ok( const Tomahawk::playlist_ptr& ); void ok( const Tomahawk::playlist_ptr& );
@@ -70,7 +71,7 @@ private:
void gotBody(); void gotBody();
bool m_autoCreate; bool m_autoCreate;
QString m_NS; QString m_NS,m_overrideTitle;
QList< Tomahawk::plentry_ptr > m_entries; QList< Tomahawk::plentry_ptr > m_entries;
QString m_title, m_info, m_creator; QString m_title, m_info, m_creator;

View File

@@ -149,6 +149,22 @@ ViewManager::queue() const
return m_queueView->queue(); return m_queueView->queue();
} }
PlaylistView*
ViewManager::createPageForPlaylist( const playlist_ptr& pl )
{
PlaylistView* view = new PlaylistView();
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
view->setFrameShape( QFrame::NoFrame );
view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
model->loadPlaylist( pl );
pl->resolve();
m_playlistViews.insert( pl, view );
return view;
}
Tomahawk::ViewPage* Tomahawk::ViewPage*
ViewManager::show( const Tomahawk::playlist_ptr& playlist ) ViewManager::show( const Tomahawk::playlist_ptr& playlist )
@@ -156,15 +172,7 @@ ViewManager::show( const Tomahawk::playlist_ptr& playlist )
PlaylistView* view; PlaylistView* view;
if ( !m_playlistViews.contains( playlist ) ) if ( !m_playlistViews.contains( playlist ) )
{ {
view = new PlaylistView(); view = createPageForPlaylist( playlist );
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
view->setFrameShape( QFrame::NoFrame );
view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
model->loadPlaylist( playlist );
playlist->resolve();
m_playlistViews.insert( playlist, view );
} }
else else
{ {

View File

@@ -67,6 +67,7 @@ public:
QWidget* widget() const { return m_widget; } QWidget* widget() const { return m_widget; }
PlaylistView* queue() const; PlaylistView* queue() const;
TopBar* topbar() const { return m_topbar; }
bool isSuperCollectionVisible() const; bool isSuperCollectionVisible() const;
bool isNewPlaylistPageVisible() const; bool isNewPlaylistPageVisible() const;
@@ -76,14 +77,6 @@ public:
Tomahawk::ViewPage* pageForInterface( PlaylistInterface* interface ) const; Tomahawk::ViewPage* pageForInterface( PlaylistInterface* interface ) const;
int positionInHistory( Tomahawk::ViewPage* page ) const; int positionInHistory( Tomahawk::ViewPage* page ) const;
// Returns the shown viewpage
Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist );
Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album );
Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection );
Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source );
Tomahawk::ViewPage* show( Tomahawk::ViewPage* page ); Tomahawk::ViewPage* show( Tomahawk::ViewPage* page );
Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; }
@@ -94,6 +87,9 @@ public:
Tomahawk::ViewPage* pageForDynPlaylist( const Tomahawk::dynplaylist_ptr& pl ) const; Tomahawk::ViewPage* pageForDynPlaylist( const Tomahawk::dynplaylist_ptr& pl ) const;
Tomahawk::ViewPage* pageForCollection( const Tomahawk::collection_ptr& pl ) const; Tomahawk::ViewPage* pageForCollection( const Tomahawk::collection_ptr& pl ) const;
// only use this is you need to create a playlist and show it directly and want it to be
// linked to the sidebar. call it right after creating the playlist
PlaylistView* createPageForPlaylist( const Tomahawk::playlist_ptr& pl );
signals: signals:
void numSourcesChanged( unsigned int sources ); void numSourcesChanged( unsigned int sources );
void numTracksChanged( unsigned int tracks ); void numTracksChanged( unsigned int tracks );
@@ -127,6 +123,14 @@ public slots:
Tomahawk::ViewPage* showWelcomePage(); Tomahawk::ViewPage* showWelcomePage();
void showCurrentTrack(); void showCurrentTrack();
// Returns the shown viewpage
Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist );
Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album );
Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection );
Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source );
void historyBack(); void historyBack();
void historyForward(); void historyForward();
void showHistory( int historyPosition ); void showHistory( int historyPosition );

View File

@@ -0,0 +1,32 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "webcollection.h"
using namespace Tomahawk;
WebCollection::WebCollection( const source_ptr& source, const QString& name, QObject* parent )
: Collection( source, name, parent )
{
}
WebCollection::~WebCollection()
{
}

View File

@@ -0,0 +1,43 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef WEBCOLLECTION_H
#define WEBCOLLECTION_H
#include "collection.h"
#include "dllmacro.h"
namespace Tomahawk
{
class DLLEXPORT WebCollection : public Collection
{
Q_OBJECT
public:
WebCollection( const source_ptr& source, const QString& name = QString(), QObject* parent = 0 );
virtual ~WebCollection();
virtual void removeTracks( const QDir& ) {}
virtual void addTracks( const QList< QVariant >& ) {}
};
}
#endif // WEBCOLLECTION_H

View File

@@ -80,9 +80,9 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track )
trackInfo["artist"] = track->artist()->name(); trackInfo["artist"] = track->artist()->name();
trackInfo["album"] = track->album()->name(); trackInfo["album"] = track->album()->name();
trackInfo["duration"] = QString::number( track->duration() ); trackInfo["duration"] = QString::number( track->duration() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying, s_scInfoIdentifier, Tomahawk::InfoSystem::InfoSubmitNowPlaying,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
m_scrobblePoint = ScrobblePoint( track->duration() / 2 ); m_scrobblePoint = ScrobblePoint( track->duration() / 2 );
} }
@@ -128,9 +128,9 @@ Scrobbler::scrobble()
{ {
Q_ASSERT( QThread::currentThread() == thread() ); Q_ASSERT( QThread::currentThread() == thread() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitScrobble, s_scInfoIdentifier, Tomahawk::InfoSystem::InfoSubmitScrobble,
QVariant(), Tomahawk::InfoSystem::InfoCustomData() ); QVariant() );
} }
@@ -141,13 +141,7 @@ Scrobbler::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
Q_UNUSED( output ); Q_UNUSED( output );
Q_UNUSED( customData ); Q_UNUSED( customData );
if ( caller == s_scInfoIdentifier ) if ( caller == s_scInfoIdentifier )
{
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if ( type == Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying )
qDebug() << "Scrobbler received now playing response from InfoSystem";
else if ( type == Tomahawk::InfoSystem::InfoMiscSubmitScrobble )
qDebug() << "Scrobbler received scrobble response from InfoSystem";
}
} }

View File

@@ -8,7 +8,6 @@ add_definitions( -DSIPDLLEXPORT_PRO )
set( jabberSources set( jabberSources
jabber.cpp jabber.cpp
jabber_p.cpp
tomahawksipmessage.cpp tomahawksipmessage.cpp
tomahawksipmessagefactory.cpp tomahawksipmessagefactory.cpp
avatarmanager.cpp avatarmanager.cpp
@@ -16,7 +15,6 @@ set( jabberSources
set( jabberHeaders set( jabberHeaders
jabber.h jabber.h
jabber_p.h
tomahawksipmessage.h tomahawksipmessage.h
tomahawksipmessagefactory.h tomahawksipmessagefactory.h
avatarmanager.h avatarmanager.h

View File

@@ -10,7 +10,6 @@ set( googleHeaders
set( googleSources set( googleSources
../jabber.cpp ../jabber.cpp
../jabber_p.cpp
../tomahawksipmessage.cpp ../tomahawksipmessage.cpp
../tomahawksipmessagefactory.cpp ../tomahawksipmessagefactory.cpp
../avatarmanager.cpp ../avatarmanager.cpp

View File

@@ -19,13 +19,27 @@
#include "jabber.h" #include "jabber.h"
#include "config.h"
#include "tomahawksettings.h" #include "tomahawksettings.h"
#include "tomahawksipmessage.h"
#include "tomahawksipmessagefactory.h"
#include <jreen/jid.h>
#include <jreen/capabilities.h>
#include <jreen/vcardupdate.h>
#include <jreen/vcard.h>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#include <QtPlugin> #include <QtPlugin>
#include <QStringList> #include <QStringList>
#include <QInputDialog> #include <QInputDialog>
#include <QLineEdit> #include <QLineEdit>
#include <QMessageBox> #include <QMessageBox>
#include <QDateTime>
#include <QTimer>
#include "ui_configwidget.h" #include "ui_configwidget.h"
@@ -41,14 +55,16 @@ JabberFactory::icon() const
return QIcon( ":/jabber-icon.png" ); return QIcon( ":/jabber-icon.png" );
} }
JabberPlugin::JabberPlugin( const QString& pluginId ) JabberPlugin::JabberPlugin( const QString& pluginId )
: SipPlugin( pluginId ) : SipPlugin( pluginId )
, p( 0 )
, m_menu( 0 ) , m_menu( 0 )
, m_addFriendAction( 0 ) , m_addFriendAction( 0 )
, m_state( Disconnected ) , m_state( Disconnected )
{ {
qDebug() << Q_FUNC_INFO;
qsrand(QDateTime::currentDateTime().toTime_t());
m_configWidget = QWeakPointer< QWidget >( new QWidget ); m_configWidget = QWeakPointer< QWidget >( new QWidget );
m_ui = new Ui_JabberConfig; m_ui = new Ui_JabberConfig;
m_ui->setupUi( m_configWidget.data() ); m_ui->setupUi( m_configWidget.data() );
@@ -60,17 +76,56 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
m_ui->jabberServer->setText( readServer() ); m_ui->jabberServer->setText( readServer() );
m_ui->jabberPort->setValue( readPort() ); m_ui->jabberPort->setValue( readPort() );
// setup JID object
Jreen::JID jid = Jreen::JID( accountName() );
// general client setup
m_client = new Jreen::Client( jid, m_currentPassword );
m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) );
m_client->setResource( m_currentResource );
// add VCardUpdate extension to own presence
m_client->presence().addExtension( new Jreen::VCardUpdate() );
// initialize the AvatarManager
m_avatarManager = new AvatarManager( m_client );
// setup disco
m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
m_client->disco()->addFeature( TOMAHAWK_FEATURE );
// setup caps node, legacy peer detection - used before 0.1
Jreen::Capabilities::Ptr caps = m_client->presence().findExtension<Jreen::Capabilities>();
caps->setNode( TOMAHAWK_CAP_NODE_NAME );
//FIXME: caps->setVersion( TOMAHAWK_VERSION );
// print connection parameters
qDebug() << "Our JID set to:" << m_client->jid().full();
qDebug() << "Our Server set to:" << m_client->server();
qDebug() << "Our Port set to" << m_client->port();
// setup slots
connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError)));
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onConnect()));
connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
} }
JabberPlugin::~JabberPlugin() JabberPlugin::~JabberPlugin()
{ {
delete p;
} }
void void
JabberPlugin::setProxy( QNetworkProxy* proxy ) JabberPlugin::setProxy( QNetworkProxy* proxy )
{ {
p->setProxy( proxy ); qDebug() << Q_FUNC_INFO << "Not implemented";
} }
@@ -124,32 +179,13 @@ JabberPlugin::connectPlugin( bool startup )
QString password = m_currentPassword = readPassword(); QString password = m_currentPassword = readPassword();
unsigned int port = m_currentPort = readPort(); unsigned int port = m_currentPort = readPort();
QStringList splitJid = jid.split( '@', QString::SkipEmptyParts ); qDebug() << "Connecting to the XMPP server..." << (m_state == Connected);
if ( splitJid.size() < 2 ) qDebug() << m_client->jid().full();
{ //m_client->setServer( m_client->jid().domain() );
qDebug() << "JID did not have an @ in it, could not find a server part"; qDebug() << m_client->server() << m_client->port();
return false;
}
if ( port < 1 || port > 65535 || jid.isEmpty() || password.isEmpty() ) QTimer::singleShot(1000, m_client, SLOT( connectToServer() ) );
{ //m_client->connectToServer();
qDebug() << "Jabber credentials look wrong, not connecting";
return false;
}
delete p;
p = new Jabber_p( jid, password, ( server.isEmpty() ? QString() : server ), port );
QObject::connect( p, SIGNAL( peerOnline( QString ) ), SIGNAL( peerOnline( QString ) ) );
QObject::connect( p, SIGNAL( peerOffline( QString ) ), SIGNAL( peerOffline( QString ) ) );
QObject::connect( p, SIGNAL( msgReceived( QString, QString ) ), SIGNAL( msgReceived( QString, QString ) ) );
QObject::connect( p, SIGNAL( connected() ), SLOT( onConnected() ) );
QObject::connect( p, SIGNAL( disconnected() ), SLOT( onDisconnected() ) );
QObject::connect( p, SIGNAL( authError( int, QString ) ), SLOT( onAuthError( int, QString ) ) );
QObject::connect( p, SIGNAL( avatarReceived( QString, QPixmap ) ), SIGNAL( avatarReceived( QString, QPixmap ) ) );
QObject::connect( p, SIGNAL( avatarReceived( QPixmap ) ), SIGNAL( avatarReceived( QPixmap) ) );
m_state = Connecting; m_state = Connecting;
emit stateChanged( m_state ); emit stateChanged( m_state );
@@ -159,58 +195,131 @@ JabberPlugin::connectPlugin( bool startup )
void void
JabberPlugin::disconnectPlugin() JabberPlugin::disconnectPlugin()
{ {
onDisconnected(); qDebug() << Q_FUNC_INFO << (m_state == Connected);
if ( p ) if( m_state == Disconnected )
p->disconnect(); return;
delete p; foreach(const Jreen::JID &peer, m_peers.keys())
p = 0; {
handlePeerStatus(peer, Jreen::Presence::Unavailable);
}
//m_roster->deleteLater();
//m_roster = 0;
//m_room->deleteLater();
//m_room = 0;
m_peers.clear();
m_legacy_peers.clear();
m_client->disconnectFromServer(true);
} }
void void
JabberPlugin::onConnected() JabberPlugin::onConnect()
{ {
if( !m_menu ) { qDebug() << Q_FUNC_INFO;
m_menu = new QMenu( QString( "JREEN (" ).append( accountName() ).append(")" ) );
m_addFriendAction = m_menu->addAction( "Add Friend..." );
QAction *connectAction = m_menu->addAction( "Connect" );
connect( m_addFriendAction, SIGNAL(triggered() ), // update jid resource, servers like gtalk use resource binding and may
this, SLOT( showAddFriendDialog() ) ); // have changed our requested /resource
connect( connectAction, SIGNAL( triggered() ), SLOT( connectPlugin() ) ); if ( m_client->jid().resource() != m_currentResource )
{
emit addMenu( m_menu ); m_currentResource = m_client->jid().resource();
emit jidChanged( m_client->jid().full() );
} }
qDebug() << "Connected as:" << m_client->jid().full();
// set presence to least valid value
m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
// set ping timeout to 15 secs (TODO: verify if this works)
m_client->setPingInterval(1000);
// load roster
m_roster = new Jreen::SimpleRoster( m_client );
m_roster->load();
//FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
// join MUC with bare jid as nickname
//TODO: make the room a list of rooms and make that configurable
QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) );
//m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
//m_room->setHistorySeconds(0);
//m_room->join();
// treat muc participiants like contacts
//connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
//connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
m_state = Connected; m_state = Connected;
emit stateChanged( m_state ); emit stateChanged( m_state );
addMenuHelper();
} }
void void
JabberPlugin::onDisconnected() JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
{ {
if( m_menu && m_addFriendAction ) { qDebug() << Q_FUNC_INFO;
emit removeMenu( m_menu );
delete m_menu; QString errorMessage;
m_menu = 0; bool reconnect = false;
m_addFriendAction = 0; // deleted by menu int reconnectInSeconds = 0;
switch( reason )
{
case Jreen::Client::User:
errorMessage = "User Interaction";
break;
case Jreen::Client::HostUnknown:
errorMessage = "Host is unknown";
break;
case Jreen::Client::ItemNotFound:
errorMessage = "Item not found";
break;
case Jreen::Client::AuthorizationError:
errorMessage = "Authorization Error";
break;
case Jreen::Client::RemoteStreamError:
errorMessage = "Remote Stream Error";
reconnect = true;
break;
case Jreen::Client::RemoteConnectionFailed:
errorMessage = "Remote Connection failed";
break;
case Jreen::Client::InternalServerError:
errorMessage = "Internal Server Error";
reconnect = true;
break;
case Jreen::Client::SystemShutdown:
errorMessage = "System shutdown";
reconnect = true;
reconnectInSeconds = 60;
break;
case Jreen::Client::Conflict:
errorMessage = "Conflict";
break;
case Jreen::Client::Unknown:
errorMessage = "Unknown";
break;
default:
qDebug() << "Not all Client::DisconnectReasons checked";
Q_ASSERT(false);
break;
} }
m_state = Disconnected; switch( reason )
emit stateChanged( m_state );
}
void
JabberPlugin::onAuthError( int code, const QString& msg )
{
switch( code )
{ {
case Jreen::Client::User:
break;
case Jreen::Client::AuthorizationError: case Jreen::Client::AuthorizationError:
emit error( SipPlugin::AuthError, msg ); emit error( SipPlugin::AuthError, errorMessage );
break; break;
case Jreen::Client::HostUnknown: case Jreen::Client::HostUnknown:
@@ -221,7 +330,7 @@ JabberPlugin::onAuthError( int code, const QString& msg )
case Jreen::Client::SystemShutdown: case Jreen::Client::SystemShutdown:
case Jreen::Client::Conflict: case Jreen::Client::Conflict:
case Jreen::Client::Unknown: case Jreen::Client::Unknown:
emit error( SipPlugin::ConnectionError, msg ); emit error( SipPlugin::ConnectionError, errorMessage );
break; break;
default: default:
@@ -230,29 +339,97 @@ JabberPlugin::onAuthError( int code, const QString& msg )
break; break;
} }
m_state = Disconnected; m_state = Disconnected;
emit stateChanged( m_state ); emit stateChanged( m_state );
removeMenuHelper();
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, this, SLOT(connectPlugin()));
}
void
JabberPlugin::onAuthError( int code, const QString& msg )
{
} }
void void
JabberPlugin::sendMsg(const QString& to, const QString& msg) JabberPlugin::sendMsg(const QString& to, const QString& msg)
{ {
if ( p ) qDebug() << Q_FUNC_INFO << to << msg;
p->sendMsg( to, msg );
if ( !m_client ) {
return;
}
if( m_legacy_peers.contains( to ) )
{
qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg;
Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
m_client->send( m );
return;
}
/*******************************************************
* Obsolete this by a SipMessage class
*/
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
qDebug() << "Invalid JSON in XMPP msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
TomahawkSipMessage *sipMessage;
if(m["visible"].toBool())
{
sipMessage = new TomahawkSipMessage(m["ip"].toString(),
m["port"].toInt(),
m["uniqname"].toString(),
m["key"].toString(),
m["visible"].toBool()
);
}
else
{
sipMessage = new TomahawkSipMessage();
}
qDebug() << "Send sip messsage to " << to;
Jreen::IQ iq( Jreen::IQ::Set, to );
iq.addExtension( sipMessage );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), SipMessageSent );
} }
void void
JabberPlugin::broadcastMsg(const QString& msg) JabberPlugin::broadcastMsg(const QString& msg)
{ {
if ( p ) qDebug() << Q_FUNC_INFO;
p->broadcastMsg( msg );
if ( !m_client )
return;
foreach( const Jreen::JID& jid, m_peers.keys() )
{
sendMsg( jid.full(), msg );
}
} }
void void
JabberPlugin::addContact(const QString& jid, const QString& msg) JabberPlugin::addContact(const QString& jid, const QString& msg)
{ {
if ( p ) // Add contact to the Tomahawk group on the roster
p->addContact( jid, msg ); m_roster->subscribe( jid, msg, jid, QStringList() << "Tomahawk" );
return;
} }
void void
@@ -287,13 +464,299 @@ JabberPlugin::checkSettings()
m_currentServer = readServer(); m_currentServer = readServer();
m_currentPort = readPort(); m_currentPort = readPort();
if ( reconnect && ( p || readAutoConnect() ) ) if ( reconnect )
{ {
qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin...";
disconnectPlugin(); disconnectPlugin();
m_currentUsername = accountName();
m_currentPassword = readPassword();
m_currentServer = readServer();
m_currentPort = readPort();
Jreen::JID jid = Jreen::JID( accountName() );
m_client->setJID( jid );
m_client->setPassword( m_currentPassword );
m_client->setServer( m_currentServer );
m_client->setPort( m_currentPort );
qDebug() << Q_FUNC_INFO << "Updated settings";
connectPlugin( false ); connectPlugin( false );
} }
} }
void JabberPlugin::addMenuHelper()
{
if( !m_menu )
{
m_menu = new QMenu( QString( "JREEN (" ).append( accountName() ).append(")" ) );
m_addFriendAction = m_menu->addAction( "Add Friend..." );
connect( m_addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) );
emit addMenu( m_menu );
}
}
void JabberPlugin::removeMenuHelper()
{
if( m_menu && m_addFriendAction )
{
emit removeMenu( m_menu );
delete m_menu;
m_menu = 0;
m_addFriendAction = 0; // deleted by menu
}
}
void JabberPlugin::onNewMessage(const Jreen::Message& message)
{
QString from = message.from().full();
QString msg = message.body();
if ( msg.isEmpty() )
return;
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
QString to = from;
QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
" (http://gettomahawk.com). If you are getting this message, the person you"
" are trying to reach is probably not signed on, so please try again later!") );
// this is not a sip message, so we send it directly through the client
m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) );
return;
}
qDebug() << Q_FUNC_INFO << "From:" << message.from().full() << ":" << message.body();
emit msgReceived( from, msg );
}
void JabberPlugin::onNewPresence( const Jreen::Presence& presence)
{
Jreen::JID jid = presence.from();
QString fulljid( jid.full() );
qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype();
if( jid == m_client->jid() )
return;
if ( presence.error() ) {
//qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
return;
}
// ignore anyone not Running tomahawk:
Jreen::Capabilities::Ptr caps = presence.findExtension<Jreen::Capabilities>();
if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
{
// must be a jreen resource, implementation in gloox was broken
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node();
handlePeerStatus( jid, presence.subtype() );
}
else if( caps )
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node()
<< "requesting disco..";
// request disco features
QString node = caps->node() + '#' + caps->ver();
Jreen::IQ iq( Jreen::IQ::Get, jid );
iq.addExtension( new Jreen::Disco::Info( node ) );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
}
else if( !caps )
{
qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
}
}
void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
{
if( context == RequestDisco )
{
qDebug() << Q_FUNC_INFO << "Received disco IQ...";
Jreen::Disco::Info *discoInfo = iq.findExtension<Jreen::Disco::Info>().data();
if(!discoInfo)
return;
iq.accept();
Jreen::JID jid = iq.from();
Jreen::DataForm::Ptr form = discoInfo->form();
if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
{
qDebug() << Q_FUNC_INFO << jid.full() << "Running tomahawk/feature enabled: yes";
// the actual presence doesn't matter, it just needs to be "online"
handlePeerStatus( jid, Jreen::Presence::Available );
}
else
{
qDebug() << Q_FUNC_INFO << jid.full() << "Running tomahawk/feature enabled: no";
//LEGACY: accept resources starting with tomahawk too
if( jid.resource().startsWith("tomahawk") )
{
qDebug() << Q_FUNC_INFO << jid.full() << "Detected legacy tomahawk..";
// add to legacy peers, so we can send text messages instead of iqs
m_legacy_peers.append( jid );
handlePeerStatus( jid, Jreen::Presence::Available );
}
}
}
else if(context == RequestedDisco)
{
qDebug() << "Sent IQ(Set), what should be happening here?";
}
else if(context == SipMessageSent )
{
qDebug() << "Sent SipMessage... what now?!";
}
/*else if(context == RequestedVCard )
{
qDebug() << "Requested VCard... what now?!";
}*/
else
{
TomahawkSipMessage *sipMessage = iq.findExtension<TomahawkSipMessage>().data();
if(sipMessage)
{
iq.accept();
qDebug() << Q_FUNC_INFO << "Got SipMessage ...";
qDebug() << "ip" << sipMessage->ip();
qDebug() << "port" << sipMessage->port();
qDebug() << "uniqname" << sipMessage->uniqname();
qDebug() << "key" << sipMessage->key();
qDebug() << "visible" << sipMessage->visible();
QVariantMap m;
if( sipMessage->visible() )
{
m["visible"] = true;
m["ip"] = sipMessage->ip();
m["port"] = sipMessage->port();
m["key"] = sipMessage->key();
m["uniqname"] = sipMessage->uniqname();
}
else
{
m["visible"] = false;
}
QJson::Serializer ser;
QByteArray ba = ser.serialize( m );
QString msg = QString::fromAscii( ba );
QString from = iq.from().full();
qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg;
emit msgReceived( from, msg );
}
}
}
bool JabberPlugin::presenceMeansOnline(Jreen::Presence::Type p)
{
switch(p)
{
case Jreen::Presence::Invalid:
case Jreen::Presence::Unavailable:
case Jreen::Presence::Error:
return false;
break;
default:
return true;
}
}
void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type presenceType)
{
QString fulljid = jid.full();
// "going offline" event
if ( !presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) ||
presenceMeansOnline( m_peers.value( jid ) )
)
)
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
// remove peer from legacy peers
if( m_legacy_peers.contains( jid ) )
{
m_legacy_peers.removeAll( jid );
}
emit peerOffline( fulljid );
return;
}
// "coming online" event
if( presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) ||
!presenceMeansOnline( m_peers.value( jid ) )
)
)
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
emit peerOnline( fulljid );
if(!m_avatarManager->avatar(jid.bare()).isNull())
onNewAvatar( jid.bare() );
return;
}
//qDebug() << "Updating presence data for" << fulljid;
m_peers[ jid ] = presenceType;
}
void JabberPlugin::onNewAvatar(const QString& jid)
{
qDebug() << Q_FUNC_INFO << jid;
Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
// find peers for the jid
QList<Jreen::JID> peers = m_peers.keys();
foreach(const Jreen::JID &peer, peers)
{
if( peer.bare() == jid )
{
emit avatarReceived ( peer.full(), m_avatarManager->avatar( jid ) );
}
}
if( jid == m_client->jid().bare() )
// own avatar
emit avatarReceived ( m_avatarManager->avatar( jid ) );
else
// someone else's avatar
emit avatarReceived ( jid, m_avatarManager->avatar( jid ) );
}
QString QString
JabberPlugin::readPassword() JabberPlugin::readPassword()
{ {

View File

@@ -21,11 +21,29 @@
#define JABBER_H #define JABBER_H
#include "sip/SipPlugin.h" #include "sip/SipPlugin.h"
#include "jabber_p.h"
#include "../sipdllmacro.h" #include "avatarmanager.h"
#include <jreen/client.h>
#include <jreen/disco.h>
#include <jreen/message.h>
#include <jreen/messagesession.h>
#include <jreen/stanza.h>
#include <jreen/jreen.h>
#include <jreen/error.h>
#include <jreen/presence.h>
#include <jreen/vcard.h>
#include <jreen/abstractroster.h>
#include <jreen/connection.h>
#include <jreen/mucroom.h>
#include <QNetworkProxy>
#define MYNAME "SIPJREEN" #define MYNAME "SIPJREEN"
#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
#include "../sipdllmacro.h"
class Ui_JabberConfig; class Ui_JabberConfig;
@@ -64,6 +82,8 @@ public:
virtual void saveConfig(); virtual void saveConfig();
void setProxy( QNetworkProxy* proxy ); void setProxy( QNetworkProxy* proxy );
signals:
void jidChanged( const QString& );
public slots: public slots:
virtual bool connectPlugin( bool startup ); virtual bool connectPlugin( bool startup );
@@ -78,17 +98,31 @@ protected:
private slots: private slots:
void showAddFriendDialog(); void showAddFriendDialog();
void onConnected(); void onConnect();
void onDisconnected(); void onDisconnect(Jreen::Client::DisconnectReason reason);
void onAuthError(int code, const QString &msg); void onAuthError(int code, const QString &msg);
void onNewPresence( const Jreen::Presence& presence );
void onNewMessage( const Jreen::Message& message );
void onError( const Jreen::Connection::SocketError& e )
{
qDebug() << e;
}
void onNewIq( const Jreen::IQ &iq, int context = NoContext );
void onNewAvatar( const QString &jid );
private: private:
QString readPassword(); QString readPassword();
QString readServer(); QString readServer();
bool readAutoConnect(); bool readAutoConnect();
int readPort(); int readPort();
Jabber_p* p; void addMenuHelper();
void removeMenuHelper();
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
QMenu* m_menu; QMenu* m_menu;
QAction* m_addFriendAction; QAction* m_addFriendAction;
@@ -99,6 +133,18 @@ private:
ConnectionState m_state; ConnectionState m_state;
QWeakPointer< QWidget > m_configWidget; QWeakPointer< QWidget > m_configWidget;
QString m_currentResource;
// sort out
Jreen::Client *m_client;
Jreen::MUCRoom *m_room;
Jreen::SimpleRoster *m_roster;
QHash<Jreen::JID, Jreen::Presence::Type> m_peers;
enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard };
QStringList m_legacy_peers;
AvatarManager *m_avatarManager;
}; };
#endif #endif

View File

@@ -1,576 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jabber_p.h"
#include "tomahawksipmessage.h"
#include "tomahawksipmessagefactory.h"
#include "config.h"
#include "utils/tomahawkutils.h"
#include <jreen/capabilities.h>
#include <jreen/tcpconnection.h>
#include <jreen/vcardupdate.h>
#include <jreen/vcard.h>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#include <QDebug>
#include <QTime>
#include <QTimer>
#include <QString>
#include <QRegExp>
#include <QThread>
#include <QVariant>
#include <QMap>
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
#include <QPixmap>
//remove
#include <QLabel>
#include <QtGui/QLabel>
#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
Jabber_p::Jabber_p( const QString& jid, const QString& password, const QString& server, const int port )
: QObject()
, m_server()
{
qDebug() << Q_FUNC_INFO;
qsrand(QDateTime::currentDateTime().toTime_t());
// setup JID object
m_jid = Jreen::JID( jid );
// general client setup
m_client = new Jreen::Client( jid, password );
if ( !server.isEmpty() )
{
m_client->setServer( server );
m_client->setPort( port );
}
m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
m_client->setResource( QString( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) ) );
// add VCardUpdate extension to own presence
m_client->presence().addExtension( new Jreen::VCardUpdate() );
// initialize the AvatarManager
m_avatarManager = new AvatarManager(m_client);
// setup disco
m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
m_client->disco()->addFeature( TOMAHAWK_FEATURE );
// setup caps node, legacy peer detection - used before 0.1
Jreen::Capabilities::Ptr caps = m_client->presence().findExtension<Jreen::Capabilities>();
caps->setNode( TOMAHAWK_CAP_NODE_NAME );
// print connection parameters
qDebug() << "Our JID set to:" << m_client->jid().full();
qDebug() << "Our Server set to:" << m_client->server();
qDebug() << "Our Port set to" << m_client->port();
m_client->setConnectionImpl( new Jreen::TcpConnection( m_client->server(), m_client->port() ) );
// setup slots
connect(qobject_cast<Jreen::Connection*>(m_client->connection()), SIGNAL(error(const Jreen::Connection::SocketError&)), SLOT(onError(const Jreen::Connection::SocketError&)));
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onConnect()));
connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
connect(m_client, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroy(QObject*)));
connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
// connect
qDebug() << "Connecting to the XMPP server...";
m_client->connectToServer();
}
Jabber_p::~Jabber_p()
{
delete m_client;
}
void
Jabber_p::setProxy( QNetworkProxy* proxy )
{
qDebug() << Q_FUNC_INFO << "NOT IMPLEMENTED";
}
void
Jabber_p::disconnect()
{
if ( m_client )
{
m_client->disconnect();
}
}
void
Jabber_p::sendMsg( const QString& to, const QString& msg )
{
qDebug() << Q_FUNC_INFO << to << msg;
if ( !m_client ) {
return;
}
if( m_legacy_peers.contains( to ) )
{
qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg;
Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
m_client->send( m );
return;
}
/*******************************************************
* Obsolete this by a SipMessage class
*/
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
qDebug() << "Invalid JSON in XMPP msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
TomahawkSipMessage *sipMessage;
if(m["visible"].toBool())
{
sipMessage = new TomahawkSipMessage(m["ip"].toString(),
m["port"].toInt(),
m["uniqname"].toString(),
m["key"].toString(),
m["visible"].toBool()
);
}
else
{
sipMessage = new TomahawkSipMessage();
}
qDebug() << "Send sip messsage to " << to;
Jreen::IQ iq( Jreen::IQ::Set, to );
iq.addExtension( sipMessage );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), SipMessageSent );
}
void
Jabber_p::broadcastMsg( const QString &msg )
{
qDebug() << Q_FUNC_INFO;
if ( !m_client )
return;
foreach( const QString& jidstr, m_peers.keys() )
{
sendMsg( jidstr, msg );
}
}
void
Jabber_p::addContact( const QString& jid, const QString& msg )
{
// Add contact to the Tomahawk group on the roster
m_roster->add( jid, jid, QStringList() << "Tomahawk" );
return;
}
void
Jabber_p::onConnect()
{
qDebug() << Q_FUNC_INFO;
// update jid resource, servers like gtalk use resource binding and may
// have changed our requested /resource
if ( m_client->jid().resource() != m_jid.resource() )
{
// TODO: check if this is still neccessary with jreen
m_jid.setResource( m_client->jid().resource() );
QString jidstr( m_jid.full() );
emit jidChanged( jidstr );
}
emit connected();
qDebug() << "Connected as:" << m_jid.full();
// set presence to least valid value
m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
// set ping timeout to 15 secs (TODO: verify if this works)
m_client->setPingInterval(15000);
// load roster
m_roster = new Jreen::SimpleRoster( m_client );
m_roster->load();
//FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
// join MUC with bare jid as nickname
//TODO: make the room a list of rooms and make that configurable
QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_jid.bare() ).replace( "@", "-" ) );
m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
//m_room->setHistorySeconds(0);
//m_room->join();
// treat muc participiants like contacts
connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
}
void
Jabber_p::onDisconnect( Jreen::Client::DisconnectReason reason )
{
QString error;
bool reconnect = false;
int reconnectInSeconds = 0;
switch( reason )
{
case Jreen::Client::User:
error = "User Interaction";
break;
case Jreen::Client::HostUnknown:
error = "Host is unknown";
break;
case Jreen::Client::ItemNotFound:
error = "Item not found";
break;
case Jreen::Client::AuthorizationError:
error = "Authorization Error";
break;
case Jreen::Client::RemoteStreamError:
error = "Remote Stream Error";
reconnect = true;
break;
case Jreen::Client::RemoteConnectionFailed:
error = "Remote Connection failed";
break;
case Jreen::Client::InternalServerError:
error = "Internal Server Error";
reconnect = true;
break;
case Jreen::Client::SystemShutdown:
error = "System shutdown";
reconnect = true;
reconnectInSeconds = 60;
break;
case Jreen::Client::Conflict:
error = "Conflict";
break;
case Jreen::Client::Unknown:
error = "Unknown";
break;
default:
qDebug() << "Not all Client::DisconnectReasons checked";
Q_ASSERT(false);
break;
}
qDebug() << "Disconnected from server:" << error;
if( reason != Jreen::Client::User )
{
emit authError( reason, error );
}
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, m_client, SLOT(connectToServer()));
emit disconnected();
}
void
Jabber_p::onNewMessage( const Jreen::Message& m )
{
QString from = m.from().full();
QString msg = m.body();
if ( msg.isEmpty() )
return;
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
if ( m.from().domain().contains( "googlemail." )
|| m.from().domain().contains( "gmail." )
|| m.from().domain().contains( "gtalk." )
)
return;
QString to = from;
QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
" (http://gettomahawk.com). If you are getting this message, the person you"
" are trying to reach is probably not signed on, so please try again later!") );
// this is not a sip message, so we send it directly through the client
m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) );
return;
}
qDebug() << Q_FUNC_INFO << "From:" << m.from().full() << ":" << m.body();
emit msgReceived( from, msg );
}
void Jabber_p::onNewPresence( const Jreen::Presence& presence)
{
Jreen::JID jid = presence.from();
QString fulljid( jid.full() );
qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype();
if( jid == m_jid )
return;
if ( presence.error() ) {
//qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
return;
}
// ignore anyone not Running tomahawk:
Jreen::Capabilities::Ptr caps = presence.findExtension<Jreen::Capabilities>();
if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
{
// must be a jreen resource, implementation in gloox was broken
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node();
handlePeerStatus( fulljid, presence.subtype() );
}
else if( caps )
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node()
<< "requesting disco..";
// request disco features
QString node = caps->node() + '#' + caps->ver();
Jreen::IQ iq( Jreen::IQ::Get, jid );
iq.addExtension( new Jreen::Disco::Info( node ) );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
}
else if( !caps )
{
qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
}
}
void
Jabber_p::onNewIq( const Jreen::IQ &iq, int context )
{
if( context == RequestDisco )
{
qDebug() << Q_FUNC_INFO << "Received disco IQ...";
Jreen::Disco::Info *discoInfo = iq.findExtension<Jreen::Disco::Info>().data();
if(!discoInfo)
return;
iq.accept();
QString fulljid = iq.from().full();
Jreen::DataForm::Ptr form = discoInfo->form();
if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: yes";
// the actual presence doesn't matter, it just needs to be "online"
handlePeerStatus( fulljid, Jreen::Presence::Available );
}
else
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: no";
//LEGACY: accept resources starting with tomahawk too
if( iq.from().resource().startsWith("tomahawk") )
{
qDebug() << Q_FUNC_INFO << fulljid << "Detected legacy tomahawk..";
// add to legacy peers, so we can send text messages instead of iqs
m_legacy_peers.append( fulljid );
handlePeerStatus( fulljid, Jreen::Presence::Available );
}
}
}
else if(context == RequestedDisco)
{
qDebug() << "Sent IQ(Set), what should be happening here?";
}
else if(context == SipMessageSent )
{
qDebug() << "Sent SipMessage... what now?!";
}
/*else if(context == RequestedVCard )
{
qDebug() << "Requested VCard... what now?!";
}*/
else
{
TomahawkSipMessage *sipMessage = iq.findExtension<TomahawkSipMessage>().data();
if(sipMessage)
{
iq.accept();
qDebug() << Q_FUNC_INFO << "Got SipMessage ...";
qDebug() << "ip" << sipMessage->ip();
qDebug() << "port" << sipMessage->port();
qDebug() << "uniqname" << sipMessage->uniqname();
qDebug() << "key" << sipMessage->key();
qDebug() << "visible" << sipMessage->visible();
QVariantMap m;
if( sipMessage->visible() )
{
m["visible"] = true;
m["ip"] = sipMessage->ip();
m["port"] = sipMessage->port();
m["key"] = sipMessage->key();
m["uniqname"] = sipMessage->uniqname();
}
else
{
m["visible"] = false;
}
QJson::Serializer ser;
QByteArray ba = ser.serialize( m );
QString msg = QString::fromAscii( ba );
QString from = iq.from().full();
qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg;
emit msgReceived( from, msg );
}
}
}
bool
Jabber_p::presenceMeansOnline( Jreen::Presence::Type p )
{
switch(p)
{
case Jreen::Presence::Invalid:
case Jreen::Presence::Unavailable:
case Jreen::Presence::Error:
return false;
break;
default:
return true;
}
}
void
Jabber_p::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType )
{
QString fulljid = jid.full();
// "going offline" event
if ( !presenceMeansOnline( presenceType ) &&
( !m_peers.contains( fulljid ) ||
presenceMeansOnline( m_peers.value( fulljid ) )
)
)
{
m_peers[ fulljid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
// remove peer from legacy peers
if( m_legacy_peers.contains( fulljid ) )
{
m_legacy_peers.removeAll( fulljid );
}
emit peerOffline( fulljid );
return;
}
// "coming online" event
if( presenceMeansOnline( presenceType ) &&
( !m_peers.contains( fulljid ) ||
!presenceMeansOnline( m_peers.value( fulljid ) )
)
)
{
m_peers[ fulljid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
emit peerOnline( fulljid );
if(!m_avatarManager->avatar(jid.bare()).isNull())
onNewAvatar( jid.bare() );
return;
}
//qDebug() << "Updating presence data for" << fulljid;
m_peers[ fulljid ] = presenceType;
}
void Jabber_p::onNewAvatar(const QString& jid)
{
qDebug() << Q_FUNC_INFO << jid;
Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
// find peers for the jid
QStringList peers = m_peers.keys();
foreach(const QString &peer, peers)
{
if( peer.startsWith(jid) )
{
emit avatarReceived ( peer, m_avatarManager->avatar( jid ) );
}
}
if( jid == m_client->jid().bare() )
// own avatar
emit avatarReceived ( m_avatarManager->avatar( jid ) );
else
// someone else's avatar
emit avatarReceived ( jid, m_avatarManager->avatar( jid ) );
}

View File

@@ -1,114 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk 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.
*
* Tomahawk 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 Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JABBER_P_H
#define JABBER_P_H
#include "../sipdllmacro.h"
#include "avatarmanager.h"
#include <jreen/client.h>
#include <jreen/disco.h>
#include <jreen/message.h>
#include <jreen/messagesession.h>
#include <jreen/stanza.h>
#include <jreen/jreen.h>
#include <jreen/error.h>
#include <jreen/presence.h>
#include <jreen/vcard.h>
#include <jreen/abstractroster.h>
#include <jreen/connection.h>
#include <jreen/mucroom.h>
#include <QObject>
#include <QSharedPointer>
#include <QMap>
#include <QNetworkProxy>
#if defined( WIN32 ) || defined( _WIN32 )
#include <windows.h>
#endif
class SIPDLLEXPORT Jabber_p :
public QObject
{
Q_OBJECT
public:
explicit Jabber_p( const QString& jid, const QString& password, const QString& server = "", const int port = -1 );
virtual ~Jabber_p();
void setProxy( QNetworkProxy* proxy );
signals:
void msgReceived( const QString&, const QString& ); //from, msg
void peerOnline( const QString& );
void peerOffline( const QString& );
void connected();
void disconnected();
void jidChanged( const QString& );
void avatarReceived( const QPixmap& avatar );
void avatarReceived( const QString&, const QPixmap& avatar );
void authError( int, const QString& );
public slots:
void sendMsg( const QString& to, const QString& msg );
void broadcastMsg( const QString& msg );
void addContact( const QString& jid, const QString& msg = QString() );
void disconnect();
void onDisconnect(Jreen::Client::DisconnectReason reason);
void onConnect();
private slots:
virtual void onNewPresence( const Jreen::Presence& presence );
virtual void onNewMessage( const Jreen::Message& msg );
virtual void onError( const Jreen::Connection::SocketError& e )
{
qDebug() << e;
}
virtual void onDestroy( QObject */*object*/ )
{
qDebug() << Q_FUNC_INFO;
}
virtual void onNewIq( const Jreen::IQ &iq, int context = NoContext );
virtual void onNewAvatar( const QString &jid );
private:
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
Jreen::Client *m_client;
Jreen::MUCRoom *m_room;
Jreen::SimpleRoster *m_roster;
Jreen::JID m_jid;
QMap<Jreen::Presence::Type, QString> m_presences;
QMap<QString, Jreen::Presence::Type> m_peers;
QString m_server;
enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard };
QStringList m_legacy_peers;
AvatarManager *m_avatarManager;
};
#endif // JABBER_H

View File

@@ -48,6 +48,9 @@
#include "shortcuthandler.h" #include "shortcuthandler.h"
#include "scanmanager.h" #include "scanmanager.h"
#include "tomahawksettings.h" #include "tomahawksettings.h"
#include "globalactionmanager.h"
#include "webcollection.h"
#include "database/localcollection.h"
#include "audio/audioengine.h" #include "audio/audioengine.h"
#include "utils/xspfloader.h" #include "utils/xspfloader.h"
@@ -223,7 +226,7 @@ TomahawkApp::init()
#else #else
qDebug() << "Setting NAM."; qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new QNetworkAccessManager ); TomahawkUtils::setNam( new QNetworkAccessManager() );
#endif #endif
// Set up proxy // Set up proxy
@@ -241,7 +244,6 @@ TomahawkApp::init()
else else
TomahawkUtils::setProxy( new QNetworkProxy( QNetworkProxy::NoProxy ) ); TomahawkUtils::setProxy( new QNetworkProxy( QNetworkProxy::NoProxy ) );
Echonest::Config::instance()->setAPIKey( "JRIHWEP6GPOER2QQ6" ); Echonest::Config::instance()->setAPIKey( "JRIHWEP6GPOER2QQ6" );
Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() ); Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() );
@@ -249,7 +251,6 @@ TomahawkApp::init()
qDebug() << "Init SIP system."; qDebug() << "Init SIP system.";
#ifndef TOMAHAWK_HEADLESS #ifndef TOMAHAWK_HEADLESS
if ( !m_headless ) if ( !m_headless )
{ {
@@ -462,12 +463,19 @@ void
TomahawkApp::initLocalCollection() TomahawkApp::initLocalCollection()
{ {
source_ptr src( new Source( 0, "My Collection" ) ); source_ptr src( new Source( 0, "My Collection" ) );
collection_ptr coll( new DatabaseCollection( src ) ); collection_ptr coll( new LocalCollection( src ) );
src->addCollection( coll ); src->addCollection( coll );
SourceList::instance()->setLocal( src ); SourceList::instance()->setLocal( src );
// src->collection()->tracks(); // src->collection()->tracks();
// dummy source/collection for web-based result-hints.
source_ptr dummy( new Source( -1, "" ) );
dummy->setOnline();
collection_ptr dummycol( new WebCollection( dummy ) );
dummy->addCollection( dummycol );
SourceList::instance()->setWebSource( dummy );
// to make the stats signal be emitted by our local source // to make the stats signal be emitted by our local source
// this will update the sidebar, etc. // this will update the sidebar, etc.
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src ); DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src );
@@ -503,7 +511,9 @@ TomahawkApp::setupSIP()
qDebug() << "Connecting SIP classes"; qDebug() << "Connecting SIP classes";
SipHandler::instance()->loadFromConfig( true ); SipHandler::instance()->loadFromConfig( true );
// SipHandler::instance()->setProxy( *TomahawkUtils::proxy() );
// m_sipHandler->setProxy( *TomahawkUtils::proxy() );
} }
} }
@@ -520,28 +530,22 @@ TomahawkApp::activate()
bool bool
TomahawkApp::loadUrl( const QString& url ) TomahawkApp::loadUrl( const QString& url )
{ {
if( url.contains( "tomahawk://" ) ) { if( url.startsWith( "tomahawk://" ) )
QString cmd = url.mid( 11 ); return GlobalActionManager::instance()->parseTomahawkLink( url );
qDebug() << "tomahawk!s" << cmd; else
if( cmd.startsWith( "load/?" ) ) { {
cmd = cmd.mid( 6 );
qDebug() << "loading.." << cmd;
if( cmd.startsWith( "xspf=" ) ) {
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << cmd.mid( 5 );
l->load( QUrl( cmd.mid( 5 ) ) );
}
}
} else {
QFile f( url ); QFile f( url );
QFileInfo info( f ); QFileInfo info( f );
if( f.exists() && info.suffix() == "xspf" ) { if( f.exists() && info.suffix() == "xspf" ) {
XSPFLoader* l = new XSPFLoader( true, this ); XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << url; qDebug() << "Loading spiff:" << url;
l->load( QUrl::fromUserInput( url ) ); l->load( QUrl::fromUserInput( url ) );
return true;
} }
} }
return true;
return false;
} }
@@ -555,6 +559,7 @@ TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
return; return;
} }
loadUrl( instance.arguments.at( 1 ) ); QString arg1 = instance.arguments[ 1 ];
loadUrl( arg1 );
} }

View File

@@ -21,6 +21,8 @@
#include <QAction> #include <QAction>
#include <QCloseEvent> #include <QCloseEvent>
#include <QShowEvent>
#include <QHideEvent>
#include <QInputDialog> #include <QInputDialog>
#include <QPixmap> #include <QPixmap>
#include <QPropertyAnimation> #include <QPropertyAnimation>
@@ -161,7 +163,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this ); qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this );
updater->SetNetworkAccessManager( TomahawkUtils::nam() ); updater->SetNetworkAccessManager( TomahawkUtils::nam() );
updater->SetVersion( VERSION ); updater->SetVersion( TOMAHAWK_VERSION );
ui->menu_Help->addSeparator(); ui->menu_Help->addSeparator();
QAction* checkForUpdates = ui->menu_Help->addAction( tr( "Check For Updates...") ); QAction* checkForUpdates = ui->menu_Help->addAction( tr( "Check For Updates...") );
@@ -267,6 +269,13 @@ TomahawkWindow::setupSignals()
connect( ui->actionCreate_New_Station, SIGNAL( triggered() ), SLOT( createStation() )); connect( ui->actionCreate_New_Station, SIGNAL( triggered() ), SLOT( createStation() ));
connect( ui->actionAboutTomahawk, SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) ); connect( ui->actionAboutTomahawk, SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) );
connect( ui->actionExit, SIGNAL( triggered() ), APP, SLOT( quit() ) ); connect( ui->actionExit, SIGNAL( triggered() ), APP, SLOT( quit() ) );
#if defined( Q_OS_DARWIN )
connect( ui->actionMinimize, SIGNAL( triggered() ), SLOT( minimize() ) );
connect( ui->actionZoom, SIGNAL( triggered() ), SLOT( maximize() ) );
#else
ui->menuWindow->clear();
ui->menuWindow->menuAction()->setVisible( false );
#endif
// <SipHandler> // <SipHandler>
connect( APP->sipHandler(), SIGNAL( connected() ), SLOT( onSipConnected() ) ); connect( APP->sipHandler(), SIGNAL( connected() ), SLOT( onSipConnected() ) );
@@ -294,7 +303,6 @@ TomahawkWindow::changeEvent( QEvent* e )
} }
} }
void void
TomahawkWindow::closeEvent( QCloseEvent* e ) TomahawkWindow::closeEvent( QCloseEvent* e )
{ {
@@ -310,6 +318,27 @@ TomahawkWindow::closeEvent( QCloseEvent* e )
e->accept(); e->accept();
} }
void
TomahawkWindow::showEvent( QShowEvent* e )
{
QMainWindow::showEvent( e );
#if defined( Q_OS_DARWIN )
ui->actionMinimize->setDisabled( false );
ui->actionZoom->setDisabled( false );
#endif
}
void
TomahawkWindow::hideEvent( QHideEvent* e )
{
QMainWindow::hideEvent( e );
#if defined( Q_OS_DARWIN )
ui->actionMinimize->setDisabled( true );
ui->actionZoom->setDisabled( true );
#endif
}
void void
TomahawkWindow::showSettingsDialog() TomahawkWindow::showSettingsDialog()
@@ -530,3 +559,25 @@ TomahawkWindow::checkForUpdates()
Tomahawk::checkForUpdates(); Tomahawk::checkForUpdates();
#endif #endif
} }
void
TomahawkWindow::minimize()
{
if ( isMinimized() )
{
showNormal();
} else {
showMinimized();
}
}
void
TomahawkWindow::maximize()
{
if ( isMaximized() )
{
showNormal();
} else {
showMaximized();
}
}

View File

@@ -57,6 +57,8 @@ public:
protected: protected:
void changeEvent( QEvent* e ); void changeEvent( QEvent* e );
void closeEvent( QCloseEvent* e ); void closeEvent( QCloseEvent* e );
void showEvent( QShowEvent* e );
void hideEvent( QHideEvent* e );
public slots: public slots:
void createAutomaticPlaylist(); void createAutomaticPlaylist();
@@ -84,6 +86,10 @@ private slots:
void onSipPluginAdded( SipPlugin* p ); void onSipPluginAdded( SipPlugin* p );
void onSipPluginRemoved( SipPlugin* p ); void onSipPluginRemoved( SipPlugin* p );
void minimize();
void maximize();
private: private:
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();

View File

@@ -72,6 +72,13 @@
<addaction name="actionToggleConnect"/> <addaction name="actionToggleConnect"/>
<addaction name="separator"/> <addaction name="separator"/>
</widget> </widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>&amp;Window</string>
</property>
<addaction name="actionMinimize"/>
<addaction name="actionZoom"/>
</widget>
<widget class="QMenu" name="menu_Help"> <widget class="QMenu" name="menu_Help">
<property name="title"> <property name="title">
<string>&amp;Help</string> <string>&amp;Help</string>
@@ -82,6 +89,7 @@
<addaction name="menuPlaylist"/> <addaction name="menuPlaylist"/>
<addaction name="menuNetwork"/> <addaction name="menuNetwork"/>
<addaction name="menuSettings"/> <addaction name="menuSettings"/>
<addaction name="menuWindow"/>
<addaction name="menu_Help"/> <addaction name="menu_Help"/>
</widget> </widget>
<widget class="QStatusBar" name="statusBar"/> <widget class="QStatusBar" name="statusBar"/>
@@ -157,6 +165,22 @@
<string>Hide Offline Sources</string> <string>Hide Offline Sources</string>
</property> </property>
</action> </action>
<action name="actionMinimize">
<property name="text">
<string>Minimize</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="actionZoom">
<property name="text">
<string>Zoom</string>
</property>
<property name="shortcut">
<string>Meta+Ctrl+Z</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>

View File

@@ -78,7 +78,7 @@ if(UNIX)
endif(APPLE) endif(APPLE)
endif(UNIX) endif(UNIX)
if(WIN32) if(WIN32)
set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp) set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp ws/win/Pac.cpp ws/win/NdisEvents.cpp )
set(MOC_HEADERS ${MOC_HEADERS} ws/win/WNetworkConnectionMonitor.h) set(MOC_HEADERS ${MOC_HEADERS} ws/win/WNetworkConnectionMonitor.h)
endif(WIN32) endif(WIN32)
@@ -100,9 +100,10 @@ ENDIF()
target_link_libraries(tomahawk_lastfm2 target_link_libraries(tomahawk_lastfm2
${QT_LIBRARIES} ${QT_LIBRARIES}
${QT_QTDBUS_LIBRARY} ${QT_QTDBUS_LIBRARY}
) )
set_target_properties(tomahawk_lastfm2 PROPERTIES COMPILE_FLAGS "-DLASTFM_OHAI_QMAKE" ) set_target_properties(tomahawk_lastfm2 PROPERTIES COMPILE_FLAGS "-DLASTFM_OHAI_QMAKE" )
if(APPLE) if(APPLE)
target_link_libraries(tomahawk_lastfm2 target_link_libraries(tomahawk_lastfm2

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -34,11 +34,11 @@
static struct NetworkAccessManagerInit static struct NetworkAccessManagerInit
{ {
// We do this upfront because then our Firehose QTcpSocket will have a proxy // We do this upfront because then our Firehose QTcpSocket will have a proxy
// set by default. As well as any plain QNetworkAcessManager stuff, and the // set by default. As well as any plain QNetworkAcessManager stuff, and the
// scrobbler // scrobbler
// In theory we should do this every request in case the configuration // In theory we should do this every request in case the configuration
// changes but that is fairly unlikely use case, init? Maybe we should // changes but that is fairly unlikely use case, init? Maybe we should
// anyway.. // anyway..
NetworkAccessManagerInit() NetworkAccessManagerInit()
@@ -50,7 +50,7 @@ static struct NetworkAccessManagerInit
// at two seconds, so that hangs startup // at two seconds, so that hangs startup
if (!s.fAutoDetect && s.lpszProxy) if (!s.fAutoDetect && s.lpszProxy)
{ {
QUrl url( QString::fromUtf16(s.lpszProxy) ); QUrl url( QString::fromUtf16((const unsigned short*)s.lpszProxy) );
QNetworkProxy proxy( QNetworkProxy::HttpProxy ); QNetworkProxy proxy( QNetworkProxy::HttpProxy );
proxy.setHostName( url.host() ); proxy.setHostName( url.host() );
proxy.setPort( url.port() ); proxy.setPort( url.port() );
@@ -69,10 +69,10 @@ static struct NetworkAccessManagerInit
} }
#endif #endif
} }
} init; } init;
namespace lastfm namespace lastfm
{ {
LASTFM_DLLEXPORT QByteArray UserAgent; LASTFM_DLLEXPORT QByteArray UserAgent;
} }
@@ -106,12 +106,12 @@ lastfm::NetworkAccessManager::~NetworkAccessManager()
QNetworkProxy QNetworkProxy
lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request ) lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request )
{ {
Q_UNUSED( request ); Q_UNUSED( request );
#ifdef WIN32 #ifdef WIN32
IeSettings s; IeSettings s;
if (s.fAutoDetect) if (s.fAutoDetect)
{ {
if (!m_pac) { if (!m_pac) {
m_pac = new Pac; m_pac = new Pac;
@@ -122,9 +122,9 @@ lastfm::NetworkAccessManager::proxy( const QNetworkRequest& request )
} }
} }
return m_pac->resolve( request, s.lpszAutoConfigUrl ); return m_pac->resolve( request, s.lpszAutoConfigUrl );
} }
#endif #endif
return QNetworkProxy::applicationProxy(); return QNetworkProxy::applicationProxy();
} }
@@ -136,7 +136,7 @@ lastfm::NetworkAccessManager::createRequest( Operation op, const QNetworkRequest
request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
request.setRawHeader( "User-Agent", lastfm::UserAgent ); request.setRawHeader( "User-Agent", lastfm::UserAgent );
#ifdef WIN32 #ifdef WIN32
// PAC proxies can vary by domain, so we have to check everytime :( // PAC proxies can vary by domain, so we have to check everytime :(
QNetworkProxy proxy = this->proxy( request ); QNetworkProxy proxy = this->proxy( request );
@@ -152,7 +152,7 @@ void
lastfm::NetworkAccessManager::onConnectivityChanged( bool up ) lastfm::NetworkAccessManager::onConnectivityChanged( bool up )
{ {
Q_UNUSED( up ); Q_UNUSED( up );
#ifdef WIN32 #ifdef WIN32
if (up && m_pac) m_pac->resetFailedState(); if (up && m_pac) m_pac->resetFailedState();
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -23,12 +23,13 @@
#endif #endif
#include <objbase.h> #include <objbase.h>
#include <atlbase.h> //#include <boost/range/atl.hpp>
#include <atlcom.h> //#include <atlbase.h>
//#include <atlcom.h>
#include <winable.h>
/** @brief WsConnectionMonitor needs Com to work as early as possible so we do this /** @brief WsConnectionMonitor needs Com to work as early as possible so we do this
* @author <doug@last.fm> * @author <doug@last.fm>
*/ */
class ComSetup class ComSetup
{ {
@@ -37,27 +38,27 @@ public:
{ {
HRESULT hr = CoInitialize(0); HRESULT hr = CoInitialize(0);
m_bComInitialised = SUCCEEDED(hr); m_bComInitialised = SUCCEEDED(hr);
_ASSERT(m_bComInitialised); //_ASSERT(m_bComInitialised);
if (m_bComInitialised) { if (m_bComInitialised) {
setupSecurity(); setupSecurity();
} }
} }
void setupSecurity() void setupSecurity()
{ {
CSecurityDescriptor sd; //CSecurityDescriptor sd;
sd.InitializeFromThreadToken(); //sd.InitializeFromThreadToken();
HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); //HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
_ASSERT(SUCCEEDED(hr)); //_ASSERT(SUCCEEDED(hr));
} }
~ComSetup() ~ComSetup()
{ {
if (m_bComInitialised) { if (m_bComInitialised) {
CoUninitialize(); CoUninitialize();
} }
} }
private: private:
bool m_bComInitialised; bool m_bComInitialised;
}; };

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -26,6 +26,7 @@
*/ */
struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
{ {
#ifndef WIN32
IeSettings() IeSettings()
{ {
if (!WinHttpGetIEProxyConfigForCurrentUser(this)) { if (!WinHttpGetIEProxyConfigForCurrentUser(this)) {
@@ -33,7 +34,8 @@ struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0; lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0;
} }
} }
#endif
~IeSettings() ~IeSettings()
{ {
if (lpszAutoConfigUrl) GlobalFree(lpszAutoConfigUrl); if (lpszAutoConfigUrl) GlobalFree(lpszAutoConfigUrl);

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -32,35 +32,37 @@ NdisEvents::NdisEvents()
NdisEvents::~NdisEvents() NdisEvents::~NdisEvents()
{ {
#ifndef WIN32
if (m_pSink) if (m_pSink)
m_pSink->disconnect(); m_pSink->disconnect();
if (m_pServices && m_pSink) #endif
m_pServices->CancelAsyncCall(m_pSink); //if (m_pServices && m_pSink)
//m_pServices->CancelAsyncCall(m_pSink);
// and reference counting will take care of the WmiSink object // and reference counting will take care of the WmiSink object
} }
HRESULT HRESULT
NdisEvents::registerForNdisEvents() NdisEvents::registerForNdisEvents()
{ {
HRESULT hr = m_pLocator.CoCreateInstance(CLSID_WbemLocator); HRESULT hr = 0; //m_pLocator.CoCreateInstance(CLSID_WbemLocator);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
// Connect to the root\wmi namespace with the current user. // Connect to the root\wmi namespace with the current user.
hr = m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource hr = 0; /*m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource
NULL, // strUser NULL, // strUser
NULL, // strPassword NULL, // strPassword
NULL, // strLocale NULL, // strLocale
0, // lSecurityFlags 0, // lSecurityFlags
CComBSTR(""), // strAuthority CComBSTR(""), // strAuthority
NULL, // pCtx NULL, // pCtx
&m_pServices &m_pServices
); );*/
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
#ifndef WIN32
m_pSink = new WmiSink(this); m_pSink = new WmiSink(this);
#endif
////////////////////////// //////////////////////////
// other notifications we're not interested in right now include... // other notifications we're not interested in right now include...
@@ -75,12 +77,12 @@ NdisEvents::registerForNdisEvents()
// MSNdis_StatusProtocolUnbind // MSNdis_StatusProtocolUnbind
// MSNdis_StatusMediaSpecificIndication // MSNdis_StatusMediaSpecificIndication
CComBSTR wql("WQL"); /*CComBSTR wql("WQL");
CComBSTR query("SELECT * FROM MSNdis_StatusMediaDisconnect"); CComBSTR query("SELECT * FROM MSNdis_StatusMediaDisconnect");
hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink); hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);
query = "SELECT * FROM MSNdis_StatusMediaConnect"; query = "SELECT * FROM MSNdis_StatusMediaConnect";
hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink); hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);*/
return S_OK; return S_OK;
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -21,8 +21,8 @@
#define NDIS_EVENTS_H #define NDIS_EVENTS_H
#include <windows.h> #include <windows.h>
#include <atlbase.h> //#include <atlbase.h>
#include <WbemCli.h> //#include <WbemCli.h>
class NdisEvents class NdisEvents
{ {
@@ -35,8 +35,8 @@ public:
virtual void onConnectionDown(BSTR name) = 0; virtual void onConnectionDown(BSTR name) = 0;
private: private:
CComPtr<IWbemLocator> m_pLocator; //CComPtr<IWbemLocator> m_pLocator;
CComPtr<IWbemServices> m_pServices; //CComPtr<IWbemServices> m_pServices;
class WmiSink *m_pSink; class WmiSink *m_pSink;
}; };

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -21,8 +21,9 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QStringList> #include <QStringList>
#include <QUrl> #include <QUrl>
#include <atlbase.h> //#include <atlbase.h>
#include <atlconv.h> //#include <atlconv.h>
#include <winhttp.h>
static bool static bool
@@ -45,7 +46,7 @@ parsePacServer(const QString &s, QNetworkProxy &p)
static QList<QNetworkProxy> static QList<QNetworkProxy>
parsePacResult(const QString &pacResult) parsePacResult(const QString &pacResult)
{ {
// msdn says: "The proxy server list contains one or more of the // msdn says: "The proxy server list contains one or more of the
// following strings separated by semicolons or whitespace." // following strings separated by semicolons or whitespace."
// ([<scheme>=][<scheme>"://"]<server>[":"<port>]) // ([<scheme>=][<scheme>"://"]<server>[":"<port>])
@@ -73,8 +74,10 @@ lastfm::Pac::Pac()
lastfm::Pac::~Pac() lastfm::Pac::~Pac()
{ {
#ifndef WIN32
if (m_hSession) if (m_hSession)
WinHttpCloseHandle(m_hSession); WinHttpCloseHandle(m_hSession);
#endif
} }
QNetworkProxy QNetworkProxy
@@ -86,42 +89,45 @@ lastfm::Pac::resolve(const QNetworkRequest &request, const wchar_t* pacUrl)
if (!m_hSession) if (!m_hSession)
{ {
QByteArray user_agent = request.rawHeader("user-agent"); QByteArray user_agent = request.rawHeader("user-agent");
m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC); //m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC);
} }
if (m_hSession) if (m_hSession)
{ {
WINHTTP_PROXY_INFO info; WINHTTP_PROXY_INFO info;
WINHTTP_AUTOPROXY_OPTIONS opts; WINHTTP_AUTOPROXY_OPTIONS opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
if (pacUrl) if (pacUrl)
{ {
opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; //opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
opts.lpszAutoConfigUrl = pacUrl; //opts.lpszAutoConfigUrl = pacUrl;
} }
else else
{ {
opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; //opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; //opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
} }
opts.fAutoLogonIfChallenged = TRUE; opts.fAutoLogonIfChallenged = TRUE;
#ifndef WIN32
if (WinHttpGetProxyForUrl(m_hSession, request.url().toString().utf16(), &opts, &info)) { if (WinHttpGetProxyForUrl(m_hSession, (const WCHAR*)(request.url().toString().utf16()), &opts, &info)) {
if (info.lpszProxy) if (info.lpszProxy)
{ {
QList<QNetworkProxy> proxies = parsePacResult(QString::fromUtf16(info.lpszProxy)); QList<QNetworkProxy> proxies = parsePacResult(QString::fromUtf16((const ushort*)info.lpszProxy));
if (!proxies.empty()) if (!proxies.empty())
{ {
out = proxies.at(0); out = proxies.at(0);
} }
GlobalFree(info.lpszProxy); // pay attention! casting away constness
GlobalFree((void*)info.lpszProxy);
} }
if (info.lpszProxyBypass) if (info.lpszProxyBypass)
{ {
GlobalFree(info.lpszProxyBypass); // pay attention! casting away constness
GlobalFree((void*)info.lpszProxyBypass);
} }
} else { } else {
m_bFailed = true; m_bFailed = true;
} }
#endif
} }
return out; return out;

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -24,14 +24,14 @@
#include <windows.h> #include <windows.h>
#include <winhttp.h> #include <winhttp.h>
class QNetworkRequest; class QNetworkRequest;
namespace lastfm namespace lastfm
{ {
/** @brief simple wrapper to do per url automatic proxy detection /** @brief simple wrapper to do per url automatic proxy detection
* @author <doug@last.fm> * @author <doug@last.fm>
*/ */
class Pac class Pac
{ {
HINTERNET m_hSession; HINTERNET m_hSession;
bool m_bFailed; bool m_bFailed;
@@ -49,4 +49,4 @@ namespace lastfm
}; };
} }
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2009 Last.fm Ltd. Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell - Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm. This file is part of liblastfm.
@@ -20,7 +20,7 @@
#ifndef WMISINK_WIN_H #ifndef WMISINK_WIN_H
#define WMISINK_WIN_H #define WMISINK_WIN_H
#include "WbemCli.h" #include "wbemcli.h"
// Sink object for WMI NDIS notifications // Sink object for WMI NDIS notifications
class WmiSink : public IWbemObjectSink class WmiSink : public IWbemObjectSink

View File

@@ -25,9 +25,13 @@
#include <QDomElement> #include <QDomElement>
#include <QLocale> #include <QLocale>
#include <QStringList> #include <QStringList>
#include <QThread>
#include <QMutex>
#include <QUrl> #include <QUrl>
static QNetworkAccessManager* nam = 0;
static QMap< QThread*, QNetworkAccessManager* > threadNamHash;
static QMap< QThread*, bool > ourNamHash;
static QMutex namAccessMutex;
QString QString
lastfm::ws::host() lastfm::ws::host()
@@ -191,18 +195,34 @@ lastfm::ws::parse( QNetworkReply* reply ) throw( ParseError )
QNetworkAccessManager* QNetworkAccessManager*
lastfm::nam() lastfm::nam()
{ {
if (!::nam) ::nam = new NetworkAccessManager( qApp ); QMutexLocker l( &namAccessMutex );
return ::nam; QThread* thread = QThread::currentThread();
if ( !threadNamHash.contains( thread ) )
{
NetworkAccessManager* newNam = new NetworkAccessManager();
threadNamHash[thread] = newNam;
ourNamHash[thread] = true;
return newNam;
}
return threadNamHash[thread];
} }
void void
lastfm::setNetworkAccessManager( QNetworkAccessManager* nam ) lastfm::setNetworkAccessManager( QNetworkAccessManager* nam )
{ {
delete ::nam; if ( !nam )
::nam = nam; return;
nam->setParent( qApp ); // ensure it isn't deleted out from under us
QMutexLocker l( &namAccessMutex );
QThread* thread = QThread::currentThread();
if ( threadNamHash.contains( thread ) && ourNamHash.contains( thread ) && ourNamHash[thread] )
delete threadNamHash[thread];
threadNamHash[thread] = nam;
ourNamHash[thread] = false;
} }