summaryrefslogtreecommitdiff
path: root/src/trg-rss-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trg-rss-model.c')
-rw-r--r--src/trg-rss-model.c277
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