From 3f1a5e1c3b62ad8aa9a46f50c45a03fe208338b3 Mon Sep 17 00:00:00 2001 From: Patrick von Reth Date: Tue, 23 Jul 2013 21:17:42 +0200 Subject: [PATCH] added snorenotification support, this adds growl(on windows and mac), windows 8 and snarl nottification support --- src/infoplugins/generic/CMakeLists.txt | 14 + .../generic/snorenotify/SnoreNotifyPlugin.cpp | 285 ++++++++++++++++++ .../generic/snorenotify/SnoreNotifyPlugin.h | 83 +++++ 3 files changed, 382 insertions(+) create mode 100644 src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.cpp create mode 100644 src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.h diff --git a/src/infoplugins/generic/CMakeLists.txt b/src/infoplugins/generic/CMakeLists.txt index 549c32756..94ea682bd 100644 --- a/src/infoplugins/generic/CMakeLists.txt +++ b/src/infoplugins/generic/CMakeLists.txt @@ -2,6 +2,20 @@ include_directories( ${ECHONEST_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ) +if(WIN32 OR APPLE) +find_package(Libsnore) +if(BUILD_GUI AND LIBSNORE_FOUND) + SET(snore_srcs + snorenotify/SnoreNotifyPlugin.cpp + ) + SET(SNORE_LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBSNORE_LIBRARIES} ) + + tomahawk_add_plugin(snorenotify + TYPE infoplugin EXPORT_MACRO INFOPLUGINDLLEXPORT_PRO + SOURCES "${snore_srcs}" LINK_LIBRARIES "${SNORE_LINK_LIBRARIES}" + ) +endif(BUILD_GUI AND LIBSNORE_FOUND) +endif(WIN32 OR APPLE) list(APPEND simple_plugins Echonest diff --git a/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.cpp b/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.cpp new file mode 100644 index 000000000..4550559d4 --- /dev/null +++ b/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.cpp @@ -0,0 +1,285 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013 , Patrick von Reth + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2012, Jeff Mitchell + * + * 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 . + */ + +// Marked portions of this file are subject to the following copyright: +/* + * Copyright (C) 2009 by Aur??lien G??teau + * + * 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, 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 "SnoreNotifyPlugin.h" + + +#include "TomahawkSettings.h" + +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" +#include "utils/TomahawkUtilsGui.h" + +#include +#include + +#include + +#include +// QTextDocument provides Qt::escape() +#include + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +SnoreNotifyPlugin::SnoreNotifyPlugin() + : InfoPlugin(), + m_defaultIcon( RESPATH "icons/tomahawk-icon-512x512.png" ) +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; + m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoTrackUnresolved << InfoNowStopped << InfoInboxReceived; + + m_snore = new Snore::SnoreCore(); + m_snore->loadPlugins( Snore::PluginContainer::BACKEND ); + QString backend = qgetenv( "SNORE_BACKEND" ).constData(); + backend.isEmpty()?m_snore->setPrimaryNotificationBackend():m_snore->setPrimaryNotificationBackend(backend); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << m_snore->primaryNotificationBackend(); + m_application = new Snore::Application( qApp->applicationName(), m_defaultIcon ); + + m_snore->addApplication(m_application); + m_snore->applicationIsInitialized(m_application); + + addAlert( InfoNotifyUser,tr("Notify User") ); + addAlert( InfoNowPlaying,tr("Now Playing") ); + addAlert( InfoTrackUnresolved, tr("Unresolved track") ); + addAlert( InfoNowStopped, tr("Playback Stopped") ); + addAlert( InfoInboxReceived, tr("You recived a Song recomondation") ); + + connect(m_snore,SIGNAL(actionInvoked(Snore::Notification)),this,SLOT(slotActionInvoked(Snore::Notification))); + + +} + + +SnoreNotifyPlugin::~SnoreNotifyPlugin() +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; + m_snore->deleteLater(); + m_application->deleteLater(); + + foreach(Snore::Alert *alert,m_alerts) + { + alert->deleteLater(); + } +} + +void +SnoreNotifyPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "showing notification:" << TomahawkSettings::instance()->songChangeNotificationEnabled(); + if ( !TomahawkSettings::instance()->songChangeNotificationEnabled() ) + return; + + + switch ( pushData.type ) + { + case Tomahawk::InfoSystem::InfoTrackUnresolved: + notifyUser( Tomahawk::InfoSystem::InfoTrackUnresolved,"The current track could not be resolved. Tomahawk will pick back up with the next resolvable track from this source." ); + return; + + case Tomahawk::InfoSystem::InfoNotifyUser: + notifyUser( Tomahawk::InfoSystem::InfoNotifyUser,pushData.infoPair.second.toString() ); + return; + + case Tomahawk::InfoSystem::InfoNowStopped: + notifyUser( Tomahawk::InfoSystem::InfoNowStopped, "Tomahawk stopped playback." ); + return; + + case Tomahawk::InfoSystem::InfoNowPlaying: + nowPlaying( pushData.infoPair.second ); + return; + + case Tomahawk::InfoSystem::InfoInboxReceived: + inboxReceived( pushData.infoPair.second ); + return; + + default: + return; + } + +} + +void +SnoreNotifyPlugin::slotActionInvoked( Snore::Notification n ) +{ + Q_UNUSED(n) + TomahawkUtils::bringToFront(); +} + + +void +SnoreNotifyPlugin::notifyUser( Tomahawk::InfoSystem::InfoType type, const QString& messageText, Snore::Icon icon ) +{ + if(!icon.isValid()) + { + icon = m_defaultIcon; + } + Snore::Alert *alert = m_alerts[type]; + Snore::Notification n( qApp->applicationName(), alert->name(), alert->title(), messageText, icon ); + m_snore->broadcastNotification(n); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "showing notification:" << messageText; + +} + +void +SnoreNotifyPlugin::addAlert( Tomahawk::InfoSystem::InfoType type, const QString &title ) +{ + Snore::Alert *alert = new Snore::Alert( title, title, m_defaultIcon ); + m_application->addAlert( alert ); + m_alerts[ type ] = alert; +} + +void +SnoreNotifyPlugin::nowPlaying( const QVariant& input ) +{ + + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; + if ( !input.canConvert< QVariantMap >() ) + return; + + QVariantMap map = input.toMap(); + if ( !map.contains( "trackinfo" ) || !map[ "trackinfo" ].canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + return; + + InfoStringHash hash = map[ "trackinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) ) + return; + + QString messageText; + // If the window manager supports notification styling then use it. + if ( m_snore->primaryBackendSupportsRichtext() ) + { + // Remark: If using xml-based markup in notifications, the supplied strings need to be escaped. + QString album; + if ( !hash[ "album" ].isEmpty() ) + album = QString( "\n%1 %2" ).arg( tr( "on", "'on' is followed by an album name" ) ).arg( Qt::escape( hash[ "album" ] ) ); + + messageText = tr( "%1%4 %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing, %4 is the preposition used to link track and artist ('by' in english)" ) + .arg( Qt::escape( hash[ "title" ] ) ) + .arg( Qt::escape( hash[ "artist" ] ) ) + .arg( album ) + .arg( QString( "\n%1" ).arg( tr( "by", "preposition to link track and artist" ) ) ); + + // Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text + messageText = QString( "%1" ).arg( messageText ); + } + else + { + QString album; + if ( !hash[ "album" ].isEmpty() ) + album = QString( " %1" ).arg( tr( "on \"%1\"", "%1 is an album name" ).arg( hash[ "album" ] ) ); + + messageText = tr( "\"%1\" by %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing" ) + .arg( hash[ "title" ] ) + .arg( hash[ "artist" ] ) + .arg( album ); + } + + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "sending message" << messageText; + + // If there is a cover availble use it, else use Tomahawk logo as default. + Snore::Icon image; + if ( map.contains( "coveruri" ) && map[ "coveruri" ].canConvert< QString >() ) + { + image = Snore::Icon( QImage(map[ "coveruri" ].toString(),"PNG")); + tDebug( LOGVERBOSE ) << Q_FUNC_INFO << map[ "coveruri" ].toString(); + } + notifyUser( InfoNowPlaying, messageText, image ); +} + + + +void +SnoreNotifyPlugin::inboxReceived( const QVariant& input ) +{ + tDebug( LOGVERBOSE ) << Q_FUNC_INFO; + if ( !input.canConvert< QVariantMap >() ) + return; + + QVariantMap map = input.toMap(); + + if ( !map.contains( "trackinfo" ) || !map[ "trackinfo" ].canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + return; + if ( !map.contains( "sourceinfo" ) || !map[ "sourceinfo" ].canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + return; + + InfoStringHash hash = map[ "trackinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !hash.contains( "title" ) || !hash.contains( "artist" ) ) + return; + + InfoStringHash src = map[ "sourceinfo" ].value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !src.contains( "friendlyname" ) ) + return; + + QString messageText; + // If the window manager supports notification styling then use it. + if ( m_snore->primaryBackendSupportsRichtext() ) + { + // Remark: If using xml-based markup in notifications, the supplied strings need to be escaped. + messageText = tr( "%1 sent you\n%2%4 %3.", "%1 is a nickname, %2 is a title, %3 is an artist, %4 is the preposition used to link track and artist ('by' in english)" ) + .arg( Qt::escape( src["friendlyname"] ) ) + .arg( Qt::escape( hash[ "title" ] ) ) + .arg( Qt::escape( hash[ "artist" ] ) ) + .arg( QString( "\n%1" ).arg( tr( "by", "preposition to link track and artist" ) ) ); + + // Dirty hack(TM) so that KNotify/QLabel recognizes the message as Rich Text + messageText = QString( "%1" ).arg( messageText ); + } + else + { + messageText = tr( "%1 sent you \"%2\" by %3.", "%1 is a nickname, %2 is a title, %3 is an artist" ) + .arg( src["friendlyname"] ) + .arg( hash[ "title" ] ) + .arg( hash[ "artist" ] ); + } + + Snore::Icon icon( RESPATH "images/inbox-512x512.png" ); + notifyUser( Tomahawk::InfoSystem::InfoNowPlaying, messageText, icon ); +} + + +} //ns InfoSystem + +} //ns Tomahawk + +Q_EXPORT_PLUGIN2( Tomahawk::InfoSystem::InfoPlugin, Tomahawk::InfoSystem::SnoreNotifyPlugin ) diff --git a/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.h b/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.h new file mode 100644 index 000000000..45ea97495 --- /dev/null +++ b/src/infoplugins/generic/snorenotify/SnoreNotifyPlugin.h @@ -0,0 +1,83 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013 , Patrick von Reth + * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Jeff Mitchell + * + * 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 . + */ + +#ifndef SNORENOTIFYPLUGIN_H +#define SNORENOTIFYPLUGIN_H + +#include "../../InfoPluginDllMacro.h" + +#include "infosystem/InfoSystem.h" +#include + +class QDBusPendingCallWatcher; + +namespace Tomahawk +{ + +namespace InfoSystem +{ + +class INFOPLUGINDLLEXPORT SnoreNotifyPlugin : public InfoPlugin +{ + Q_PLUGIN_METADATA( IID "org.tomahawk-player.Player.InfoPlugin" ) + Q_OBJECT + Q_INTERFACES( Tomahawk::InfoSystem::InfoPlugin ) + +public: + SnoreNotifyPlugin(); + virtual ~SnoreNotifyPlugin(); + + +protected slots: + virtual void init() {} + + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) + { + Q_UNUSED( requestData ); + } + + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ); + + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) + { + Q_UNUSED( criteria ); + Q_UNUSED( requestData ); + } + +protected slots: + void slotActionInvoked(Snore::Notification n); + +private: + void notifyUser(InfoType type, const QString &messageText, Snore::Icon icon = Snore::Icon()); + void addAlert(Tomahawk::InfoSystem::InfoType type,const QString &title); + Snore::SnoreCore *m_snore; + Snore::Application *m_application; + Snore::Icon m_defaultIcon; + QHash m_alerts; + + void nowPlaying(const QVariant &input); + void inboxReceived(const QVariant &input); +}; + +} + +} + +#endif // SNORENOTIFYPLUGIN_H