1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implemetation files for podcast download manager
5 * Copyright (C) 2005 Renato Araujo Oliveira Filho - INdT <renato.filho@indt.org.br>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <glib/gi18n.h>
30 #include <glib/gstdio.h>
32 #include <libgnomevfs/gnome-vfs-uri.h>
34 #include "rb-preferences.h"
35 #include "eel-gconf-extensions.h"
36 #include "rb-podcast-manager.h"
37 #include "rb-file-helpers.h"
39 #include "rb-marshal.h"
41 #include "rhythmdb-query-model.h"
42 #include "rb-podcast-parse.h"
43 #include "rb-dialog.h"
44 #include "rb-metadata.h"
46 #define CONF_STATE_PODCAST_PREFIX CONF_PREFIX "/state/podcast"
47 #define CONF_STATE_PODCAST_DOWNLOAD_DIR CONF_STATE_PODCAST_PREFIX "/download_prefix"
48 #define CONF_STATE_PODCAST_DOWNLOAD_INTERVAL CONF_STATE_PODCAST_PREFIX "/download_interval"
49 #define CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME CONF_STATE_PODCAST_PREFIX "/download_next_time"
71 FEED_UPDATES_AVALIABLE
,
81 struct RBPodcastManagerPrivate
87 guint update_interval_notify_id
;
89 GMutex
*download_list_mutex
;
91 gboolean remove_files
;
93 GAsyncQueue
*event_queue
;
96 #define RB_PODCAST_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PODCAST_MANAGER, RBPodcastManagerPrivate))
98 /* used on event loop */
101 RBPodcastEventType type
;
102 RBPodcastChannel
*channel
;
103 } RBPodcastManagerEvent
;
105 /* used on donwload thread */
108 RBPodcastManager
*pd
;
109 RhythmDBEntry
*entry
;
110 GnomeVFSAsyncHandle
*read_handle
;
111 GnomeVFSURI
*write_uri
;
112 GnomeVFSURI
*read_uri
;
113 GMutex
*mutex_working
;
118 } RBPodcastManagerInfo
;
120 /* used on subscribe thread */
123 RBPodcastManager
*pd
;
125 } RBPodcastThreadInfo
;
127 static guint rb_podcast_manager_signals
[LAST_SIGNAL
] = { 0 };
130 static void rb_podcast_manager_class_init (RBPodcastManagerClass
*klass
);
131 static void rb_podcast_manager_init (RBPodcastManager
*dp
);
132 static GObject
*rb_podcast_manager_constructor (GType type
, guint n_construct_properties
,
133 GObjectConstructParam
*construct_properties
);
134 static void rb_podcast_manager_finalize (GObject
*object
);
135 static void rb_podcast_manager_set_property (GObject
*object
,
139 static void rb_podcast_manager_get_property (GObject
*object
,
143 static void rb_podcast_manager_copy_post (RBPodcastManager
*pd
);
144 static gboolean
rb_podcast_manager_sync_head_cb (gpointer data
);
145 static gboolean
rb_podcast_manager_head_query_cb (GtkTreeModel
*query_model
,
148 RBPodcastManager
*data
);
149 static gboolean
rb_podcast_manager_save_metadata (RhythmDB
*db
,
150 RhythmDBEntry
*entry
,
152 static void rb_podcast_manager_db_entry_added_cb (RBPodcastManager
*pd
,
153 RhythmDBEntry
*entry
);
154 static void rb_podcast_manager_db_entry_deleted_cb (RBPodcastManager
*pd
,
155 RhythmDBEntry
*entry
);
156 static gboolean
rb_podcast_manager_next_file (RBPodcastManager
* pd
);
157 static void rb_podcast_manager_insert_feed (RBPodcastManager
*pd
, RBPodcastChannel
*data
);
158 static void rb_podcast_manager_abort_subscribe (RBPodcastManager
*pd
);
161 static gboolean
rb_podcast_manager_event_loop (RBPodcastManager
*pd
) ;
162 static gpointer
rb_podcast_manager_thread_parse_feed (RBPodcastThreadInfo
*info
);
164 /* async read file functions */
165 static guint
download_progress_cb (GnomeVFSXferProgressInfo
*info
,
167 static guint
download_progress_update_cb (GnomeVFSAsyncHandle
*handle
,
168 GnomeVFSXferProgressInfo
*info
,
171 /* internal functions */
172 static void download_info_free (RBPodcastManagerInfo
*data
);
173 static RBPodcastManagerInfo
*download_info_new (void);
174 static void start_job (RBPodcastManagerInfo
*data
);
175 static void end_job (RBPodcastManagerInfo
*data
);
176 static void cancel_job (RBPodcastManagerInfo
*pd
);
177 static void write_job_data (RBPodcastManagerInfo
*data
);
178 static void rb_podcast_manager_update_synctime (RBPodcastManager
*pd
);
179 static void rb_podcast_manager_config_changed (GConfClient
* client
,
184 G_DEFINE_TYPE (RBPodcastManager
, rb_podcast_manager
, G_TYPE_OBJECT
)
187 rb_podcast_manager_class_init (RBPodcastManagerClass
*klass
)
189 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
191 object_class
->constructor
= rb_podcast_manager_constructor
;
192 object_class
->finalize
= rb_podcast_manager_finalize
;
194 object_class
->set_property
= rb_podcast_manager_set_property
;
195 object_class
->get_property
= rb_podcast_manager_get_property
;
197 g_object_class_install_property (object_class
,
199 g_param_spec_object ("db",
205 rb_podcast_manager_signals
[STATUS_CHANGED
] =
206 g_signal_new ("status_changed",
207 G_OBJECT_CLASS_TYPE (object_class
),
209 G_STRUCT_OFFSET (RBPodcastManagerClass
, status_changed
),
211 rb_marshal_VOID__BOXED_ULONG
,
217 rb_podcast_manager_signals
[START_DOWNLOAD
] =
218 g_signal_new ("start_download",
219 G_OBJECT_CLASS_TYPE (object_class
),
221 G_STRUCT_OFFSET (RBPodcastManagerClass
, start_download
),
223 g_cclosure_marshal_VOID__BOXED
,
226 RHYTHMDB_TYPE_ENTRY
);
228 rb_podcast_manager_signals
[FINISH_DOWNLOAD
] =
229 g_signal_new ("finish_download",
230 G_OBJECT_CLASS_TYPE (object_class
),
232 G_STRUCT_OFFSET (RBPodcastManagerClass
, finish_download
),
234 g_cclosure_marshal_VOID__BOXED
,
237 RHYTHMDB_TYPE_ENTRY
);
239 rb_podcast_manager_signals
[FEED_UPDATES_AVALIABLE
] =
240 g_signal_new ("feed_updates_avaliable",
241 G_OBJECT_CLASS_TYPE (object_class
),
243 G_STRUCT_OFFSET (RBPodcastManagerClass
, feed_updates_avaliable
),
245 g_cclosure_marshal_VOID__BOXED
,
248 RHYTHMDB_TYPE_ENTRY
);
250 rb_podcast_manager_signals
[PROCESS_ERROR
] =
251 g_signal_new ("process_error",
252 G_OBJECT_CLASS_TYPE (object_class
),
254 G_STRUCT_OFFSET (RBPodcastManagerClass
, process_error
),
256 g_cclosure_marshal_VOID__STRING
,
261 g_type_class_add_private (klass
, sizeof (RBPodcastManagerPrivate
));
265 rb_podcast_manager_init (RBPodcastManager
*pd
)
267 pd
->priv
= RB_PODCAST_MANAGER_GET_PRIVATE (pd
);
269 pd
->priv
->source_sync
= 0;
270 pd
->priv
->mutex_job
= g_mutex_new();
271 pd
->priv
->download_list_mutex
= g_mutex_new();
272 pd
->priv
->event_queue
= g_async_queue_new ();
274 eel_gconf_monitor_add (CONF_STATE_PODCAST_PREFIX
);
278 rb_podcast_manager_constructor (GType type
, guint n_construct_properties
,
279 GObjectConstructParam
*construct_properties
)
281 RBPodcastManager
*pd
;
283 pd
= RB_PODCAST_MANAGER (G_OBJECT_CLASS (rb_podcast_manager_parent_class
)
284 ->constructor (type
, n_construct_properties
, construct_properties
));
286 pd
->priv
->update_interval_notify_id
= eel_gconf_notification_add (CONF_STATE_PODCAST_DOWNLOAD_INTERVAL
,
287 rb_podcast_manager_config_changed
,
290 return G_OBJECT (pd
);
295 rb_podcast_manager_finalize (GObject
*object
)
297 RBPodcastManager
*pd
;
298 g_return_if_fail (object
!= NULL
);
299 g_return_if_fail (RB_IS_PODCAST_MANAGER (object
));
301 pd
= RB_PODCAST_MANAGER(object
);
303 g_return_if_fail (pd
->priv
!= NULL
);
305 eel_gconf_monitor_remove (CONF_STATE_PODCAST_PREFIX
);
307 if (pd
->priv
->source_sync
) {
308 g_source_remove (pd
->priv
->source_sync
);
309 pd
->priv
->source_sync
= 0;
312 eel_gconf_notification_remove (pd
->priv
->update_interval_notify_id
);
314 if (pd
->priv
->download_list
) {
315 g_list_foreach (pd
->priv
->download_list
, (GFunc
)g_free
, NULL
);
316 g_list_free (pd
->priv
->download_list
);
319 g_mutex_free (pd
->priv
->mutex_job
);
320 g_mutex_free (pd
->priv
->download_list_mutex
);
321 g_async_queue_unref (pd
->priv
->event_queue
);
323 G_OBJECT_CLASS (rb_podcast_manager_parent_class
)->finalize (object
);
324 rb_debug ("Podcast Manager END");
328 rb_podcast_manager_set_property (GObject
*object
,
333 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (object
);
338 g_signal_handlers_disconnect_by_func (G_OBJECT (pd
->priv
->db
),
339 G_CALLBACK (rb_podcast_manager_db_entry_added_cb
),
342 g_signal_handlers_disconnect_by_func (G_OBJECT (pd
->priv
->db
),
343 G_CALLBACK (rb_podcast_manager_db_entry_deleted_cb
),
348 pd
->priv
->db
= g_value_get_object (value
);
350 g_signal_connect_object (G_OBJECT (pd
->priv
->db
),
352 G_CALLBACK (rb_podcast_manager_db_entry_added_cb
),
353 pd
, G_CONNECT_SWAPPED
);
355 g_signal_connect_object (G_OBJECT (pd
->priv
->db
),
357 G_CALLBACK (rb_podcast_manager_db_entry_deleted_cb
),
358 pd
, G_CONNECT_SWAPPED
);
362 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
367 rb_podcast_manager_get_property (GObject
*object
,
372 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (object
);
376 g_value_set_object (value
, pd
->priv
->db
);
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
385 rb_podcast_manager_new (RhythmDB
*db
)
387 RBPodcastManager
*pd
;
389 pd
= g_object_new (RB_TYPE_PODCAST_MANAGER
, "db", db
, NULL
);
394 rb_podcast_manager_download_entry (RBPodcastManager
*pd
,
395 RhythmDBEntry
*entry
)
399 g_return_if_fail (RB_IS_PODCAST_MANAGER (pd
));
404 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
405 if ((status
< RHYTHMDB_PODCAST_STATUS_COMPLETE
) ||
406 (status
== RHYTHMDB_PODCAST_STATUS_WAITING
)) {
407 RBPodcastManagerInfo
*data
;
408 if (status
< RHYTHMDB_PODCAST_STATUS_COMPLETE
) {
409 GValue status_val
= { 0, };
410 g_value_init (&status_val
, G_TYPE_ULONG
);
411 g_value_set_ulong (&status_val
, RHYTHMDB_PODCAST_STATUS_WAITING
);
412 rhythmdb_entry_set (pd
->priv
->db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
413 g_value_unset (&status_val
);
415 rb_debug ("Try insert entry for download.");
416 data
= download_info_new();
419 g_mutex_lock (pd
->priv
->download_list_mutex
);
420 pd
->priv
->download_list
= g_list_append (pd
->priv
->download_list
, data
);
421 g_mutex_unlock (pd
->priv
->download_list_mutex
);
422 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
427 rb_podcast_manager_entry_downloaded (RhythmDBEntry
*entry
)
430 const gchar
*file_name
;
431 RhythmDBEntryType type
= rhythmdb_entry_get_entry_type (entry
);
433 g_assert (type
== RHYTHMDB_ENTRY_TYPE_PODCAST_POST
);
435 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
436 file_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MOUNTPOINT
);
438 return (status
!= RHYTHMDB_PODCAST_STATUS_ERROR
&& file_name
!= NULL
);
442 rb_podcast_manager_start_sync (RBPodcastManager
*pd
)
446 g_return_if_fail (RB_IS_PODCAST_MANAGER (pd
));
448 if (pd
->priv
->next_time
> 0) {
449 next_time
= pd
->priv
->next_time
;
451 next_time
= eel_gconf_get_integer (CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME
);
455 if (pd
->priv
->source_sync
!= 0) {
456 g_source_remove (pd
->priv
->source_sync
);
457 pd
->priv
->source_sync
= 0;
459 next_time
= next_time
- ((int)time (NULL
));
460 if (next_time
<= 0) {
461 rb_podcast_manager_update_feeds (pd
);
462 pd
->priv
->next_time
= 0;
463 rb_podcast_manager_update_synctime (pd
);
466 pd
->priv
->source_sync
= g_timeout_add (next_time
* 1000, (GSourceFunc
) rb_podcast_manager_sync_head_cb
, pd
);
472 rb_podcast_manager_sync_head_cb (gpointer data
)
474 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (data
);
475 rb_podcast_manager_update_feeds (pd
);
476 pd
->priv
->source_sync
= 0;
477 pd
->priv
->next_time
= 0;
478 rb_podcast_manager_update_synctime (RB_PODCAST_MANAGER (data
));
483 rb_podcast_manager_update_feeds (RBPodcastManager
*pd
)
485 GtkTreeModel
*query_model
;
487 g_return_if_fail (RB_IS_PODCAST_MANAGER (pd
));
489 query_model
= GTK_TREE_MODEL (rhythmdb_query_model_new_empty (pd
->priv
->db
));
491 rhythmdb_do_full_query (pd
->priv
->db
,
492 RHYTHMDB_QUERY_RESULTS (query_model
),
493 RHYTHMDB_QUERY_PROP_EQUALS
,
494 RHYTHMDB_PROP_TYPE
, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
,
497 gtk_tree_model_foreach (query_model
,
498 (GtkTreeModelForeachFunc
) rb_podcast_manager_head_query_cb
,
501 g_object_unref (query_model
);
505 rb_podcast_manager_head_query_cb (GtkTreeModel
*query_model
,
508 RBPodcastManager
*manager
)
511 RhythmDBEntry
*entry
;
514 gtk_tree_model_get (query_model
, iter
, 0, &entry
, -1);
515 uri
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
);
516 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
519 rb_podcast_manager_subscribe_feed (manager
, uri
);
521 rhythmdb_entry_unref (entry
);
527 rb_podcast_manager_next_file (RBPodcastManager
* pd
)
530 rb_debug ("try lock file_process mutex");
531 if (g_mutex_trylock (pd
->priv
->mutex_job
) == TRUE
) {
534 g_mutex_lock (pd
->priv
->download_list_mutex
);
535 size
= g_list_length (pd
->priv
->download_list
);
536 g_mutex_unlock (pd
->priv
->download_list_mutex
);
539 rb_podcast_manager_copy_post (pd
);
541 g_mutex_unlock (pd
->priv
->mutex_job
);
543 rb_debug ("not start");
550 rb_podcast_manager_copy_post (RBPodcastManager
*pd
)
552 GnomeVFSURI
*remote_uri
= NULL
;
553 GnomeVFSURI
*local_uri
= NULL
;
554 GValue location_val
= { 0, };
555 const char *location
, *album_name
;
556 char *short_name
, *local_file_name
;
557 char *dir_name
, *conf_dir_name
;
558 RBPodcastManagerInfo
*data
= NULL
;
559 RhythmDBEntry
*entry
;
561 rb_debug ("Stating copy file");
562 g_value_init (&location_val
, G_TYPE_STRING
);
564 /* get first element of list */
565 g_mutex_lock (pd
->priv
->download_list_mutex
);
566 data
= (RBPodcastManagerInfo
*) g_list_first (pd
->priv
->download_list
)->data
;
567 g_mutex_unlock (pd
->priv
->download_list_mutex
);
574 g_assert (entry
!= NULL
);
576 location
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
);
577 album_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
);
579 rb_debug ("processing %s", location
);
581 remote_uri
= gnome_vfs_uri_new (location
);
583 rb_debug ("Error downloading podcast: could not create remote uri");
587 conf_dir_name
= rb_podcast_manager_get_podcast_dir (pd
);
588 dir_name
= g_build_filename (conf_dir_name
,
591 g_free (conf_dir_name
);
593 if (!g_file_test (dir_name
, G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
)) {
594 if (g_mkdir_with_parents (dir_name
, 0750) == -1) {
595 rb_debug ("Error downloading podcast: could not create local dirs %s", dir_name
);
600 short_name
= gnome_vfs_uri_extract_short_name (remote_uri
);
601 local_file_name
= g_build_filename (dir_name
,
607 rb_debug ("creating file %s\n", local_file_name
);
609 local_uri
= gnome_vfs_uri_new (local_file_name
);
611 rb_debug ("Error downloading podcast: could not create local uri");
615 if (g_file_test (local_file_name
, G_FILE_TEST_EXISTS
)) {
617 GnomeVFSFileInfo
*info
= gnome_vfs_file_info_new ();
618 GnomeVFSResult result
;
620 result
= gnome_vfs_get_file_info_uri (remote_uri
, info
, GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
621 if (result
!= GNOME_VFS_OK
) {
622 rb_debug ("unable to retrieve info on remote of podcast");
625 remote_size
= info
->size
;
628 result
= gnome_vfs_get_file_info (local_file_name
, info
, GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
629 if (result
!= GNOME_VFS_OK
) {
630 rb_debug ("unable to retrieve info on local copy of podcast");
632 } else if (remote_size
== info
->size
) {
634 char *uri
= gnome_vfs_uri_to_string (local_uri
, GNOME_VFS_URI_HIDE_NONE
);
635 char *canon_uri
= rb_canonicalise_uri (uri
);
638 rb_debug ("podcast %s already downloaded", location
);
640 g_value_init (&val
, G_TYPE_ULONG
);
641 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_COMPLETE
);
642 rhythmdb_entry_set (pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
643 g_value_unset (&val
);
645 g_value_init (&val
, G_TYPE_STRING
);
646 g_value_set_string (&val
, canon_uri
);
647 rhythmdb_entry_set (pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
, &val
);
648 g_value_unset (&val
);
650 rb_podcast_manager_save_metadata (pd
->priv
->db
, data
->entry
, canon_uri
);
651 rhythmdb_commit (pd
->priv
->db
);
655 } else if (remote_size
> info
->size
) {
656 /* TODO: suport resume file */
658 /* the local file is larger. replace it */
661 gnome_vfs_file_info_unref (info
);
664 g_free (local_file_name
);
666 data
->read_uri
= remote_uri
;
667 data
->write_uri
= local_uri
;
675 gnome_vfs_uri_unref (remote_uri
);
678 gnome_vfs_uri_unref (local_uri
);
680 g_mutex_lock (pd
->priv
->download_list_mutex
);
681 pd
->priv
->download_list
= g_list_remove (pd
->priv
->download_list
, (gconstpointer
) data
);
682 g_mutex_unlock (pd
->priv
->download_list_mutex
);
684 download_info_free (data
);
687 g_mutex_unlock (pd
->priv
->mutex_job
);
688 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
692 rb_podcast_manager_subscribe_feed (RBPodcastManager
*pd
, const char *url
)
694 RBPodcastThreadInfo
*info
;
695 gchar
*valid_url
= gnome_vfs_make_uri_from_input (url
);
697 if (valid_url
== NULL
) {
698 rb_error_dialog (NULL
, _("Invalid URL"),
699 _("The URL \"%s\" is not valid, please check it."), url
);
703 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (pd
->priv
->db
, valid_url
);
705 if (rhythmdb_entry_get_entry_type (entry
) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
) {
706 /* added as something else, probably iradio */
707 rb_error_dialog (NULL
, _("URL already added"),
708 _("The URL \"%s\" has already been added as a radio station. "
709 "If this is a podcast feed, please remove the radio station."), url
);
714 info
= g_new0 (RBPodcastThreadInfo
, 1);
716 info
->url
= valid_url
;
718 g_async_queue_ref (info
->pd
->priv
->event_queue
);
719 g_thread_create ((GThreadFunc
) rb_podcast_manager_thread_parse_feed
,
726 rb_podcast_manager_thread_parse_feed (RBPodcastThreadInfo
*info
)
728 RBPodcastManagerEvent
*event
= g_new0 (RBPodcastManagerEvent
, 1);
729 RBPodcastChannel
*feed
= g_new0 (RBPodcastChannel
, 1);
731 if (rb_podcast_parse_load_feed (feed
, info
->url
)) {
732 event
->channel
= feed
;
733 event
->type
= (feed
->title
== NULL
) ? EVENT_ERROR_FEED
: EVENT_INSERT_FEED
;
735 g_async_queue_push (info
->pd
->priv
->event_queue
, event
);
736 g_idle_add ((GSourceFunc
) rb_podcast_manager_event_loop
, info
->pd
);
745 rb_podcast_manager_add_post (RhythmDB
*db
,
748 const char *subtitle
,
749 const char *generator
,
751 const char *description
,
756 RhythmDBEntry
*entry
;
760 if (!uri
|| !name
|| !title
|| !date
|| !g_utf8_validate(uri
, -1, NULL
)) {
763 entry
= rhythmdb_entry_lookup_by_location (db
, uri
);
767 entry
= rhythmdb_entry_new (db
,
768 RHYTHMDB_ENTRY_TYPE_PODCAST_POST
,
773 g_value_init (&val
, G_TYPE_STRING
);
774 g_value_set_string (&val
, name
);
775 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_ALBUM
, &val
);
777 g_value_reset (&val
);
778 g_value_set_static_string (&val
, _("Podcast"));
779 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_GENRE
, &val
);
781 g_value_reset (&val
);
782 g_value_set_string (&val
, title
);
783 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_TITLE
, &val
);
785 g_value_reset (&val
);
787 g_value_set_string (&val
, subtitle
);
789 g_value_set_static_string (&val
, "");
790 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_SUBTITLE
, &val
);
792 g_value_reset (&val
);
794 g_value_set_string (&val
, description
);
796 g_value_set_static_string (&val
, "");
797 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_DESCRIPTION
, &val
);
799 g_value_reset (&val
);
801 g_value_set_string (&val
, generator
);
803 g_value_set_static_string (&val
, "");
804 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_ARTIST
, &val
);
805 g_value_unset (&val
);
807 g_value_init (&val
, G_TYPE_ULONG
);
808 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_PAUSED
);
809 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
811 g_value_reset (&val
);
812 g_value_set_ulong (&val
, date
);
813 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &val
);
815 g_value_reset (&val
);
816 g_value_set_ulong (&val
, duration
);
817 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_DURATION
, &val
);
819 g_value_reset (&val
);
820 g_value_set_ulong (&val
, 0);
821 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_LAST_PLAYED
, &val
);
824 g_get_current_time (&time
);
825 g_value_reset (&val
);
826 g_value_set_ulong (&val
, time
.tv_sec
);
827 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_FIRST_SEEN
, &val
);
828 g_value_unset (&val
);
830 /* initialize the rating */
831 g_value_init (&val
, G_TYPE_DOUBLE
);
832 g_value_set_double (&val
, 2.5);
833 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_RATING
, &val
);
834 g_value_unset (&val
);
836 g_value_init (&val
, G_TYPE_UINT64
);
837 g_value_set_uint64 (&val
, filesize
);
838 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_FILE_SIZE
, &val
);
839 g_value_unset (&val
);
845 rb_podcast_manager_save_metadata (RhythmDB
*db
, RhythmDBEntry
*entry
, const char *uri
)
847 RBMetaData
*md
= rb_metadata_new();
848 GError
*error
= NULL
;
852 rb_debug("Loading podcast metadata");
853 rb_metadata_load (md
, uri
, &error
);
856 /* this probably isn't an audio enclosure. or some other error */
857 g_value_init (&val
, G_TYPE_ULONG
);
858 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_ERROR
);
859 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
860 g_value_unset (&val
);
862 g_value_init (&val
, G_TYPE_STRING
);
863 g_value_set_string (&val
, error
->message
);
864 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_PLAYBACK_ERROR
, &val
);
865 g_value_unset (&val
);
867 rhythmdb_commit (db
);
870 g_error_free (error
);
875 mime
= rb_metadata_get_mime (md
);
877 g_value_init (&val
, G_TYPE_STRING
);
878 g_value_set_string (&val
, mime
);
879 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_MIMETYPE
, &val
);
880 g_value_unset (&val
);
883 if (rb_metadata_get (md
,
884 RB_METADATA_FIELD_DURATION
,
886 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_DURATION
, &val
);
887 g_value_unset (&val
);
890 if (rb_metadata_get (md
,
891 RB_METADATA_FIELD_BITRATE
,
893 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_BITRATE
, &val
);
894 g_value_unset (&val
);
897 rhythmdb_commit (db
);
904 rb_podcast_manager_db_entry_added_cb (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
906 RhythmDBEntryType type
= rhythmdb_entry_get_entry_type (entry
);
908 if (type
!= RHYTHMDB_ENTRY_TYPE_PODCAST_POST
)
911 rb_podcast_manager_download_entry (pd
, entry
);
915 write_job_data (RBPodcastManagerInfo
*data
)
919 RhythmDB
*db
= data
->pd
->priv
->db
;
921 rb_debug ("in the write_job");
923 g_value_init (&val
, G_TYPE_UINT64
);
924 g_value_set_uint64 (&val
, data
->total_size
);
925 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_FILE_SIZE
, &val
);
926 g_value_unset (&val
);
928 g_value_init (&val
, G_TYPE_ULONG
);
929 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_COMPLETE
);
930 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
931 g_value_unset (&val
);
933 rb_podcast_manager_save_metadata (db
, data
->entry
,
934 gnome_vfs_uri_to_string (data
->write_uri
, GNOME_VFS_URI_HIDE_NONE
));
936 rhythmdb_commit (db
);
940 download_info_free (RBPodcastManagerInfo
*data
)
942 if (data
->write_uri
) {
943 gnome_vfs_uri_unref (data
->write_uri
);
944 data
->write_uri
= NULL
;
947 if (data
->read_uri
) {
948 gnome_vfs_uri_unref (data
->read_uri
);
949 data
->read_uri
= NULL
;
952 g_mutex_free (data
->mutex_working
);
957 static RBPodcastManagerInfo
*
958 download_info_new (void)
960 RBPodcastManagerInfo
*data
= g_new0 (RBPodcastManagerInfo
, 1);
963 data
->write_uri
= NULL
;
964 data
->read_uri
= NULL
;
965 data
->mutex_working
= g_mutex_new ();
966 data
->total_size
= 0;
968 data
->canceled
= FALSE
;
974 start_job (RBPodcastManagerInfo
*data
)
977 GList
*source_uri_list
= NULL
;
978 GList
*target_uri_list
= NULL
;
980 rb_debug ("start job");
982 GDK_THREADS_ENTER ();
983 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[START_DOWNLOAD
],
985 GDK_THREADS_LEAVE ();
987 source_uri_list
= g_list_prepend (source_uri_list
, data
->read_uri
);
988 target_uri_list
= g_list_prepend (target_uri_list
, data
->write_uri
);
990 g_mutex_lock (data
->mutex_working
);
992 rb_debug ("start async copy");
993 gnome_vfs_async_xfer ( &data
->read_handle
,
996 GNOME_VFS_XFER_DEFAULT
,
997 GNOME_VFS_XFER_ERROR_MODE_ABORT
,
998 GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
,
999 GNOME_VFS_PRIORITY_DEFAULT
,
1000 (GnomeVFSAsyncXferProgressCallback
) download_progress_update_cb
,
1002 (GnomeVFSXferProgressCallback
) download_progress_cb
,
1008 rb_podcast_manager_cancel_all (RBPodcastManager
*pd
)
1014 g_mutex_lock (pd
->priv
->download_list_mutex
);
1015 lst
= g_list_reverse (pd
->priv
->download_list
);
1016 g_mutex_unlock (pd
->priv
->download_list_mutex
);
1018 rb_debug ("cancel all job %d", g_list_length (lst
));
1019 lst_len
= g_list_length (lst
);
1021 for (i
=0; i
< lst_len
; i
++) {
1022 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) lst
->data
;
1025 rb_debug ("cancel next job");
1029 g_mutex_lock (pd
->priv
->mutex_job
);
1030 g_mutex_unlock (pd
->priv
->mutex_job
);
1035 end_job (RBPodcastManagerInfo
*data
)
1037 RBPodcastManager
*pd
= data
->pd
;
1039 rb_debug ("end_job");
1041 g_mutex_lock (data
->pd
->priv
->download_list_mutex
);
1042 data
->pd
->priv
->download_list
= g_list_remove (data
->pd
->priv
->download_list
, (gconstpointer
) data
);
1043 g_mutex_unlock (data
->pd
->priv
->download_list_mutex
);
1045 g_mutex_unlock (data
->mutex_working
);
1047 if (data
->canceled
!= TRUE
) {
1048 GDK_THREADS_ENTER ();
1050 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[FINISH_DOWNLOAD
],
1053 GDK_THREADS_LEAVE ();
1056 download_info_free (data
);
1057 g_mutex_unlock (pd
->priv
->mutex_job
);
1059 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
1063 cancel_job (RBPodcastManagerInfo
*data
)
1065 if (g_mutex_trylock (data
->mutex_working
) == FALSE
) {
1066 rb_debug ("async cancel");
1067 data
->canceled
= TRUE
;
1070 rb_debug ("job cancel");
1072 g_mutex_lock (data
->pd
->priv
->download_list_mutex
);
1073 data
->pd
->priv
->download_list
= g_list_remove (data
->pd
->priv
->download_list
, (gconstpointer
) data
);
1074 g_mutex_unlock (data
->pd
->priv
->download_list_mutex
);
1076 g_mutex_unlock (data
->mutex_working
);
1078 download_info_free (data
);
1084 download_progress_cb (GnomeVFSXferProgressInfo
*info
, gpointer cb_data
)
1086 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) cb_data
;
1089 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1092 if (info
->status
!= GNOME_VFS_XFER_PROGRESS_STATUS_OK
||
1093 ((info
->phase
== GNOME_VFS_XFER_PHASE_COMPLETED
) && (info
->file_size
== 0))) {
1095 rb_debug ("error on download");
1096 g_value_init (&val
, G_TYPE_ULONG
);
1097 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_ERROR
);
1098 GDK_THREADS_ENTER ();
1099 rhythmdb_entry_set (data
->pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
1100 rhythmdb_commit (data
->pd
->priv
->db
);
1101 GDK_THREADS_LEAVE ();
1102 g_value_unset (&val
);
1105 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1108 if (rhythmdb_entry_get_string (data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
) == NULL
) {
1110 RhythmDB
*db
= data
->pd
->priv
->db
;
1111 char *uri
= gnome_vfs_uri_to_string (data
->write_uri
, GNOME_VFS_URI_HIDE_NONE
);
1112 char *canon_uri
= rb_canonicalise_uri (uri
);
1115 g_value_init (&val
, G_TYPE_STRING
);
1116 g_value_set_string (&val
, canon_uri
);
1117 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
, &val
);
1118 g_value_unset (&val
);
1119 rhythmdb_commit (db
);
1123 if (info
->phase
== GNOME_VFS_XFER_PHASE_COMPLETED
) {
1124 if (data
->canceled
!= TRUE
) {
1125 rb_debug ("download completed");
1126 data
->total_size
= info
->file_size
;
1127 write_job_data (data
);
1131 return GNOME_VFS_XFER_ERROR_ACTION_SKIP
;
1134 if (data
->canceled
== TRUE
) {
1135 rb_debug ("job canceled");
1136 gnome_vfs_async_cancel (data
->read_handle
);
1137 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1144 download_progress_update_cb (GnomeVFSAsyncHandle
*handle
, GnomeVFSXferProgressInfo
*info
, gpointer cb_data
)
1147 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) cb_data
;
1150 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1153 if ((info
->phase
== GNOME_VFS_XFER_PHASE_COPYING
) &&
1154 (data
->entry
!= NULL
)) {
1155 guint local_progress
= 0;
1157 if (info
->file_size
> 0)
1158 local_progress
= (gint
) 100 * info
->total_bytes_copied
/ info
->file_size
;
1160 if (local_progress
!= data
->progress
) {
1163 g_value_init (&val
, G_TYPE_ULONG
);
1164 g_value_set_ulong (&val
, local_progress
);
1165 rhythmdb_entry_set (data
->pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
1166 g_value_unset (&val
);
1168 GDK_THREADS_ENTER ();
1170 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[STATUS_CHANGED
],
1171 0, data
->entry
, local_progress
);
1173 GDK_THREADS_LEAVE ();
1174 data
->progress
= local_progress
;
1178 return GNOME_VFS_XFER_ERROR_ACTION_SKIP
;
1182 rb_podcast_manager_unsubscribe_feed (RhythmDB
*db
, const char *url
)
1184 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (db
, url
);
1187 g_value_init (&val
, G_TYPE_ULONG
);
1188 g_value_set_ulong (&val
, 0);
1189 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
1190 g_value_unset (&val
);
1196 rb_podcast_manager_remove_feed (RBPodcastManager
*pd
, const char *url
, gboolean remove_files
)
1198 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (pd
->priv
->db
, url
);
1201 rb_debug ("Removing podcast feed: %s remove_files: %d", url
, remove_files
);
1203 rb_podcast_manager_set_remove_files (pd
, remove_files
);
1204 rhythmdb_entry_delete (pd
->priv
->db
, entry
);
1205 rhythmdb_commit (pd
->priv
->db
);
1213 rb_podcast_manager_db_entry_deleted_cb (RBPodcastManager
*pd
,
1214 RhythmDBEntry
*entry
)
1216 RhythmDBEntryType type
= rhythmdb_entry_get_entry_type (entry
);
1218 if ((type
== RHYTHMDB_ENTRY_TYPE_PODCAST_POST
) && (pd
->priv
->remove_files
== TRUE
)) {
1219 const char *file_name
;
1220 const char *dir_name
;
1221 const char *conf_dir_name
;
1222 GnomeVFSResult result
;
1224 rb_debug ("Handling entry deleted");
1226 /* make sure we're not downloading it */
1227 rb_podcast_manager_cancel_download (pd
, entry
);
1229 file_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MOUNTPOINT
);
1230 if (file_name
== NULL
) {
1231 /* episode has not been downloaded */
1232 rb_debug ("Episode not downloaded, skipping.");
1236 result
= gnome_vfs_unlink (file_name
);
1237 if (result
!= GNOME_VFS_OK
) {
1238 rb_debug ("Removing episode failed: %s", gnome_vfs_result_to_string (result
));
1243 rb_debug ("removing dir");
1244 conf_dir_name
= eel_gconf_get_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
);
1246 dir_name
= g_build_filename (conf_dir_name
,
1247 rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
),
1249 gnome_vfs_remove_directory (dir_name
);
1251 } else if (type
== RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
) {
1252 GtkTreeModel
*query_model
;
1255 query_model
= GTK_TREE_MODEL (rhythmdb_query_model_new_empty (pd
->priv
->db
));
1256 rhythmdb_do_full_query (pd
->priv
->db
,
1257 RHYTHMDB_QUERY_RESULTS (query_model
),
1258 RHYTHMDB_QUERY_PROP_EQUALS
,
1259 RHYTHMDB_PROP_TYPE
, RHYTHMDB_ENTRY_TYPE_PODCAST_POST
,
1260 RHYTHMDB_QUERY_PROP_LIKE
,
1261 RHYTHMDB_PROP_SUBTITLE
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
),
1262 RHYTHMDB_QUERY_END
);
1264 if (gtk_tree_model_get_iter_first (query_model
, &iter
)) {
1267 RhythmDBEntry
*entry
;
1269 gtk_tree_model_get (query_model
, &iter
, 0, &entry
, -1);
1270 has_next
= gtk_tree_model_iter_next (query_model
, &iter
);
1271 rhythmdb_entry_delete (pd
->priv
->db
, entry
);
1272 rhythmdb_entry_unref (entry
);
1276 rhythmdb_commit (pd
->priv
->db
);
1279 g_object_unref (query_model
);
1284 rb_podcast_manager_cancel_download (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
1288 g_mutex_lock (pd
->priv
->download_list_mutex
);
1290 lst
= pd
->priv
->download_list
;
1292 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) lst
->data
;
1293 if (data
->entry
== entry
) {
1294 rb_debug ("Found job");
1299 g_mutex_unlock (pd
->priv
->download_list_mutex
);
1302 cancel_job (lst
->data
);
1306 rb_podcast_manager_update_synctime (RBPodcastManager
*pd
)
1309 gint index
= eel_gconf_get_integer (CONF_STATE_PODCAST_DOWNLOAD_INTERVAL
);
1313 case UPDATE_EVERY_HOUR
:
1314 value
= time (NULL
) + 3600;
1316 case UPDATE_EVERY_DAY
:
1317 value
= time (NULL
) + (3600 * 24);
1319 case UPDATE_EVERY_WEEK
:
1320 value
= time (NULL
) + (3600 * 24 * 7);
1322 case UPDATE_MANUALLY
:
1329 eel_gconf_set_integer (CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME
, value
);
1330 eel_gconf_suggest_sync ();
1331 pd
->priv
->next_time
= value
;
1332 rb_podcast_manager_start_sync (pd
);
1336 rb_podcast_manager_config_changed (GConfClient
* client
,
1341 rb_podcast_manager_update_synctime (RB_PODCAST_MANAGER (user_data
));
1345 rb_podcast_manager_set_remove_files (RBPodcastManager
*pd
, gboolean flag
)
1347 pd
->priv
->remove_files
= flag
;
1352 rb_podcast_manager_get_remove_files (RBPodcastManager
*pd
)
1354 return pd
->priv
->remove_files
;
1358 rb_podcast_manager_insert_feed (RBPodcastManager
*pd
, RBPodcastChannel
*data
)
1360 GValue description_val
= { 0, };
1361 GValue title_val
= { 0, };
1362 GValue subtitle_val
= { 0, };
1363 GValue summary_val
= { 0, };
1364 GValue lang_val
= { 0, };
1365 GValue copyright_val
= { 0, };
1366 GValue image_val
= { 0, };
1367 GValue author_val
= { 0, };
1368 GValue status_val
= { 0, };
1369 GValue last_post_val
= { 0, };
1370 GValue last_update_val
= { 0, };
1371 gulong last_post
= 0;
1372 gulong new_last_post
;
1373 GList
*download_entries
= NULL
;
1374 gboolean new_feed
, updated
, download_last
;
1375 RhythmDB
*db
= pd
->priv
->db
;
1377 RhythmDBEntry
*entry
;
1381 if (data
->title
== NULL
) {
1382 g_list_free (data
->posts
);
1389 /* processing podcast head */
1390 entry
= rhythmdb_entry_lookup_by_location (db
, (gchar
*)data
->url
);
1392 if (rhythmdb_entry_get_entry_type (entry
) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
)
1395 rb_debug ("Head found");
1396 g_value_init (&status_val
, G_TYPE_ULONG
);
1397 g_value_set_ulong (&status_val
, 1);
1398 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
1399 g_value_unset (&status_val
);
1400 last_post
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_POST_TIME
);
1403 rb_debug ("Insert new entry");
1404 entry
= rhythmdb_entry_new (db
,
1405 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
,
1406 (gchar
*) data
->url
);
1409 rb_debug("New entry create\n");
1411 g_value_init (&title_val
, G_TYPE_STRING
);
1412 g_value_set_string (&title_val
, (gchar
* ) data
->title
);
1413 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_TITLE
, &title_val
);
1414 g_value_unset (&title_val
);
1416 g_value_init (&author_val
, G_TYPE_STRING
);
1418 g_value_set_string (&author_val
, (gchar
*) data
->author
);
1420 g_value_set_static_string (&author_val
, _("Unknown"));
1421 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_ARTIST
, &author_val
);
1422 g_value_unset (&author_val
);
1424 if (data
->subtitle
) {
1425 g_value_init (&subtitle_val
, G_TYPE_STRING
);
1426 g_value_set_string (&subtitle_val
, (gchar
*) data
->subtitle
);
1427 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_SUBTITLE
, &subtitle_val
);
1428 g_value_unset (&subtitle_val
);
1431 if (data
->description
) {
1432 g_value_init (&description_val
, G_TYPE_STRING
);
1433 g_value_set_string (&description_val
, (gchar
*) data
->description
);
1434 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_DESCRIPTION
, &description_val
);
1435 g_value_unset (&description_val
);
1438 if (data
->summary
) {
1439 g_value_init (&summary_val
, G_TYPE_STRING
);
1440 g_value_set_string (&summary_val
, (gchar
*) data
->summary
);
1441 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_SUMMARY
, &summary_val
);
1442 g_value_unset (&summary_val
);
1446 g_value_init (&lang_val
, G_TYPE_STRING
);
1447 g_value_set_string (&lang_val
, (gchar
*) data
->lang
);
1448 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_LANG
, &lang_val
);
1449 g_value_unset (&lang_val
);
1452 if (data
->copyright
) {
1453 g_value_init (©right_val
, G_TYPE_STRING
);
1454 g_value_set_string (©right_val
, (gchar
*) data
->copyright
);
1455 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_COPYRIGHT
, ©right_val
);
1456 g_value_unset (©right_val
);
1460 g_value_init (&image_val
, G_TYPE_STRING
);
1461 g_value_set_string (&image_val
, (gchar
*) data
->img
);
1462 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_IMAGE
, &image_val
);
1463 g_value_unset (&image_val
);
1466 g_value_init (&status_val
, G_TYPE_ULONG
);
1467 g_value_set_ulong (&status_val
, 1);
1468 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
1469 g_value_unset (&status_val
);
1471 rb_debug("Podcast head Inserted");
1474 /* insert episodes */
1475 new_last_post
= last_post
;
1478 download_last
= (eel_gconf_get_integer (CONF_STATE_PODCAST_DOWNLOAD_INTERVAL
) != UPDATE_MANUALLY
);
1479 for (lst_songs
= data
->posts
; lst_songs
!= NULL
; lst_songs
= g_list_next (lst_songs
)) {
1480 RBPodcastItem
*item
= (RBPodcastItem
*) lst_songs
->data
;
1481 RhythmDBEntry
*post_entry
;
1483 if (item
->pub_date
> last_post
|| item
->pub_date
== 0) {
1487 rb_podcast_manager_add_post (db
,
1488 (gchar
*) data
->title
,
1489 (gchar
*) item
->title
,
1490 (gchar
*) data
->url
,
1491 (gchar
*) (item
->author
? item
->author
: data
->author
),
1492 (gchar
*) item
->url
,
1493 (gchar
*) item
->description
,
1494 (gulong
) (item
->pub_date
> 0 ? item
->pub_date
: data
->pub_date
),
1495 (gulong
) item
->duration
,
1497 if (post_entry
&& item
->pub_date
>= new_last_post
) {
1498 if (item
->pub_date
> new_last_post
) {
1499 g_list_free (download_entries
);
1500 download_entries
= NULL
;
1502 download_entries
= g_list_prepend (download_entries
, post_entry
);
1503 new_last_post
= item
->pub_date
;
1508 if (download_last
) {
1509 GValue status
= {0,};
1512 g_value_init (&status
, G_TYPE_ULONG
);
1513 g_value_set_ulong (&status
, RHYTHMDB_PODCAST_STATUS_WAITING
);
1514 for (t
= download_entries
; t
!= NULL
; t
= g_list_next (t
)) {
1515 rhythmdb_entry_set (db
,
1516 (RhythmDBEntry
*) t
->data
,
1517 RHYTHMDB_PROP_STATUS
,
1520 g_value_unset (&status
);
1522 g_list_free (download_entries
);
1525 g_signal_emit (pd
, rb_podcast_manager_signals
[FEED_UPDATES_AVALIABLE
],
1528 if (data
->pub_date
> new_last_post
)
1529 new_last_post
= data
->pub_date
;
1531 g_value_init (&last_post_val
, G_TYPE_ULONG
);
1532 g_value_set_ulong (&last_post_val
, new_last_post
);
1535 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &last_post_val
);
1537 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &last_post_val
);
1538 g_value_unset (&last_post_val
);
1540 g_value_init (&last_update_val
, G_TYPE_ULONG
);
1541 g_value_set_ulong (&last_update_val
, time(NULL
));
1544 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_LAST_SEEN
, &last_update_val
);
1546 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_LAST_SEEN
, &last_update_val
);
1547 g_value_unset (&last_update_val
);
1549 rhythmdb_commit (db
);
1553 rb_podcast_manager_event_loop (RBPodcastManager
*pd
)
1555 RBPodcastManagerEvent
*event
;
1557 while ((event
= g_async_queue_try_pop (pd
->priv
->event_queue
))) {
1558 switch (event
->type
)
1560 case EVENT_INSERT_FEED
:
1561 rb_podcast_manager_insert_feed (pd
, event
->channel
);
1563 case EVENT_ERROR_FEED
:
1566 error_msg
= g_strdup_printf (_("There was a problem adding this podcast. Please verify the URL: %s"),
1567 (gchar
*) event
->channel
->url
);
1568 g_signal_emit (G_OBJECT (pd
),
1569 rb_podcast_manager_signals
[PROCESS_ERROR
],
1576 rb_podcast_parse_channel_free (event
->channel
);
1580 g_async_queue_unref (pd
->priv
->event_queue
);
1586 rb_podcast_manager_abort_subscribe (RBPodcastManager
*pd
)
1588 RBPodcastManagerEvent
*event
;
1590 /* remove all event processing functions */
1591 while (g_idle_remove_by_data (pd
))
1594 /* purge the event queue */
1595 while ((event
= g_async_queue_try_pop (pd
->priv
->event_queue
))) {
1596 rb_podcast_parse_channel_free (event
->channel
);
1602 rb_podcast_manager_shutdown (RBPodcastManager
*pd
)
1604 rb_podcast_manager_cancel_all (pd
);
1605 rb_podcast_manager_abort_subscribe (pd
);
1609 rb_podcast_manager_get_podcast_dir (RBPodcastManager
*pd
)
1611 gchar
*conf_dir_name
= eel_gconf_get_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
);
1613 if (conf_dir_name
== NULL
|| (strcmp (conf_dir_name
, "") == 0)) {
1614 conf_dir_name
= g_build_filename (g_get_home_dir (),
1617 eel_gconf_set_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
, conf_dir_name
);
1620 return conf_dir_name
;