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); } }
int main (int argc, char **argv) { const ClutterColor grey = { 0x40, 0x40, 0x40, 0xff }; ClutterActor *stage, *info_panel, *align; MxApplication *app; MxWindow *window; MexFeed *feed; MexProgram *program; mex_init (&argc, &argv); app = mx_application_new (&argc, &argv, "mex-info-panel-test", 0); mex_style_load_default (); window = mx_application_create_window (app); stage = (ClutterActor *) mx_window_get_clutter_stage (window); clutter_stage_set_color ((ClutterStage *) stage, &grey); align = g_object_new (MX_TYPE_FRAME, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_END, NULL); mx_window_set_child (window, align); info_panel = mex_info_panel_new (MEX_INFO_PANEL_MODE_FULL); mx_bin_set_child (MX_BIN (align), info_panel); mx_window_set_has_toolbar (window, FALSE); clutter_actor_set_size (stage, 1024, 768); feed = mex_feed_new ("source", "title"); program = mex_program_new (feed); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_MIMETYPE, "video/mp4"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_TITLE, "The cats on the moon"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_SYNOPSIS, "An original title where cats are sent to the moon to catch all the mice which are naturally attracted there due to the large consistency of cheese, this results in a space race between NASA and CATSA, leading to war on the moon over territory claimed by cats"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_STILL, "http://farm5.static.flickr.com/4013/4305303148_5cbc986a44_m.jpg"); mex_content_view_set_content (MEX_CONTENT_VIEW (info_panel), MEX_CONTENT (program)); clutter_actor_show (stage); clutter_main (); return 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 save_old_content (MexPlayer *player) { MexPlayerPrivate *priv = player->priv; guint position; gchar str[20]; if (priv->duration && mex_generic_content_get_save_last_position (MEX_GENERIC_CONTENT (priv->content))) { priv->position = priv->current_position; position = (guint) (priv->position * priv->duration); snprintf (str, sizeof (str), "%u", position); mex_content_set_metadata (priv->content, MEX_CONTENT_METADATA_LAST_POSITION, str); } mex_content_set_last_used_metadatas (priv->content); mex_content_save_metadata (priv->content); }
static void _controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexQueueModel *model) { MexQueueModelPrivate *priv = model->priv; guint index_; MexContent *content; /* * MexGenericContent only does single items at a time so we have an * assumption here that our reference only contains a single item */ if (action == G_CONTROLLER_ADD || action == G_CONTROLLER_REMOVE) { index_ = g_controller_reference_get_index_uint (ref, 0); content = mex_model_get_content (MEX_MODEL (model), index_); } if (action == G_CONTROLLER_ADD) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, "yes"); } else if (action == G_CONTROLLER_REMOVE) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, NULL); } else if (action == G_CONTROLLER_CLEAR) { gint model_length; model_length = mex_model_get_length (MEX_MODEL (model)); for (index_=0; index_ < model_length; index_++) { content = mex_model_get_content (MEX_MODEL (model), index_); mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, NULL); } } else { GEnumClass *enum_class; enum_class = g_type_class_ref (G_TYPE_CONTROLLER_ACTION); g_critical (G_STRLOC ": Unexpected GController action: %s", (g_enum_get_value (enum_class, action))->value_name); g_type_class_unref (enum_class); } if (priv->serialise_idle_id) return; /* Need to use a high priority idle here since we want to try and write * *after* the content has been removed from the model */ priv->serialise_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)_serialise_idle_cb, g_object_ref (model), g_object_unref); }
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; } }
/* 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 void mex_suggest_complete_cb (MexDownloadQueue *queue, const gchar *uri, const gchar *buffer, gsize count, const GError *error, gpointer userdata) { RestXmlNode *root, *n; RestXmlParser *parser; MexSearchPlugin *self = userdata; MexSearchPluginPrivate *priv = self->priv; priv->suggest_id = NULL; /* hide spinner */ mx_spinner_set_animating (MX_SPINNER (priv->spinner), FALSE); clutter_actor_hide (priv->spinner); if (error) { g_warning ("Error querying Google suggestions: %s", error->message); return; } parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, buffer, count); if (!root) { g_warning ("Unknown error parsing Google suggestions XML"); g_object_unref (parser); return; } /* Clear model */ mex_model_clear (MEX_MODEL (priv->suggest_model)); /* Add new suggestions to model */ n = rest_xml_node_find (root, "CompleteSuggestion"); for (; n; n = n->next) { MexContent *content; const gchar *suggestion; RestXmlNode *node = rest_xml_node_find (n, "suggestion"); if (!node) continue; suggestion = rest_xml_node_get_attr (node, "data"); if (!suggestion) continue; content = MEX_CONTENT (mex_program_new (priv->suggest_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, suggestion); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->suggest_model), content); } /* Unref */ rest_xml_node_unref (root); g_object_unref (parser); }
static void mex_search_plugin_update_history (MexSearchPlugin *self, const gchar *term) { gint i; gsize length; gchar *contents, *current; MexSearchPluginPrivate *priv = self->priv; const gchar *base_dir = mex_settings_get_config_dir (mex_settings_get_default ()); gchar *history_file = g_build_filename (base_dir, "search", "history", NULL); /* Read the history file contents */ /* TODO: Make this less rubbish? */ g_file_get_contents (history_file, &contents, &length, NULL); /* Prepend new search-term if appropriate */ if (term) { gint terms; gchar *path; gsize new_length; gsize term_len = strlen (term); gchar *new_contents = g_malloc (length + term_len + 1); memcpy (new_contents, term, term_len); new_contents[term_len] = '\n'; new_length = term_len + 1; /* Truncate list to 10 terms and remove duplicates */ if (contents) { i = 0; terms = 1; do { gint cur_len; char *eos = strchr (contents + i, '\n'); if (!eos) cur_len = strlen (contents + i); else cur_len = eos - (contents + i); if ((cur_len != term_len) || (strncmp (contents + i, term, term_len) != 0)) { memcpy (new_contents + new_length, contents + i, cur_len + 1); new_length += cur_len + 1; if (++terms >= 10) break; } if (!eos) break; i += cur_len + 1; } while (i < length); } new_contents[new_length++] = '\0'; /* Save new list */ path = g_path_get_dirname (history_file); g_mkdir_with_parents (path, 0755); g_free (path); g_file_set_contents (history_file, new_contents, new_length, NULL); /* Replace content with new content */ g_free (contents); contents = new_contents; length = new_length; } /* Empty current list */ mex_model_clear (MEX_MODEL (priv->history_model)); /* Populate with search history */ if (contents) { current = contents; while (current < contents + length) { MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); gchar *end = g_utf8_strchr (current, -1, '\n'); if (end) *end = '\0'; if (*current) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, current); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } if (end) current = end + 1; else break; } g_free (contents); } else { /* Add a default search so the column isn't hidden. * TODO: Have a way of inserting 'stock' content rather than doing * this, I suppose. */ MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, "MeeGo"); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } }