Implement Notification support. Fixes #8.
Implemented Notification support using notify-send as opposed to libnotify. This is because notify_notification_send does a synchronous dbus call to org.freedesktop.Notification and typically results in DBus timeouts. In the near future we will rewrite this to just use our own proxy and do an async send. Refactored our GVariant metadata generation for a KotoIndexedTrack into a dedicated koto_indexed_track_get_metadata_vardict function. This can then be used across our playback engine and MPRIS.
This commit is contained in:
parent
a3632b8757
commit
3e0e21e246
6 changed files with 115 additions and 74 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gstreamer-1.0/gst/gst.h>
|
||||
#include <libnotify/notify.h>
|
||||
#include "db/cartographer.h"
|
||||
#include "db/db.h"
|
||||
#include "playback/media-keys.h"
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
#include <glib-2.0/glib.h>
|
||||
#include <gstreamer-1.0/gst/gst.h>
|
||||
#include <gstreamer-1.0/gst/player/player.h>
|
||||
#include <gtk-4.0/gtk/gtk.h>
|
||||
#include <libnotify/notify.h>
|
||||
#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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#include <gstreamer-1.0/gst/player/player.h>
|
||||
#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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue