Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of git://github.com/jonocole/lastfm-desktop

  • Loading branch information...
commit d94b9046db0034e4bbc2c0f2e3017ff68cdf94ea 2 parents 245d3e0 + 513755f
@RJ authored
View
7 .gitignore
@@ -0,0 +1,7 @@
+_build
+_files.qmake
+_version.h
+_build_parameters.pl.h
+Makefile*
+/_bin
+/_include
View
8 Last.fm.pro
@@ -4,14 +4,12 @@ SUBDIRS = lib/lastfm/core/libcore.pro \
lib/lastfm/ws/libws.pro \
lib/lastfm/types/libtypes.pro \
lib/lastfm/radio/libradio.pro \
- lib/lastfm/fingerprint/libfingerprint.pro \
lib/lastfm/scrobble/libscrobble.pro \
lib/unicorn/libunicorn.pro \
lib/listener/liblistener.pro \
- app/clientplugins/localresolver/libresolver.pro \
- app/client \
- app/twiddly \
- app/boffin
+ app/audioscrobbler \
+ app/radio \
+ app/twiddly
debug:win32 {
# make the client the default project in visual studio
View
129 app/audioscrobbler/Application.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "Application.h"
+#include "StopWatch.h"
+#include "lib/listener/legacy/LegacyPlayerListener.h"
+#include "lib/listener/PlayerListener.h"
+#include "lib/listener/PlayerMediator.h"
+#include <lastfm/Scrobbler>
+using audioscrobbler::Application;
+
+Application::Application(int& argc, char** argv) : unicorn::Application(argc, argv)
+{
+ tray = new QSystemTrayIcon(this);
+ connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(onTrayActivated(QSystemTrayIcon::ActivationReason)));
+ tray->show();
+
+ as = new Scrobbler("ass");
+
+ mediator = new PlayerMediator(this);
+ connect(mediator, SIGNAL(activeConnectionChanged( PlayerConnection* )), SLOT(setConnection( PlayerConnection* )) );
+ connect(new LegacyPlayerListener(mediator), SIGNAL(newConnection(PlayerConnection*)), mediator, SLOT(follow(PlayerConnection*)) );
+
+ try{
+ PlayerListener* listener = new PlayerListener(mediator);
+ connect(listener, SIGNAL(newConnection(PlayerConnection*)), mediator, SLOT(follow(PlayerConnection*)));
+ }
+ catch(std::runtime_error& e){
+ qWarning() << e.what();
+ //TODO user visible warning
+ }
+}
+
+void
+Application::onTrayActivated(QSystemTrayIcon::ActivationReason)
+{}
+
+void
+Application::setConnection(PlayerConnection*c)
+{
+ if(connection){
+ disconnect(connection, 0, this, 0);
+ if(watch)
+ connection->setElapsed(watch->elapsed());
+ }
+ connect(c, SIGNAL(trackStarted(Track, Track)), SLOT(onTrackStarted(Track, Track)));
+ connect(c, SIGNAL(paused()), SLOT(onTrackPaused()));
+ connect(c, SIGNAL(resumed()), SLOT(onTrackResumed()));
+ connect(c, SIGNAL(resumed()), SLOT(onTrackStopped()));
+ connection = c;
+
+ if(c->state() == Playing)
+ onTrackStarted(c->track(), Track());
+}
+
+void
+Application::onTrackStarted(const Track& t, const Track& oldtrack)
+{
+ Q_ASSERT(connection);
+
+ //TODO move to playerconnection
+ if(t == oldtrack){
+ qWarning() << "Trying to start the same track as last time, assuming programmer error and doing nothing";
+ return;
+ }
+ if(t.isNull()){
+ qWarning() << "Can't start null track!";
+ return;
+ }
+
+ delete watch;
+ as->submit();
+ as->nowPlaying(t);
+
+ ScrobblePoint timeout(t.duration()/2);
+ watch = new StopWatch(timeout, connection->elapsed());
+ connect(watch, SIGNAL(timeout()), SLOT(onStopWatchTimedOut()));
+}
+
+void
+Application::onStopWatchTimedOut()
+{
+ Q_ASSERT(connection);
+ as->cache(connection->track());
+}
+
+void
+Application::onPaused()
+{
+ Q_ASSERT(connection);
+ Q_ASSERT(watch);
+ if(watch)watch->pause();
+}
+
+void
+Application::onResumed()
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(connection);
+ Q_ASSERT(connection->state() == Paused);
+
+ if(watch)watch->resume();
+}
+
+void
+Application::onStopped()
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(connection);
+
+ delete watch;
+ as->submit();
+}
View
55 app/audioscrobbler/Application.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include <lastfm/global.h>
+#include "lib/unicorn/UnicornApplication.h"
+#include <QPointer>
+#include <QSystemTrayIcon>
+class Scrobbler;
+class PlayerMediator;
+class PlayerConnection;
+class StopWatch;
+
+
+namespace audioscrobbler
+{
+ class Application : public unicorn::Application
+ {
+ Q_OBJECT
+
+ QPointer<QSystemTrayIcon> tray;
+ QPointer<Scrobbler> as;
+ QPointer<PlayerMediator> mediator;
+ QPointer<PlayerConnection> connection;
+ QPointer<StopWatch> watch;
+
+ public:
+ Application(int& argc, char** argv);
+
+ private slots:
+ void onTrayActivated(QSystemTrayIcon::ActivationReason);
+ void onStopWatchTimedOut();
+ void setConnection(PlayerConnection*);
+
+ void onTrackStarted(const Track&, const Track&);
+ void onPaused();
+ void onResumed();
+ void onStopped();
+ };
+}
View
6 app/client/StopWatch.cpp → app/audioscrobbler/StopWatch.cpp
@@ -30,6 +30,12 @@ StopWatch::StopWatch( ScrobblePoint timeout, uint elapsed ) : m_point( timeout )
connect( m_timer, SIGNAL(timeout()), SLOT(finished()) );
}
+StopWatch::~StopWatch()
+{
+ if (!isTimedOut() && (m_point*1000) - elapsed() < 4000)
+ emit timeout();
+}
+
void
StopWatch::start() //private
View
6 app/client/StopWatch.h → app/audioscrobbler/StopWatch.h
@@ -24,7 +24,7 @@
#include <QDateTime>
#include <QObject>
#include <QTimer>
-
+namespace audioscrobbler { class Application; }
namespace mxcl
{
@@ -54,7 +54,7 @@ class StopWatch : public QObject
Q_OBJECT
Q_DISABLE_COPY( StopWatch )
- friend class StateMachine; //for access to timeout() signal
+ friend class audioscrobbler::Application; //for access to timeout() signal
friend class TestStopWatch; //for testing, duh!
public:
@@ -62,6 +62,7 @@ class StopWatch : public QObject
* The watch will not timeout() if elapsed is greater that the
* scrobble point */
StopWatch( ScrobblePoint timeout_in_seconds, uint elapsed_in_ms = 0 );
+ ~StopWatch();
bool isTimedOut() const { return m_remaining == 0 && !m_timer->isActive(); }
@@ -69,7 +70,6 @@ class StopWatch : public QObject
void resume();
/** in milliseconds */
- uint remaining() const { return m_remaining; }
uint elapsed() const { return ((m_point*1000 - m_remaining) + m_elapsed.elapsed()); }
ScrobblePoint scrobblePoint() const { return m_point; }
View
9 app/audioscrobbler/audioscrobbler.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+TARGET = audioscrobbler
+CONFIG += unicorn scrobble listener
+VERSION = 2.0.0
+
+include( $$ROOT_DIR/admin/include.qmake )
+include( _files.qmake )
+
+DEFINES += LASTFM_COLLAPSE_NAMESPACE
View
51 app/audioscrobbler/main.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "_version.h"
+#include "lib/unicorn/UniqueApplication.h"
+#include "Application.h"
+
+
+int main( int argc, char** argv )
+{
+ QCoreApplication::setApplicationName( "Audioscrobbler" );
+ QCoreApplication::setApplicationVersion( VERSION );
+
+#ifdef NDEBUG
+ UniqueApplication uapp( moose::id() );
+ if (uapp.isAlreadyRunning())
+ return uapp.forward( argc, argv ) ? 0 : 1;
+ uapp.init1();
+#endif
+
+ try
+ {
+ audioscrobbler::Application app( argc, argv );
+ #ifdef NDEBUG
+ uapp.init2( &app );
+ app.connect( &uapp, SIGNAL(arguments( QStringList )), SLOT(parseArguments( QStringList )) );
+ #endif
+ return app.exec();
+ }
+ catch (unicorn::Application::StubbornUserException&)
+ {
+ // user wouldn't log in
+ return 0;
+ }
+}
View
127 app/radio/Application.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 "Application.h"
+#include "lib/unicorn/QMessageBoxBuilder.h"
+#include <lastfm/WsError>
+#include "Radio.h"
+using moralistfad::Application;
+
+
+Application::Application( int& argc, char** argv ) : unicorn::Application( argc, argv )
+{}
+
+void
+Application::onWsError( Ws::Error e )
+{
+ switch (e)
+ {
+ case Ws::OperationFailed:
+ //TODOCOPY
+ //TODO use the non intrusive status messages
+ QMessageBoxBuilder( 0 ) //TODO window pointer
+ .setTitle( "Oops" )
+ .setText( "Last.fm is b0rked" )
+ .exec();
+ break;
+
+ case Ws::InvalidSessionKey:
+ logout();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+Application::onRadioError( int code, const QVariant& data )
+{
+ switch (code)
+ {
+ case Ws::NotEnoughContent:
+ emit error( tr("Sorry, there is no more content available for this radio station.") );
+ break;
+
+ case Ws::MalformedResponse:
+ case Ws::TryAgainLater:
+ emit error( tr("Sorry, there was a radio error at Last.fm. Please try again later.") );
+ break;
+
+ case Ws::SubscribersOnly:
+ emit error( tr("Sorry, this station is only available to Last.fm subscribers. "
+ "<A href='http://www.last.fm/subscribe'>Sign up</a>.") );
+ break;
+
+ case Ws::UnknownError:
+ // string contains Phonon generated user readable error message
+ emit error( data.toString() );
+ break;
+
+ default:
+ emit error( tr("Sorry, an unexpected error occurred.") );
+ break;
+ }
+}
+
+enum Argument
+{
+ LastFmUrl,
+ Pause, //toggles pause
+ Skip,
+ Unknown
+};
+
+Argument argument( const QString& arg )
+{
+ if (arg == "--pause") return Pause;
+ if (arg == "--skip") return Skip;
+
+ QUrl url( arg );
+ //TODO show error if invalid schema and that
+ if (url.isValid() && url.scheme() == "lastfm") return LastFmUrl;
+
+ return Unknown;
+}
+
+void
+Application::parseArguments( const QStringList& args )
+{
+ qDebug() << args;
+
+ if (args.size() == 1)
+ return;
+
+ foreach (QString const arg, args.mid( 1 ))
+ switch (argument( arg ))
+ {
+ case LastFmUrl:
+ radio->play( RadioStation( QUrl( arg ) ) );
+ break;
+
+ case Skip:
+ case Pause:
+ qDebug() << "Unimplemented:" << arg;
+ break;
+
+ case Unknown:
+ qDebug() << "Unknown argument:" << arg;
+ break;
+ }
+}
View
47 app/radio/Application.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "lib/unicorn/UnicornApplication.h"
+#include "lib/lastfm/ws/WsError.h"
+
+
+namespace moralistfad
+{
+ class Application : public unicorn::Application
+ {
+ Q_OBJECT
+
+ public:
+ Application( int&, char** );
+
+ signals:
+ /** something should show it. Currently MainWindow does */
+ void error( const QString& message );
+ void status( const QString& message, const QString& id );
+
+ public slots:
+ void parseArguments( const QStringList& args );
+
+ private slots:
+ /** all webservices connect to this and emit in the case of bad errors that
+ * need to be handled at a higher level */
+ void onWsError( Ws::Error );
+ void onRadioError( int, const class QVariant& );
+ };
+}
View
0  lib/lastfm/radio/LegacyTuner.cpp → app/radio/LegacyTuner.cpp
File renamed without changes
View
14 lib/lastfm/radio/LegacyTuner.h → app/radio/LegacyTuner.h
@@ -20,12 +20,13 @@
#ifndef LEGACY_TUNER_H
#define LEGACY_TUNER_H
-#include "lib/lastfm/global.h"
-#include "AbstractTrackSource.h"
+#include <lastfm/Track>
#include "RadioStation.h"
+/** certain stuff can only be played with the legacy tuner */
-class LASTFM_RADIO_DLLEXPORT LegacyTuner : public AbstractTrackSource
+
+class LASTFM_RADIO_DLLEXPORT LegacyTuner
{
Q_OBJECT
@@ -34,7 +35,12 @@ class LASTFM_RADIO_DLLEXPORT LegacyTuner : public AbstractTrackSource
* automatically fetches the first 5 tracks for the station */
LegacyTuner( const RadioStation&, const QString& password_md5 );
- virtual lastfm::Track takeNextTrack();
+ Track takeNextTrack();
+
+signals:
+ void title( const QString& );
+ void trackAvailable();
+ void error( Ws::Error );
private slots:
void onHandshakeReturn();
View
27 lib/lastfm/radio/Radio.cpp → app/radio/Radio.cpp
@@ -18,7 +18,7 @@
***************************************************************************/
#include "Radio.h"
-#include "AbstractTrackSource.h"
+#include <lastfm/Tuner>
#include <phonon/mediaobject.h>
#include <phonon/audiooutput.h>
#include <QThread>
@@ -30,8 +30,7 @@ using lastfm::MutableTrack;
Radio::Radio( Phonon::AudioOutput* output )
- : m_trackSource( 0 ),
- m_audioOutput( output ),
+ : m_audioOutput( output ),
m_mediaObject( 0 ),
m_state( Radio::Stopped ),
m_bErrorRecover( false )
@@ -71,7 +70,7 @@ Radio::~Radio()
void
-Radio::play( const RadioStation& station, AbstractTrackSource* trackSource )
+Radio::play( const RadioStation& station )
{
if (m_state != Stopped)
{
@@ -84,12 +83,12 @@ Radio::play( const RadioStation& station, AbstractTrackSource* trackSource )
}
m_station = station;
- delete m_trackSource;
- m_trackSource = trackSource;
+ delete m_tuner;
+ m_tuner = new Tuner(station);
- connect( m_trackSource, SIGNAL(title( QString )), SLOT(setStationNameIfCurrentlyBlank( QString )) );
- connect( m_trackSource, SIGNAL(trackAvailable()), SLOT(enqueue()) );
- connect( m_trackSource, SIGNAL(error( Ws::Error )), SLOT(onTunerError( Ws::Error )) );
+ connect( m_tuner, SIGNAL(title( QString )), SLOT(setStationNameIfCurrentlyBlank( QString )) );
+ connect( m_tuner, SIGNAL(trackAvailable()), SLOT(enqueue()) );
+ connect( m_tuner, SIGNAL(error( Ws::Error )), SLOT(onTunerError( Ws::Error )) );
changeState( TuningIn );
}
@@ -155,8 +154,7 @@ Radio::onTunerError( Ws::Error e )
void
Radio::stop()
{
- delete m_trackSource;
- m_trackSource = 0;
+ delete m_tuner;
m_mediaObject->blockSignals( true ); //prevent the error state due to setting current source to null
m_mediaObject->stop();
@@ -175,8 +173,7 @@ Radio::clear()
{
m_track = Track();
m_station = RadioStation();
- delete m_trackSource;
- m_trackSource = 0;
+ delete m_tuner;
}
@@ -230,7 +227,7 @@ Radio::onPhononStateChanged( Phonon::State newstate, Phonon::State oldstate )
void
Radio::phononEnqueue()
{
- if (m_mediaObject->queue().size() || !m_trackSource) return;
+ if (m_mediaObject->queue().size() || !m_tuner) return;
// keep only one track in the phononQueue
// Loop until we get a null url or a valid url.
@@ -238,7 +235,7 @@ Radio::phononEnqueue()
{
// consume next track from the track source. a null track
// response means wait until the trackAvailable signal
- Track t = m_trackSource->takeNextTrack();
+ Track t = m_tuner->takeNextTrack();
if (t.isNull()) break;
// Invalid urls won't trigger the correct phonon
View
20 lib/lastfm/radio/Radio.h → app/radio/Radio.h
@@ -17,16 +17,15 @@
* 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#ifndef LASTFM_RADIO_H
-#define LASTFM_RADIO_H
-
#include <lastfm/Track>
#include <lastfm/RadioStation>
#include <lastfm/WsError>
#include <phonon/phononnamespace.h>
#include <QList>
+#include <QPointer>
#include <QThread>
#include <QVariant>
+class Tuner;
namespace Phonon
{
@@ -38,7 +37,7 @@ namespace Phonon
/** @author <max@last.fm>
*/
-class LASTFM_RADIO_DLLEXPORT Radio : public QObject
+class Radio : public QObject
{
Q_OBJECT
@@ -59,7 +58,7 @@ class LASTFM_RADIO_DLLEXPORT Radio : public QObject
Phonon::AudioOutput* audioOutput() const { return m_audioOutput; }
public slots:
- void play( const RadioStation& station, class AbstractTrackSource* );
+ void play( const RadioStation& station );
void skip();
void stop();
@@ -67,13 +66,8 @@ public slots:
/** emitted up to twice, as first time may not have a title for the station
* but the second time will */
void tuningIn( const RadioStation& );
-#ifndef LASTFM_COLLAPSE_NAMESPACE
- void trackSpooled( const lastfm::Track& ); /** and we're now prebuffering */
- void trackStarted( const lastfm::Track& );
-#else
void trackSpooled( const Track& );
void trackStarted( const Track& );
-#endif
void buffering( int );
void stopped();
@@ -100,11 +94,11 @@ private slots:
/** emits signals if appropriate */
void changeState( State );
- class AbstractTrackSource* m_trackSource;
+ QPointer<Tuner> m_tuner;
Phonon::AudioOutput* m_audioOutput;
Phonon::MediaObject* m_mediaObject;
Radio::State m_state;
- lastfm::Track m_track;
+ Track m_track;
RadioStation m_station;
bool m_bErrorRecover;
};
@@ -135,4 +129,4 @@ inline QDebug operator<<( QDebug d, Phonon::State s )
Q_DECLARE_METATYPE( Radio::State );
-#endif //RADIO_H
+extern Radio* radio;
View
175 app/radio/main.cpp
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifdef __APPLE__
+ // first to prevent compilation errors with Qt 4.5.0
+ //TODO shorten this mother fucker
+ //NOTE including Carbon/Carbon.h breaks things as it has sooo many symbols
+ // in the global namespace
+ #include </System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers/AppleEvents.h>
+ static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long );
+#endif
+
+#include "_version.h"
+#include "Application.h"
+#include "Radio.h"
+#include "lib/lastfm/core/CoreSettings.h"
+#include "lib/unicorn/UniqueApplication.h"
+#include "lib/unicorn/UnicornApplication.h"
+#include "lib/unicorn/UnicornMainWindow.h"
+#include <lastfm/RadioStation>
+#include <QLineEdit>
+void setupRadio();
+void setupMainWindow( QMainWindow& );
+void cleanup();
+
+class QMainObject : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void onReturnPressed()
+ {
+ QUrl url = static_cast<QLineEdit*>(sender())->text();
+ radio->play( RadioStation(url) );
+ }
+};
+
+Radio* radio;
+QMainObject* q;
+
+
+int main( int argc, char** argv )
+{
+ QCoreApplication::setApplicationName( "Moralist Fad" );
+ QCoreApplication::setApplicationVersion( VERSION );
+ QCoreApplication::setOrganizationName( CoreSettings::organizationName() );
+ QCoreApplication::setOrganizationDomain( CoreSettings::organizationDomain() );
+
+ // ATTENTION! Under no circumstance change these strings! --mxcl
+#ifdef WIN32
+ Ws::UserAgent = "Last.fm Client " VERSION " (Windows)";
+#elif __APPLE__
+ Ws::UserAgent = "Last.fm Client " VERSION " (OS X)";
+#elif defined (Q_WS_X11)
+ Ws::UserAgent = "Last.fm Client " VERSION " (X11)";
+#endif
+
+#ifdef NDEBUG
+ UniqueApplication uapp( moose::id() );
+ if (uapp.isAlreadyRunning())
+ return uapp.forward( argc, argv ) ? 0 : 1;
+ uapp.init1();
+#endif
+
+ try
+ {
+ moralistfad::Application app( argc, argv );
+ q = new QMainObject;
+ #ifdef NDEBUG
+ uapp.init2( &app );
+ q->connect( &uapp, SIGNAL(arguments( QStringList )), SLOT(parseArguments( QStringList )) );
+ #endif
+
+ setupRadio();
+ qAddPostRoutine(cleanup);
+ app.connect( radio, SIGNAL(error(int, QVariant)), SLOT(onRadioError(int, QVariant)) );
+
+ #ifdef Q_WS_MAC
+ AEEventHandlerUPP h = NewAEEventHandlerUPP( appleEventHandler );
+ AEInstallEventHandler( 'GURL', 'GURL', h, 0, false );
+ #endif
+
+ unicorn::MainWindow window;
+ setupMainWindow( window );
+ window.finishUi();
+ window.show();
+
+ app.parseArguments( app.arguments() );
+ return app.exec();
+ }
+ catch (unicorn::Application::StubbornUserException&)
+ {
+ // user wouldn't log in
+ return 0;
+ }
+}
+
+#ifdef Q_WS_MAC
+static pascal OSErr appleEventHandler( const AppleEvent* e, AppleEvent*, long )
+{
+ OSType id = typeWildCard;
+ AEGetAttributePtr( e, keyEventIDAttr, typeType, 0, &id, sizeof(id), 0 );
+
+ switch (id)
+ {
+ case 'GURL':
+ {
+ DescType type;
+ Size size;
+
+ char buf[1024];
+ AEGetParamPtr( e, keyDirectObject, typeChar, &type, &buf, 1023, &size );
+ buf[size] = '\0';
+
+ QUrl const url = QString::fromUtf8( buf );
+ radio->play( RadioStation(url) );
+ return noErr;
+ }
+
+ default:
+ return unimpErr;
+ }
+}
+#endif
+
+void setupMainWindow( QMainWindow& window )
+{
+ QLineEdit* edit = new QLineEdit;
+ window.setCentralWidget( edit );
+ q->connect( edit, SIGNAL(returnPressed()), SLOT(onReturnPressed()) );
+}
+
+#include <phonon/audiooutput.h>
+#include <phonon/backendcapabilities.h>
+
+void setupRadio()
+{
+ Phonon::AudioOutput* audioOutput = new Phonon::AudioOutput( Phonon::MusicCategory, qApp );
+ audioOutput->setVolume( QSettings().value( "Volume", 80 ).toUInt() );
+
+ QString audioOutputDeviceName = "";//TODO moose::Settings().audioOutputDeviceName();
+ if (audioOutputDeviceName.size())
+ {
+ foreach (Phonon::AudioOutputDevice d, Phonon::BackendCapabilities::availableAudioOutputDevices())
+ if (d.name() == audioOutputDeviceName) {
+ audioOutput->setOutputDevice( d );
+ break;
+ }
+ }
+
+ radio = new Radio( audioOutput );
+}
+
+void cleanup()
+{
+ QSettings().value( "Volume", radio->audioOutput()->volume() );
+}
+
+#include "main.moc"
View
12 app/radio/radio.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+TARGET = moralistfad
+CONFIG += unicorn radio
+VERSION = 2.0.0
+
+include( $$ROOT_DIR/admin/include.qmake )
+include( _files.qmake )
+
+DEFINES += LASTFM_COLLAPSE_NAMESPACE
+
+SOURCES -= LegacyTuner.cpp
+HEADERS -= LegacyTuner.h
View
5 lib/unicorn/UnicornApplication.cpp
@@ -23,6 +23,7 @@
#include <ApplicationServices/ApplicationServices.h>
static pascal OSErr appleEventHandler( const AppleEvent*, AppleEvent*, long );
#include <QMainWindow>
+ extern void qt_mac_set_menubar_icons( bool );
#endif
#include "UnicornApplication.h"
@@ -43,6 +44,10 @@ unicorn::Application::Application( int& argc, char** argv ) throw( StubbornUserE
: QApplication( argc, argv ),
m_logoutAtQuit( false )
{
+#ifdef Q_WS_MAC
+ qt_mac_set_menubar_icons( false );
+#endif
+
CoreApplication::init();
#ifdef __APPLE__
View
8 lib/unicorn/UnicornMainWindow.h
@@ -61,6 +61,9 @@ namespace unicorn
MainWindow();
~MainWindow();
+ /** call this to add the account menu and about menu action, etc. */
+ void finishUi();
+
public slots:
void about();
void checkForUpdates();
@@ -68,8 +71,6 @@ namespace unicorn
void openLog();
protected:
-
-
struct Ui {
Ui() : account( 0 ), profile( 0 )
{}
@@ -81,9 +82,6 @@ namespace unicorn
} ui;
- /** call this to add the account menu and about menu action, etc. */
- void finishUi();
-
private slots:
void onUserGotInfo( WsReply* );
};
View
2  lib/unicorn/widgets/LoginDialog.cpp
@@ -98,7 +98,7 @@ LoginDialog::authenticate()
WsReply* reply = WsRequestBuilder( "auth.getMobileSession" )
.add( "username", m_username )
// always lowercase the username before generating the md5
- .add( "authToken", Qt::md5( (m_username + m_password).toLower().toUtf8() ) )
+ .add( "authToken", Qt::md5( (m_username + m_password).toUtf8() ) )
.get();
reply->setParent( this );
Please sign in to comment.
Something went wrong with that request. Please try again.