Beispiel #1
0
static char *
program_get_metadata_fallback (MexGenericContent *gc,
                               MexContentMetadata key)
{
  MexContent *content = MEX_CONTENT (gc);
  const gchar *showname;
  gchar *target;

  switch (key) {
  case MEX_CONTENT_METADATA_TITLE:
    showname = mex_content_get_metadata (content,
                                         MEX_CONTENT_METADATA_SERIES_NAME);

    if (!showname) {
      const gchar *url;
      gchar *basename;

      url = mex_content_get_metadata (content, MEX_CONTENT_METADATA_URL);
      basename = g_path_get_basename (url);
      target = g_uri_unescape_string (basename, NULL);
      g_free (basename);
    } else {
      const gchar *episode, *season;

      episode = mex_content_get_metadata (content,
                                          MEX_CONTENT_METADATA_EPISODE);
      season = mex_content_get_metadata (content,
                                         MEX_CONTENT_METADATA_SEASON);

      if (episode && season) {
        target = g_strdup_printf ("%s: Season %s, Episode %s",
                                  showname, season, episode);
      } else if (episode) {
        target = g_strdup_printf ("%s: Episode %s", showname, episode);
      } else if (season) {
        target = g_strdup_printf ("%s: Season %s", showname, season);
      } else {
        target = g_strdup (showname);
      }
    }
    break;

  default:
    target = NULL;
    break;
  }

  return target;
}
/* content view */
static void
mex_music_player_set_content (MexContentView *player,
                              MexContent     *content)
{
  MexMusicPlayerPrivate *priv = MEX_MUSIC_PLAYER (player)->priv;
  gchar *album_artist;
  const gchar *uri, *album, *artist, *title;
  ClutterActorIter iter;
  ClutterActor *child, *container;

  if (priv->content)
    g_object_unref (priv->content);

  priv->content = content;

  if (!content)
    return;

  g_object_ref (content);


  /* title */
  title = mex_content_get_metadata (content, MEX_CONTENT_METADATA_TITLE);
  mx_label_set_text (MX_LABEL (priv->title_label), title);


  /* subtitle (album, artist) */
  album = mex_content_get_metadata (content, MEX_CONTENT_METADATA_ALBUM);
  artist = mex_content_get_metadata (content, MEX_CONTENT_METADATA_ARTIST);
  album_artist = g_strconcat (album, ", ", artist , NULL);
  mx_label_set_text (MX_LABEL (priv->subtitle_label), album_artist);
  g_free (album_artist);

  /* uri */
  uri = mex_content_get_metadata (content, MEX_CONTENT_METADATA_STREAM);
  clutter_media_set_uri (priv->player, uri);

  /* find the item in the list */
  container = mex_script_get_actor (priv->script, "tracks");
  clutter_actor_iter_init (&iter, container);
  while (clutter_actor_iter_next (&iter, &child))
    {
      MexContent *button_content;

      button_content = g_object_get_data (G_OBJECT (child), "content");

      mx_button_set_toggled (MX_BUTTON (child), (button_content == content));
    }
}
static void
_add_remove_recursive (MexModel *queue_model, MexModel *model, gboolean add)
{
  gint len, i;

  len = mex_model_get_length (model);

  for (i=0; i < len; i++)
    {
      MexContent *content;
      const gchar *mimetype;

      content = mex_model_get_content (model, i);

      mimetype = mex_content_get_metadata (content,
                                           MEX_CONTENT_METADATA_MIMETYPE);

      /* Don't accidentally add a directory or group to the queue */
      if (!g_strcmp0 (mimetype, "x-grl/box")
          || !g_strcmp0 (mimetype, "x-mex/group"))
        continue;

      if (add)
        mex_model_add_content (queue_model, content);
      else
        mex_model_remove_content (queue_model, content);
    }
  g_object_unref (model);
}
static void
_update_thumbnail (MexContentTile *tile)
{
  MexContentTilePrivate *priv = tile->priv;
  MexDownloadQueue *queue;
  const gchar *file;

  queue = mex_download_queue_get_default ();

  /* cancel any download already in progress */
  if (priv->download_id)
    {
      mex_download_queue_cancel (queue, priv->download_id);
      priv->download_id = NULL;
    }

  /* update thumbnail */
  file = mex_content_get_metadata (priv->content,
                                   MEX_CONTENT_METADATA_STILL);

  /* TODO: Display a spinner? */
  if (file)
    priv->download_id =
      mex_download_queue_enqueue (queue, file,
                                  download_queue_completed,
                                  tile);
  else
    priv->thumbnail_loaded = TRUE;
}
static void
_update_logo (MexContentTile *tile)
{
  ClutterActor *image;
  GError *err = NULL;
  const gchar *logo_url;

  logo_url = mex_content_get_metadata (tile->priv->content,
                                       MEX_CONTENT_METADATA_STATION_LOGO);
  if (!logo_url)
    {
      mex_tile_set_primary_icon (MEX_TILE (tile), NULL);
      return;
    }

  image = mx_image_new ();

  if (g_str_has_prefix (logo_url, "file://"))
    logo_url = logo_url + 7;

  mx_image_set_from_file_at_size (MX_IMAGE (image), logo_url, 26, 26, &err);

  if (err)
    {
      g_warning ("Could not load station logo: %s", err->message);
      g_clear_error (&err);
      return;
    }

  mex_tile_set_primary_icon (MEX_TILE (tile), image);
}
Beispiel #6
0
void
mex_content_set_last_used_metadatas (MexContent *content)
{
  guint count;
  gchar str[20], *nstr;
  const gchar *play_count;
  GDateTime *datetime;
  GTimeVal tv;

  play_count = mex_content_get_metadata (content,
                                         MEX_CONTENT_METADATA_PLAY_COUNT);
  if (play_count) {
    count = atoi (play_count);
    count++;
  } else
    count = 1;
  snprintf (str, sizeof (str), "%u", count);
  mex_content_set_metadata (content, MEX_CONTENT_METADATA_PLAY_COUNT, str);

  datetime = g_date_time_new_now_local ();
  if (datetime) {
    if (g_date_time_to_timeval (datetime, &tv)) {
      tv.tv_usec = 0;
      nstr = g_time_val_to_iso8601 (&tv);
      if (nstr) {
        mex_content_set_metadata (content,
                                  MEX_CONTENT_METADATA_LAST_PLAYED_DATE,
                                  nstr);
        g_free (nstr);
      }
    }
    g_date_time_unref (datetime);
  }
}
static void
mex_content_box_toggle_open (MexContentBox *box)
{
  MexContentBoxPrivate *priv = box->priv;
  gboolean close_notified, next_is_open;
  const gchar *mimetype;

  /* search history items should not appear in the "open" state */
  mimetype = mex_content_get_metadata (priv->content,
                                       MEX_CONTENT_METADATA_MIMETYPE);
  if (!g_strcmp0 (mimetype, "x-mex/search"))
    return;


  /* if the close animation was cancelled then no notify for the closed state
   * will have been sent, therefore notify for the opened state does not need
   * to be emitted */
  close_notified = (!priv->is_open
                    && !clutter_timeline_is_playing (priv->timeline));

  next_is_open = !priv->is_open;

  if (next_is_open)
    {
      /* opening */
      clutter_timeline_set_direction (priv->timeline,
                                      CLUTTER_TIMELINE_FORWARD);
      mx_stylable_set_style_class (MX_STYLABLE (box), "open");

      /* refresh the action list */
      mex_content_view_set_content (MEX_CONTENT_VIEW (priv->action_list),
                                    priv->content);

      priv->extras_visible = TRUE;
      if (close_notified)
        g_object_notify_by_pspec (G_OBJECT (box), properties[PROP_OPEN]);

      mex_push_focus (MX_FOCUSABLE (priv->action_list));
    }
  else
    {
      priv->is_closing = TRUE;

      /* closing */
      mex_push_focus (MX_FOCUSABLE (priv->tile));
      clutter_timeline_set_direction (priv->timeline,
                                      CLUTTER_TIMELINE_BACKWARD);

      priv->is_closing = FALSE;
      priv->extras_visible = TRUE;
    }

  if (!clutter_timeline_is_playing (priv->timeline))
    clutter_timeline_rewind (priv->timeline);

  clutter_timeline_start (priv->timeline);

  priv->is_open = next_is_open;
}
Beispiel #8
0
/*
 * If we need to, generate a thumbnail.
 *
 * If the URL is not file:/// then we assume it's okay to use.
 *
 */
