diff --git a/src/indexer/structs.h b/src/indexer/structs.h index c50fd01..85c601f 100644 --- a/src/indexer/structs.h +++ b/src/indexer/structs.h @@ -111,6 +111,7 @@ KotoIndexedTrack* koto_indexed_track_new(KotoIndexedAlbum *album, const gchar *p KotoIndexedTrack* koto_indexed_track_new_with_uuid(const gchar *uuid); void koto_indexed_track_commit(KotoIndexedTrack *self); +GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self); gchar* koto_indexed_track_get_uuid(KotoIndexedTrack *self); void koto_indexed_track_parse_name(KotoIndexedTrack *self); void koto_indexed_track_remove_from_playlist(KotoIndexedTrack *self, gchar *playlist_uuid); diff --git a/src/indexer/track.c b/src/indexer/track.c index 9ccc55c..68b08f7 100644 --- a/src/indexer/track.c +++ b/src/indexer/track.c @@ -278,6 +278,59 @@ void koto_indexed_track_commit(KotoIndexedTrack *self) { g_free(commit_op_errmsg); } +GVariant* koto_indexed_track_get_metadata_vardict(KotoIndexedTrack *self) { + if (!KOTO_IS_INDEXED_TRACK(self)) { + return NULL; + } + + GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); + + gchar *album_art_path = NULL; + gchar *album_name = NULL; + gchar *artist_name = NULL; + + KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, self->artist_uuid); + KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, self->album_uuid); + + g_object_get(album, + "art-path", &album_art_path, + "name", &album_name, + NULL); + + g_object_get(artist, + "name", &artist_name, + NULL); + + g_variant_builder_add(builder, "{sv}", "mpris:trackid", g_variant_new_string(self->uuid)); + + if (koto_utils_is_string_valid(album_art_path)) { // Valid album art path + album_art_path = g_strconcat("file://", album_art_path, NULL); // Prepend with file:// + g_variant_builder_add(builder, "{sv}", "mpris:artUrl", g_variant_new_string(album_art_path)); + } + + g_variant_builder_add(builder, "{sv}", "xesam:album", g_variant_new_string(album_name)); + + if (koto_utils_is_string_valid(artist_name)) { // Valid artist name + GVariant *artist_name_variant; + GVariantBuilder *artist_list_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); + g_variant_builder_add(artist_list_builder, "s", artist_name); + artist_name_variant = g_variant_new("as", artist_list_builder); + g_variant_builder_unref(artist_list_builder); + + g_variant_builder_add(builder, "{sv}", "xesam:artist", artist_name_variant); + g_variant_builder_add(builder, "{sv}", "playbackengine:artist", g_variant_new_string(artist_name)); // Add a sort of "meta" string val for our playback engine so we don't need to mess about with the array + } + + g_variant_builder_add(builder, "{sv}", "xesam:discNumber", g_variant_new_uint64(GPOINTER_TO_UINT(self->cd))); + g_variant_builder_add(builder, "{sv}", "xesam:title", g_variant_new_string(self->parsed_name)); + g_variant_builder_add(builder, "{sv}", "xesam:url", g_variant_new_string(self->path)); + g_variant_builder_add(builder, "{sv}", "xesam:trackNumber", g_variant_new_uint64(GPOINTER_TO_UINT(self->position))); + + GVariant *metadata_ret = g_variant_builder_end(builder); + + return metadata_ret; +} + gchar* koto_indexed_track_get_uuid(KotoIndexedTrack *self) { if (!KOTO_IS_INDEXED_TRACK(self)) { return NULL; diff --git a/src/main.c b/src/main.c index f6f28ba..106416d 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,7 @@ #include #include +#include #include "db/cartographer.h" #include "db/db.h" #include "playback/media-keys.h" diff --git a/src/playback/engine.c b/src/playback/engine.c index f5f600a..1d3805d 100644 --- a/src/playback/engine.c +++ b/src/playback/engine.c @@ -18,9 +18,12 @@ #include #include #include +#include +#include #include "../db/cartographer.h" #include "../playlist/current.h" #include "../indexer/structs.h" +#include "../koto-utils.h" #include "engine.h" #include "mpris.h" @@ -54,6 +57,7 @@ struct _KotoPlaybackEngine { GstQuery *position_query; KotoIndexedTrack *current_track; + NotifyNotification *track_notification; gboolean is_muted; gboolean is_repeat_enabled; @@ -426,8 +430,49 @@ void koto_playback_engine_set_track_by_uuid(KotoPlaybackEngine *self, gchar *tra koto_playback_engine_set_position(self, 0); koto_playback_engine_set_volume(self, self->volume); // Re-enforce our volume on the updated playbin + GVariant *metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata + GVariantDict *metadata_dict = g_variant_dict_new(metadata); + g_signal_emit(self, playback_engine_signals[SIGNAL_TRACK_CHANGE], 0); // Emit our track change signal koto_update_mpris_info_for_track(self->current_track); + + GVariant *track_name_var = g_variant_dict_lookup_value(metadata_dict, "xesam:title", NULL); // Get the GVariant for the name of the track + const gchar *track_name = g_variant_get_string(track_name_var, NULL); // Get the string of the track name + + GVariant *album_name_var = g_variant_dict_lookup_value(metadata_dict, "xesam:album", NULL); // Get the GVariant for the album name + const gchar *album_name = g_variant_get_string(album_name_var, NULL); // Get the string for the album name + + GVariant *artist_name_var = g_variant_dict_lookup_value(metadata_dict, "playbackengine:artist", NULL); // Get the GVariant for the name of the artist + const gchar *artist_name = g_variant_get_string(artist_name_var, NULL); // Get the string for the artist name + + gchar *artist_album_combo = g_strjoin(" - ", artist_name, album_name, NULL); // Join artist and album name separated by " - " + + gchar *icon_name = "audio-x-generic-symbolic"; + + if (g_variant_dict_contains(metadata_dict, "mpris:artUrl")) { // If we have artwork specified + GVariant *art_url_var = g_variant_dict_lookup_value(metadata_dict, "mpris:artUrl", NULL); // Get the GVariant for the art URL + const gchar *art_uri = g_variant_get_string(art_url_var, NULL); // Get the string for the artwork + icon_name = koto_utils_replace_string_all(g_strdup(art_uri), "file://", ""); + } + + // Super important note: We are not using libnotify directly because the synchronous nature of notify_notification_send seems to result in dbus timeouts + if (g_find_program_in_path("notify-send") != NULL) { // Have notify-send + char *argv[12]; + argv[0] = "notify-send"; + argv[1] = "-a"; + argv[2] = "Koto"; + argv[3] = "-i"; + argv[4] = icon_name; + argv[5] = "-c"; + argv[6] = "x-gnome.music"; + argv[7] = "-h"; + argv[8] = "string:desktop-entry:com.github.joshstrobl.koto"; + argv[9] = g_strdup(track_name); + argv[10] = artist_album_combo; + argv[11] = NULL; + + g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); + } } void koto_playback_engine_set_volume(KotoPlaybackEngine *self, gdouble volume) { diff --git a/src/playback/mpris.c b/src/playback/mpris.c index 4f995c0..cb4c11d 100644 --- a/src/playback/mpris.c +++ b/src/playback/mpris.c @@ -200,15 +200,14 @@ GVariant* handle_get_property( } if (g_strcmp0(property_name, "Metadata") == 0) { // Metadata - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); - KotoIndexedTrack *current_track = koto_playback_engine_get_current_track(playback_engine); if (KOTO_IS_INDEXED_TRACK(current_track)) { // Currently playing a track - koto_push_track_info_to_builder(builder, current_track); + ret = koto_indexed_track_get_metadata_vardict(current_track); + } else { // No track + GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); // Create an empty builder + ret = g_variant_builder_end(builder); // return the vardict } - - ret = g_variant_builder_end(builder); } if ( @@ -277,69 +276,6 @@ gboolean handle_set_property( return FALSE; } -void koto_push_track_info_to_builder(GVariantBuilder *builder, KotoIndexedTrack *track) { - if (!KOTO_IS_INDEXED_TRACK(track)) { - return; - } - - gchar *album_art_path = NULL; - gchar *album_name = NULL; - gchar *album_uuid = NULL; - gchar *artist_uuid = NULL; - gchar *artist_name = NULL; - gchar *track_name = NULL; - gchar *track_path = NULL; - gchar *track_uuid = NULL; - guint track_position = 0; - guint track_disc = 0; - - g_object_get(track, - "album-uuid", &album_uuid, - "artist-uuid", &artist_uuid, - "cd", &track_disc, - "path", &track_path, - "parsed-name", &track_name, - "position", &track_position, - "uuid", &track_uuid, - NULL); - - KotoIndexedArtist *artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); - KotoIndexedAlbum *album = koto_cartographer_get_album_by_uuid(koto_maps, album_uuid); - - g_object_get(album, - "art-path", &album_art_path, - "name", &album_name, - NULL); - - g_object_get(artist, - "name", &artist_name, - NULL); - - g_variant_builder_add(builder, "{sv}", "mpris:trackid", g_variant_new_string(track_uuid)); - - if (koto_utils_is_string_valid(album_art_path)) { // Valid album art path - album_art_path = g_strconcat("file://", album_art_path, NULL); // Prepend with file:// - g_variant_builder_add(builder, "{sv}", "mpris:artUrl", g_variant_new_string(album_art_path)); - } - - g_variant_builder_add(builder, "{sv}", "xesam:album", g_variant_new_string(album_name)); - - if (koto_utils_is_string_valid(artist_name)) { // Valid artist name - GVariant *artist_name_variant; - GVariantBuilder *artist_list_builder = g_variant_builder_new(G_VARIANT_TYPE("as")); - g_variant_builder_add(artist_list_builder, "s", artist_name); - artist_name_variant = g_variant_new("as", artist_list_builder); - g_variant_builder_unref(artist_list_builder); - - g_variant_builder_add(builder, "{sv}", "xesam:artist", artist_name_variant); - } - - g_variant_builder_add(builder, "{sv}", "xesam:discNumber", g_variant_new_uint64(track_disc)); - g_variant_builder_add(builder, "{sv}", "xesam:title", g_variant_new_string(track_name)); - g_variant_builder_add(builder, "{sv}", "xesam:url", g_variant_new_string(track_path)); - g_variant_builder_add(builder, "{sv}", "xesam:trackNumber", g_variant_new_uint64(track_position)); -} - void koto_update_mpris_playback_state(GstState state) { GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); @@ -366,12 +302,17 @@ void koto_update_mpris_info_for_track(KotoIndexedTrack *track) { return; } - GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); - GVariantBuilder *metadata_builder = g_variant_builder_new(G_VARIANT_TYPE_VARDICT); + GVariant *metadata = koto_indexed_track_get_metadata_vardict(track); // Get the GVariantBuilder variable dict for the metadata + koto_update_mpris_info_for_track_with_metadata(track, metadata); +} - koto_push_track_info_to_builder(metadata_builder, track); - GVariant *metadata_ret = g_variant_builder_end(metadata_builder); - g_variant_builder_add(builder, "{sv}", "Metadata", metadata_ret); +void koto_update_mpris_info_for_track_with_metadata(KotoIndexedTrack *track, GVariant *metadata) { + if (!KOTO_IS_INDEXED_TRACK(track)) { + return; + } + + GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); + g_variant_builder_add(builder, "{sv}", "Metadata", metadata); g_dbus_connection_emit_signal(dbus_conn, NULL, diff --git a/src/playback/mpris.h b/src/playback/mpris.h index ce15e02..097acd1 100644 --- a/src/playback/mpris.h +++ b/src/playback/mpris.h @@ -21,9 +21,9 @@ #include #include "../indexer/structs.h" -void koto_push_track_info_to_builder(GVariantBuilder *builder, KotoIndexedTrack *track); void koto_update_mpris_playback_state(GstState state); void koto_update_mpris_info_for_track(KotoIndexedTrack *track); +void koto_update_mpris_info_for_track_with_metadata(KotoIndexedTrack *track, GVariant *metadata); void handle_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data); GVariant* handle_get_property(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data); gboolean handle_set_property(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data);