From 8d0775986922ec256b304dc937fc74434e22d27b Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 28 Nov 2017 14:32:59 +0900 Subject: [PATCH] implement metadata for mpris so evene thumbs work for non-thumbed files this allows us to port to artfiles always too... this way music-control displays the albumart. music-control is a bit broken in that it doesnt keep aspect ratio etc. of these. need to fix that over there.... but... it's coming together. --- src/bin/mpris.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++-- src/bin/mpris.h | 1 + src/bin/thumb.c | 8 +++ src/bin/video.c | 132 +++++++++++++++++++++++++++++++++++++------- src/bin/video.h | 5 +- 5 files changed, 261 insertions(+), 29 deletions(-) diff --git a/src/bin/mpris.c b/src/bin/mpris.c index 2820c12..ab9c0ec 100644 --- a/src/bin/mpris.c +++ b/src/bin/mpris.c @@ -45,7 +45,6 @@ https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html * * Not implemented: * Tracklist objects - * Metadata * SetPosition (requires Tracklist objects) * * In rage generally and here: @@ -677,14 +676,140 @@ SETTER(shuffle) return eldbus_message_method_return_new(msg); } -/* GETTER(metadata) { - // XXX: return metadata - eldbus_message_iter_arguments_append(iter, "a{sv}", NULL); + Inf *inf = evas_object_data_get(mainwin, "inf"); + Eldbus_Message_Iter *array = NULL, *entry = NULL, *var, *var2; + uint64_t len = 0; + char *buf = NULL; + const char *s; + + // XXX: TODO: + // mpris:trackid + + eldbus_message_iter_arguments_append(iter, "a{sv}", &array); + + s = video_file_get(inf->vid); + if (s) + { + if (s[0] == '/') + { + buf = alloca(strlen(s) + sizeof("file://") + 1); + sprintf(buf, "file://%s", s); + } + else if (strstr(s, "://")) + { + buf = alloca(strlen(s) + 1); + strcpy(buf, s); + } + else + { + char cwd[PATH_MAX]; + + if (getcwd(cwd, sizeof(cwd) - 1)) + { + cwd[sizeof(cwd) - 1] = 0; + buf = alloca(strlen(cwd) + 1 + strlen(s) + sizeof("file://") + 1); + sprintf(buf, "file://%s/%s", cwd, s); + } + } + } + if (buf) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:url"); + var = eldbus_message_iter_container_new(entry, 'v', "s"); + eldbus_message_iter_basic_append(var, 's', buf); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_artfile_get(inf->vid); + if (s) + { + buf = alloca(strlen(s) + sizeof("file://") + 1); + sprintf(buf, "file://%s", s); + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "mpris:artUrl"); + var = eldbus_message_iter_container_new(entry, 'v', "s"); + eldbus_message_iter_basic_append(var, 's', buf); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_title_get(inf->vid); + if (!s) s = video_meta_title_get(inf->vid); + if (s) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:title"); + var = eldbus_message_iter_container_new(entry, 'v', "s"); + eldbus_message_iter_basic_append(var, 's', buf); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_meta_album_get(inf->vid); + if (s) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:album"); + var = eldbus_message_iter_container_new(entry, 'v', "s"); + eldbus_message_iter_basic_append(var, 's', buf); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_meta_artist_get(inf->vid); + if (s) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:artist"); + var = eldbus_message_iter_container_new(entry, 'v', "as"); + eldbus_message_iter_arguments_append(var, "as", &var2); + eldbus_message_iter_basic_append(var2, 's', s); + eldbus_message_iter_container_close(var, var2); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_meta_comment_get(inf->vid); + if (s) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:comment"); + var = eldbus_message_iter_container_new(entry, 'v', "as"); + eldbus_message_iter_arguments_append(var, "as", &var2); + eldbus_message_iter_basic_append(var2, 's', s); + eldbus_message_iter_container_close(var, var2); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + s = video_meta_genre_get(inf->vid); + if (s) + { + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "xesam:genre"); + var = eldbus_message_iter_container_new(entry, 'v', "as"); + eldbus_message_iter_arguments_append(var, "as", &var2); + eldbus_message_iter_basic_append(var2, 's', s); + eldbus_message_iter_container_close(var, var2); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + } + + len = video_length_get(inf->vid) * 1000000.0; + eldbus_message_iter_arguments_append(array, "{sv}", &entry); + eldbus_message_iter_basic_append(entry, 's', "mpris:length"); + var = eldbus_message_iter_container_new(entry, 'v', "x"); + eldbus_message_iter_basic_append(var, 'x', len); + eldbus_message_iter_container_close(entry, var); + eldbus_message_iter_container_close(array, entry); + + eldbus_message_iter_container_close(iter, array); return EINA_TRUE; } -*/ GETTER(volume) { @@ -782,7 +907,7 @@ static const Eldbus_Property properties_player[] = PROP_RW("LoopStatus", "s", loop_status), PROP_RW("Rate", "d", rate), PROP_RW("Shuffle", "b", shuffle), -// PROP_RO("Metadata", "a{sv}", metadata), + PROP_RO("Metadata", "a{sv}", metadata), PROP_RW("Volume", "d", volume), PROP_RO("Position", "x", position), PROP_RO("MinimumRate", "d", minimum_rate), @@ -949,6 +1074,13 @@ mpris_position_change(double pos) eldbus_service_property_changed(iface_player, "Position"); } +void +mpris_metadata_change(void) +{ + if (!iface_player) return; + eldbus_service_property_changed(iface_player, "Metadata"); +} + void mpris_init(Evas_Object *win) { diff --git a/src/bin/mpris.h b/src/bin/mpris.h index 481e521..045800c 100644 --- a/src/bin/mpris.h +++ b/src/bin/mpris.h @@ -3,5 +3,6 @@ void mpris_volume_change(void); void mpris_loop_status_change(void); void mpris_playback_status_change(void); void mpris_position_change(double pos); +void mpris_metadata_change(void); void mpris_init(Evas_Object *win); void mpris_shutdown(void); diff --git a/src/bin/thumb.c b/src/bin/thumb.c index 12b5c83..288051b 100644 --- a/src/bin/thumb.c +++ b/src/bin/thumb.c @@ -9,6 +9,7 @@ static Evas_Object *vidimage = NULL; static Eet_File *ef = NULL; static Ecore_Timer *vid_timeout = NULL; static Eina_Bool is_audio = EINA_FALSE; +static Eina_Bool is_video = EINA_FALSE; static Eina_Bool is_movie = EINA_FALSE; static int iw, ih, incr = 0; static Eina_Bool poster = 0; @@ -78,6 +79,7 @@ _cb_loaded(void *data, Evas_Object *obj, void *info EINA_UNUSED) (len >= (60.0 * 60.0)) && (len <= (5.0 * 60.0 * 60.0))) is_movie = EINA_TRUE; + if (poster == 2) is_video = EINA_TRUE; } if (is_movie) @@ -86,6 +88,12 @@ _cb_loaded(void *data, Evas_Object *obj, void *info EINA_UNUSED) _cb_fetched, (void *)file); return; } + else if (is_video) + { + albumart_find(file, NULL, NULL, title, NULL, + _cb_fetched, (void *)file); + return; + } else { char buf_base[PATH_MAX]; diff --git a/src/bin/video.c b/src/bin/video.c index 1b31a76..3efc0ae 100644 --- a/src/bin/video.c +++ b/src/bin/video.c @@ -3,6 +3,7 @@ #include "rage_config.h" #include "config.h" #include "albumart.h" +#include "mpris.h" typedef struct _Video Video; @@ -13,6 +14,10 @@ struct _Video Ecore_Timer *smooth_timer; Ecore_Job *restart_job; const char *file; + const char *realfile; + const char *artfile; + Ecore_Exe *exe; + Ecore_Event_Handler *exe_handler; int w, h; int iw, ih, piw, pih, tw, th; int resizes; @@ -33,6 +38,27 @@ static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL; static void _ob_resize(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h); +static Eina_Bool +_cb_thumb_exe(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Exe_Event_Del *ev = event; + Video *sd = evas_object_smart_data_get(data); + char *path; + + if (!sd) return EINA_TRUE; + if (ev->exe == sd->exe) + { + sd->exe = NULL; + if (ev->exit_code == 0) + { + path = albumart_file_get(sd->realfile); + eina_stringshare_replace(&(sd->artfile), path); + mpris_metadata_change(); + } + } + return EINA_TRUE; +} + static void _art_check(Evas_Object *obj) { @@ -50,28 +76,9 @@ _art_check(Evas_Object *obj) } if (sd->doart) { - char *thumb = NULL, *realfile = NULL; + char *thumb = NULL; - evas_object_show(sd->o_img); - if (!strncasecmp(sd->file, "file:/", 6)) - { - Efreet_Uri *uri = efreet_uri_decode(sd->file); - if (uri) - { - realfile = ecore_file_realpath(uri->path); - efreet_uri_free(uri); - } - } - else if ((!strncasecmp(sd->file, "http:/", 6)) || - (!strncasecmp(sd->file, "https:/", 7))) - realfile = strdup(sd->file); - else - realfile = ecore_file_realpath(sd->file); - if (realfile) - { - thumb = albumart_file_get(realfile); - free(realfile); - } + thumb = albumart_file_get(sd->realfile); if (thumb) { Evas_Coord ox, oy, ow, oh; @@ -83,6 +90,8 @@ _art_check(Evas_Object *obj) evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); _ob_resize(obj, ox, oy, ow, oh); } + eina_stringshare_replace(&(sd->artfile), thumb); + mpris_metadata_change(); free(thumb); } } @@ -90,6 +99,39 @@ _art_check(Evas_Object *obj) { evas_object_hide(sd->o_img); } + if (!sd->artfile) + { + char buf[PATH_MAX]; + const char *libdir; + char *s; + + ecore_exe_run_priority_set(10); + s = ecore_file_escape_name(sd->realfile); + if (s) + { + libdir = elm_app_lib_dir_get(); + if (libdir) + { + if (!sd->exe_handler) + sd->exe_handler = ecore_event_handler_add + (ECORE_EXE_EVENT_DEL, _cb_thumb_exe, obj); + snprintf(buf, sizeof(buf), + "%s/rage/utils/rage_thumb %s 10000 %i", + libdir, s, 2); + if (sd->exe) + { + ecore_exe_kill(sd->exe); + ecore_exe_free(sd->exe); + sd->exe = NULL; + } + sd->exe = ecore_exe_pipe_run(buf, + ECORE_EXE_TERM_WITH_PARENT | + ECORE_EXE_NOT_LEADER, + obj); + } + free(s); + } + } } static void @@ -153,11 +195,13 @@ _cb_vid_stop(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) { sd->restart_job = ecore_job_add(_cb_restart, data); evas_object_smart_callback_call(data, "loop", NULL); + mpris_metadata_change(); } else { sd->restart_job = NULL; evas_object_smart_callback_call(data, "stop", NULL); + mpris_metadata_change(); } } @@ -184,6 +228,7 @@ _cb_open_done(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) if (!sd) return; evas_object_smart_callback_call(data, "opened", NULL); _art_check(data); + mpris_metadata_change(); } static void @@ -200,6 +245,7 @@ _cb_length_change(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNU Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "length", NULL); + mpris_metadata_change(); } static void @@ -208,6 +254,7 @@ _cb_title_change(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUS Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "title", NULL); + mpris_metadata_change(); } static void @@ -216,6 +263,7 @@ _cb_audio_change(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUS Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "audio", NULL); + mpris_metadata_change(); } static void @@ -224,6 +272,7 @@ _cb_channels_change(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_U Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "channels", NULL); + mpris_metadata_change(); } static void @@ -232,6 +281,7 @@ _cb_play_start(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "play_start", NULL); + mpris_metadata_change(); } static void @@ -240,6 +290,7 @@ _cb_play_finish(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSE Video *sd = evas_object_smart_data_get(data); if (!sd) return; evas_object_smart_callback_call(data, "play_finish", NULL); + mpris_metadata_change(); } static void @@ -355,6 +406,8 @@ _smart_del(Evas_Object *obj) Video *sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->file) eina_stringshare_del(sd->file); + if (sd->realfile) eina_stringshare_del(sd->realfile); + if (sd->artfile) eina_stringshare_del(sd->artfile); if (sd->clip) evas_object_del(sd->clip); if (sd->o_vid) evas_object_del(sd->o_vid); if (sd->o_img) evas_object_del(sd->o_img); @@ -362,6 +415,17 @@ _smart_del(Evas_Object *obj) if (sd->smooth_timer) sd->smooth_timer = ecore_timer_del(sd->smooth_timer); if (sd->restart_job) ecore_job_del(sd->restart_job); + if (sd->exe) + { + ecore_exe_kill(sd->exe); + ecore_exe_free(sd->exe); + sd->exe = NULL; + } + if (sd->exe_handler) + { + ecore_event_handler_del(sd->exe_handler); + sd->exe_handler = NULL; + } _parent_sc.del(obj); emotion_shutdown(); @@ -563,12 +627,30 @@ video_add(Evas_Object *parent) void video_file_set(Evas_Object *obj, const char *file) { + char *realfile = NULL; Video *sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_hide(sd->o_img); evas_object_hide(sd->o_vid); evas_object_hide(sd->clip); eina_stringshare_replace(&(sd->file), file); + if (!strncasecmp(sd->file, "file:/", 6)) + { + Efreet_Uri *uri = efreet_uri_decode(sd->file); + if (uri) + { + realfile = ecore_file_realpath(uri->path); + efreet_uri_free(uri); + } + } + else if ((!strncasecmp(sd->file, "http:/", 6)) || + (!strncasecmp(sd->file, "https:/", 7))) + realfile = strdup(sd->file); + else + realfile = ecore_file_realpath(sd->file); + eina_stringshare_replace(&(sd->realfile), realfile); + free(realfile); + eina_stringshare_replace(&(sd->artfile), NULL); emotion_object_file_set(sd->o_vid, sd->file); video_position_set(obj, 0.0); if ((sd->file) && (sd->doart)) @@ -1082,6 +1164,14 @@ video_file_autosub_set(Evas_Object *obj, const char *file, const char *sub) video_file_set(obj, file); } +const char * +video_artfile_get(Evas_Object *obj) +{ + Video *sd = evas_object_smart_data_get(obj); + if (!sd) return NULL; + return sd->artfile; +} + // emotion_object_seekable_get // emotion_object_play_speed_set // emotion_object_play_speed_get diff --git a/src/bin/video.h b/src/bin/video.h index 5562882..7c635c4 100644 --- a/src/bin/video.h +++ b/src/bin/video.h @@ -26,7 +26,7 @@ void video_eject(Evas_Object *obj); int video_chapter_count(Evas_Object *obj); void video_chapter_set(Evas_Object *obj, int chapter); int video_chapter_get(Evas_Object *obj); -const char * video_chapter_name_get(Evas_Object *obj, int chapter); +const char *video_chapter_name_get(Evas_Object *obj, int chapter); void video_volume_set(Evas_Object *obj, double vol); double video_volume_get(Evas_Object *obj); Eina_Bool video_has_video_get(Evas_Object *obj); @@ -56,5 +56,6 @@ const char *video_meta_year_get(Evas_Object *obj); const char *video_meta_genre_get(Evas_Object *obj); const char *video_meta_comment_get(Evas_Object *obj); void video_file_autosub_set(Evas_Object *obj, const char *file, const char *sub); -Evas_Object * video_meta_artwork_get(Evas_Object *obj, const char *path, int type); +Evas_Object *video_meta_artwork_get(Evas_Object *obj, const char *path, int type); +const char *video_artfile_get(Evas_Object *obj); #endif