static void
mex_grilo_program_thumbnail (MexContent *content, GrlMedia *media)
{
  const char *url;
  char *thumb_path;

  /* If the media isn't local, then we'll ignore it for now */
  url = grl_media_get_url (media);
  if (url == NULL || !g_str_has_prefix (url, "file:///"))
    return;

  if (GRL_IS_MEDIA_BOX (media))
    {
      gchar *tmp;

      tmp = g_build_filename (mex_get_data_dir (), "common", "folder-tile.png",
                              NULL);
      mex_grilo_program_set_metadata (content, MEX_CONTENT_METADATA_STILL, tmp);
      g_free (tmp);
      return;
    }

  /*
   * If we're already got a thumbnail, see if we're happy with it or want to
   * ignore it.
   */
  thumb_path = (char*)mex_content_get_metadata (content,
                                                MEX_CONTENT_METADATA_STILL);
  if (thumb_path) {
    /* If the thumbnail is already a good one, we're done */
    if (thumb_path && strstr (thumb_path, "/.thumbnails/x-huge/"))
      return;

    /*
     * If the thumbnail currently set is a "normal" thumbnail we ignore it on the
     * basis that it's likely to have been generated by Totem, and thus is bad.
     * If your platform doesn't have Totem then this can be removed!
     */
    if (thumb_path && strstr (thumb_path, "/.thumbnails/normal/"))
      mex_grilo_program_set_metadata (content, MEX_CONTENT_METADATA_STILL, NULL);
  }

  /*
   * Now see if we've a thumbnail generated already.  TODO: use the Tumbler API
   * to do this.
   */
  thumb_path = get_thumbnail_path_for_uri (url);
  if (g_file_test (thumb_path, G_FILE_TEST_EXISTS)) {
    gchar *thumb_uri = g_filename_to_uri (thumb_path, NULL, NULL);
    mex_grilo_program_set_metadata (content, MEX_CONTENT_METADATA_STILL,
                                    thumb_uri);
    g_free (thumb_uri);
  } else {
    mex_thumbnailer_generate (url, grl_media_get_mime (media),
                              thumbnail_cb, content);
  }
  g_free (thumb_path);
}
static void
mex_content_box_notify_key_focus_cb (ClutterStage  *stage,
                                     GParamSpec    *pspec,
                                     MexContentBox *self)
{
  MexContentBoxPrivate *priv = self->priv;
  ClutterActor *focus = clutter_stage_get_key_focus (stage);

  if (focus == priv->tile)
    {
      gboolean show_info;

      if (mex_content_get_metadata (priv->content,
                                    MEX_CONTENT_METADATA_SYNOPSIS) ||
          mex_content_get_metadata (priv->content,
                                    MEX_CONTENT_METADATA_DATE) ||
          mex_content_get_metadata (priv->content,
                                    MEX_CONTENT_METADATA_CREATION_DATE) ||
          mex_content_get_metadata (priv->content,
                                    MEX_CONTENT_METADATA_DURATION))
        show_info = TRUE;
      else
        {
          MexActionManager *manager = mex_action_manager_get_default ();
          GList *actions =
            mex_action_manager_get_actions_for_content (manager, priv->content);

          if (actions && actions->next)
            show_info = TRUE;
          else
            show_info = FALSE;

          g_list_free (actions);
        }

      if (show_info)
        {
          ClutterActor *icon = mx_icon_new ();
          mx_stylable_set_style_class (MX_STYLABLE (icon), "Info");
          mex_tile_set_secondary_icon (MEX_TILE (priv->tile), icon);
        }
    }
  else
    mex_tile_set_secondary_icon (MEX_TILE (priv->tile), NULL);
}
Beispiel #10
0
static void
mex_search_plugin_mimetype_set_cb (MexContent *content)
{
  const gchar *mime = mex_content_get_metadata (content,
                                                MEX_CONTENT_METADATA_MIMETYPE);
  if (!mime || !(*mime) || g_str_equal (mime, "application/x-shockwave-flash"))
    mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE,
                              "x-mex/media");
}
static void
mex_media_controls_show_description (MexMediaControls *self,
                                     gboolean          show)
{
    MexMediaControlsPrivate *priv = self->priv;
    MxLabel *label;
    ClutterActor *play_pause_button, *stop_button, *placeholder,
                 *add_to_queue_button;
    const gchar *text;

    label = (MxLabel*) clutter_script_get_object (priv->script, "progress-label");

    play_pause_button =
        (ClutterActor*) clutter_script_get_object (priv->script,
                "play-pause-button");
    stop_button =
        (ClutterActor*) clutter_script_get_object (priv->script,
                "stop-button");

    add_to_queue_button =
        (ClutterActor*) clutter_script_get_object (priv->script,
                "add-to-queue-button");

    /* the placeholder actor will accept focus so that the title and description
     * become visible as the user navigates up and down */
    placeholder =
        (ClutterActor*) clutter_script_get_object (priv->script, "placeholder");

    if (show)
    {
        clutter_actor_hide (priv->slider);
        clutter_actor_hide (play_pause_button);
        clutter_actor_hide (stop_button);
        clutter_actor_hide (add_to_queue_button);
        clutter_actor_show (placeholder);

        if (priv->content)
            text = mex_content_get_metadata (priv->content,
                                             MEX_CONTENT_METADATA_SYNOPSIS);
        else
            text = NULL;

        mx_label_set_text (label, (text) ? text : "");
    }
    else
    {
        mx_label_set_text (label, "");
        clutter_actor_show (priv->slider);
        clutter_actor_show (play_pause_button);
        clutter_actor_show (stop_button);
        clutter_actor_show (add_to_queue_button);
        clutter_actor_hide (placeholder);
    }

    priv->show_description = show;
}
Beispiel #12
0
static gint
order_by_func (gconstpointer a,
               gconstpointer b,
               gpointer      user_data)
{
  MexContent **content_a = (MexContent **) a;
  MexContent **content_b = (MexContent **) b;
  SortFuncInfo *info = user_data;
  const gchar *value_a, *value_b;

  value_a = mex_content_get_metadata (*content_a, info->key);
  value_b = mex_content_get_metadata (*content_b, info->key);

  if (info->descending)
    return g_strcmp0 (value_b, value_a);
  else
    return g_strcmp0 (value_a, value_b);

}
static void
_update_thumbnail (MexContentTile *tile)
{
  MexContentTilePrivate *priv = tile->priv;
  MexDownloadQueue *queue;
  const gchar *uri;
  GFile *file;

  queue = mex_download_queue_get_default ();

  /* cancel any download already in progress */
  if (priv->download_id)
    {
      mex_download_queue_cancel (queue, priv->download_id);
      priv->download_id = NULL;
    }

  /* update thumbnail */
  uri = mex_content_get_metadata (priv->content,
                                  MEX_CONTENT_METADATA_STILL);
  if (uri)
    {
      file = g_file_new_for_uri (uri);

      /* TODO: Display a spinner? */
      if (file)
        {
          gchar *path = g_file_get_path (file);

          if (path)
            {
              mx_image_set_from_file_at_size (MX_IMAGE (priv->image), path,
                                              priv->thumb_width,
                                              priv->thumb_height,
                                              NULL);
              priv->thumbnail_loaded = TRUE;
              priv->image_set = TRUE;
              clutter_actor_set_size (priv->image,
                                      priv->thumb_width, priv->thumb_height);
              g_free (path);
            }
          else
            {
              priv->download_id =
                mex_download_queue_enqueue (queue, uri,
                                            download_queue_completed,
                                            tile);
            }

          g_object_unref (file);
        }
    }
  else
    priv->thumbnail_loaded = TRUE;
}
static void
_update_title (MexContentTile *tile)
{
  MexContentTilePrivate *priv = tile->priv;
  const gchar *title;

  /* set title */
  title = mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_TITLE);

  mex_tile_set_label (MEX_TILE (tile), title);
}
Beispiel #15
0
static void
mex_search_plugin_history_cb (MxAction        *action,
                              MexSearchPlugin *self)
{
  MexSearchPluginPrivate *priv = self->priv;
  MexContent *content = mex_action_get_content (action);
  const gchar *text = mex_content_get_metadata (content,
                                                MEX_CONTENT_METADATA_TITLE);

  mx_entry_set_text (MX_ENTRY (priv->search_entry), text);
  mex_search_plugin_search_cb (self);
}
static void
tile_created_cb (MexProxy *proxy,
                 GObject  *content,
                 GObject  *object,
                 gpointer  controls)
{
    const gchar *mime_type;
    ClutterEffect *effect;
    ClutterColor color = { 0, 0, 0, 60 };

    /* filter out folders */
    mime_type = mex_content_get_metadata (MEX_CONTENT (content),
                                          MEX_CONTENT_METADATA_MIMETYPE);

    if (g_strcmp0 (mime_type, "x-grl/box") == 0)
    {
        g_signal_stop_emission_by_name (proxy, "object-created");
        return;
    }

    mex_tile_set_important (MEX_TILE (object), TRUE);
    clutter_actor_set_reactive (CLUTTER_ACTOR (object), TRUE);

    g_object_set (object, "thumb-height", 140, "thumb-width", 250, NULL);

    g_signal_connect (object, "key-press-event", G_CALLBACK (key_press_event_cb),
                      controls);
    g_signal_connect (object, "button-release-event",
                      G_CALLBACK (button_release_event_cb), controls);

    effect = g_object_new (MEX_TYPE_SHADOW,
                           "radius-x", 15,
                           "radius-y", 15,
                           "color", &color,
                           "enabled", FALSE,
                           NULL);
    clutter_actor_add_effect_with_name (CLUTTER_ACTOR (object), "shadow", effect);

    effect = g_object_new (MEX_TYPE_SHADOW,
                           "radius-x", 15,
                           "radius-y", 15,
                           "color", &color,
                           NULL);
    clutter_actor_add_effect_with_name (mx_bin_get_child (MX_BIN (object)),
                                        "shadow", effect);

    g_signal_connect (object, "focus-in", G_CALLBACK (tile_focus_in_cb), NULL);
    g_signal_connect (object, "focus-out", G_CALLBACK (tile_focus_out_cb), NULL);
    tile_focus_out_cb (MX_BIN (object));
}
static void
mex_media_controls_update_header (MexMediaControls *self)
{
    MexMediaControlsPrivate *priv = self->priv;
    ClutterActor *label, *image;
    const gchar *logo_url;
    GError *err = NULL;

    label = (ClutterActor*) clutter_script_get_object (priv->script,
            "title-label");
    image = (ClutterActor*) clutter_script_get_object (priv->script, "logo");

    mx_label_set_text (MX_LABEL (label),
                       mex_content_get_metadata (priv->content,
                               MEX_CONTENT_METADATA_TITLE));

    logo_url = mex_content_get_metadata (priv->content,
                                         MEX_CONTENT_METADATA_STATION_LOGO);
    if (!logo_url)
    {
        clutter_actor_hide (image);
    }
    else
    {
        clutter_actor_show (image);

        if (g_str_has_prefix (logo_url, "file://"))
            logo_url = logo_url + 7;

        mx_image_set_from_file (MX_IMAGE (image), logo_url, &err);
        if (err)
        {
            g_warning ("Could not load logo: %s", err->message);
            g_clear_error (&err);
        }
    }
}
Beispiel #18
0
void
mex_program_get_thumbnail (MexProgram          *program,
                           MexGetThumbnailReply reply,
                           gpointer             userdata)
{
  MexProgramClass *klass;
  MexProgramPrivate *priv;
  const char *still;

  g_return_if_fail (MEX_IS_PROGRAM (program));
  priv = program->priv;

  /* Some backends (eg. Apple trailers) may be able to cache the stream
     so we can just use the standard metadata method to obtain it */
  still = mex_content_get_metadata (MEX_CONTENT (program),
                                    MEX_PROGRAM_METADATA_STILL);
  if (stream != NULL) {
    struct _GetStreamPayload *payload = g_slice_new (struct _GetStreamPayload);
    payload->program = g_object_ref (program);
    payload->reply = reply;
    payload->userdata = userdata;

    /* Technically the stream could be freed before the idle is called
       Great, now I want refcounted strings */
    payload->stream = g_strdup (stream);

    g_idle_add (emit_get_stream_reply, payload);
    return;
  }

  /* Other backends require custom methods to get the stream url */
  klass = MEX_PROGRAM_GET_CLASS (program);
  if (klass->get_stream) {
    klass->get_stream (program, reply, userdata);
  } else {
    struct _GetStreamPayload *payload = g_slice_new (struct _GetStreamPayload);
    payload->program = g_object_ref (program);
    payload->reply = reply;
    payload->userdata = userdata;
    payload->stream = NULL;

    g_idle_add (emit_get_stream_reply, payload);
  }
}
static void
mex_queue_button_update (MexQueueButton *button)
{
  MexQueueButtonPrivate *priv = button->priv;
  if (mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_QUEUED))
    {
      mx_label_set_text (MX_LABEL (priv->label),
                         _("Remove from queue"));

      g_signal_handlers_block_by_func (button,
                                       _queue_button_notify_toggled_cb,
                                       button);
      mx_button_set_toggled (MX_BUTTON (button), TRUE);
      g_signal_handlers_unblock_by_func (button,
                                         _queue_button_notify_toggled_cb,
                                        button);
    } else {
      mx_label_set_text (MX_LABEL (priv->label),
                         _("Add to queue"));

      g_signal_handlers_block_by_func (button,
                                       _queue_button_notify_toggled_cb,
                                       button);
      mx_button_set_toggled (MX_BUTTON (button), FALSE);
      g_signal_handlers_unblock_by_func (button,
                                         _queue_button_notify_toggled_cb,
                                         button);
    }

  if (mx_spinner_get_animating (MX_SPINNER (button->priv->spinner)))
    {
      mx_label_set_text (MX_LABEL (button->priv->label),
                                   _("Adding to queue"));
      clutter_actor_hide (button->priv->icon);
      clutter_actor_show (button->priv->spinner);
    } else {
      clutter_actor_hide (button->priv->spinner);
      clutter_actor_show (button->priv->icon);
  }
}
static void
_queue_button_notify_toggled_cb (MxButton       *button,
                                 GParamSpec     *pspec,
                                 MexQueueButton *q_button)
{
  MexQueueButtonPrivate *priv = q_button->priv;
  const gchar *mimetype;

  gboolean directory;

  mimetype = mex_content_get_metadata (priv->content,
                                       MEX_CONTENT_METADATA_MIMETYPE);
  directory = !g_strcmp0 (mimetype, "x-grl/box")
    || !g_strcmp0 (mimetype, "x-mex/group");

  /* Triggers a train of actions that makes content have it's queued
   * property set which then runs the notify cb which calls
   * mex_queue_button_update so we don't need to run it directly
   */

  if (mx_button_get_toggled (button))
    {
      mex_queue_button_set_animated (q_button, TRUE);

      if (directory)
        _add_from_directory (q_button, TRUE);
      else
        mex_model_add_content (priv->queue_model, priv->content);
    }
  else
    {
      mex_queue_button_set_animated (q_button, FALSE);

      if (directory)
          _add_from_directory (q_button, FALSE);
      else
        mex_model_remove_content (priv->queue_model, priv->content);
    }
}
static void
mex_music_player_set_context (MexContentView *player,
                              MexModel       *model)
{
  MexMusicPlayerPrivate *priv = MEX_MUSIC_PLAYER (player)->priv;
  ClutterActor *box, *button;
  MexContent *content;
  gint i;

  if (priv->model)
    g_object_unref (priv->model);

  priv->model = model;

  if (model)
    g_object_ref (model);

  box = mex_script_get_actor (priv->script, "tracks");
  clutter_actor_remove_all_children (box);

  for (i = 0; (content = mex_model_get_content (model, i)); i++)
    {
      const gchar *title;

      title = mex_content_get_metadata (content, MEX_CONTENT_METADATA_TITLE);
      button = mx_button_new_with_label (title);
      mx_stylable_set_style_class (MX_STYLABLE (button), "Track");
      mx_button_set_is_toggle (MX_BUTTON (button), TRUE);
      g_object_set_data (G_OBJECT (button), "content", content);
      g_signal_connect (button, "clicked",
                        G_CALLBACK (mex_music_player_item_clicked), player);

      mx_button_set_icon_position (MX_BUTTON (button), MX_POSITION_RIGHT);

      clutter_actor_add_child (box, button);
    }
}
static void
mex_content_box_set_content (MexContentView *view,
                             MexContent     *content)
{
  MexContentBox *box = (MexContentBox *) view;
  MexContentBoxPrivate *priv;

  priv = box->priv;

  if (priv->content == content)
    return;

  mex_content_view_set_content (MEX_CONTENT_VIEW (priv->tile), content);
  mex_content_view_set_content (MEX_CONTENT_VIEW (priv->action_list), content);

  if (priv->content)
    {
      GList *l;

      for (l = priv->bindings; l; l = l->next)
        g_object_unref (l->data);

      g_list_free (priv->bindings);
      priv->bindings = NULL;

      g_object_unref (priv->content);
      priv->content = NULL;
    }

  if (content)
    {
      int i;

      priv->content = g_object_ref_sink (content);
      for (i = 0; content_bindings[i].id != MEX_CONTENT_METADATA_NONE; i++)
        {
          const gchar *property;
          GBinding *binding;

          property = mex_content_get_property_name (content,
                                                    content_bindings[i].id);

          if (property == NULL)
            {
              /* The Content does not provide a GObject property for this
               * kind of metadata, we can only sync at creation time */
              const gchar *metadata;

              metadata = mex_content_get_metadata (content,
                                                   content_bindings[i].id);
              g_object_set (box, content_bindings[i].target, metadata, NULL);

              continue;
            }

          if (content_bindings[i].fallback)
            binding = g_object_bind_property_full (content, property,
                                                   box,
                                                   content_bindings[i].target,
                                                   G_BINDING_SYNC_CREATE,
                                                   content_bindings[i].fallback,
                                                   NULL,
                                                   content, NULL);
          else
            binding = g_object_bind_property (content, property, box,
                                              content_bindings[i].target,
                                              G_BINDING_SYNC_CREATE);

          priv->bindings = g_list_prepend (priv->bindings, binding);
        }
    }
}
void
mex_media_controls_set_content (MexMediaControls *self,
                                MexContent       *content,
                                MexModel         *context)
{
    MexMediaControlsPrivate *priv = self->priv;
    gboolean show_description;

    g_return_if_fail (MEX_IS_CONTENT (content));

    if (priv->model == context)
    {
        if (priv->content == content)
            return;

        if (priv->content)
            g_object_unref (priv->content);
        if (content)
            priv->content = g_object_ref_sink (content);

        mex_media_controls_focus_content (self, priv->content);
        mex_media_controls_update_header (self);
        return;
    }

    if (priv->model)
    {
        g_object_unref (priv->model);
        priv->model = NULL;
    }
    if (context)
        priv->model = g_object_ref_sink (context);
    if (priv->content)
    {
        g_object_unref (priv->content);
        priv->content = NULL;
    }
    if (content)
        priv->content = g_object_ref_sink (content);
    priv->is_queue_model = FALSE;

    mex_media_controls_update_header (self);


    /* We may not have a context if we're launched by something like SetUri*/
    if (context)
    {
        MexModel *orig_model;

        orig_model = mex_model_get_model (context);
        g_object_set (G_OBJECT (priv->proxy_model), "model", orig_model, NULL);

        mex_view_model_set_start_content (priv->proxy_model, priv->content);
        mex_view_model_set_loop (priv->proxy_model, TRUE);

        /* Work out if the context was a queue FIXME unreliable */
        /* From coloumn context = MexViewModel MexAggregateModel MexQueueModel */
        /* From grid  context = MexProxyModel MexProxyModel MexQueueModel */

        if (MEX_IS_PROXY_MODEL (context))
        {
            MexModel *model_from_proxy;
            model_from_proxy =
                mex_proxy_model_get_model (MEX_PROXY_MODEL (orig_model));

            if (MEX_IS_QUEUE_MODEL (model_from_proxy))
                priv->is_queue_model = TRUE;
        }
        else if (MEX_IS_AGGREGATE_MODEL (orig_model))
        {
            MexModel *real_model;
            real_model =
                mex_aggregate_model_get_model_for_content (MEX_AGGREGATE_MODEL (orig_model), content);
            if (MEX_IS_QUEUE_MODEL (real_model))
                priv->is_queue_model = TRUE;
        }
    }
    /* Update content on the queue button */
    mex_content_view_set_content (MEX_CONTENT_VIEW (priv->queue_button),
                                  priv->content);

    /* show the description rather than the seek bar for certain content */
    show_description = !g_strcmp0 ("x-mex/tv",
                                   mex_content_get_metadata (priv->content,
                                           MEX_CONTENT_METADATA_MIMETYPE));

    mex_media_controls_show_description(self, show_description);
}
Beispiel #24
0
static void
mex_get_stream_cb (MexProgram   *program,
                   const gchar  *url,
                   const GError *error,
                   gpointer      user_data)
{
  MexPlayer *player = user_data;
  MexPlayerPrivate *priv = player->priv;
  MexGenericContent  *generic_content;
#ifdef USE_PLAYER_CLUTTER_GST
  ClutterGstVideoTexture *video_texture;
#endif

  /* if idle mode has been set before the program stream was found */
  if (priv->idle_mode)
    return;

  if (G_UNLIKELY (error))
    {
      g_warning ("Could not play content: %s (%s)", error->message, url);
      return;
    }

#ifdef USE_PLAYER_CLUTTER_GST
  /* We seek at the precise time when the file is local, but we
   * seek to key frame when streaming */
  video_texture = CLUTTER_GST_VIDEO_TEXTURE (priv->media);
  if (g_str_has_prefix (url, "file://"))
    {
      clutter_gst_video_texture_set_seek_flags (video_texture,
                                                CLUTTER_GST_SEEK_FLAG_ACCURATE);
    }
  else
    {
      clutter_gst_video_texture_set_seek_flags (video_texture,
                                                CLUTTER_GST_SEEK_FLAG_NONE);
    }

  /* TODO when we have settings we can configure this feature */

  if (g_str_has_prefix (mex_content_get_metadata (priv->content,
                                                  MEX_CONTENT_METADATA_MIMETYPE),
                        "audio/"))
    {
      GstElement *gst_element, *visual;
      gint gst_flags;

      gst_element = clutter_gst_video_texture_get_pipeline (video_texture);
      g_object_get (G_OBJECT (gst_element), "flags", &gst_flags, NULL);

      gst_flags = (GST_PLAY_FLAG_VIS | gst_flags);

      g_object_set (G_OBJECT (gst_element), "flags", gst_flags, NULL);

      visual = gst_element_factory_make ("libvisual_infinite", NULL);

      if (visual)
        g_object_set (G_OBJECT (gst_element), "vis-plugin", visual, NULL);
    }
#endif

  clutter_media_set_uri (CLUTTER_MEDIA (priv->media), url);
  generic_content = MEX_GENERIC_CONTENT (priv->content);
  if (mex_generic_content_get_last_position_start (generic_content))
    clutter_media_set_progress (CLUTTER_MEDIA (priv->media), priv->position);
  clutter_media_set_playing (CLUTTER_MEDIA (priv->media), TRUE);
}
GList *
mex_action_manager_get_actions_for_content (MexActionManager *manager,
                                            MexContent      *content)
{
  GList *a, *actions;
  gpointer key, value;
  GHashTableIter iter;
  MexActionManagerPrivate *priv;
  const gchar *last_position, *mime;

  g_return_val_if_fail (MEX_IS_ACTION_MANAGER (manager), NULL);

  mime = mex_content_get_metadata (content, MEX_CONTENT_METADATA_MIMETYPE);

  last_position = mex_content_get_metadata (content,
                                            MEX_CONTENT_METADATA_LAST_POSITION);

  actions = NULL;
  priv = manager->priv;

  g_hash_table_iter_init (&iter, priv->actions);
  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      gint i;
      MexActionInfo *info = value;
      const gchar *action_name;
      action_name = mx_action_get_name (info->action);

      /* If there isn't a last position skip: */
      if (!last_position)
        {
          if (g_str_equal (action_name, "play-from-last") ||
              g_str_equal (action_name, "play-from-begin") ||
              g_str_equal (action_name, "listen-from-begin"))
            continue;
        }
      else
        {
          /* We don't want resume and listen or play because
           * this action is provided by the start
           */
          if (g_str_equal (action_name, "play") ||
              g_str_equal (action_name, "listen"))
            continue;
        }

      /* If we've been asked for actions that apply to a
       * blank mime-type, only return actions that were
       * registered for a blank mime-type.
       */
      if (!mime || !*mime)
        {
          if (!info->mime_types ||
              !info->mime_types[0] ||
              !(*info->mime_types[0]))
            actions = g_list_prepend (actions, info);

          continue;
        }

      /* Add actions that match a mime prefix */
      for (i = 0; info->mime_types[i]; i++)
        {
          if (g_str_has_prefix (mime, info->mime_types[i]))
            {
              actions = g_list_prepend (actions, info);
              break;
            }
        }

      /* Now check that this action isn't for an excluded mimetype */
      if (!info->exclude_mime_types)
        continue;

      for (i = 0; info->exclude_mime_types[i]; i++)
        {
          if (g_str_has_prefix (mime, info->exclude_mime_types[i]))
            {
              actions = g_list_remove (actions, info);
              break;
            }
        }
    }

  actions = g_list_sort (actions, mex_action_manager_sort_cb);
  for (a = actions; a; a = a->next)
    a->data = ((MexActionInfo *)a->data)->action;

  return actions;
}
Beispiel #26
0
/* MexContentView implementation */
static void
mex_player_set_content (MexContentView *view,
                        MexContent     *content)
{
  MexPlayerPrivate *priv = MEX_PLAYER (view)->priv;

  if (priv->model)
    mex_media_controls_set_content (MEX_MEDIA_CONTROLS (priv->controls),
                                    content, priv->model);

  if (priv->related_tile)
    {
      g_object_unref (priv->related_tile);
      priv->related_tile = NULL;
    }

  if (content)
    {
      const gchar *sposition, *sduration;

      if (priv->content) {
        save_old_content (MEX_PLAYER (view));
        g_object_unref (priv->content);
        priv->content = NULL;
      }

      priv->content = g_object_ref_sink (content);

      sposition = mex_content_get_metadata (content,
                                            MEX_CONTENT_METADATA_LAST_POSITION);
      sduration = mex_content_get_metadata (content,
                                            MEX_CONTENT_METADATA_DURATION);


      if (sduration &&
          !mex_media_controls_get_playing_queue (MEX_MEDIA_CONTROLS (priv->controls)))
        priv->duration = atoi (sduration);
      else
        priv->duration = 0;

      if (priv->duration > 0)
        {
          if (sposition)
            {
              int position = atoi (sposition);
              priv->position = (gdouble) position / (gdouble) priv->duration;
            }
          else
            {
              priv->position = 0.0;
            }
        }

      if (MEX_IS_PROGRAM (content))
        {
          mex_program_get_stream (MEX_PROGRAM (content),
                                  mex_get_stream_cb,
                                  view);
        }
      else
        {
          const gchar *uri;

          uri = mex_content_get_metadata (content,
                                          MEX_CONTENT_METADATA_STREAM);
          mex_get_stream_cb (NULL, uri, NULL, view);
        }

      if (priv->info_visible)
        {
          clutter_actor_animate (priv->info_panel, CLUTTER_EASE_IN_SINE,
                                 250, "opacity", 0x00, NULL);
          mx_widget_set_disabled (MX_WIDGET (priv->info_panel), TRUE);
          priv->info_visible = FALSE;
        }

      mex_player_set_controls_visible (MEX_PLAYER (view), TRUE);
    }
  else {
    if (priv->content) {
      g_object_unref (priv->content);
      priv->content = NULL;
    }
  }
}
/* When the MexContent set on the queue button is a directory we
 * try to add the children of the directory and mark the directory
 * as queued. When the child items are added to the queue model they
 * are marked as queued via the controller
 */
