@ -3,11 +3,16 @@
# include <sstream>
# include <sstream>
# include <array>
# include <array>
# include "dbus_info.h"
# include "dbus_info.h"
# include "string_utils.h"
using ms = std : : chrono : : milliseconds ;
using ms = std : : chrono : : milliseconds ;
struct metadata spotify ;
struct metadata spotify ;
struct metadata generic_mpris ;
typedef std : : vector < std : : pair < std : : string , std : : string > > string_pair_vec ;
typedef std : : vector < std : : pair < std : : string , std : : string > > string_pair_vec ;
typedef std : : unordered_map < std : : string , string_pair_vec > string_pair_vec_map ;
typedef std : : unordered_map < std : : string , std : : string > string_map ;
std : : string format_signal ( const DBusSignal & s )
std : : string format_signal ( const DBusSignal & s )
{
{
@ -104,7 +109,6 @@ static void parse_mpris_metadata(libdbus_loader& dbus, DBusMessageIter *iter_, s
while ( dbus . message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_INVALID )
while ( dbus . message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_INVALID )
{
{
dbus . message_iter_next ( & iter ) ;
//std::cerr << "\ttype: " << (char)dbus.message_iter_get_arg_type(&iter) << std::endl;
//std::cerr << "\ttype: " << (char)dbus.message_iter_get_arg_type(&iter) << std::endl;
if ( ! get_variant_string ( dbus , & iter , key ) )
if ( ! get_variant_string ( dbus , & iter , key ) )
return ;
return ;
@ -123,10 +127,11 @@ static void parse_mpris_metadata(libdbus_loader& dbus, DBusMessageIter *iter_, s
entries . push_back ( { key , s } ) ;
entries . push_back ( { key , s } ) ;
}
}
}
}
dbus . message_iter_next ( & iter ) ;
}
}
}
}
static void parse_mpris_properties ( libdbus_loader & dbus , DBusMessage * msg , std : : string & source , string_pair_vec & entries )
static void parse_mpris_properties ( libdbus_loader & dbus , DBusMessage * msg , std : : string & source , string_pair_vec _map & entries _map )
{
{
const char * val_char = nullptr ;
const char * val_char = nullptr ;
DBusMessageIter iter ;
DBusMessageIter iter ;
@ -180,14 +185,14 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
continue ;
continue ;
dbus . message_iter_recurse ( & iter , & iter ) ;
dbus . message_iter_recurse ( & iter , & iter ) ;
parse_mpris_metadata ( dbus , & iter , entries ) ;
parse_mpris_metadata ( dbus , & iter , entries _map[ " Metadata " ] ) ;
}
}
else if ( key = = " PlaybackStatus " ) {
else if ( key = = " PlaybackStatus " ) {
dbus . message_iter_recurse ( & stack . back ( ) , & iter ) ;
dbus . message_iter_recurse ( & stack . back ( ) , & iter ) ;
dbus . message_iter_next ( & iter ) ;
dbus . message_iter_next ( & iter ) ;
if ( get_variant_string ( dbus , & iter , val ) )
if ( get_variant_string ( dbus , & iter , val ) )
entries . push_back ( { key , val } ) ;
entries _map[ " PlaybackStatus " ] . push_back ( { key , val } ) ;
}
}
dbus . message_iter_next ( & stack . back ( ) ) ;
dbus . message_iter_next ( & stack . back ( ) ) ;
@ -351,8 +356,11 @@ bool get_dict_string_array(libdbus_loader& dbus, DBusMessage *msg, string_pair_v
return true ;
return true ;
}
}
static void assign_metadata ( metadata & meta , string_pair_vec & entries )
static void assign_metadata ( metadata & meta , string_pair_vec _map & entries _map )
{
{
string_pair_vec_map : : const_iterator it ;
it = entries_map . find ( " Metadata " ) ;
if ( it ! = entries_map . end ( ) ) {
meta . title . clear ( ) ;
meta . title . clear ( ) ;
meta . artists . clear ( ) ;
meta . artists . clear ( ) ;
meta . album . clear ( ) ;
meta . album . clear ( ) ;
@ -360,13 +368,12 @@ static void assign_metadata(metadata& meta, string_pair_vec& entries)
std : : lock_guard < std : : mutex > lk ( meta . mutex ) ;
std : : lock_guard < std : : mutex > lk ( meta . mutex ) ;
std : : vector < std : : string > artists ;
std : : vector < std : : string > artists ;
meta . valid = false ;
meta . valid = false ;
for ( auto & kv : entries ) {
for ( auto & kv : it- > second ) {
# ifndef NDEBUG
# ifndef NDEBUG
std : : cerr < < kv . first < < " = " < < kv . second < < std : : endl ;
std : : cerr < < kv . first < < " = " < < kv . second < < std : : endl ;
# endif
# endif
if ( kv . first = = " xesam:artist " ) {
if ( kv . first = = " xesam:artist " )
artists . push_back ( kv . second ) ;
artists . push_back ( kv . second ) ;
}
else if ( kv . first = = " xesam:title " )
else if ( kv . first = = " xesam:title " )
meta . title = kv . second ;
meta . title = kv . second ;
else if ( kv . first = = " xesam:album " )
else if ( kv . first = = " xesam:album " )
@ -383,6 +390,15 @@ static void assign_metadata(metadata& meta, string_pair_vec& entries)
if ( p ! = artists . end ( ) - 1 )
if ( p ! = artists . end ( ) - 1 )
meta . artists + = " , " ;
meta . artists + = " , " ;
}
}
}
it = entries_map . find ( " PlaybackStatus " ) ;
if ( it ! = entries_map . end ( ) ) {
for ( auto & kv : it - > second ) {
if ( kv . first = = " PlaybackStatus " )
meta . playing = ( kv . second = = " Playing " ) ;
}
}
if ( meta . artists . size ( ) | | ! meta . title . empty ( ) )
if ( meta . artists . size ( ) | | ! meta . title . empty ( ) )
meta . valid = meta . playing ;
meta . valid = meta . playing ;
@ -393,7 +409,97 @@ static void assign_metadata(metadata& meta, string_pair_vec& entries)
meta . ticker . dir = - 1 ;
meta . ticker . dir = - 1 ;
}
}
void dbus_get_spotify_property ( dbusmgr : : dbus_manager & dbus_mgr , string_pair_vec & entries , const char * prop )
bool dbus_get_name_owner ( dbusmgr : : dbus_manager & dbus_mgr , std : : string & name_owner , const char * name )
{
auto & dbus = dbus_mgr . dbus ( ) ;
DBusError error ;
dbus . error_init ( & error ) ;
DBusMessage * dbus_reply = nullptr ;
DBusMessage * dbus_msg = nullptr ;
// dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:"org.mpris.MediaPlayer2.spotify"
if ( nullptr = = ( dbus_msg = dbus . message_new_method_call ( " org.freedesktop.DBus " , " /org/freedesktop/DBus " , " org.freedesktop.DBus " , " GetNameOwner " ) ) ) {
throw std : : runtime_error ( " unable to allocate memory for dbus message " ) ;
}
if ( ! dbus . message_append_args ( dbus_msg , DBUS_TYPE_STRING , & name , DBUS_TYPE_INVALID ) ) {
dbus . message_unref ( dbus_msg ) ;
std : : cerr < < " MANGOHUD: " < < __func__ < < " : dbus_message_append_args failed \n " ;
dbus . error_free ( & error ) ;
return false ;
}
if ( nullptr = = ( dbus_reply = dbus . connection_send_with_reply_and_block ( dbus_mgr . get_conn ( ) , dbus_msg , DBUS_TIMEOUT_USE_DEFAULT , & error ) ) ) {
dbus . message_unref ( dbus_msg ) ;
std : : cerr < < " MANGOHUD: " < < __func__ < < " : " < < error . message < < " \n " ;
dbus . error_free ( & error ) ;
return false ;
}
const char * val = nullptr ;
DBusMessageIter iter ;
dbus . message_iter_init ( dbus_reply , & iter ) ;
if ( dbus . message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_STRING )
return false ;
dbus . message_iter_get_basic ( & iter , & val ) ;
if ( val )
name_owner = val ;
dbus . message_unref ( dbus_msg ) ;
dbus . message_unref ( dbus_reply ) ;
dbus . error_free ( & error ) ;
return true ;
}
bool dbus_list_name_to_owner ( dbusmgr : : dbus_manager & dbus_mgr , string_map & name_owners )
{
auto & dbus = dbus_mgr . dbus ( ) ;
DBusError error ;
dbus . error_init ( & error ) ;
std : : vector < std : : string > names ;
std : : string owner ;
DBusMessageIter iter ;
DBusMessage * dbus_reply = nullptr ;
DBusMessage * dbus_msg = nullptr ;
// dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:"org.mpris.MediaPlayer2.spotify"
if ( nullptr = = ( dbus_msg = dbus . message_new_method_call ( " org.freedesktop.DBus " , " /org/freedesktop/DBus " , " org.freedesktop.DBus " , " ListNames " ) ) ) {
throw std : : runtime_error ( " unable to allocate memory for dbus message " ) ;
}
if ( nullptr = = ( dbus_reply = dbus . connection_send_with_reply_and_block ( dbus_mgr . get_conn ( ) , dbus_msg , DBUS_TIMEOUT_USE_DEFAULT , & error ) ) ) {
dbus . message_unref ( dbus_msg ) ;
std : : cerr < < " MANGOHUD: " < < __func__ < < " : " < < error . message < < " \n " ;
dbus . error_free ( & error ) ;
return false ;
}
dbus . message_iter_init ( dbus_reply , & iter ) ;
if ( ! get_string_array ( dbus , & iter , names ) )
return false ;
for ( auto & name : names ) {
if ( ! starts_with ( name , " org.mpris.MediaPlayer2. " ) )
continue ;
if ( dbus_get_name_owner ( dbus_mgr , owner , name . c_str ( ) ) ) {
name_owners [ name ] = owner ;
}
}
dbus . message_unref ( dbus_msg ) ;
dbus . message_unref ( dbus_reply ) ;
dbus . error_free ( & error ) ;
return true ;
}
void dbus_get_player_property ( dbusmgr : : dbus_manager & dbus_mgr , string_pair_vec & entries , const char * dest , const char * prop )
{
{
auto & dbus = dbus_mgr . dbus ( ) ;
auto & dbus = dbus_mgr . dbus ( ) ;
DBusError error ;
DBusError error ;
@ -403,7 +509,7 @@ void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus_mgr, string_pair_vec&
DBusMessage * dbus_msg = nullptr ;
DBusMessage * dbus_msg = nullptr ;
// dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'
// dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'
if ( nullptr = = ( dbus_msg = dbus . message_new_method_call ( " org.mpris.MediaPlayer2.spotify " , " /org/mpris/MediaPlayer2 " , " org.freedesktop.DBus.Properties " , " Get " ) ) ) {
if ( nullptr = = ( dbus_msg = dbus . message_new_method_call ( dest , " /org/mpris/MediaPlayer2 " , " org.freedesktop.DBus.Properties " , " Get " ) ) ) {
throw std : : runtime_error ( " unable to allocate memory for dbus message " ) ;
throw std : : runtime_error ( " unable to allocate memory for dbus message " ) ;
}
}
@ -411,10 +517,9 @@ void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus_mgr, string_pair_vec&
" org.mpris.MediaPlayer2.Player " ,
" org.mpris.MediaPlayer2.Player " ,
} ;
} ;
std : : cerr < < __func__ < < " : " < < prop < < std : : endl ;
if ( ! dbus . message_append_args ( dbus_msg , DBUS_TYPE_STRING , & v_STRINGS [ 0 ] , DBUS_TYPE_STRING , & prop , DBUS_TYPE_INVALID ) ) {
if ( ! dbus . message_append_args ( dbus_msg , DBUS_TYPE_STRING , & v_STRINGS [ 0 ] , DBUS_TYPE_STRING , & prop , DBUS_TYPE_INVALID ) ) {
dbus . message_unref ( dbus_msg ) ;
dbus . message_unref ( dbus_msg ) ;
throw std : : runtime_error ( error . message ) ;
throw std : : runtime_error ( " dbus_message_append_args failed " ) ;
}
}
if ( nullptr = = ( dbus_reply = dbus . connection_send_with_reply_and_block ( dbus_mgr . get_conn ( ) , dbus_msg , DBUS_TIMEOUT_USE_DEFAULT , & error ) ) ) {
if ( nullptr = = ( dbus_reply = dbus . connection_send_with_reply_and_block ( dbus_mgr . get_conn ( ) , dbus_msg , DBUS_TIMEOUT_USE_DEFAULT , & error ) ) ) {
@ -437,9 +542,9 @@ void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus_mgr, string_pair_vec&
void get_spotify_metadata ( dbusmgr : : dbus_manager & dbus , metadata & meta )
void get_spotify_metadata ( dbusmgr : : dbus_manager & dbus , metadata & meta )
{
{
meta . artists . clear ( ) ;
meta . artists . clear ( ) ;
string_pair_vec entries ;
string_pair_vec _map entries ;
dbus_get_ spotify _property( dbus , entries , " Metadata " ) ;
dbus_get_ player _property( dbus , entries [ " Metadata " ] , " org.mpris.MediaPlayer2.spotify " , " Metadata " ) ;
dbus_get_ spotify _property( dbus , entries , " PlaybackStatus " ) ;
dbus_get_ player _property( dbus , entries [ " PlaybackStatus " ] , " org.mpris.MediaPlayer2.spotify " , " PlaybackStatus " ) ;
assign_metadata ( meta , entries ) ;
assign_metadata ( meta , entries ) ;
}
}
@ -461,6 +566,8 @@ void dbus_manager::init()
}
}
std : : cout < < " Connected to D-Bus as \" " < < m_dbus_ldr . bus_get_unique_name ( m_dbus_conn ) < < " \" . " < < std : : endl ;
std : : cout < < " Connected to D-Bus as \" " < < m_dbus_ldr . bus_get_unique_name ( m_dbus_conn ) < < " \" . " < < std : : endl ;
dbus_list_name_to_owner ( * this , m_name_owners ) ;
connect_to_signals ( ) ;
connect_to_signals ( ) ;
m_inited = true ;
m_inited = true ;
}
}
@ -560,24 +667,35 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
if ( dbus . message_is_signal ( msg , sig . intf , sig . signal ) )
if ( dbus . message_is_signal ( msg , sig . intf , sig . signal ) )
{
{
const char * sender = dbus . message_get_sender ( msg ) ;
# ifndef NDEBUG
# ifndef NDEBUG
std : : cerr < < __func__ < < " : " < < sig . intf < < " :: " < < sig . signal < < std : : endl ;
std : : cerr < < __func__ < < " : " < < sig . intf < < " :: " < < sig . signal < < " \n " ;
std : : cerr < < " Sender: " < < sender < < " \n " ;
# endif
# endif
switch ( sig . type ) {
switch ( sig . type ) {
case ST_PROPERTIESCHANGED :
case ST_PROPERTIESCHANGED :
{
{
std : : string source ;
std : : string source ;
st d: : vector < std : : pair < std : : string , std : : string > > entries ;
st ring_pair_vec_map entries_map ;
//parse_property_changed(msg, source, entries);
//parse_property_changed(msg, source, entries);
parse_mpris_properties ( dbus , msg , source , entries ) ;
parse_mpris_properties ( dbus , msg , source , entries _map ) ;
# ifndef NDEBUG
# ifndef NDEBUG
std : : cerr < < " Source: " < < source < < std : : endl ;
std : : cerr < < " Source: " < < source < < " \n " ;
# endif
# endif
if ( source ! = " org.mpris.MediaPlayer2.Player " )
if ( source ! = " org.mpris.MediaPlayer2.Player " )
break ;
break ;
assign_metadata ( spotify , entries ) ;
if ( pmgr - > m_name_owners [ " org.mpris.MediaPlayer2.spotify " ] = = sender ) {
assign_metadata ( spotify , entries_map ) ;
} else {
assign_metadata ( generic_mpris , entries_map ) ;
if ( generic_mpris . playing & & ! generic_mpris . valid ) {
dbus_get_player_property ( * pmgr , entries_map [ " Metadata " ] , sender , " Metadata " ) ;
assign_metadata ( generic_mpris , entries_map ) ;
}
}
}
}
break ;
break ;
case ST_NAMEOWNERCHANGED :
case ST_NAMEOWNERCHANGED :
@ -593,15 +711,34 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
dbus . message_iter_next ( & iter ) ;
dbus . message_iter_next ( & iter ) ;
}
}
// did spotify quit?
// register new name
if ( str . size ( ) = = 3
if ( str . size ( ) = = 3
& & st r[ 0 ] = = " org.mpris.MediaPlayer2. spotify "
& & st arts_with( str [ 0 ] , " org.mpris.MediaPlayer2. " )
& & str [ 2 ] . empty ( )
& & ! str [ 2 ] . empty ( )
)
)
{
{
pmgr - > m_name_owners [ str [ 0 ] ] = str [ 2 ] ;
}
// did a player quit?
if ( str [ 2 ] . empty ( ) ) {
if ( str . size ( ) = = 3
& & str [ 0 ] = = " org.mpris.MediaPlayer2.spotify "
) {
spotify . valid = false ;
spotify . valid = false ;
} else {
auto it = pmgr - > m_name_owners . find ( str [ 0 ] ) ;
if ( it ! = pmgr - > m_name_owners . end ( )
& & it - > second = = str [ 1 ] ) {
generic_mpris . artists . clear ( ) ;
generic_mpris . title . clear ( ) ;
generic_mpris . album . clear ( ) ;
generic_mpris . valid = false ;
}
}
}
}
}
}
break ;
break ;
default :
default :
break ;
break ;