File indexing completed on 2024-06-02 04:51:23

0001 /****************************************************************************************
0002  * Copyright (c) 2009 Oleksandr Khayrullin <saniokh@gmail.com>                          *
0003  * Copyright (c) 2009 Nathan Sala <sala.nathan@gmail.com>                               *
0004  * Copyright (c) 2009-2010 Ludovic Deveaux <deveaux.ludovic31@gmail.com>                *
0005  * Copyright (c) 2010 Hormiere Guillaume <hormiere.guillaume@gmail.com>                 *
0006  *                                                                                      *
0007  * This program is free software; you can redistribute it and/or modify it under        *
0008  * the terms of the GNU General Public License as published by the Free Software        *
0009  * Foundation; either version 2 of the License, or (at your option) any later           *
0010  * version.                                                                             *
0011  *                                                                                      *
0012  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0013  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0014  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0015  *                                                                                      *
0016  * You should have received a copy of the GNU General Public License along with         *
0017  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0018  ****************************************************************************************/
0019 
0020 #define DEBUG_PREFIX "UpcomingEventsEngine"
0021 
0022 #include "UpcomingEventsEngine.h"
0023 
0024 #include "context/ContextView.h"
0025 #include "context/applets/upcomingevents/LastFmEventXmlParser.h"
0026 #include "core/meta/Meta.h"
0027 #include "core/support/Amarok.h"
0028 #include "core/support/Debug.h"
0029 #include "EngineController.h"
0030 
0031 #include <KDateTime>
0032 
0033 #include <QXmlStreamReader>
0034 
0035 AMAROK_EXPORT_DATAENGINE( upcomingEvents, UpcomingEventsEngine )
0036 
0037 using namespace Context;
0038 
0039 UpcomingEventsEngine::UpcomingEventsEngine( QObject* parent, const QList<QVariant>& /*args*/ )
0040         : DataEngine( parent )
0041 {
0042     m_timeSpan = Amarok::config("UpcomingEvents Applet").readEntry( "timeSpan", "AllEvents" );
0043 
0044     EngineController *engine = The::engineController();
0045 
0046     connect( engine, SIGNAL(trackChanged(Meta::TrackPtr)),
0047              this, SLOT(updateDataForArtist()) );
0048     connect( engine, SIGNAL(trackMetadataChanged(Meta::TrackPtr)),
0049              this, SLOT(updateDataForArtist()) );
0050 }
0051 
0052 UpcomingEventsEngine::~UpcomingEventsEngine()
0053 {
0054 }
0055 
0056 bool
0057 UpcomingEventsEngine::sourceRequestEvent( const QString &source )
0058 {
0059     if( source == "artistevents" )
0060     {
0061         updateDataForArtist();
0062         return false; // data is not ready yet, but will be soon
0063     }
0064     else if( source == "venueevents" )
0065     {
0066         m_venueIds.clear();
0067         QStringList venues = Amarok::config("UpcomingEvents Applet").readEntry( "favVenues", QStringList() );
0068         foreach( const QString &venue, venues )
0069         {
0070             QStringList frag = venue.split( QChar(';') );
0071             m_venueIds << frag.at( 0 ).toInt();
0072         }
0073         updateDataForVenues();
0074         return true;
0075     }
0076     else if( source == "venueevents:update" )
0077     {
0078         removeAllData( source );
0079         sourceRequestEvent( "venueevents" );
0080     }
0081     else if( source == "timespan:update" )
0082     {
0083         // user has changed the timespan.
0084         m_timeSpan = Amarok::config("UpcomingEvents Applet").readEntry( "timeSpan", "AllEvents" );
0085         sourceRequestEvent( "venueevents:update" );
0086         updateDataForArtist();
0087         return true;
0088     }
0089     return false;
0090 }
0091 
0092 void
0093 UpcomingEventsEngine::updateDataForVenues()
0094 {
0095     if( !m_venueIds.isEmpty() )
0096     {
0097         int id = m_venueIds.takeFirst();
0098         QUrl url;
0099         url.setScheme( "http" );
0100         url.setHost( "ws.audioscrobbler.com" );
0101         url.setPath( "/2.0/" );
0102         url.addQueryItem( "method", "venue.getEvents" );
0103         url.addQueryItem( "api_key", Amarok::lastfmApiKey() );
0104         url.addQueryItem( "venue", QString::number( id ) );
0105         The::networkAccessManager()->getData( url, this,
0106              SLOT(venueEventsFetched(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) );
0107         QTimer::singleShot( 50, this, SLOT(updateDataForVenues()) );
0108     }
0109 }
0110 
0111 void
0112 UpcomingEventsEngine::updateDataForArtist()
0113 {
0114     Meta::TrackPtr track = The::engineController()->currentTrack();
0115     if( !track )
0116         return;
0117 
0118     Meta::ArtistPtr artist = track->artist();
0119     if( !artist || artist == m_currentArtist || artist->name().isEmpty() )
0120         return;
0121 
0122     m_currentArtist = artist;
0123 
0124     // Prepares the url for LastFm request
0125     m_urls.clear();
0126     QUrl url;
0127     url.setScheme( "http" );
0128     url.setHost( "ws.audioscrobbler.com" );
0129     url.setPath( "/2.0/" );
0130     url.addQueryItem( "method", "artist.getEvents" );
0131     url.addQueryItem( "api_key", Amarok::lastfmApiKey() );
0132     url.addQueryItem( "artist", m_currentArtist->name() );
0133     m_urls << url;
0134     The::networkAccessManager()->getData( url, this,
0135          SLOT(artistEventsFetched(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) );
0136 }
0137 
0138 void
0139 UpcomingEventsEngine::artistEventsFetched( const QUrl &url, const QByteArray &data,
0140                                            NetworkAccessManagerProxy::Error e )
0141 {
0142     if( !m_urls.contains( url ) )
0143         return;
0144 
0145     m_urls.remove( url );
0146     if( e.code != QNetworkReply::NoError )
0147     {
0148         debug() << "Error received getting upcoming artist events" << e.description;
0149         return;
0150     }
0151 
0152     QXmlStreamReader xml( data );
0153     LastFmEventXmlParser eventsParser( xml );
0154     removeAllData( "artistevents" );
0155     Plasma::DataEngine::Data engineData;
0156     if( eventsParser.read() )
0157     {
0158         LastFmEvent::List artistEvents = filterEvents( eventsParser.events() );
0159         engineData[ "artist" ] = m_currentArtist->name();
0160         engineData[ "events" ] = QVariant::fromValue( artistEvents );
0161     }
0162     setData( "artistevents", engineData );
0163 }
0164 
0165 void
0166 UpcomingEventsEngine::venueEventsFetched( const QUrl &url, const QByteArray data&,
0167                                           NetworkAccessManagerProxy::Error e )
0168 {
0169     Q_UNUSED( url )
0170     if( e.code != QNetworkReply::NoError )
0171     {
0172         debug() << "Error received getting upcoming venue events" << e.description;
0173         return;
0174     }
0175 
0176     QXmlStreamReader xml( data );
0177     LastFmEventXmlParser eventsParser( xml );
0178     Plasma::DataEngine::Data engineData;
0179     if( eventsParser.read() )
0180     {
0181         LastFmEvent::List venueEvents = filterEvents( eventsParser.events() );
0182         if( !venueEvents.isEmpty() )
0183         {
0184             engineData[ "venue"  ] = QVariant::fromValue( venueEvents.first()->venue() );
0185             engineData[ "events" ] = QVariant::fromValue( venueEvents );
0186         }
0187     }
0188     setData( "venueevents", engineData );
0189 }
0190 
0191 LastFmEvent::List
0192 UpcomingEventsEngine::filterEvents( const LastFmEvent::List &events ) const
0193 {
0194     KDateTime currentTime( KDateTime::currentLocalDateTime() );
0195 
0196     if( m_timeSpan == "ThisWeek")
0197         currentTime = currentTime.addDays( 7 );
0198     else if( m_timeSpan == "ThisMonth" )
0199         currentTime = currentTime.addMonths( 1 );
0200     else if( m_timeSpan == "ThisYear" )
0201         currentTime = currentTime.addYears( 1 );
0202     else
0203         return events; // no filtering is done
0204 
0205     LastFmEvent::List newEvents;
0206     foreach( const LastFmEventPtr &event, events )
0207     {
0208         if( event->date() < currentTime )
0209             newEvents << event;
0210     }
0211     return newEvents;
0212 }
0213 
0214 #include "UpcomingEventsEngine.moc"