static void
_add_from_directory (MexQueueButton *q_button, gboolean add)
{
  MexQueueButtonPrivate *priv = q_button->priv;
  MexFeed *feed;
  GrlSource *source;
  GList *metadata_keys;
  GList *query_keys;

  const gchar *filter;
  const gchar *stream_uri;

  /* check if this content is a group */
  if (MEX_IS_GROUP_ITEM (priv->content))
    {
      MexModel *model;

      model = mex_group_item_get_model (MEX_GROUP_ITEM (priv->content));

      _add_remove_recursive (priv->queue_model,
                             g_object_ref (model),
                             add);

      /* _add_remove_recursive will unref feed */

      mex_content_set_metadata (priv->content, MEX_CONTENT_METADATA_QUEUED,
                                (add) ? "yes" : NULL);

      return;
    }


  if (!MEX_IS_GRILO_PROGRAM (priv->content))
    return;

  g_object_get (priv->content, "feed", &feed, NULL);

  if (MEX_IS_GRILO_FEED (feed))
    {
      g_object_get (feed,
                    "grilo-source", &source,
                    "grilo-query-keys", &query_keys,
                    "grilo-metadata-keys", &metadata_keys,
                    NULL);

      stream_uri =
        mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_STREAM);

      /* tracker filesystem feed */
      if (MEX_IS_GRILO_TRACKER_FEED (feed))
        {
          gchar *orig_filter;
          g_object_get (feed, "tracker-filter", &orig_filter, NULL);

                   filter =
            g_strdup_printf("FILTER(fn:starts-with(nie:url(?urn), '%s'))",
                            stream_uri);

          feed = mex_grilo_tracker_feed_new (source,
                                             query_keys,
                                             metadata_keys,
                                             filter, NULL);

          mex_grilo_feed_query (MEX_GRILO_FEED (feed), orig_filter, 0,
                                G_MAXINT);
          if (orig_filter)
            g_free (orig_filter);
        }
      /* We already know that the content is ia MexGriloProgram
       * box provides the root Grlio media content.
       * filesystem grilo feed
       */
      else
        {
          GrlMedia *box;
          g_object_get (priv->content, "grilo-media", &box, NULL);

          feed = mex_grilo_feed_new (source, query_keys, metadata_keys, box);
          mex_grilo_feed_browse (MEX_GRILO_FEED (feed), 0, G_MAXINT);
          g_object_unref (box);
        }
      /* unref/free the stuff we g_object_get'ed */
      if (source)
        g_object_unref (source);
      if (query_keys)
        g_list_free (query_keys);
      if (metadata_keys)
        g_list_free (metadata_keys);

      /* we don't actually want to add the priv->content into the queue model,
       * only it's children, which is where the QUEUED flag is usually set
       */

      if (add)
        {
          g_signal_connect (feed, "notify::completed",
                            G_CALLBACK (_add_directory_query_complete_cb),
                            q_button);

          mex_content_set_metadata (priv->content, MEX_CONTENT_METADATA_QUEUED,
                                    "yes");
        }
      else
        {
          g_signal_connect (feed, "notify::completed",
                            G_CALLBACK (_remove_directory_query_complete_cb),
                            q_button);

          mex_content_set_metadata (priv->content, MEX_CONTENT_METADATA_QUEUED,
                                    NULL);
        }
    }
  else
    {
      /* We're not working with a grilo feed therefore we can't help :( */
      return;
    }
}
static gboolean
_start_video_preview (MexContentTile *self)
{
  MexContentTilePrivate *priv = self->priv;
  GstElement *pipeline;
  gint gst_flags;

  const gchar *mimetype, *uri;

  /* Check we're still focused */
  if (!mex_actor_has_focus (CLUTTER_ACTOR (self)))
    return FALSE;

  /* Don't play if the main player is still playing..
   * too many videos spoil the broth.
   */
  if (clutter_media_get_playing (mex_player_get_clutter_media (mex_player_get_default ())))
    return FALSE;

  mimetype = mex_content_get_metadata (priv->content,
                                       MEX_CONTENT_METADATA_MIMETYPE);

  if ((mimetype) && strncmp (mimetype, "video/", 6) != 0)
    return FALSE;

  if (!(uri = mex_content_get_metadata (priv->content,
                                        MEX_CONTENT_METADATA_STREAM)))
    return FALSE;

  priv->video_preview = clutter_gst_video_texture_new ();

  pipeline = clutter_gst_video_texture_get_pipeline (CLUTTER_GST_VIDEO_TEXTURE (priv->video_preview));
  g_object_get (G_OBJECT (pipeline), "flags", &gst_flags, NULL);

  gst_flags = 1;//GST_PLAY_FLAG_VIDEO;

  g_object_set (G_OBJECT (pipeline), "flags", gst_flags, NULL);


  clutter_gst_video_texture_set_idle_material (CLUTTER_GST_VIDEO_TEXTURE (priv->video_preview),
                                               NULL);
  g_signal_connect (priv->video_preview, "eos",
                    G_CALLBACK (_stop_video_eos),
                    self);

  clutter_actor_set_opacity (priv->video_preview, 0);

  g_object_ref (priv->image);
  clutter_actor_remove_child (CLUTTER_ACTOR (self), priv->image);
  clutter_actor_add_child (CLUTTER_ACTOR (self), priv->video_preview);


  clutter_actor_animate (priv->video_preview, CLUTTER_LINEAR, 500,
                         "opacity", 0xff, NULL);

  clutter_actor_set_size (priv->video_preview,
                          (gfloat)priv->thumb_width,
                          (gfloat)priv->thumb_height);

  clutter_media_set_uri (CLUTTER_MEDIA (priv->video_preview), uri);
  clutter_media_set_playing (CLUTTER_MEDIA (priv->video_preview), TRUE);

  if (priv->stop_video_preview <= 0)
    priv->stop_video_preview =
      g_timeout_add_seconds (180, (GSourceFunc)_stop_video_preview, self);

  return FALSE;
}
static void
_reset_thumbnail (MexContentTile *tile)
{
  MexContentTilePrivate *priv = tile->priv;
  MexDownloadQueue *queue = mex_download_queue_get_default ();
  const gchar *mime = NULL;
  gchar *placeholder_filename = NULL;

  queue = mex_download_queue_get_default ();

  /* cancel any download already in progress */
  if (priv->download_id)
    {
      mex_download_queue_cancel (queue, priv->download_id);
      priv->download_id = NULL;
    }

  priv->thumbnail_loaded = FALSE;

  /* Load placeholder image */
  if (priv->content)
    mime = mex_content_get_metadata (priv->content,
                                     MEX_CONTENT_METADATA_MIMETYPE);

  if (mime && g_str_has_prefix (mime, "image/"))
    {
      placeholder_filename = "thumb-image.png";
    }
  else if (mime && g_str_equal (mime, "x-mex/tv"))
    {
      placeholder_filename = "thumb-tv.png";
    }
  else if (mime && g_str_equal (mime, "video/dvd"))
    {
      placeholder_filename = "thumb-disc.png";
    }
  else if (mime && (g_str_has_prefix (mime, "video/") ||
                    g_str_equal (mime, "x-mex/media")))
    {
      placeholder_filename = "thumb-video.png";
    }
  else if (mime && (g_str_has_prefix (mime, "audio/")))
    {
      placeholder_filename = "thumb-music.png";
    }
  else if (mime && g_str_equal (mime, "x-grl/box"))
    {
      placeholder_filename = "folder-tile.png";
    }
  else if (mime && g_str_equal (mime, "x-mex/group"))
    {
      placeholder_filename = "folder-tile.png";
    }
  else if (mime && g_str_equal (mime, "x-mex/app"))
    {
      placeholder_filename = "thumb-app.png";
    }

  if (placeholder_filename)
    {
      gchar *tmp;
      const gchar *dir = mex_get_data_dir ();

      tmp = g_build_filename (dir, "style", placeholder_filename, NULL);
      _update_thumbnail_from_image (tile, tmp);
      g_free (tmp);
    }
  else
    {
      mx_image_clear (MX_IMAGE (priv->image));

      /* Reset the height - really, we ought to reset the width and height,
       * but for all our use-cases, we want to keep the set width.
       */
      clutter_actor_set_height (priv->image, -1);
      priv->image_set = FALSE;

      return;
    }

  clutter_actor_set_size (priv->image,
                          priv->thumb_width, priv->thumb_height);
}
Beispiel #30
0
static void
set_metadata_from_media (MexContent          *content,
                         GrlMedia            *media,
                         MexContentMetadata   mex_key)
{
  gchar       *string;
  const gchar *cstring;
  GrlKeyID     grl_key = _get_grl_key_from_mex (mex_key);
  gint n;
  gint year = 0;

  if (!grl_key)
    return;

  switch (grl_metadata_key_get_type (grl_key)) {
  case G_TYPE_STRING:
    cstring = grl_data_get_string (GRL_DATA (media), grl_key);

    if (cstring)
      {
        if (mex_key == MEX_CONTENT_METADATA_TITLE)
          {
            gchar *showname = NULL, *title, *season_str;
            gint season, episode;
            gchar *replacement;
            const gchar *mimetype;

            mimetype = mex_content_get_metadata (content,
                                                 MEX_CONTENT_METADATA_MIMETYPE);

            if (!mimetype)
              mimetype = "";

            if (g_str_has_prefix (mimetype, "video/"))
              {
                mex_metadata_from_uri (cstring, &title, &showname, &year,
                                       &season, &episode);
              }

            if (showname)
              {
                replacement = g_strdup_printf (_("Episode %d"), episode);
              }
            else
              {
                GRegex *regex;

                /* strip off any file extensions */
                regex = g_regex_new ("\\.....?$", 0, 0, NULL);
                replacement = g_regex_replace (regex, cstring, -1, 0, "", 0, NULL);

                g_regex_unref (regex);
              }

            if (!replacement)
              replacement = g_strdup (cstring);

            mex_content_set_metadata (content, mex_key, replacement);
            mex_content_set_metadata (content, MEX_CONTENT_METADATA_SERIES_NAME,
                                      showname);
            season_str = g_strdup_printf (_("Season %d"), season);
            mex_content_set_metadata (content, MEX_CONTENT_METADATA_SEASON,
                                      season_str);
            g_free (season_str);

            if (year)
              {
                replacement = g_strdup_printf ("%d", year);
                mex_content_set_metadata (content, MEX_CONTENT_METADATA_YEAR,
                                          replacement);

                g_free (replacement);
              }
          }
        else
          mex_content_set_metadata (content, mex_key, cstring);
      }
    break;

  case G_TYPE_INT:
    n = grl_data_get_int (GRL_DATA (media), grl_key);

    string = g_strdup_printf ("%i", n);
    mex_content_set_metadata (content, mex_key, string);
    g_free (string);
    break;

  case G_TYPE_FLOAT:
    string = g_strdup_printf ("%f", grl_data_get_float (GRL_DATA (media),
                                                        grl_key));
    mex_content_set_metadata (content, mex_key, string);
    g_free (string);
    break;
  }
}