/src/tomahawkapp.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 808 lines · 619 code · 144 blank · 45 comment · 63 complexity · 05bd4019927211da160327fb64dcf0bc MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
  5. * Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  6. *
  7. * Tomahawk is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Tomahawk is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "TomahawkApp.h"
  21. #include "TomahawkVersion.h"
  22. #include "AclRegistryImpl.h"
  23. #include "Album.h"
  24. #include "Artist.h"
  25. #include "Collection.h"
  26. #include "infosystem/InfoSystem.h"
  27. #include "accounts/AccountManager.h"
  28. #include "accounts/spotify/SpotifyAccount.h"
  29. #include "accounts/lastfm/LastFmAccount.h"
  30. #include "database/Database.h"
  31. #include "database/DatabaseCollection.h"
  32. #include "database/DatabaseCommand_CollectionStats.h"
  33. #include "database/DatabaseResolver.h"
  34. #include "playlist/dynamic/GeneratorFactory.h"
  35. #include "playlist/dynamic/echonest/EchonestGenerator.h"
  36. #include "playlist/dynamic/database/DatabaseGenerator.h"
  37. #include "playlist/XspfUpdater.h"
  38. #include "network/Servent.h"
  39. #include "web/Api_v1.h"
  40. #include "SourceList.h"
  41. #include "ShortcutHandler.h"
  42. #include "libtomahawk/filemetadata/ScanManager.h"
  43. #include "TomahawkSettings.h"
  44. #include "GlobalActionManager.h"
  45. #include "database/LocalCollection.h"
  46. #include "Pipeline.h"
  47. #include "DropJob.h"
  48. #include "EchonestCatalogSynchronizer.h"
  49. #include "audio/AudioEngine.h"
  50. #include "utils/XspfLoader.h"
  51. #include "utils/JspfLoader.h"
  52. #include "utils/Logger.h"
  53. #include "utils/TomahawkUtilsGui.h"
  54. #include "accounts/lastfm/LastFmAccount.h"
  55. #include "accounts/spotify/SpotifyAccount.h"
  56. #include "accounts/spotify/SpotifyPlaylistUpdater.h"
  57. #include "utils/TomahawkCache.h"
  58. #ifndef ENABLE_HEADLESS
  59. #include "resolvers/QtScriptResolver.h"
  60. #include "resolvers/ScriptResolver.h"
  61. #include "utils/SpotifyParser.h"
  62. #include "AtticaManager.h"
  63. #include "TomahawkWindow.h"
  64. #include "SettingsDialog.h"
  65. #include "ActionCollection.h"
  66. #include "widgets/HeaderLabel.h"
  67. #include "TomahawkSettingsGui.h"
  68. #endif
  69. #include "config.h"
  70. #ifndef ENABLE_HEADLESS
  71. #include <QMessageBox>
  72. #endif
  73. #ifdef Q_WS_MAC
  74. #include "mac/MacShortcutHandler.h"
  75. #include <sys/resource.h>
  76. #include <sys/sysctl.h>
  77. #endif
  78. #include <QPluginLoader>
  79. #include <QDir>
  80. #include <QMetaType>
  81. #include <QTime>
  82. #include <QNetworkReply>
  83. #include <QFile>
  84. #include <QFileInfo>
  85. #include <QTranslator>
  86. #include <iostream>
  87. const char* enApiSecret = "BNvTzfthHr/d1eNhHLvL1Jo=";
  88. void
  89. increaseMaxFileDescriptors()
  90. {
  91. #ifdef Q_WS_MAC
  92. /// Following code taken from Clementine project, main.cpp. Thanks!
  93. // Bump the soft limit for the number of file descriptors from the default of 256 to
  94. // the maximum (usually 1024).
  95. struct rlimit limit;
  96. getrlimit( RLIMIT_NOFILE, &limit );
  97. // getrlimit() lies about the hard limit so we have to check sysctl.
  98. int max_fd = 0;
  99. size_t len = sizeof( max_fd );
  100. sysctlbyname( "kern.maxfilesperproc", &max_fd, &len, NULL, 0 );
  101. limit.rlim_cur = max_fd;
  102. int ret = setrlimit( RLIMIT_NOFILE, &limit );
  103. if ( ret == 0 )
  104. qDebug() << "Max fd:" << max_fd;
  105. #endif
  106. }
  107. using namespace Tomahawk;
  108. TomahawkApp::TomahawkApp( int& argc, char *argv[] )
  109. : TOMAHAWK_APPLICATION( argc, argv )
  110. #ifndef ENABLE_HEADLESS
  111. , m_mainwindow( 0 )
  112. #endif
  113. , m_headless( false )
  114. , m_loaded( false )
  115. {
  116. setOrganizationName( QLatin1String( TOMAHAWK_ORGANIZATION_NAME ) );
  117. setOrganizationDomain( QLatin1String( TOMAHAWK_ORGANIZATION_DOMAIN ) );
  118. setApplicationName( QLatin1String( TOMAHAWK_APPLICATION_NAME ) );
  119. setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) );
  120. registerMetaTypes();
  121. installTranslator();
  122. }
  123. void
  124. TomahawkApp::installTranslator()
  125. {
  126. QString locale = QLocale::system().name();
  127. if ( locale == "C" )
  128. locale = "en";
  129. // Tomahawk translations
  130. QTranslator* translator = new QTranslator( this );
  131. if ( translator->load( QString( ":/lang/tomahawk_" ) + locale ) )
  132. {
  133. tDebug( LOGVERBOSE ) << "Translation: Tomahawk: Using system locale:" << locale;
  134. }
  135. else
  136. {
  137. tDebug( LOGVERBOSE ) << "Translation: Tomahawk: Using default locale, system locale one not found:" << locale;
  138. translator->load( QString( ":/lang/tomahawk_en" ) );
  139. }
  140. TOMAHAWK_APPLICATION::installTranslator( translator );
  141. // Qt translations
  142. translator = new QTranslator( this );
  143. if ( translator->load( QString( ":/lang/qt_" ) + locale ) )
  144. {
  145. tDebug( LOGVERBOSE ) << "Translation: Qt: Using system locale:" << locale;
  146. }
  147. else
  148. {
  149. tDebug( LOGVERBOSE ) << "Translation: Qt: Using default locale, system locale one not found:" << locale;
  150. }
  151. TOMAHAWK_APPLICATION::installTranslator( translator );
  152. }
  153. void
  154. TomahawkApp::init()
  155. {
  156. if ( arguments().contains( "--help" ) || arguments().contains( "-h" ) )
  157. {
  158. printHelp();
  159. ::exit( 0 );
  160. }
  161. qDebug() << "TomahawkApp thread:" << thread();
  162. Logger::setupLogfile();
  163. qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) );
  164. tLog() << "Starting Tomahawk...";
  165. #ifdef ENABLE_HEADLESS
  166. m_headless = true;
  167. #else
  168. m_headless = arguments().contains( "--headless" );
  169. setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
  170. setQuitOnLastWindowClosed( false );
  171. QFont f = font();
  172. #ifdef Q_OS_MAC
  173. f.setPointSize( f.pointSize() - 2 );
  174. setFont( f );
  175. #endif
  176. tDebug() << "Default font:" << f.pixelSize() << f.pointSize() << f.pointSizeF() << f.family();
  177. tDebug() << "Font height:" << QFontMetrics( f ).height();
  178. TomahawkUtils::setDefaultFontSize( f.pointSize() );
  179. #endif
  180. TomahawkUtils::setHeadless( m_headless );
  181. TomahawkSettings* s = TomahawkSettings::instance();
  182. new ACLRegistryImpl( this );
  183. tDebug( LOGINFO ) << "Setting NAM.";
  184. // Cause the creation of the nam, but don't need to address it directly, so prevent warning
  185. Q_UNUSED( TomahawkUtils::nam() );
  186. m_audioEngine = QWeakPointer<AudioEngine>( new AudioEngine );
  187. // init pipeline and resolver factories
  188. new Pipeline();
  189. m_servent = QWeakPointer<Servent>( new Servent( this ) );
  190. connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
  191. tDebug() << "Init Database.";
  192. initDatabase();
  193. m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
  194. #ifndef ENABLE_HEADLESS
  195. Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) );
  196. Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1 ) );
  197. new ActionCollection( this );
  198. connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
  199. #endif
  200. QByteArray magic = QByteArray::fromBase64( enApiSecret );
  201. QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() );
  202. int length = magic.length(), n2 = wand.length();
  203. for ( int i=0; i<length; i++ ) magic[i] = magic[i] ^ wand[i%n2];
  204. Echonest::Config::instance()->setAPIKey( magic );
  205. #ifndef ENABLE_HEADLESS
  206. tDebug() << "Init Echonest Factory.";
  207. GeneratorFactory::registerFactory( "echonest", new EchonestFactory );
  208. #endif
  209. tDebug() << "Init Database Factory.";
  210. GeneratorFactory::registerFactory( "database", new DatabaseFactory );
  211. // Register shortcut handler for this platform
  212. #ifdef Q_WS_MAC
  213. m_shortcutHandler = QWeakPointer<Tomahawk::ShortcutHandler>( new MacShortcutHandler( this ) );
  214. Tomahawk::setShortcutHandler( static_cast<MacShortcutHandler*>( m_shortcutHandler.data() ) );
  215. Tomahawk::setApplicationHandler( this );
  216. increaseMaxFileDescriptors();
  217. #endif
  218. // Connect up shortcuts
  219. if ( !m_shortcutHandler.isNull() )
  220. {
  221. connect( m_shortcutHandler.data(), SIGNAL( playPause() ), m_audioEngine.data(), SLOT( playPause() ) );
  222. connect( m_shortcutHandler.data(), SIGNAL( pause() ), m_audioEngine.data(), SLOT( pause() ) );
  223. connect( m_shortcutHandler.data(), SIGNAL( stop() ), m_audioEngine.data(), SLOT( stop() ) );
  224. connect( m_shortcutHandler.data(), SIGNAL( previous() ), m_audioEngine.data(), SLOT( previous() ) );
  225. connect( m_shortcutHandler.data(), SIGNAL( next() ), m_audioEngine.data(), SLOT( next() ) );
  226. connect( m_shortcutHandler.data(), SIGNAL( volumeUp() ), m_audioEngine.data(), SLOT( raiseVolume() ) );
  227. connect( m_shortcutHandler.data(), SIGNAL( volumeDown() ), m_audioEngine.data(), SLOT( lowerVolume() ) );
  228. connect( m_shortcutHandler.data(), SIGNAL( mute() ), m_audioEngine.data(), SLOT( mute() ) );
  229. }
  230. tDebug() << "Init InfoSystem.";
  231. m_infoSystem = QWeakPointer<Tomahawk::InfoSystem::InfoSystem>( Tomahawk::InfoSystem::InfoSystem::instance() );
  232. tDebug() << "Init AccountManager.";
  233. m_accountManager = QWeakPointer< Tomahawk::Accounts::AccountManager >( new Tomahawk::Accounts::AccountManager( this ) );
  234. connect( m_accountManager.data(), SIGNAL( ready() ), SLOT( accountManagerReady() ) );
  235. Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() );
  236. #ifndef ENABLE_HEADLESS
  237. EchonestGenerator::setupCatalogs();
  238. if ( !m_headless )
  239. {
  240. tDebug() << "Init MainWindow.";
  241. m_mainwindow = new TomahawkWindow();
  242. m_mainwindow->setWindowTitle( "Tomahawk" );
  243. m_mainwindow->setObjectName( "TH_Main_Window" );
  244. if ( !arguments().contains( "--hide" ) )
  245. {
  246. m_mainwindow->show();
  247. }
  248. }
  249. #endif
  250. tDebug() << "Init Local Collection.";
  251. initLocalCollection();
  252. tDebug() << "Init Pipeline.";
  253. initPipeline();
  254. #ifndef ENABLE_HEADLESS
  255. // load remote list of resolvers able to be installed
  256. AtticaManager::instance();
  257. #endif
  258. if ( arguments().contains( "--http" ) || TomahawkSettings::instance()->value( "network/http", true ).toBool() )
  259. {
  260. initHTTP();
  261. }
  262. connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) );
  263. #ifndef ENABLE_HEADLESS
  264. if ( !s->hasScannerPaths() )
  265. {
  266. m_mainwindow->showSettingsDialog();
  267. }
  268. #endif
  269. #ifdef LIBLASTFM_FOUND
  270. tDebug() << "Init Scrobbler.";
  271. m_scrobbler = new Scrobbler( this );
  272. #endif
  273. if ( arguments().contains( "--filescan" ) )
  274. {
  275. m_scanManager.data()->runFullRescan();
  276. }
  277. // Set up echonest catalog synchronizer
  278. Tomahawk::EchonestCatalogSynchronizer::instance();
  279. PlaylistUpdaterInterface::registerUpdaterFactory( new XspfUpdaterFactory );
  280. PlaylistUpdaterInterface::registerUpdaterFactory( new SpotifyUpdaterFactory );
  281. // Following work-around/fix taken from Clementine rev. 13e13ccd9a95 and courtesy of David Sansome
  282. // A bug in Qt means the wheel_scroll_lines setting gets ignored and replaced
  283. // with the default value of 3 in QApplicationPrivate::initialize.
  284. {
  285. QSettings qt_settings( QSettings::UserScope, "Trolltech" );
  286. qt_settings.beginGroup( "Qt" );
  287. QApplication::setWheelScrollLines( qt_settings.value( "wheelScrollLines", QApplication::wheelScrollLines() ).toInt() );
  288. }
  289. #ifndef ENABLE_HEADLESS
  290. // Make sure to init GAM in the gui thread
  291. GlobalActionManager::instance();
  292. // check if our spotify playlist api server is up and running, and enable spotify playlist drops if so
  293. QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( SPOTIFY_PLAYLIST_API_URL "/pong" ) ) );
  294. connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) );
  295. #endif
  296. #ifdef Q_OS_MAC
  297. // Make sure to do this after main window is inited
  298. Tomahawk::enableFullscreen( m_mainwindow );
  299. #endif
  300. }
  301. TomahawkApp::~TomahawkApp()
  302. {
  303. tLog() << "Shutting down Tomahawk...";
  304. if ( !m_session.isNull() )
  305. delete m_session.data();
  306. if ( !m_connector.isNull() )
  307. delete m_connector.data();
  308. if ( Pipeline::instance() )
  309. Pipeline::instance()->stop();
  310. if ( !m_servent.isNull() )
  311. delete m_servent.data();
  312. delete dynamic_cast< ACLRegistryImpl* >( ACLRegistry::instance() );
  313. if ( !m_scanManager.isNull() )
  314. delete m_scanManager.data();
  315. if ( !m_audioEngine.isNull() )
  316. delete m_audioEngine.data();
  317. delete Tomahawk::Accounts::AccountManager::instance();
  318. #ifndef ENABLE_HEADLESS
  319. delete AtticaManager::instance();
  320. delete m_mainwindow;
  321. #endif
  322. if ( !m_database.isNull() )
  323. delete m_database.data();
  324. delete Pipeline::instance();
  325. if ( !m_infoSystem.isNull() )
  326. delete m_infoSystem.data();
  327. delete TomahawkUtils::Cache::instance();
  328. tLog() << "Finished shutdown.";
  329. }
  330. TomahawkApp*
  331. TomahawkApp::instance()
  332. {
  333. return (TomahawkApp*)TOMAHAWK_APPLICATION::instance();
  334. }
  335. void
  336. TomahawkApp::printHelp()
  337. {
  338. #define echo( X ) std::cout << QString( X ).toAscii().data() << "\n"
  339. echo( "Usage: " + arguments().at( 0 ) + " [options] [url]" );
  340. echo( "Options are:" );
  341. echo( " --help Show this help" );
  342. echo( " --http Initialize HTTP server" );
  343. echo( " --filescan Scan files on startup" );
  344. // echo( " --headless Run without a GUI" );
  345. echo( " --hide Hide main window on startup" );
  346. echo( " --testdb Use a test database instead of real collection" );
  347. echo( " --noupnp Disable UPnP" );
  348. echo( " --nosip Disable SIP" );
  349. echo();
  350. echo( "Playback Controls:" );
  351. echo( " --play Start/resume playback" );
  352. echo( " --pause Pause playback" );
  353. echo( " --playpause Toggle playing/paused state" );
  354. echo( " --stop Stop playback" );
  355. echo( " --prev Returns to the previous track (if available)" );
  356. echo( " --next Advances to the next track (if available)" );
  357. echo( " --voldown Decrease the volume" );
  358. echo( " --volup Increase the volume" );
  359. echo();
  360. echo( "url is a tomahawk:// command or alternatively a url that Tomahawk can recognize." );
  361. echo( "For more documentation, see http://wiki.tomahawk-player.org/index.php/Tomahawk://_Links" );
  362. }
  363. #ifndef ENABLE_HEADLESS
  364. AudioControls*
  365. TomahawkApp::audioControls()
  366. {
  367. return m_mainwindow->audioControls();
  368. }
  369. #endif
  370. void
  371. TomahawkApp::registerMetaTypes()
  372. {
  373. qRegisterMetaType< QSharedPointer<DatabaseCommand> >("QSharedPointer<DatabaseCommand>");
  374. qRegisterMetaType< DBSyncConnection::State >("DBSyncConnection::State");
  375. qRegisterMetaType< msg_ptr >("msg_ptr");
  376. qRegisterMetaType< QList<dbop_ptr> >("QList<dbop_ptr>");
  377. qRegisterMetaType< QList<QVariantMap> >("QList<QVariantMap>");
  378. qRegisterMetaType< QList<QString> >("QList<QString>");
  379. qRegisterMetaType< QList<uint> >("QList<uint>");
  380. qRegisterMetaType< Connection* >("Connection*");
  381. qRegisterMetaType< QAbstractSocket::SocketError >("QAbstractSocket::SocketError");
  382. qRegisterMetaType< QTcpSocket* >("QTcpSocket*");
  383. qRegisterMetaType< QSharedPointer<QIODevice> >("QSharedPointer<QIODevice>");
  384. qRegisterMetaType< QFileInfo >("QFileInfo");
  385. qRegisterMetaType< QDir >("QDir");
  386. qRegisterMetaType< QHostAddress >("QHostAddress");
  387. qRegisterMetaType< QMap<QString, unsigned int> >("QMap<QString, unsigned int>");
  388. qRegisterMetaType< QMap< QString, plentry_ptr > >("QMap< QString, plentry_ptr >");
  389. qRegisterMetaType< QHash< QString, QMap<quint32, quint16> > >("QHash< QString, QMap<quint32, quint16> >");
  390. qRegisterMetaType< QMap< QString, QMap< unsigned int, unsigned int > > >("QMap< QString, QMap< unsigned int, unsigned int > >");
  391. qRegisterMetaType< PairList >("PairList");
  392. qRegisterMetaType<GeneratorMode>("GeneratorMode");
  393. qRegisterMetaType<Tomahawk::GeneratorMode>("Tomahawk::GeneratorMode");
  394. qRegisterMetaType<ModelMode>("Tomahawk::ModelMode");
  395. qRegisterMetaType<Tomahawk::ModelMode>("Tomahawk::ModelMode");
  396. // Extra definition for namespaced-versions of signals/slots required
  397. qRegisterMetaType< Tomahawk::Resolver* >("Tomahawk::Resolver*");
  398. qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr");
  399. qRegisterMetaType< Tomahawk::collection_ptr >("Tomahawk::collection_ptr");
  400. qRegisterMetaType< Tomahawk::result_ptr >("Tomahawk::result_ptr");
  401. qRegisterMetaType< Tomahawk::query_ptr >("Tomahawk::query_ptr");
  402. qRegisterMetaType< Tomahawk::album_ptr >("Tomahawk::album_ptr");
  403. qRegisterMetaType< Tomahawk::artist_ptr >("Tomahawk::artist_ptr");
  404. qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr");
  405. qRegisterMetaType< Tomahawk::dyncontrol_ptr >("Tomahawk::dyncontrol_ptr");
  406. qRegisterMetaType< Tomahawk::playlist_ptr >("Tomahawk::playlist_ptr");
  407. qRegisterMetaType< Tomahawk::playlistinterface_ptr >("Tomahawk::playlistinterface_ptr");
  408. qRegisterMetaType< Tomahawk::dynplaylist_ptr >("Tomahawk::dynplaylist_ptr");
  409. qRegisterMetaType< Tomahawk::geninterface_ptr >("Tomahawk::geninterface_ptr");
  410. qRegisterMetaType< QList<Tomahawk::playlist_ptr> >("QList<Tomahawk::playlist_ptr>");
  411. qRegisterMetaType< QList<Tomahawk::dynplaylist_ptr> >("QList<Tomahawk::dynplaylist_ptr>");
  412. qRegisterMetaType< QList<Tomahawk::dyncontrol_ptr> >("QList<Tomahawk::dyncontrol_ptr>");
  413. qRegisterMetaType< QList<Tomahawk::geninterface_ptr> >("QList<Tomahawk::geninterface_ptr>");
  414. qRegisterMetaType< QList<Tomahawk::plentry_ptr> >("QList<Tomahawk::plentry_ptr>");
  415. qRegisterMetaType< QList<Tomahawk::query_ptr> >("QList<Tomahawk::query_ptr>");
  416. qRegisterMetaType< QList<Tomahawk::result_ptr> >("QList<Tomahawk::result_ptr>");
  417. qRegisterMetaType< QList<Tomahawk::artist_ptr> >("QList<Tomahawk::artist_ptr>");
  418. qRegisterMetaType< QList<Tomahawk::album_ptr> >("QList<Tomahawk::album_ptr>");
  419. qRegisterMetaType< QList<Tomahawk::source_ptr> >("QList<Tomahawk::source_ptr>");
  420. qRegisterMetaType< QMap< QString, Tomahawk::plentry_ptr > >("QMap< QString, Tomahawk::plentry_ptr >");
  421. qRegisterMetaType< Tomahawk::PlaylistRevision >("Tomahawk::PlaylistRevision");
  422. qRegisterMetaType< Tomahawk::DynamicPlaylistRevision >("Tomahawk::DynamicPlaylistRevision");
  423. qRegisterMetaType< Tomahawk::QID >("Tomahawk::QID");
  424. qRegisterMetaType< AudioErrorCode >("AudioErrorCode");
  425. qRegisterMetaType< Tomahawk::InfoSystem::InfoStringHash >( "Tomahawk::InfoSystem::InfoStringHash" );
  426. qRegisterMetaType< Tomahawk::InfoSystem::InfoType >( "Tomahawk::InfoSystem::InfoType" );
  427. qRegisterMetaType< Tomahawk::InfoSystem::PushInfoFlags >( "Tomahawk::InfoSystem::PushInfoFlags" );
  428. qRegisterMetaType< Tomahawk::InfoSystem::PushInfoPair >( "Tomahawk::InfoSystem::PushInfoPair" );
  429. qRegisterMetaType< Tomahawk::InfoSystem::InfoRequestData >( "Tomahawk::InfoSystem::InfoRequestData" );
  430. qRegisterMetaType< Tomahawk::InfoSystem::InfoPushData >( "Tomahawk::InfoSystem::InfoPushData" );
  431. qRegisterMetaType< Tomahawk::InfoSystem::InfoSystemCache* >( "Tomahawk::InfoSystem::InfoSystemCache*" );
  432. qRegisterMetaType< Tomahawk::InfoSystem::InfoPluginPtr >( "Tomahawk::InfoSystem::InfoPluginPtr" );
  433. qRegisterMetaType< Tomahawk::InfoSystem::InfoPlugin* >( "Tomahawk::InfoSystem::InfoPlugin*" );
  434. qRegisterMetaType< QList< Tomahawk::InfoSystem::InfoStringHash > >("QList< Tomahawk::InfoSystem::InfoStringHash > ");
  435. qRegisterMetaType< TomahawkSettings::PrivateListeningMode >( "TomahawkSettings::PrivateListeningMode" );
  436. qRegisterMetaTypeStreamOperators< QList< Tomahawk::InfoSystem::InfoStringHash > >("QList< Tomahawk::InfoSystem::InfoStringHash > ");
  437. qRegisterMetaType< QPersistentModelIndex >( "QPersistentModelIndex" );
  438. qRegisterMetaType< Tomahawk::PlaylistModes::LatchMode >( "Tomahawk::PlaylistModes::LatchMode" );
  439. qRegisterMetaType< Tomahawk::PlaylistModes::RepeatMode >( "Tomahawk::PlaylistModes::RepeatMode" );
  440. qRegisterMetaType< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" );
  441. qRegisterMetaTypeStreamOperators< TomahawkUtils::CacheData >( "TomahawkUtils::CacheData" );
  442. }
  443. void
  444. TomahawkApp::initDatabase()
  445. {
  446. QString dbpath;
  447. if ( arguments().contains( "--testdb" ) )
  448. {
  449. dbpath = QDir::currentPath() + "/test.db";
  450. }
  451. else
  452. {
  453. dbpath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.db" );
  454. }
  455. tDebug( LOGEXTRA ) << "Using database:" << dbpath;
  456. m_database = QWeakPointer<Database>( new Database( dbpath, this ) );
  457. Pipeline::instance()->databaseReady();
  458. }
  459. void
  460. TomahawkApp::initHTTP()
  461. {
  462. if ( !TomahawkSettings::instance()->httpEnabled() )
  463. {
  464. tLog() << "Stopping HTTPd, not enabled";
  465. if ( !m_session.isNull() )
  466. delete m_session.data();
  467. if ( !m_connector.isNull() )
  468. delete m_connector.data();
  469. return;
  470. }
  471. if ( m_session )
  472. {
  473. tLog() << "HTTPd session already exists, returning";
  474. return;
  475. }
  476. m_session = QWeakPointer< QxtHttpSessionManager >( new QxtHttpSessionManager() );
  477. m_connector = QWeakPointer< QxtHttpServerConnector >( new QxtHttpServerConnector );
  478. if ( m_session.isNull() || m_connector.isNull() )
  479. {
  480. if ( !m_session.isNull() )
  481. delete m_session.data();
  482. if ( !m_connector.isNull() )
  483. delete m_connector.data();
  484. tLog() << "Failed to start HTTPd, could not create object";
  485. return;
  486. }
  487. m_session.data()->setPort( 60210 ); //TODO config
  488. m_session.data()->setListenInterface( QHostAddress::LocalHost );
  489. m_session.data()->setConnector( m_connector.data() );
  490. Api_v1* api = new Api_v1( m_session.data() );
  491. m_session.data()->setStaticContentService( api );
  492. tLog() << "Starting HTTPd on" << m_session.data()->listenInterface().toString() << m_session.data()->port();
  493. m_session.data()->start();
  494. }
  495. void
  496. TomahawkApp::initPipeline()
  497. {
  498. // setup resolvers for local content, and (cached) remote collection content
  499. Pipeline::instance()->addResolver( new DatabaseResolver( 100 ) );
  500. }
  501. void
  502. TomahawkApp::initLocalCollection()
  503. {
  504. connect( SourceList::instance(), SIGNAL( ready() ), SLOT( initServent() ) );
  505. source_ptr src( new Source( 0, tr( "My Collection" ) ) );
  506. collection_ptr coll( new LocalCollection( src ) );
  507. src->addCollection( coll );
  508. SourceList::instance()->setLocal( src );
  509. SourceList::instance()->loadSources();
  510. // to make the stats signal be emitted by our local source
  511. // this will update the sidebar, etc.
  512. DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src );
  513. connect( cmd, SIGNAL( done( const QVariantMap& ) ),
  514. src.data(), SLOT( setStats( const QVariantMap& ) ), Qt::QueuedConnection );
  515. Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
  516. }
  517. void
  518. TomahawkApp::initServent()
  519. {
  520. tDebug() << "Init Servent.";
  521. bool upnp = !arguments().contains( "--noupnp" );
  522. int port = TomahawkSettings::instance()->externalPort();
  523. if ( !Servent::instance()->startListening( QHostAddress( QHostAddress::Any ), upnp, port ) )
  524. {
  525. tLog() << "Failed to start listening with servent";
  526. exit( 1 );
  527. }
  528. }
  529. // Called after Servent emits ready()
  530. void
  531. TomahawkApp::initSIP()
  532. {
  533. tDebug() << Q_FUNC_INFO;
  534. //FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings
  535. if ( !arguments().contains( "--nosip" ) )
  536. {
  537. tDebug( LOGINFO ) << "Connecting SIP classes";
  538. Accounts::AccountManager::instance()->initSIP();
  539. }
  540. m_loaded = true;
  541. emit tomahawkLoaded();
  542. }
  543. void
  544. TomahawkApp::spotifyApiCheckFinished()
  545. {
  546. #ifndef ENABLE_HEADLESS
  547. QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
  548. Q_ASSERT( reply );
  549. DropJob::setCanParseSpotifyPlaylists( !reply->error() );
  550. #endif
  551. }
  552. void
  553. TomahawkApp::accountManagerReady()
  554. {
  555. Tomahawk::Accounts::LastFmAccountFactory* lastfmFactory = new Tomahawk::Accounts::LastFmAccountFactory();
  556. m_accountManager.data()->addAccountFactory( lastfmFactory );
  557. Tomahawk::Accounts::SpotifyAccountFactory* spotifyFactory = new Tomahawk::Accounts::SpotifyAccountFactory;
  558. m_accountManager.data()->addAccountFactory( spotifyFactory );
  559. m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory );
  560. Tomahawk::Accounts::AccountManager::instance()->loadFromConfig();
  561. }
  562. void
  563. TomahawkApp::activate()
  564. {
  565. #ifndef ENABLE_HEADLESS
  566. TomahawkUtils::bringToFront();
  567. #endif
  568. }
  569. bool
  570. TomahawkApp::loadUrl( const QString& url )
  571. {
  572. #ifndef ENABLE_HEADLESS
  573. if ( url.startsWith( "tomahawk://" ) )
  574. return GlobalActionManager::instance()->parseTomahawkLink( url );
  575. else if ( url.contains( "open.spotify.com" ) || url.contains( "spotify:track" ) )
  576. return GlobalActionManager::instance()->openSpotifyLink( url );
  577. else if ( url.contains( "www.rdio.com" ) )
  578. return GlobalActionManager::instance()->openRdioLink( url );
  579. else
  580. {
  581. QFile f( url );
  582. QFileInfo info( f );
  583. if ( info.suffix() == "xspf" )
  584. {
  585. XSPFLoader* l = new XSPFLoader( true, this );
  586. tDebug( LOGINFO ) << "Loading spiff:" << url;
  587. l->load( QUrl::fromUserInput( url ) );
  588. return true;
  589. }
  590. else if ( info.suffix() == "jspf" )
  591. {
  592. JSPFLoader* l = new JSPFLoader( true, this );
  593. tDebug( LOGINFO ) << "Loading j-spiff:" << url;
  594. l->load( QUrl::fromUserInput( url ) );
  595. return true;
  596. }
  597. }
  598. #endif
  599. return false;
  600. }
  601. bool
  602. TomahawkApp::notify( QObject *receiver, QEvent *e )
  603. {
  604. try
  605. {
  606. return TOMAHAWK_APPLICATION::notify( receiver, e );
  607. }
  608. catch ( const std::exception& e )
  609. {
  610. qWarning( "TomahawkApp::notify caught a std exception in a Qt event handler: " );
  611. // the second parameter surpresses a format-security warning
  612. qFatal( e.what(), "" );
  613. }
  614. catch ( ... )
  615. {
  616. qFatal( "TomahawkApp::notify caught a non-std-exception from a Qt event handler. Aborting." );
  617. }
  618. return false;
  619. }
  620. void
  621. TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
  622. {
  623. tDebug( LOGINFO ) << "Instance started!" << instance.pid() << instance.arguments();
  624. const QStringList arguments = instance.arguments();
  625. if ( arguments.size() < 2 )
  626. {
  627. activate();
  628. return;
  629. }
  630. QString arg1 = arguments[ 1 ];
  631. if ( loadUrl( arg1 ) )
  632. {
  633. activate();
  634. return;
  635. }
  636. if ( arguments.contains( "--next" ) )
  637. AudioEngine::instance()->next();
  638. else if ( arguments.contains( "--prev" ) )
  639. AudioEngine::instance()->previous();
  640. else if ( arguments.contains( "--playpause" ) )
  641. AudioEngine::instance()->playPause();
  642. else if ( arguments.contains( "--play" ) )
  643. AudioEngine::instance()->play();
  644. else if ( arguments.contains( "--pause" ) )
  645. AudioEngine::instance()->pause();
  646. else if ( arguments.contains( "--stop" ) )
  647. AudioEngine::instance()->stop();
  648. else if ( arguments.contains( "--voldown" ) )
  649. AudioEngine::instance()->lowerVolume();
  650. else if ( arguments.contains( "--volup" ) )
  651. AudioEngine::instance()->raiseVolume();
  652. else
  653. activate();
  654. }
  655. TomahawkWindow*
  656. TomahawkApp::mainWindow() const
  657. {
  658. return m_mainwindow;
  659. }
  660. bool
  661. TomahawkApp::isTomahawkLoaded() const
  662. {
  663. return m_loaded;
  664. }