[grilo] grl-launch: Add tool to use Grilo from command-line



commit 45ef80ea31ce5461df34a7d16a75b03a13318afe
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Fri Mar 28 10:29:39 2014 +0100

    grl-launch: Add tool to use Grilo from command-line
    
    Inspired by gst-launch, this tool allows to use Grilo from command line,
    invoking most of commands and features in a simple way.
    
    Results can be saved to filename and loaded later with a spreadsheet, as
    results are stored in CSV format.
    grl-launch: Add tool to use Grilo from command-line
    
    Inspired by gst-launch, this tool allows to use Grilo from command line,
    invoking most of commands and features in a simple way.
    
    Results can be saved to filename and loaded later with a spreadsheet, as
    results are stored in CSV format.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=727223

 configure.ac                    |    1 +
 tools/Makefile.am               |    4 +-
 tools/grilo-launch/Makefile.am  |   25 ++
 tools/grilo-launch/grl-launch.c |  678 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 706 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 4436503..b5f6fc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -332,6 +332,7 @@ AC_CONFIG_FILES([
   tools/Makefile
   tools/grilo-test-ui/Makefile
   tools/grilo-inspect/Makefile
+  tools/grilo-launch/Makefile
   bindings/Makefile
   bindings/vala/Makefile
   bindings/vala/grilo-uninstalled.files
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 5ca65be..575d7c2 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -5,12 +5,12 @@
 #
 # Copyright (C) 2010 Igalia S.L. All rights reserved.
 
-SUBDIRS = grilo-inspect
+SUBDIRS = grilo-inspect grilo-launch
 
 if BUILD_GRILO_TEST_UI
 SUBDIRS += grilo-test-ui
 endif
 
-DIST_SUBDIRS = grilo-test-ui grilo-inspect
+DIST_SUBDIRS = grilo-test-ui grilo-inspect grilo-launch
 
 -include $(top_srcdir)/git.mk
diff --git a/tools/grilo-launch/Makefile.am b/tools/grilo-launch/Makefile.am
new file mode 100644
index 0000000..f9c3304
--- /dev/null
+++ b/tools/grilo-launch/Makefile.am
@@ -0,0 +1,25 @@
+#
+# Makefile.am
+#
+# Author: Juan A. Suarez Romero <jasuarez igalia com>
+#
+# Copyright (C) 2014 Igalia S.L.
+
+INCLUDES = $(DEPS_CFLAGS)
+
+bin_PROGRAMS =       \
+   grl-launch- GRL_MAJORMINOR@
+
+grl_launch_ GRL_MAJORMINOR@_SOURCES =  \
+   grl-launch.c
+
+grl_launch_ GRL_MAJORMINOR@_CFLAGS =   \
+   -DPREFIX=$(prefix)                  \
+   -I$(top_srcdir)/src                 \
+   -I$(top_srcdir)/src/data
+
+grl_launch_ GRL_MAJORMINOR@_LDADD =    \
+   $(DEPS_LIBS)                        \
+   $(top_builddir)/src/lib GRL_NAME@.la
+
+-include $(top_srcdir)/git.mk
diff --git a/tools/grilo-launch/grl-launch.c b/tools/grilo-launch/grl-launch.c
new file mode 100644
index 0000000..21918ed
--- /dev/null
+++ b/tools/grilo-launch/grl-launch.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <grilo.h>
+#include <glib.h>
+
+#include "config.h"
+
+#define GRL_LOG_DOMAIN_DEFAULT grl_launch_log_domain
+GRL_LOG_DOMAIN_STATIC(grl_launch_log_domain);
+
+static GMainLoop *mainloop = NULL;
+static GOptionContext *context = NULL;
+static GrlMediaSerializeType serialize_type;
+static GrlRegistry *registry = NULL;
+static gboolean full;
+static gboolean serialize;
+static gboolean titles;
+static gboolean version;
+static gchar **operation_list = NULL;
+static gchar *conffile = NULL;
+static gchar *flags_parameter;
+static gchar *keys_parameter;
+static gint count = G_MAXINT;
+static gint delay = 1;
+static gint skip = 0;
+
+static GOptionEntry entries[] = {
+  { "config", 'C', 0,
+    G_OPTION_ARG_STRING, &conffile,
+    "Configuration file to send to sources",
+    NULL },
+  { "count", 'c', 0,
+    G_OPTION_ARG_INT, &count,
+    "Number of elements to return",
+    NULL },
+  { "delay", 'd', 0,
+    G_OPTION_ARG_INT, &delay,
+    "Wait some seconds before performing the operation (default 1 second)",
+    NULL },
+  { "flags", 'f', 0,
+    G_OPTION_ARG_STRING, &flags_parameter,
+    "List of comma-separated flags to use",
+    "full|fast_only|idle_relay" },
+  { "full", 'F', 0,
+    G_OPTION_ARG_NONE, &full,
+    "Full serialize",
+    NULL },
+  { "keys", 'k', 0,
+    G_OPTION_ARG_STRING, &keys_parameter,
+    "List of comma-separated keys to retrieve",
+    NULL },
+  { "serialize", 'S', 0,
+    G_OPTION_ARG_NONE, &serialize,
+    "Serialize",
+    NULL },
+  { "skip", 's', 0,
+    G_OPTION_ARG_INT, &skip,
+    "Number of elements to skip",
+    NULL },
+  { "titles", 'T', 0,
+    G_OPTION_ARG_NONE, &titles,
+    "Print titles",
+    NULL },
+  { "version", 'V', 0,
+    G_OPTION_ARG_NONE, &version,
+    "Print version",
+    NULL },
+  { G_OPTION_REMAINING, '\0', 0,
+    G_OPTION_ARG_STRING_ARRAY, &operation_list,
+    "<operation> <options>",
+    NULL },
+  { NULL }
+};
+
+static gboolean
+quit (gboolean print_help)
+{
+  gchar *help;
+
+  if (print_help) {
+    help = g_option_context_get_help (context, TRUE, NULL);
+    g_print ("%s", help);
+    g_free (help);
+  }
+
+  g_main_loop_quit (mainloop);
+  return FALSE;
+}
+
+static void
+print_version (void)
+{
+  g_print ("grl-launch-" GRL_MAJORMINOR " version " VERSION "\n");
+  g_print ("Grilo " VERSION "\n");
+  g_print ("https://wiki.gnome.org/Projects/Grilo\n";);
+}
+
+static void
+print_key (GrlMedia *media,
+           GrlKeyID key)
+{
+  GByteArray *binary_blob;
+  const GValue *value;
+  gboolean has_comma;
+  gchar *str_value;
+
+  value = grl_data_get (GRL_DATA (media), key);
+
+  if (!value) {
+    return;
+  }
+
+  if (G_VALUE_HOLDS_STRING (value)) {
+    str_value = (gchar *) g_value_get_string (value);
+    has_comma = g_strstr_len (str_value, -1, ",") != NULL;
+    if (has_comma) {
+      g_print ("\"%s\"", str_value);
+    } else {
+      g_print ("%s", str_value);
+    }
+  } else if (G_VALUE_HOLDS_INT (value)) {
+    g_print ("%d", g_value_get_int (value));
+  } else if (G_VALUE_HOLDS_FLOAT (value)) {
+    g_print ("%f", g_value_get_float (value));
+  } else if (G_VALUE_HOLDS_BOOLEAN (value)) {
+    g_print ("%s", g_value_get_boolean (value)? "true": "false");
+  } else if (G_VALUE_TYPE (value) == G_TYPE_BYTE_ARRAY) {
+    binary_blob = g_value_get_boxed (value);
+    str_value = g_base64_encode (binary_blob->data, binary_blob->len);
+    g_print ("%s", str_value);
+    g_free (str_value);
+  } else if (G_VALUE_TYPE (value) == G_TYPE_DATE_TIME) {
+    str_value = g_date_time_format (g_value_get_boxed (value), "%FT%T");
+    g_print ("%s", str_value);
+    g_free (str_value);
+  }
+}
+
+static void
+print_titles (GList *keys)
+{
+  gboolean print_newline = FALSE;
+
+  if (!titles) {
+    return;
+  }
+
+  if (serialize || keys) {
+    print_newline = TRUE;
+  }
+
+  if (serialize) {
+    g_print ("media");
+    if (keys) {
+      g_print (",");
+    }
+  }
+
+  while (keys) {
+    g_print ("%s", grl_metadata_key_get_name (GRLPOINTER_TO_KEYID (keys->data)));
+    keys = g_list_next (keys);
+    if (keys) {
+      g_print (",");
+    }
+  }
+
+  if (print_newline) {
+    g_print ("\n");
+  }
+}
+
+static void
+print_result_cb (GrlSource *source,
+                 guint operation_id,
+                 GrlMedia *media,
+                 guint remaining,
+                 gpointer user_data,
+                 const GError *error)
+{
+  GList *keys = (GList *) user_data;
+  gboolean print_newline = FALSE;
+  gchar *media_serial;
+  static guint total_results = 0;
+
+  if (error) {
+    g_print ("Error: %s\n", error->message);
+  }
+
+  if (media) {
+    if (serialize || keys) {
+      print_newline = TRUE;
+    }
+
+    total_results++;
+    if (serialize) {
+      media_serial = grl_media_serialize_extended (media, serialize_type);
+      g_print ("%s", media_serial);
+      g_free (media_serial);
+      if (keys) {
+        g_print (",");
+      }
+    }
+    while (keys) {
+      print_key (media, GRLPOINTER_TO_KEYID (keys->data));
+      keys = g_list_next (keys);
+      if (keys) {
+        g_print (",");
+      }
+    }
+
+    g_object_unref (media);
+
+    if (print_newline) {
+      g_print ("\n");
+    }
+  }
+
+  if (remaining == 0) {
+    switch (total_results) {
+    case 0:
+      g_print ("No results\n");
+      break;
+    case 1:
+      g_print ("1 result\n");
+      break;
+    default:
+      g_print ("%u results\n", total_results);
+    }
+    g_list_free (keys);
+    quit (FALSE);
+  }
+}
+
+static void
+print_single_result_cb (GrlSource *source,
+                        guint operation_id,
+                        GrlMedia *media,
+                        gpointer user_data,
+                        const GError *error)
+{
+  print_result_cb (source, operation_id, media, 0, user_data, error);
+}
+
+static GList *
+get_keys (void)
+{
+  GList *keys = NULL;
+  GrlKeyID key;
+  GrlRegistry *registry;
+  gchar **keys_array;
+  gint i;
+
+  if (!keys_parameter) {
+    return NULL;
+  }
+
+  registry = grl_registry_get_default ();
+  keys_array = g_strsplit (keys_parameter, ",", -1);
+
+  for (i = 0; keys_array[i]; i++) {
+    if (g_strcmp0 (keys_array[i], "*") == 0) {
+      g_list_free (keys);
+      g_strfreev (keys_array);
+      return grl_registry_get_metadata_keys (registry);
+    }
+
+    key = grl_registry_lookup_metadata_key (registry, keys_array[i]);
+    if (key == GRL_METADATA_KEY_INVALID) {
+      g_print ("Unknown %s key\n", keys_array[i]);
+    } else {
+      keys = g_list_append (keys, GRLKEYID_TO_POINTER (key));
+    }
+  }
+
+  g_strfreev (keys_array);
+
+  return keys;
+}
+
+static GrlResolutionFlags
+get_flags (void)
+{
+  GrlResolutionFlags flags = GRL_RESOLVE_NORMAL;
+  gchar **flags_array;
+  gint i;
+
+  if (!flags_parameter) {
+    return flags;
+  }
+
+  flags_array = g_strsplit (flags_parameter, ",", -1);
+
+  for (i = 0; flags_array[i]; i++) {
+    if (g_strcmp0 (flags_array[i], "full") == 0) {
+      flags |= GRL_RESOLVE_FULL;
+    } else if (g_strcmp0 (flags_array[i], "idle_relay") == 0) {
+      flags |= GRL_RESOLVE_IDLE_RELAY;
+    } else if (g_strcmp0 (flags_array[i], "fast_only") == 0) {
+      flags |= GRL_RESOLVE_FAST_ONLY;
+    } else {
+      g_print ("Unknown %s flag\n", flags_array[i]);
+    }
+  }
+
+  g_strfreev (flags_array);
+
+  return flags;
+}
+
+static void
+get_source_and_media (const gchar *str,
+                      GrlSource **source,
+                      GrlMedia **media)
+{
+  GrlRegistry *registry = grl_registry_get_default();
+
+  /* Check if str is a source */
+  *source = grl_registry_lookup_source (registry, str);
+  if (*source) {
+    *media = NULL;
+  } else {
+    /* Check then if this is a media */
+    *media = grl_media_unserialize (str);
+    if (*media) {
+      *source = grl_registry_lookup_source (registry, grl_media_get_source (*media));
+    }
+  }
+}
+
+static gboolean
+run_search (gchar **search_params)
+{
+  GList *keys;
+  GrlOperationOptions *options;
+  GrlRegistry *registry;
+  GrlSource *source;
+  gchar *term;
+
+  if (g_strv_length (search_params) != 2) {
+    return quit (TRUE);
+  }
+
+  /* Empty string means "search all" */
+  if (search_params[0][0] == '\0') {
+    term = NULL;
+  } else {
+    term = search_params[0];
+  }
+
+  registry = grl_registry_get_default ();
+  source = grl_registry_lookup_source (registry, search_params[1]);
+
+  if (!source) {
+    g_print ("%s is not a valid source\n", search_params[1]);
+    return quit (FALSE);
+  }
+
+  if (!(grl_source_supported_operations (source) & GRL_OP_SEARCH)) {
+    g_print ("%s do not support search\n", search_params[1]);
+    return quit (FALSE);
+  }
+
+  keys = get_keys ();
+
+  options = grl_operation_options_new (NULL);
+  grl_operation_options_set_flags (options, get_flags ());
+  grl_operation_options_set_count (options, count);
+  grl_operation_options_set_skip (options, skip);
+
+  print_titles (keys);
+
+  grl_source_search (source, term, keys, options, print_result_cb, keys);
+
+  g_object_unref (options);
+
+  return FALSE;
+}
+
+static gboolean
+run_browse (gchar **browse_params)
+{
+  GList *keys;
+  GrlMedia *media;
+  GrlOperationOptions *options;
+  GrlSource *source;
+
+  if (g_strv_length (browse_params) != 1) {
+    return quit (TRUE);
+  }
+
+  get_source_and_media (browse_params[0], &source, &media);
+  if (media && !GRL_IS_MEDIA_BOX (media)) {
+    g_print ("%s is not a media box\n", browse_params[0]);
+    return quit (FALSE);
+  }
+
+  if (!source) {
+    g_print ("%s is not a valid source\n", browse_params[0]);
+    return quit (FALSE);
+  }
+
+  if (!(grl_source_supported_operations (source)  & GRL_OP_BROWSE)) {
+    g_print ("%s do not support browse\n", grl_source_get_id (source));
+    return quit (FALSE);
+  }
+
+  keys = get_keys();
+
+  options = grl_operation_options_new (NULL);
+  grl_operation_options_set_flags (options, get_flags ());
+  grl_operation_options_set_count (options, count);
+  grl_operation_options_set_skip (options, skip);
+
+  print_titles (keys);
+
+  grl_source_browse (source, media, keys, options, print_result_cb, keys);
+
+  g_object_unref (options);
+
+  return FALSE;
+}
+
+static gboolean
+run_resolve (gchar **resolve_params)
+{
+  GList *print_keys;
+  GList *search_keys;
+  GrlMedia *media;
+  GrlOperationOptions *options;
+  GrlRegistry *registry;
+  GrlSource *source;
+
+  if (g_strv_length (resolve_params) > 2) {
+    return quit (TRUE);
+  }
+
+  get_source_and_media (resolve_params[0], &source, &media);
+
+  if (resolve_params[1]) {
+    /* Ask the other source */
+    registry = grl_registry_get_default ();
+    source = grl_registry_lookup_source (registry, resolve_params[1]);
+  }
+
+  if (!source) {
+    g_print ("%s is not a valid source\n", resolve_params[1]? resolve_params[1]: resolve_params[0]);
+    return quit (FALSE);
+  }
+
+
+  if (!(grl_source_supported_operations (source)  & GRL_OP_RESOLVE)) {
+    g_print ("%s do not support resolve\n", grl_source_get_id (source));
+    return quit (FALSE);
+  }
+
+  print_keys = get_keys();
+
+  if (print_keys) {
+    search_keys = print_keys;
+  } else {
+    /* Resolve requires some key to resolve; let's use "id" */
+    search_keys = g_list_append (NULL, GRLKEYID_TO_POINTER (GRL_METADATA_KEY_ID));
+  }
+
+  options = grl_operation_options_new (NULL);
+  grl_operation_options_set_flags (options, get_flags ());
+
+  print_titles (print_keys);
+
+  grl_source_resolve (source, media, search_keys, options, print_single_result_cb, print_keys);
+
+  g_object_unref (options);
+
+  return FALSE;
+}
+
+static gboolean
+run_may_resolve (gchar **may_resolve_params)
+{
+  GList *required_keys = NULL;
+  GrlKeyID resolve_key;
+  GrlMedia *media;
+  GrlRegistry *registry;
+  GrlSource *source;
+  gboolean may;
+
+  if (g_strv_length (may_resolve_params) > 3) {
+    return quit (TRUE);
+  }
+
+  registry = grl_registry_get_default ();
+  resolve_key = grl_registry_lookup_metadata_key (registry, may_resolve_params[0]);
+  if (resolve_key == GRL_METADATA_KEY_INVALID) {
+    g_print ("Unknown %s key\n", may_resolve_params[0]);
+    return quit (FALSE);
+  }
+
+  get_source_and_media (may_resolve_params[1], &source, &media);
+
+  if (may_resolve_params[2]) {
+    /* Ask the other source */
+    registry = grl_registry_get_default ();
+    source = grl_registry_lookup_source (registry, may_resolve_params[2]);
+  }
+
+  if (!source) {
+    g_print ("%s is not a valid source\n", may_resolve_params[2]? may_resolve_params[2]: 
may_resolve_params[1]);
+    return quit (FALSE);
+  }
+
+
+  if (!(grl_source_supported_operations (source)  & GRL_OP_RESOLVE)) {
+    g_print ("%s do not support resolve\n", grl_source_get_id (source));
+    return quit (FALSE);
+  }
+
+  may = grl_source_may_resolve (source, media, resolve_key, &required_keys);
+
+  if (may) {
+    g_print ("%s can resolve %s key\n", grl_source_get_id (source), may_resolve_params[0]);
+  } else {
+    g_print ("%s cannot resolve %s key", grl_source_get_id (source), may_resolve_params[0]);
+    if (required_keys) {
+      g_print (". It requires ");
+      while (required_keys) {
+        g_print ("%s", grl_metadata_key_get_name (GRLPOINTER_TO_KEYID (required_keys->data)));
+        required_keys = g_list_next (required_keys);
+        if (required_keys) {
+          g_print (",");
+        }
+      }
+    }
+    g_print ("\n");
+  }
+
+  return quit (FALSE);
+}
+
+
+static gboolean
+run_query (gchar **query_params)
+{
+  GList *keys;
+  GrlOperationOptions *options;
+  GrlRegistry *registry;
+  GrlSource *source;
+
+  if (g_strv_length (query_params) != 2) {
+    return quit (TRUE);
+  }
+
+  registry = grl_registry_get_default ();
+  source = grl_registry_lookup_source (registry, query_params[1]);
+
+  if (!source) {
+    g_print ("%s is not a valid source\n", query_params[1]);
+    return quit (FALSE);
+  }
+
+  if (!(grl_source_supported_operations (source) & GRL_OP_QUERY)) {
+    g_print ("%s do not support query\n", query_params[1]);
+    return quit (FALSE);
+  }
+
+  keys = get_keys ();
+
+  options = grl_operation_options_new (NULL);
+  grl_operation_options_set_flags (options, get_flags ());
+  grl_operation_options_set_count (options, count);
+  grl_operation_options_set_skip (options, skip);
+
+  print_titles (keys);
+
+  grl_source_query (source, query_params[0], keys, options, print_result_cb, keys);
+
+  g_object_unref (options);
+
+  return FALSE;
+}
+
+static gboolean
+run (gpointer data)
+{
+  if (!operation_list) {
+    return quit (TRUE);
+  }
+
+  if (g_strcmp0 (operation_list[0], "search") == 0) {
+    return run_search (++operation_list);
+  } else if (g_strcmp0 (operation_list[0], "browse") == 0) {
+    return run_browse (++operation_list);
+  } else if (g_strcmp0 (operation_list[0], "resolve") == 0) {
+    return run_resolve (++operation_list);
+  } else if (g_strcmp0 (operation_list[0], "may_resolve") == 0) {
+    return run_may_resolve (++operation_list);
+  } else if (g_strcmp0 (++operation_list[0], "query") == 0) {
+    return run_query (++operation_list);
+  }
+
+  return quit (TRUE);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GError *error = NULL;
+
+  context = g_option_context_new ("OPERATION PARAMETERS...");
+  g_option_context_add_main_entries (context, entries, NULL);
+  g_option_context_add_group (context, grl_init_get_option_group ());
+  g_option_context_set_summary (context,
+                                "\tbrowse <source>|<media box>\n"
+                                "\tmay_resolve <key> <source>|<media box> [<source>]\n"
+                                "\tquery <expression> <source>\n"
+                                "\tresolve <source>|<media> [<source>]\n"
+                                "\tsearch <term> <source>");
+
+  g_option_context_parse (context, &argc, &argv, &error);
+
+  if (error) {
+    g_printerr ("Invalid arguments, %s\n", error->message);
+    g_clear_error (&error);
+    return -1;
+  }
+
+  if (version) {
+    print_version ();
+    return 0;
+  }
+
+  serialize_type = full? GRL_MEDIA_SERIALIZE_FULL: GRL_MEDIA_SERIALIZE_BASIC;
+
+  grl_init (&argc, &argv);
+
+  GRL_LOG_DOMAIN_INIT (grl_launch_log_domain, "grl-launch");
+
+  registry = grl_registry_get_default ();
+  if (conffile) {
+    grl_registry_add_config_from_file (registry, conffile, &error);
+    if (error) {
+      GRL_WARNING ("Unable to load configuration: %s", error->message);
+      g_error_free (error);
+    }
+  }
+
+  mainloop = g_main_loop_new (NULL, FALSE);
+
+  grl_registry_load_all_plugins (registry, NULL);
+
+  g_timeout_add_seconds ((guint) delay, run, NULL);
+
+  g_main_loop_run (mainloop);
+
+  g_option_context_free (context);
+  grl_deinit ();
+
+  return 0;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]