diff options
Diffstat (limited to 'src/trg-rss-model.c')
-rw-r--r-- | src/trg-rss-model.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c new file mode 100644 index 0000000..aa15829 --- /dev/null +++ b/src/trg-rss-model.c @@ -0,0 +1,277 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_RSS + +#include <gtk/gtk.h> +#include <json-glib/json-glib.h> +#include <rss-glib/rss-glib.h> + +#include "config.h" +#include "torrent.h" +#include "trg-client.h" +#include "trg-model.h" +#include "trg-rss-model.h" + +enum { + PROP_0, PROP_CLIENT +}; + +enum { + SIGNAL_GET_ERROR, SIGNAL_PARSE_ERROR, SIGNAL_COUNT +}; + +static guint signals[SIGNAL_COUNT] = { 0 }; + +G_DEFINE_TYPE(TrgRssModel, trg_rss_model, GTK_TYPE_LIST_STORE) +#define TRG_RSS_MODEL_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_RSS_MODEL, TrgRssModelPrivate)) +typedef struct _TrgRssModelPrivate TrgRssModelPrivate; + +struct _TrgRssModelPrivate { + TrgClient *client; + GHashTable *table; + guint index; +}; + +typedef struct { + TrgRssModel *model; + gchar *feed_id; + gchar *feed_url; + gchar *feed_cookie; + GError *error; + trg_response *response; +} feed_update; + +static void feed_update_free(feed_update *update) { + if (update->error) + g_error_free(update->error); + + g_free(update->feed_id); + g_free(update->feed_url); + g_free(update->feed_cookie); + + g_free(update); +} + +static gboolean on_rss_receive(gpointer data) { + trg_response *response = (trg_response *) data; + feed_update *update = (feed_update*) response->cb_data; + TrgRssModel *model = update->model; + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); + + if (response->status == CURLE_OK) { + RssParser* parser = rss_parser_new(); + GError *error = NULL; + if (rss_parser_load_from_data(parser, response->raw, + response->size, &error)) { + RssDocument *doc = rss_parser_get_document(parser); + GtkTreeIter iter; + GList *list, *tmp; + + list = rss_document_get_items(doc); + + for (tmp = list; tmp != NULL; tmp = tmp->next) { + RssItem *item = (RssItem*) tmp->data; + const gchar *guid = rss_item_get_guid(item); + if (g_hash_table_lookup(priv->table, guid) != (void*) 1) { + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, RSSCOL_ID, + guid, RSSCOL_TITLE, rss_item_get_title(item), + RSSCOL_LINK, rss_item_get_link(item), RSSCOL_FEED, + update->feed_id, RSSCOL_COOKIE, update->feed_cookie, RSSCOL_PUBDATE, + rss_item_get_pub_date(item), -1); + g_hash_table_insert(priv->table, g_strdup(guid), (void*) 1); + } + } + + g_list_free(list); + g_object_unref(doc); + g_object_unref(parser); + } else { + rss_parse_error perror; + perror.error = error; + perror.feed_id = update->feed_id; + + g_signal_emit(model, signals[SIGNAL_PARSE_ERROR], 0, + &perror); + + g_message("parse error: %s", error->message); + g_error_free(error); + } + } else { + rss_get_error get_error; + get_error.error_code = response->status; + get_error.feed_id = update->feed_id; + + g_signal_emit(model, signals[SIGNAL_GET_ERROR], 0, + &get_error); + } + + trg_response_free(response); + feed_update_free(update); + + return FALSE; +} + +void trg_rss_model_update(TrgRssModel * model) { + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); + TrgPrefs *prefs = trg_client_get_prefs(priv->client); + JsonArray *feeds = trg_prefs_get_rss(prefs); + GRegex *cookie_regex; + GList *li; + + if (!feeds) + return; + + cookie_regex = g_regex_new("(.*):COOKIE:(.*)", 0, 0, NULL); + + for (li = json_array_get_elements(feeds); li != NULL; + li = g_list_next(li)) { + JsonObject *feed = json_node_get_object((JsonNode *) li->data); + const gchar *feed_url = json_object_get_string_member(feed, "url"); + const gchar *id = json_object_get_string_member(feed, "id"); + feed_update *update; + GMatchInfo *match; + + if (!feed_url || !id) + continue; + + update = g_new0(feed_update, 1); + update->feed_id = g_strdup(id); + update->model = model; + + if (g_regex_match (cookie_regex, feed_url, 0, &match)) { + update->feed_url = g_match_info_fetch(match, 1); + update->feed_cookie = g_match_info_fetch(match, 2); + g_match_info_free(match); + } else { + update->feed_url = g_strdup(feed_url); + } + + async_http_request(priv->client, update->feed_url, update->feed_cookie, on_rss_receive, + update); + } + + g_regex_unref(cookie_regex); + + /*trg_model_remove_removed(GTK_LIST_STORE(model), + RSSCOL_UPDATESERIAL, updateSerial);*/ +} + +static void trg_rss_model_set_property(GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_CLIENT: + priv->client = g_value_get_pointer(value); + break; + } +} + +static void trg_rss_model_get_property(GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { +} + +static GObject *trg_rss_model_constructor(GType type, + guint n_construct_properties, GObjectConstructParam * construct_params) { + GObject *obj = G_OBJECT_CLASS + (trg_rss_model_parent_class)->constructor(type, + n_construct_properties, construct_params); + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(obj); + + priv->table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + return obj; +} + +static void trg_rss_model_dispose(GObject * object) { + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(object); + g_hash_table_destroy(priv->table); + G_OBJECT_CLASS(trg_rss_model_parent_class)->dispose(object); +} + +static void trg_rss_model_class_init(TrgRssModelClass * klass) { + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(TrgRssModelPrivate)); + + object_class->set_property = trg_rss_model_set_property; + object_class->get_property = trg_rss_model_get_property; + object_class->constructor = trg_rss_model_constructor; + object_class->dispose = trg_rss_model_dispose; + + g_object_class_install_property(object_class, PROP_CLIENT, + g_param_spec_pointer("client", "client", "client", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); + + signals[SIGNAL_GET_ERROR] = g_signal_new("get-error", + G_TYPE_FROM_CLASS + (object_class), + G_SIGNAL_RUN_LAST | + G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgRssModelClass, + get_error), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[SIGNAL_PARSE_ERROR] = g_signal_new("parse-error", + G_TYPE_FROM_CLASS + (object_class), + G_SIGNAL_RUN_LAST | + G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgRssModelClass, + parse_error), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); +} + +static void trg_rss_model_init(TrgRssModel * self) { + GType column_types[RSSCOL_COLUMNS]; + + column_types[RSSCOL_ID] = G_TYPE_STRING; + column_types[RSSCOL_TITLE] = G_TYPE_STRING; + column_types[RSSCOL_LINK] = G_TYPE_STRING; + column_types[RSSCOL_COOKIE] = G_TYPE_STRING; + column_types[RSSCOL_FEED] = G_TYPE_STRING; + column_types[RSSCOL_PUBDATE] = G_TYPE_STRING; + column_types[RSSCOL_UPLOADED] = G_TYPE_BOOLEAN; + + gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, + column_types); +} + +TrgRssModel *trg_rss_model_new(TrgClient *client) { + return g_object_new(TRG_TYPE_RSS_MODEL, "client", client, NULL); +} + +#endif |