Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kew for openSUSE:Factory checked in at 2024-01-26 22:48:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kew (Old) and /work/SRC/openSUSE:Factory/.kew.new.1815 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kew" Fri Jan 26 22:48:15 2024 rev:10 rq:1141779 version:2.1.1 Changes: -------- --- /work/SRC/openSUSE:Factory/kew/kew.changes 2024-01-22 20:38:36.902839446 +0100 +++ /work/SRC/openSUSE:Factory/.kew.new.1815/kew.changes 2024-01-26 22:48:30.506879931 +0100 @@ -1,0 +2,8 @@ +Fri Jan 26 15:47:54 UTC 2024 - Muhammad Akbar Yanuar Mantari <mantari...@pm.me> + +- Update to version 2.1.1 + * Fixed a few issues related to passing cover art url and track + length to mpris. Should now display cover and progress + correctly in widgets on gnome/wayland. + +------------------------------------------------------------------- Old: ---- kew-2.0.4.tar.gz New: ---- kew-2.1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kew.spec ++++++ --- /var/tmp/diff_new_pack.4V5FCb/_old 2024-01-26 22:48:31.226905861 +0100 +++ /var/tmp/diff_new_pack.4V5FCb/_new 2024-01-26 22:48:31.230906005 +0100 @@ -17,7 +17,7 @@ Name: kew -Version: 2.0.4 +Version: 2.1.1 Release: 0 Summary: A command-line music player License: GPL-2.0-only ++++++ kew-2.0.4.tar.gz -> kew-2.1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/kew.c new/kew-2.1.1/src/kew.c --- old/kew-2.0.4/src/kew.c 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/kew.c 2024-01-26 15:17:06.000000000 +0100 @@ -370,7 +370,7 @@ pthread_mutex_unlock(&(loadingdata.mutex)); } - emitMetadataChanged("", "", "", "", "/org/mpris/MediaPlayer2/TrackList/NoTrack", NULL); + emitMetadataChanged("", "", "", "", "/org/mpris/MediaPlayer2/TrackList/NoTrack", NULL, 0); emitPlaybackStoppedMpris(); @@ -461,13 +461,15 @@ if (refresh && songData != NULL && songData->deleted == false && songData->hasErrors == false && currentSong != NULL && songData->metadata != NULL) { + gint64 length = llround((*songData->duration) * G_USEC_PER_SEC); // update mpris emitMetadataChanged( songData->metadata->title, songData->metadata->artist, songData->metadata->album, songData->coverArtPath, - songData->trackId != NULL ? songData->trackId : "", currentSong); + songData->trackId != NULL ? songData->trackId : "", currentSong, + length); } printPlayer(songData, elapsedSeconds, &playlist); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/mpris.c new/kew-2.1.1/src/mpris.c --- old/kew-2.0.4/src/mpris.c 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/mpris.c 2024-01-26 15:17:06.000000000 +0100 @@ -16,7 +16,6 @@ static const gchar *LoopStatus = "None"; static gdouble Rate = 1.0; static gdouble Volume = 0.5; -static gint64 Position = 0; static gdouble MinimumRate = 1.0; static gdouble MaximumRate = 1.0; static gboolean CanGoNext = TRUE; @@ -263,6 +262,11 @@ } } +static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ + // g_print("Acquired bus name: %s\n", name); +} + static void on_bus_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { // g_print("Acquired bus name: %s\n", name); @@ -349,11 +353,19 @@ artistList[0] = ""; artistList[1] = NULL; } + + gchar *coverArtUrl = g_strdup_printf("file://%s", currentSongData->coverArtPath); + g_variant_builder_add(&metadata_builder, "{sv}", "xesam:artist", g_variant_new_strv(artistList, -1)); g_variant_builder_add(&metadata_builder, "{sv}", "xesam:album", g_variant_new_string(currentSongData->metadata->album)); g_variant_builder_add(&metadata_builder, "{sv}", "xesam:contentCreated", g_variant_new_string(currentSongData->metadata->date)); - g_variant_builder_add(&metadata_builder, "{sv}", "mpris:artUrl", g_variant_new_string(currentSongData->coverArtPath)); + g_variant_builder_add(&metadata_builder, "{sv}", "mpris:artUrl", g_variant_new_string(coverArtUrl)); g_variant_builder_add(&metadata_builder, "{sv}", "mpris:trackid", g_variant_new_object_path(currentSongData->trackId)); + + gint64 length = llround((*currentSongData->duration) * G_USEC_PER_SEC); + g_variant_builder_add(&metadata_builder, "{sv}", "mpris:length", g_variant_new_int64(length)); + + g_free(coverArtUrl); } else { @@ -363,6 +375,9 @@ g_variant_builder_add(&metadata_builder, "{sv}", "xesam:contentCreated", g_variant_new_string("")); g_variant_builder_add(&metadata_builder, "{sv}", "mpris:artUrl", g_variant_new_string("")); g_variant_builder_add(&metadata_builder, "{sv}", "mpris:trackid", g_variant_new_object_path("/org/mpris/MediaPlayer2/TrackList/NoTrack")); + + gint64 placeholderLength = 0; + g_variant_builder_add(&metadata_builder, "{sv}", "mpris:length", g_variant_new_int64(placeholderLength)); } GVariant *metadata_variant = g_variant_builder_end(&metadata_builder); @@ -387,7 +402,11 @@ const gchar *property_name, GVariant **value, GError **error, gpointer user_data) { - *value = g_variant_new_int64(Position); + // Convert elapsedSeconds from milliseconds to microseconds + gint64 positionMicroseconds = llround(elapsedSeconds * G_USEC_PER_SEC); + + *value = g_variant_new_int64(positionMicroseconds); + return TRUE; } @@ -692,69 +711,66 @@ void initMpris() { - if (global_main_context == NULL) + GError *error = NULL; + connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); + if (!connection) { - global_main_context = g_main_context_new(); + g_printerr("Failed to connect to D-Bus: %s\n", error->message); + g_error_free(error); + exit(1); } - GDBusNodeInfo *introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); - connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); + bus_name_id = g_bus_own_name(G_BUS_TYPE_SESSION, + "org.mpris.MediaPlayer2.kew", + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_bus_name_acquired, + on_bus_name_lost, + NULL, + NULL); - if (!connection) + if (bus_name_id == 0) { - g_printerr("Failed to connect to D-Bus\n"); - exit(0); + printf("Failed to initiate owning D-Bus name.\n"); + exit(1); } - const char *app_name = "org.mpris.MediaPlayer2.kew"; - char unique_name[256]; - snprintf(unique_name, sizeof(unique_name), "%s%d", app_name, getpid()); - - GError *error = NULL; - bus_name_id = g_bus_own_name_on_connection(connection, - unique_name, - G_BUS_NAME_OWNER_FLAGS_NONE, - on_bus_name_acquired, - on_bus_name_lost, - NULL, - NULL); - - if (bus_name_id == 0) + GDBusNodeInfo *introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error); + if (!introspection_data) { - printf("Failed to own D-Bus name: %s\n", unique_name); - exit(0); + g_printerr("Failed to load introspection data: %s\n", error->message); + g_error_free(error); + exit(1); } - registration_id = g_dbus_connection_register_object( - connection, - "/org/mpris/MediaPlayer2", - introspection_data->interfaces[0], - &media_player_interface_vtable, - NULL, - NULL, - &error); + registration_id = g_dbus_connection_register_object(connection, + "/org/mpris/MediaPlayer2", + introspection_data->interfaces[0], + &media_player_interface_vtable, + NULL, + NULL, + &error); - if (!registration_id) + if (registration_id == 0) { g_printerr("Failed to register media player object: %s\n", error->message); g_error_free(error); - exit(0); + exit(1); } - player_registration_id = g_dbus_connection_register_object( - connection, - "/org/mpris/MediaPlayer2", - introspection_data->interfaces[1], - &player_interface_vtable, - NULL, - NULL, - &error); + player_registration_id = g_dbus_connection_register_object(connection, + "/org/mpris/MediaPlayer2", + introspection_data->interfaces[1], + &player_interface_vtable, + NULL, + NULL, + &error); - if (!player_registration_id) + if (player_registration_id == 0) { - g_printerr("Failed to register media player object: %s\n", error->message); + g_printerr("Failed to register player object: %s\n", error->message); g_error_free(error); - exit(0); + exit(1); } } @@ -770,17 +786,14 @@ NULL); } -void emitMetadataChanged(const gchar *title, const gchar *artist, const gchar *album, const gchar *coverArtPath, const gchar *trackId, Node *currentSong) +void emitMetadataChanged(const gchar *title, const gchar *artist, const gchar *album, const gchar *coverArtPath, const gchar *trackId, Node *currentSong, gint64 length) { - // Convert the coverArtPath to a valid URL format gchar *coverArtUrl = g_strdup_printf("file://%s", coverArtPath); - // Create a GVariantBuilder for the metadata dictionary GVariantBuilder metadata_builder; g_variant_builder_init(&metadata_builder, G_VARIANT_TYPE_DICTIONARY); g_variant_builder_add(&metadata_builder, "{sv}", "xesam:title", g_variant_new_string(title)); - // Build list of strings for artist const gchar *artistList[2]; if (artist) { @@ -797,6 +810,7 @@ g_variant_builder_add(&metadata_builder, "{sv}", "xesam:album", g_variant_new_string(album)); g_variant_builder_add(&metadata_builder, "{sv}", "mpris:artUrl", g_variant_new_string(coverArtUrl)); g_variant_builder_add(&metadata_builder, "{sv}", "mpris:trackid", g_variant_new_object_path(trackId)); + g_variant_builder_add(&metadata_builder, "{sv}", "mpris:length", g_variant_new_int64(length)); GVariantBuilder changed_properties_builder; g_variant_builder_init(&changed_properties_builder, G_VARIANT_TYPE("a{sv}")); @@ -809,4 +823,6 @@ g_variant_builder_clear(&metadata_builder); g_variant_builder_clear(&changed_properties_builder); + + g_free(coverArtUrl); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/mpris.h new/kew-2.1.1/src/mpris.h --- old/kew-2.0.4/src/mpris.h 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/mpris.h 2024-01-26 15:17:06.000000000 +0100 @@ -19,7 +19,7 @@ void emitBooleanPropertyChanged(const gchar *propertyName, gboolean newValue); -void emitMetadataChanged(const gchar *title, const gchar *artist, const gchar *album, const gchar *coverArtPath, const gchar *trackId, Node *currentSong); +void emitMetadataChanged(const gchar *title, const gchar *artist, const gchar *album, const gchar *coverArtPath, const gchar *trackId, Node *currentSong, gint64 length); void emitStartPlayingMpris(void); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/player.c new/kew-2.1.1/src/player.c --- old/kew-2.0.4/src/player.c 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/player.c 2024-01-26 15:17:06.000000000 +0100 @@ -24,7 +24,7 @@ AppState appState; -const char VERSION[] = "2.0.4"; +const char VERSION[] = "2.1.1"; const int LOGO_COLOR = 3; const int ARTIST_COLOR = 6; const int ENQUEUED_COLOR = 6; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/playerops.c new/kew-2.1.1/src/playerops.c --- old/kew-2.0.4/src/playerops.c 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/playerops.c 2024-01-26 15:17:06.000000000 +0100 @@ -16,6 +16,7 @@ struct timespec pause_time; struct timespec lastInputTime; struct timespec lastPlaylistChangeTime; +struct timespec lastUpdateTime = {0, 0}; bool playlistNeedsUpdate = false; bool nextSongNeedsRebuilding = false; @@ -87,21 +88,21 @@ void skip() { setCurrentImplementationType(NONE); - + setRepeatEnabled(false); audioData.endOfListReached = false; rebuildAndUpdatePlaylist(); if (!isPlaying()) - { + { switchAudioImplementation(); } else { setSkipToNext(true); } - + refresh = true; } @@ -120,6 +121,42 @@ clock_gettime(CLOCK_MONOTONIC, &lastInputTime); } +void updatePlaybackPosition(double elapsedSeconds) +{ + GVariantBuilder changedPropertiesBuilder; + g_variant_builder_init(&changedPropertiesBuilder, G_VARIANT_TYPE_DICTIONARY); + g_variant_builder_add(&changedPropertiesBuilder, "{sv}", "Position", g_variant_new_int64(llround(elapsedSeconds * G_USEC_PER_SEC))); + + GVariant *parameters = g_variant_new("(sa{sv}as)", "org.mpris.MediaPlayer2.Player", &changedPropertiesBuilder, NULL); + + g_dbus_connection_emit_signal(connection, + NULL, + "/org/mpris/MediaPlayer2", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + parameters, + NULL); + + g_variant_unref(parameters); +} + +void emitSeekedSignal(double newPositionSeconds) +{ + gint64 newPositionMicroseconds = llround(newPositionSeconds * G_USEC_PER_SEC); + + GVariant *parameters = g_variant_new("(x)", newPositionMicroseconds); + + g_dbus_connection_emit_signal(connection, + NULL, + "/org/mpris/MediaPlayer2", + "org.mpris.MediaPlayer2.Player", + "Seeked", + parameters, + NULL); + + g_variant_unref(parameters); +} + void emitStringPropertyChanged(const gchar *propertyName, const gchar *newValue) { GVariantBuilder changed_properties_builder; @@ -218,7 +255,7 @@ } else { - playlist = deepCopyPlayList(originalPlaylist); + playlist = deepCopyPlayList(originalPlaylist); currentSong = findSongInPlaylist(currentSong, &playlist); emitBooleanPropertyChanged("Shuffle", FALSE); } @@ -284,13 +321,17 @@ void calcElapsedTime() { clock_gettime(CLOCK_MONOTONIC, ¤t_time); + + double timeSinceLastUpdate = (double)(current_time.tv_sec - lastUpdateTime.tv_sec) + + (double)(current_time.tv_nsec - lastUpdateTime.tv_nsec) / 1e9; + if (!isPaused()) { elapsedSeconds = (double)(current_time.tv_sec - start_time.tv_sec) + (double)(current_time.tv_nsec - start_time.tv_nsec) / 1e9; double seekElapsed = getSeekElapsed(); double diff = elapsedSeconds + (seekElapsed + seekAccumulatedSeconds - totalPauseSeconds); - + if (diff < 0) seekElapsed -= diff; @@ -304,6 +345,13 @@ { elapsedSeconds = 0.0; } + + if (currentSong != NULL && timeSinceLastUpdate >= 1.0) + { + updatePlaybackPosition(elapsedSeconds); + // Update the last update time to the current time + lastUpdateTime = current_time; + } } else { @@ -336,6 +384,9 @@ } seekPercentage(percentage); + + + emitSeekedSignal(elapsedSeconds); } } @@ -777,7 +828,7 @@ if (loadingdata.loadA) { if (loadingdata.songdataA != NULL) - { + { userData.filenameA = loadingdata.songdataA->pcmFilePath; userData.songdataA = loadingdata.songdataA; @@ -820,7 +871,7 @@ char filepath[MAXPATHLEN]; c_strcpy(filepath, sizeof(filepath), loadingdata->filePath); - + SongData *songdata = NULL; if (loadingdata->loadA) @@ -841,7 +892,7 @@ if (loadingdata->loadA) { - loadingdata->songdataA = songdata; + loadingdata->songdataA = songdata; } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/playerops.h new/kew-2.1.1/src/playerops.h --- old/kew-2.0.4/src/playerops.h 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/playerops.h 2024-01-26 15:17:06.000000000 +0100 @@ -132,4 +132,6 @@ Node *findSelectedEntryById(PlayList *playlist, int id); +void emitSeekedSignal(double newPositionSeconds); + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kew-2.0.4/src/soundgapless.c new/kew-2.1.1/src/soundgapless.c --- old/kew-2.0.4/src/soundgapless.c 2024-01-21 20:47:48.000000000 +0100 +++ new/kew-2.1.1/src/soundgapless.c 2024-01-26 15:17:06.000000000 +0100 @@ -3,6 +3,7 @@ #define MINIAUDIO_IMPLEMENTATION #include <miniaudio.h> #include "soundgapless.h" +#include "mpris.h" /* @@ -113,6 +114,7 @@ result = ma_device_start(device); if (result != MA_SUCCESS) return; + emitStringPropertyChanged("PlaybackStatus", "Playing"); } void builtin_createAudioDevice(UserData *userData, ma_device *device, ma_context *context, ma_data_source_vtable *vtable) @@ -154,6 +156,7 @@ printf("Failed to start miniaudio device.\n"); return; } + emitStringPropertyChanged("PlaybackStatus", "Playing"); } void opus_createAudioDevice(UserData *userData, ma_device *device, ma_context *context, ma_data_source_vtable *vtable) @@ -186,6 +189,7 @@ printf("Failed to start miniaudio device.\n"); return; } + emitStringPropertyChanged("PlaybackStatus", "Playing"); } void cleanupAudioData()