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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
30 #include <libgnomevfs/gnome-vfs-uri.h>
32 #include "rb-preferences.h"
33 #include "eel-gconf-extensions.h"
34 #include "rb-podcast-manager.h"
35 #include "rb-file-helpers.h"
37 #include "rb-podcast-marshal.h"
39 #include "rhythmdb-query-model.h"
40 #include "rb-podcast-parse.h"
41 #include "rb-dialog.h"
42 #include "rb-metadata.h"
44 #define CONF_STATE_PODCAST_PREFIX CONF_PREFIX "/state/podcast"
45 #define CONF_STATE_PODCAST_DOWNLOAD_DIR CONF_STATE_PODCAST_PREFIX "/download_prefix"
46 #define CONF_STATE_PODCAST_DOWNLOAD_INTERVAL CONF_STATE_PODCAST_PREFIX "/download_interval"
47 #define CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME CONF_STATE_PODCAST_PREFIX "/download_next_time"
69 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
;
106 /* used on donwload thread */
109 RBPodcastManager
*pd
;
110 RhythmDBEntry
*entry
;
111 GnomeVFSAsyncHandle
*read_handle
;
112 GnomeVFSURI
*write_uri
;
113 GnomeVFSURI
*read_uri
;
114 GMutex
*mutex_working
;
119 } RBPodcastManagerInfo
;
121 /* used on subscribe thread */
124 RBPodcastManager
*pd
;
126 } RBPodcastThreadInfo
;
129 static guint rb_podcast_manager_signals
[LAST_SIGNAL
] = { 0 };
132 static void rb_podcast_manager_class_init (RBPodcastManagerClass
*klass
);
133 static void rb_podcast_manager_init (RBPodcastManager
*dp
);
134 static GObject
*rb_podcast_manager_constructor (GType type
, guint n_construct_properties
,
135 GObjectConstructParam
*construct_properties
);
136 static void rb_podcast_manager_finalize (GObject
*object
);
137 static void rb_podcast_manager_set_property (GObject
*object
,
141 static void rb_podcast_manager_get_property (GObject
*object
,
145 static void rb_podcast_manager_copy_post (RBPodcastManager
*pd
);
146 static int rb_podcast_manager_mkdir_with_parents (const gchar
*pathname
,
148 static gboolean
rb_podcast_manager_sync_head_cb (gpointer data
);
149 static gboolean
rb_podcast_manager_head_query_cb (GtkTreeModel
*query_model
,
152 RBPodcastManager
*data
);
153 static gboolean
rb_podcast_manager_save_metadata (RhythmDB
*db
,
154 RhythmDBEntry
*entry
,
156 static void rb_podcast_manager_db_entry_added_cb (RBPodcastManager
*pd
,
157 RhythmDBEntry
*entry
);
158 static void rb_podcast_manager_db_entry_deleted_cb (RBPodcastManager
*pd
,
159 RhythmDBEntry
*entry
);
160 static gboolean
rb_podcast_manager_next_file (RBPodcastManager
* pd
);
161 static void rb_podcast_manager_insert_feed (RBPodcastManager
*pd
, RBPodcastChannel
*data
);
162 static void rb_podcast_manager_abort_subscribe (RBPodcastManager
*pd
);
165 static gboolean
rb_podcast_manager_event_loop (RBPodcastManager
*pd
) ;
166 static gpointer
rb_podcast_manager_thread_parse_feed (RBPodcastThreadInfo
*info
);
169 /* async read file functions */
170 static guint
download_progress_cb (GnomeVFSXferProgressInfo
*info
,
172 static guint
download_progress_update_cb (GnomeVFSAsyncHandle
*handle
,
173 GnomeVFSXferProgressInfo
*info
,
176 /* internal functions */
177 static void download_info_free (RBPodcastManagerInfo
*data
);
178 static RBPodcastManagerInfo
*download_info_new (void);
179 static void start_job (RBPodcastManagerInfo
*data
);
180 static void end_job (RBPodcastManagerInfo
*data
);
181 static void cancel_job (RBPodcastManagerInfo
*pd
);
182 static void write_job_data (RBPodcastManagerInfo
*data
);
183 static void rb_podcast_manager_update_synctime (RBPodcastManager
*pd
);
184 static void rb_podcast_manager_config_changed (GConfClient
* client
,
189 G_DEFINE_TYPE (RBPodcastManager
, rb_podcast_manager
, G_TYPE_OBJECT
)
193 rb_podcast_manager_class_init (RBPodcastManagerClass
*klass
)
195 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
197 object_class
->constructor
= rb_podcast_manager_constructor
;
198 object_class
->finalize
= rb_podcast_manager_finalize
;
200 object_class
->set_property
= rb_podcast_manager_set_property
;
201 object_class
->get_property
= rb_podcast_manager_get_property
;
203 g_object_class_install_property (object_class
,
205 g_param_spec_object ("db",
211 rb_podcast_manager_signals
[STATUS_CHANGED
] =
212 g_signal_new ("status_changed",
213 G_OBJECT_CLASS_TYPE (object_class
),
215 G_STRUCT_OFFSET (RBPodcastManagerClass
, status_changed
),
217 rb_podcast_marshal_VOID__POINTER_ULONG
,
223 rb_podcast_manager_signals
[START_DOWNLOAD
] =
224 g_signal_new ("start_download",
225 G_OBJECT_CLASS_TYPE (object_class
),
227 G_STRUCT_OFFSET (RBPodcastManagerClass
, start_download
),
229 g_cclosure_marshal_VOID__POINTER
,
234 rb_podcast_manager_signals
[FINISH_DOWNLOAD
] =
235 g_signal_new ("finish_download",
236 G_OBJECT_CLASS_TYPE (object_class
),
238 G_STRUCT_OFFSET (RBPodcastManagerClass
, finish_download
),
240 g_cclosure_marshal_VOID__POINTER
,
245 rb_podcast_manager_signals
[FEED_UPDATES_AVALIABLE
] =
246 g_signal_new ("feed_updates_avaliable",
247 G_OBJECT_CLASS_TYPE (object_class
),
249 G_STRUCT_OFFSET (RBPodcastManagerClass
, feed_updates_avaliable
),
251 g_cclosure_marshal_VOID__POINTER
,
256 rb_podcast_manager_signals
[PROCESS_ERROR
] =
257 g_signal_new ("process_error",
258 G_OBJECT_CLASS_TYPE (object_class
),
260 G_STRUCT_OFFSET (RBPodcastManagerClass
, process_error
),
262 g_cclosure_marshal_VOID__STRING
,
267 g_type_class_add_private (klass
, sizeof (RBPodcastManagerPrivate
));
271 rb_podcast_manager_init (RBPodcastManager
*pd
)
273 pd
->priv
= RB_PODCAST_MANAGER_GET_PRIVATE (pd
);
275 pd
->priv
->source_sync
= 0;
276 pd
->priv
->mutex_job
= g_mutex_new();
277 pd
->priv
->download_list_mutex
= g_mutex_new();
278 pd
->priv
->event_queue
= g_async_queue_new ();
280 eel_gconf_monitor_add (CONF_STATE_PODCAST_PREFIX
);
284 rb_podcast_manager_constructor (GType type
, guint n_construct_properties
,
285 GObjectConstructParam
*construct_properties
)
287 RBPodcastManager
*pd
;
289 pd
= RB_PODCAST_MANAGER (G_OBJECT_CLASS (rb_podcast_manager_parent_class
)
290 ->constructor (type
, n_construct_properties
, construct_properties
));
292 pd
->priv
->update_interval_notify_id
= eel_gconf_notification_add (CONF_STATE_PODCAST_DOWNLOAD_INTERVAL
,
293 rb_podcast_manager_config_changed
,
297 return G_OBJECT (pd
);
302 rb_podcast_manager_finalize (GObject
*object
)
304 RBPodcastManager
*pd
;
305 g_return_if_fail (object
!= NULL
);
306 g_return_if_fail (RB_IS_PODCAST_MANAGER (object
));
308 pd
= RB_PODCAST_MANAGER(object
);
310 g_return_if_fail (pd
->priv
!= NULL
);
313 eel_gconf_monitor_remove (CONF_STATE_PODCAST_PREFIX
);
315 if (pd
->priv
->source_sync
) {
316 g_source_remove (pd
->priv
->source_sync
);
317 pd
->priv
->source_sync
= 0;
321 eel_gconf_notification_remove (pd
->priv
->update_interval_notify_id
);
324 if (pd
->priv
->download_list
) {
325 g_list_foreach (pd
->priv
->download_list
, (GFunc
)g_free
, NULL
);
326 g_list_free (pd
->priv
->download_list
);
330 g_mutex_free (pd
->priv
->mutex_job
);
331 g_mutex_free (pd
->priv
->download_list_mutex
);
332 g_async_queue_unref (pd
->priv
->event_queue
);
334 G_OBJECT_CLASS (rb_podcast_manager_parent_class
)->finalize (object
);
335 rb_debug ("Podcast Manager END");
339 rb_podcast_manager_set_property (GObject
*object
,
344 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (object
);
349 g_signal_handlers_disconnect_by_func (G_OBJECT (pd
->priv
->db
),
350 G_CALLBACK (rb_podcast_manager_db_entry_added_cb
),
353 g_signal_handlers_disconnect_by_func (G_OBJECT (pd
->priv
->db
),
354 G_CALLBACK (rb_podcast_manager_db_entry_deleted_cb
),
359 pd
->priv
->db
= g_value_get_object (value
);
361 g_signal_connect_object (G_OBJECT (pd
->priv
->db
),
363 G_CALLBACK (rb_podcast_manager_db_entry_added_cb
),
364 pd
, G_CONNECT_SWAPPED
);
366 g_signal_connect_object (G_OBJECT (pd
->priv
->db
),
368 G_CALLBACK (rb_podcast_manager_db_entry_deleted_cb
),
369 pd
, G_CONNECT_SWAPPED
);
373 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
378 rb_podcast_manager_get_property (GObject
*object
,
383 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (object
);
387 g_value_set_object (value
, pd
->priv
->db
);
390 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
397 rb_podcast_manager_new (RhythmDB
*db
)
399 RBPodcastManager
*pd
;
401 pd
= g_object_new (RB_TYPE_PODCAST_MANAGER
, "db", db
, NULL
);
407 rb_podcast_manager_download_entry (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
413 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
414 if ((status
< RHYTHMDB_PODCAST_STATUS_COMPLETE
) ||
415 (status
== RHYTHMDB_PODCAST_STATUS_WAITING
)) {
416 RBPodcastManagerInfo
*data
;
417 if (status
< RHYTHMDB_PODCAST_STATUS_COMPLETE
) {
418 GValue status_val
= { 0, };
419 g_value_init (&status_val
, G_TYPE_ULONG
);
420 g_value_set_ulong (&status_val
, RHYTHMDB_PODCAST_STATUS_WAITING
);
421 rhythmdb_entry_set_nonotify (pd
->priv
->db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
422 g_value_unset (&status_val
);
424 rb_debug ("Try insert entry for download.");
425 data
= download_info_new();
428 g_mutex_lock (pd
->priv
->download_list_mutex
);
429 pd
->priv
->download_list
= g_list_append (pd
->priv
->download_list
, data
);
430 g_mutex_unlock (pd
->priv
->download_list_mutex
);
431 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
436 rb_podcast_manager_entry_downloaded (RhythmDBEntry
*entry
)
439 const gchar
*file_name
;
442 type
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TYPE
);
443 g_assert (type
== RHYTHMDB_ENTRY_TYPE_PODCAST_POST
);
445 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
446 file_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MOUNTPOINT
);
448 return (status
!= RHYTHMDB_PODCAST_STATUS_ERROR
&& file_name
!= NULL
);
452 rb_podcast_manager_start_sync (RBPodcastManager
*pd
)
455 if (pd
->priv
->next_time
> 0) {
456 next_time
= pd
->priv
->next_time
;
458 next_time
= eel_gconf_get_integer(CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME
);
462 if (pd
->priv
->source_sync
!= 0) {
463 g_source_remove (pd
->priv
->source_sync
);
464 pd
->priv
->source_sync
= 0;
466 next_time
= next_time
- ((int)time (NULL
));
467 if (next_time
<= 0) {
468 rb_podcast_manager_update_feeds (pd
);
469 pd
->priv
->next_time
= 0;
470 rb_podcast_manager_update_synctime (pd
);
473 pd
->priv
->source_sync
= g_timeout_add (next_time
* 1000, (GSourceFunc
) rb_podcast_manager_sync_head_cb
, pd
);
479 rb_podcast_manager_sync_head_cb (gpointer data
)
481 RBPodcastManager
*pd
= RB_PODCAST_MANAGER (data
);
482 rb_podcast_manager_update_feeds (pd
);
483 pd
->priv
->source_sync
= 0;
484 pd
->priv
->next_time
= 0;
485 rb_podcast_manager_update_synctime (RB_PODCAST_MANAGER (data
));
490 rb_podcast_manager_update_feeds (RBPodcastManager
*pd
)
492 GtkTreeModel
* query_model
= GTK_TREE_MODEL (rhythmdb_query_model_new_empty(pd
->priv
->db
));
494 rhythmdb_do_full_query (pd
->priv
->db
,
495 RHYTHMDB_QUERY_RESULTS (query_model
),
496 RHYTHMDB_QUERY_PROP_EQUALS
,
497 RHYTHMDB_PROP_TYPE
, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
,
500 gtk_tree_model_foreach (query_model
,
501 (GtkTreeModelForeachFunc
) rb_podcast_manager_head_query_cb
,
504 g_object_unref (query_model
);
508 rb_podcast_manager_head_query_cb (GtkTreeModel
*query_model
,
509 GtkTreePath
*path
, GtkTreeIter
*iter
,
510 RBPodcastManager
*manager
)
513 RhythmDBEntry
* entry
;
516 gtk_tree_model_get (query_model
, iter
, 0, &entry
, -1);
517 uri
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
);
518 status
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_STATUS
);
520 rb_podcast_manager_subscribe_feed (manager
, uri
);
526 rb_podcast_manager_next_file (RBPodcastManager
* pd
)
529 rb_debug ("try lock file_process mutex");
530 if (g_mutex_trylock (pd
->priv
->mutex_job
) == TRUE
) {
533 g_mutex_lock (pd
->priv
->download_list_mutex
);
534 size
= g_list_length (pd
->priv
->download_list
);
535 g_mutex_unlock (pd
->priv
->download_list_mutex
);
538 rb_podcast_manager_copy_post (pd
);
540 g_mutex_unlock (pd
->priv
->mutex_job
);
542 rb_debug ("not start");
549 rb_podcast_manager_copy_post (RBPodcastManager
*pd
)
551 GnomeVFSURI
*remote_uri
= NULL
;
552 GnomeVFSURI
*local_uri
= NULL
;
553 GValue location_val
= { 0, };
554 const char *location
, *album_name
;
555 char *short_name
, *local_file_name
;
556 char *dir_name
, *conf_dir_name
;
557 RBPodcastManagerInfo
*data
= NULL
;
558 RhythmDBEntry
*entry
;
560 rb_debug ("Stating copy file");
561 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
);
575 g_assert (entry
!= NULL
);
577 location
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
);
578 album_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
);
580 rb_debug ("processing %s", location
);
582 remote_uri
= gnome_vfs_uri_new (location
);
584 rb_debug ("Error downloading podcast: could not create remote uri");
588 if (gnome_vfs_uri_is_local (remote_uri
)) {
589 rb_debug ("Error downloading podcast: uri is local");
594 conf_dir_name
= rb_podcast_manager_get_podcast_dir (pd
);
595 dir_name
= g_build_filename (conf_dir_name
,
598 g_free (conf_dir_name
);
600 if (!g_file_test (dir_name
, G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
)) {
601 if (rb_podcast_manager_mkdir_with_parents (dir_name
, 0750) != 0) {
602 rb_debug ("Error downloading podcast: could not create local dirs");
607 short_name
= gnome_vfs_uri_extract_short_name (remote_uri
);
608 local_file_name
= g_build_filename (dir_name
,
614 rb_debug ("creating file %s\n", local_file_name
);
616 local_uri
= gnome_vfs_uri_new (local_file_name
);
618 rb_debug ("Error downloading podcast: could not create local uri");
622 if (g_file_test (local_file_name
, G_FILE_TEST_EXISTS
)) {
624 GnomeVFSFileInfo
*info
= gnome_vfs_file_info_new ();
625 GnomeVFSResult result
;
627 result
= gnome_vfs_get_file_info_uri (remote_uri
, info
, GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
628 if (result
!= GNOME_VFS_OK
) {
629 rb_debug ("unable to retrieve info on remote of podcast");
632 remote_size
= info
->size
;
635 result
= gnome_vfs_get_file_info (local_file_name
, info
, GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
636 if (result
!= GNOME_VFS_OK
) {
637 rb_debug ("unable to retrieve info on local copy of podcast");
639 } else if (remote_size
== info
->size
) {
641 char *uri
= gnome_vfs_uri_to_string (local_uri
, GNOME_VFS_URI_HIDE_NONE
);
643 rb_debug ("podcast %s already downloaded", location
);
645 g_value_init (&val
, G_TYPE_ULONG
);
646 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_COMPLETE
);
647 rhythmdb_entry_set (pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
648 g_value_unset (&val
);
650 g_value_init (&val
, G_TYPE_STRING
);
651 g_value_set_string (&val
, uri
);
652 rhythmdb_entry_set (pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
, &val
);
653 g_value_unset (&val
);
655 rb_podcast_manager_save_metadata (pd
->priv
->db
, data
->entry
, uri
);
656 rhythmdb_commit (pd
->priv
->db
);
659 } else if (remote_size
> info
->size
) {
660 /* TODO: suport resume file */
662 /* the local file is larger. replace it */
665 gnome_vfs_file_info_unref (info
);
668 g_free (local_file_name
);
670 data
->read_uri
= remote_uri
;
671 data
->write_uri
= local_uri
;
679 gnome_vfs_uri_unref (remote_uri
);
682 gnome_vfs_uri_unref (local_uri
);
684 g_mutex_lock (pd
->priv
->download_list_mutex
);
685 pd
->priv
->download_list
= g_list_remove (pd
->priv
->download_list
, (gconstpointer
) data
);
686 g_mutex_unlock (pd
->priv
->download_list_mutex
);
688 download_info_free (data
);
691 g_mutex_unlock (pd
->priv
->mutex_job
);
692 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
697 rb_podcast_manager_mkdir_with_parents (const gchar
*pathname
,
702 if (pathname
== NULL
|| *pathname
== '\0')
707 fn
= g_strdup (pathname
);
709 if (g_path_is_absolute (fn
))
710 p
= (gchar
*) g_path_skip_root (fn
);
716 while (*p
&& !G_IS_DIR_SEPARATOR (*p
))
724 if (!g_file_test (fn
, G_FILE_TEST_EXISTS
))
726 if (g_mkdir (fn
, mode
) == -1)
732 else if (!g_file_test (fn
, G_FILE_TEST_IS_DIR
))
739 *p
++ = G_DIR_SEPARATOR
;
740 while (*p
&& G_IS_DIR_SEPARATOR (*p
))
752 rb_podcast_manager_subscribe_feed (RBPodcastManager
*pd
, const char* url
)
754 RBPodcastThreadInfo
*info
;
755 gchar
*valid_url
= gnome_vfs_make_uri_from_input (url
);
757 if (valid_url
== NULL
) {
758 rb_error_dialog (NULL
, _("Invalid URL"),
759 _("The URL \"%s\" is not valid, please check it."), url
);
763 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (pd
->priv
->db
, valid_url
);
765 if (rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TYPE
) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
) {
766 /* added as something else, probably iradio */
767 rb_error_dialog (NULL
, _("URL already added"),
768 _("The URL \"%s\" has already been added as a radio station. "
769 "If this is a podcast feed, please remove the radio station."), url
);
774 info
= g_new0 (RBPodcastThreadInfo
, 1);
776 info
->url
= valid_url
;
778 g_async_queue_ref (info
->pd
->priv
->event_queue
);
779 g_thread_create ((GThreadFunc
) rb_podcast_manager_thread_parse_feed
,
786 rb_podcast_manager_thread_parse_feed (RBPodcastThreadInfo
*info
)
788 RBPodcastManagerEvent
*event
= g_new0 (RBPodcastManagerEvent
, 1);
789 RBPodcastChannel
*feed
= g_new0 (RBPodcastChannel
, 1);
791 rb_podcast_parse_load_feed (feed
, info
->url
);
793 event
->channel
= feed
;
794 event
->type
= (feed
->title
== NULL
) ? EVENT_ERROR_FEED
: EVENT_INSERT_FEED
;
796 g_async_queue_push (info
->pd
->priv
->event_queue
, event
);
797 g_idle_add ((GSourceFunc
) rb_podcast_manager_event_loop
, info
->pd
);
805 rb_podcast_manager_add_post (RhythmDB
*db
,
808 const char *subtitle
,
809 const char *generator
,
811 const char *description
,
818 if (uri
&& name
&& title
&& date
&& g_utf8_validate(uri
, -1, NULL
)) {
819 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (db
, uri
);
826 entry
= rhythmdb_entry_new (db
,
827 RHYTHMDB_ENTRY_TYPE_PODCAST_POST
,
832 g_value_init (&val
, G_TYPE_STRING
);
833 g_value_set_string (&val
, name
);
834 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_ALBUM
, &val
);
836 g_value_reset (&val
);
837 g_value_set_static_string (&val
, _("Podcast"));
838 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_GENRE
, &val
);
840 g_value_reset (&val
);
841 g_value_set_string (&val
, title
);
842 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_TITLE
, &val
);
844 g_value_reset (&val
);
846 g_value_set_string (&val
, subtitle
);
848 g_value_set_static_string (&val
, "");
849 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_SUBTITLE
, &val
);
851 g_value_reset (&val
);
853 g_value_set_string (&val
, description
);
855 g_value_set_static_string (&val
, "");
856 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_DESCRIPTION
, &val
);
858 g_value_reset (&val
);
860 g_value_set_string (&val
, generator
);
862 g_value_set_static_string (&val
, "");
863 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_ARTIST
, &val
);
864 g_value_unset (&val
);
866 g_value_init (&val
, G_TYPE_ULONG
);
867 g_value_set_ulong (&val
, status
);
868 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
870 g_value_reset (&val
);
871 g_value_set_ulong (&val
, date
);
872 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &val
);
874 g_value_reset (&val
);
875 g_value_set_ulong (&val
, duration
);
876 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_DURATION
, &val
);
878 g_value_reset (&val
);
879 g_value_set_ulong (&val
, 0);
880 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_LAST_PLAYED
, &val
);
883 g_get_current_time (&time
);
884 g_value_reset (&val
);
885 g_value_set_ulong (&val
, time
.tv_sec
);
886 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_FIRST_SEEN
, &val
);
887 g_value_unset (&val
);
889 /* initialize the rating */
890 g_value_init (&val
, G_TYPE_DOUBLE
);
891 g_value_set_double (&val
, 2.5);
892 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_RATING
, &val
);
893 g_value_unset (&val
);
895 g_value_init (&val
, G_TYPE_UINT64
);
896 g_value_set_uint64 (&val
, filesize
);
897 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_FILE_SIZE
, &val
);
898 g_value_unset (&val
);
907 rb_podcast_manager_save_metadata (RhythmDB
*db
, RhythmDBEntry
*entry
, const char* uri
)
909 RBMetaData
*md
= rb_metadata_new();
910 GError
*error
= NULL
;
914 rb_debug("Loading podcast metadata");
915 rb_metadata_load (md
, uri
, &error
);
918 /* this probably isn't an audio enclosure. or some other error */
919 g_value_init (&val
, G_TYPE_ULONG
);
920 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_ERROR
);
921 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
922 g_value_unset (&val
);
924 g_value_init (&val
, G_TYPE_STRING
);
925 g_value_set_string (&val
, error
->message
);
926 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_PLAYBACK_ERROR
, &val
);
927 g_value_unset (&val
);
929 rhythmdb_commit (db
);
935 mime
= rb_metadata_get_mime (md
);
937 g_value_init (&val
, G_TYPE_STRING
);
938 g_value_set_string (&val
, mime
);
939 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_MIMETYPE
, &val
);
940 g_value_unset (&val
);
943 if (rb_metadata_get (md
,
944 RB_METADATA_FIELD_DURATION
,
946 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_DURATION
, &val
);
947 g_value_unset (&val
);
950 if (rb_metadata_get (md
,
951 RB_METADATA_FIELD_BITRATE
,
953 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_BITRATE
, &val
);
954 g_value_unset (&val
);
957 rhythmdb_commit (db
);
964 rb_podcast_manager_db_entry_added_cb (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
967 gulong type
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TYPE
);
968 if (type
!= RHYTHMDB_ENTRY_TYPE_PODCAST_POST
)
971 rb_podcast_manager_download_entry (pd
, entry
);
975 write_job_data (RBPodcastManagerInfo
*data
)
979 RhythmDB
*db
= data
->pd
->priv
->db
;
981 rb_debug ("in the write_job");
983 g_value_init (&val
, G_TYPE_UINT64
);
984 g_value_set_uint64 (&val
, data
->total_size
);
985 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_FILE_SIZE
, &val
);
986 g_value_unset (&val
);
988 g_value_init (&val
, G_TYPE_ULONG
);
989 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_COMPLETE
);
990 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
991 g_value_unset (&val
);
993 rb_podcast_manager_save_metadata (db
, data
->entry
,
994 gnome_vfs_uri_to_string (data
->write_uri
, GNOME_VFS_URI_HIDE_NONE
));
996 rhythmdb_commit (db
);
1000 download_info_free (RBPodcastManagerInfo
*data
)
1002 if (data
->write_uri
) {
1003 gnome_vfs_uri_unref (data
->write_uri
);
1004 data
->write_uri
= NULL
;
1007 if (data
->read_uri
) {
1008 gnome_vfs_uri_unref (data
->read_uri
);
1009 data
->read_uri
= NULL
;
1013 g_mutex_free (data
->mutex_working
);
1018 static RBPodcastManagerInfo
*
1019 download_info_new (void)
1021 RBPodcastManagerInfo
*data
= g_new0 (RBPodcastManagerInfo
, 1);
1024 data
->write_uri
= NULL
;
1025 data
->read_uri
= NULL
;
1026 data
->mutex_working
= g_mutex_new ();
1027 data
->total_size
= 0;
1029 data
->canceled
= FALSE
;
1035 start_job (RBPodcastManagerInfo
*data
)
1038 GList
*source_uri_list
= NULL
;
1039 GList
*target_uri_list
= NULL
;
1041 rb_debug ("start job");
1043 GDK_THREADS_ENTER ();
1044 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[START_DOWNLOAD
],
1046 GDK_THREADS_LEAVE ();
1048 source_uri_list
= g_list_prepend (source_uri_list
, data
->read_uri
);
1049 target_uri_list
= g_list_prepend (target_uri_list
, data
->write_uri
);
1051 g_mutex_lock (data
->mutex_working
);
1053 rb_debug ("start async copy");
1054 gnome_vfs_async_xfer ( &data
->read_handle
,
1057 GNOME_VFS_XFER_DEFAULT
,
1058 GNOME_VFS_XFER_ERROR_MODE_ABORT
,
1059 GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
,
1060 GNOME_VFS_PRIORITY_DEFAULT
,
1061 (GnomeVFSAsyncXferProgressCallback
) download_progress_update_cb
,
1063 (GnomeVFSXferProgressCallback
) download_progress_cb
,
1069 rb_podcast_manager_cancel_all (RBPodcastManager
*pd
)
1075 g_mutex_lock (pd
->priv
->download_list_mutex
);
1076 lst
= g_list_reverse (pd
->priv
->download_list
);
1077 g_mutex_unlock (pd
->priv
->download_list_mutex
);
1079 rb_debug ("cancel all job %d", g_list_length (lst
));
1080 lst_len
= g_list_length (lst
);
1082 for (i
=0; i
< lst_len
; i
++) {
1083 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) lst
->data
;
1086 rb_debug ("cancel next job");
1090 g_mutex_lock (pd
->priv
->mutex_job
);
1091 g_mutex_unlock (pd
->priv
->mutex_job
);
1096 end_job (RBPodcastManagerInfo
*data
)
1098 RBPodcastManager
*pd
= data
->pd
;
1100 rb_debug ("end_job");
1102 g_mutex_lock (data
->pd
->priv
->download_list_mutex
);
1103 data
->pd
->priv
->download_list
= g_list_remove (data
->pd
->priv
->download_list
, (gconstpointer
) data
);
1104 g_mutex_unlock (data
->pd
->priv
->download_list_mutex
);
1106 g_mutex_unlock (data
->mutex_working
);
1109 if (data
->canceled
!= TRUE
) {
1110 GDK_THREADS_ENTER ();
1112 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[FINISH_DOWNLOAD
],
1115 GDK_THREADS_LEAVE ();
1118 download_info_free (data
);
1119 g_mutex_unlock (pd
->priv
->mutex_job
);
1121 gtk_idle_add ((GtkFunction
) rb_podcast_manager_next_file
, pd
);
1125 cancel_job (RBPodcastManagerInfo
*data
)
1127 if (g_mutex_trylock (data
->mutex_working
) == FALSE
) {
1128 rb_debug ("async cancel");
1129 data
->canceled
= TRUE
;
1132 rb_debug ("job cancel");
1134 g_mutex_lock (data
->pd
->priv
->download_list_mutex
);
1135 data
->pd
->priv
->download_list
= g_list_remove (data
->pd
->priv
->download_list
, (gconstpointer
) data
);
1136 g_mutex_unlock (data
->pd
->priv
->download_list_mutex
);
1138 g_mutex_unlock (data
->mutex_working
);
1140 download_info_free (data
);
1146 download_progress_cb (GnomeVFSXferProgressInfo
*info
, gpointer cb_data
)
1148 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) cb_data
;
1151 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1154 if (info
->status
!= GNOME_VFS_XFER_PROGRESS_STATUS_OK
) {
1156 rb_debug ("error on download");
1157 g_value_init (&val
, G_TYPE_ULONG
);
1158 g_value_set_ulong (&val
, RHYTHMDB_PODCAST_STATUS_ERROR
);
1159 GDK_THREADS_ENTER ();
1160 rhythmdb_entry_set (data
->pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
1161 rhythmdb_commit (data
->pd
->priv
->db
);
1162 GDK_THREADS_LEAVE ();
1163 g_value_unset (&val
);
1166 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1169 if (rhythmdb_entry_get_string (data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
) == NULL
) {
1171 RhythmDB
*db
= data
->pd
->priv
->db
;
1173 g_value_init (&val
, G_TYPE_STRING
);
1174 g_value_set_string (&val
,
1175 gnome_vfs_uri_to_string (data
->write_uri
, GNOME_VFS_URI_HIDE_NONE
));
1176 rhythmdb_entry_set (db
, data
->entry
, RHYTHMDB_PROP_MOUNTPOINT
, &val
);
1177 g_value_unset (&val
);
1178 rhythmdb_commit (db
);
1181 if (info
->phase
== GNOME_VFS_XFER_PHASE_COMPLETED
) {
1182 if (data
->canceled
!= TRUE
) {
1183 rb_debug ("download completed");
1184 data
->total_size
= info
->file_size
;
1185 write_job_data (data
);
1189 return GNOME_VFS_XFER_ERROR_ACTION_SKIP
;
1192 if (data
->canceled
== TRUE
) {
1193 rb_debug ("job canceled");
1194 gnome_vfs_async_cancel (data
->read_handle
);
1195 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1203 download_progress_update_cb (GnomeVFSAsyncHandle
*handle
, GnomeVFSXferProgressInfo
*info
, gpointer cb_data
)
1206 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) cb_data
;
1209 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1213 if ((info
->phase
== GNOME_VFS_XFER_PHASE_COPYING
) &&
1214 (data
->entry
!= NULL
)) {
1215 guint local_progress
= 0;
1217 if (info
->file_size
> 0)
1218 local_progress
= (gint
) 100 * info
->total_bytes_copied
/ info
->file_size
;
1220 if (local_progress
!= data
->progress
) {
1223 g_value_init (&val
, G_TYPE_ULONG
);
1224 g_value_set_ulong (&val
, local_progress
);
1225 rhythmdb_entry_set (data
->pd
->priv
->db
, data
->entry
, RHYTHMDB_PROP_STATUS
, &val
);
1226 g_value_unset (&val
);
1228 GDK_THREADS_ENTER ();
1230 g_signal_emit (data
->pd
, rb_podcast_manager_signals
[STATUS_CHANGED
],
1231 0, data
->entry
, local_progress
);
1233 GDK_THREADS_LEAVE ();
1234 data
->progress
= local_progress
;
1238 return GNOME_VFS_XFER_ERROR_ACTION_SKIP
;
1242 rb_podcast_manager_unsubscribe_feed (RhythmDB
*db
, const char* url
)
1244 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (db
, url
);
1247 g_value_init (&val
, G_TYPE_ULONG
);
1248 g_value_set_ulong (&val
, 0);
1249 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &val
);
1250 g_value_unset (&val
);
1256 rb_podcast_manager_remove_feed (RBPodcastManager
*pd
, const char* url
, gboolean remove_files
)
1258 RhythmDBEntry
*entry
= rhythmdb_entry_lookup_by_location (pd
->priv
->db
, url
);
1260 rb_podcast_manager_set_remove_files (pd
, remove_files
);
1261 rhythmdb_entry_delete (pd
->priv
->db
, entry
);
1262 rhythmdb_commit (pd
->priv
->db
);
1270 rb_podcast_manager_db_entry_deleted_cb (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
1273 gulong type
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TYPE
);
1275 if ((type
== RHYTHMDB_ENTRY_TYPE_PODCAST_POST
) && (pd
->priv
->remove_files
== TRUE
) )
1277 const gchar
*file_name
;
1278 const gchar
*dir_name
;
1279 const gchar
*conf_dir_name
;
1282 /* make sure we're not downloading it */
1283 rb_podcast_manager_cancel_download (pd
, entry
);
1285 file_name
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MOUNTPOINT
);
1286 if (file_name
== NULL
) {
1287 /* episode has not been downloaded */
1291 uri
= gnome_vfs_uri_new (file_name
);
1293 if ((uri
!= NULL
) && (gnome_vfs_uri_is_local (uri
) == TRUE
)) {
1294 gnome_vfs_unlink (rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_MOUNTPOINT
));
1297 rb_debug ("removing dir");
1298 conf_dir_name
= eel_gconf_get_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
);
1300 dir_name
= g_build_filename (conf_dir_name
,
1301 rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
),
1303 gnome_vfs_remove_directory (dir_name
);
1306 else if (type
== RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
)
1308 GtkTreeModel
* query_model
= GTK_TREE_MODEL (rhythmdb_query_model_new_empty(pd
->priv
->db
));
1311 rhythmdb_do_full_query (pd
->priv
->db
,
1312 RHYTHMDB_QUERY_RESULTS (query_model
),
1313 RHYTHMDB_QUERY_PROP_EQUALS
,
1314 RHYTHMDB_PROP_TYPE
, RHYTHMDB_ENTRY_TYPE_PODCAST_POST
,
1315 RHYTHMDB_QUERY_PROP_LIKE
,
1316 RHYTHMDB_PROP_SUBTITLE
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
),
1317 RHYTHMDB_QUERY_END
);
1319 if (gtk_tree_model_get_iter_first (query_model
, &iter
)) {
1322 RhythmDBEntry
*entry
;
1323 gtk_tree_model_get (query_model
, &iter
, 0, &entry
, -1);
1324 has_next
= gtk_tree_model_iter_next (query_model
, &iter
);
1325 rhythmdb_entry_delete (pd
->priv
->db
, entry
);
1327 rhythmdb_commit (pd
->priv
->db
);
1334 rb_podcast_manager_cancel_download (RBPodcastManager
*pd
, RhythmDBEntry
*entry
)
1338 g_mutex_lock (pd
->priv
->download_list_mutex
);
1340 lst
= pd
->priv
->download_list
;
1342 RBPodcastManagerInfo
*data
= (RBPodcastManagerInfo
*) lst
->data
;
1343 if (data
->entry
== entry
) {
1344 rb_debug ("Found job");
1349 g_mutex_unlock (pd
->priv
->download_list_mutex
);
1352 cancel_job (lst
->data
);
1357 rb_podcast_manager_update_synctime (RBPodcastManager
*pd
)
1360 gint index
= eel_gconf_get_integer (CONF_STATE_PODCAST_DOWNLOAD_INTERVAL
);
1364 case UPDATE_EVERY_HOUR
:
1365 value
= time (NULL
) + 3600;
1367 case UPDATE_EVERY_DAY
:
1368 value
= time (NULL
) + (3600 * 24);
1370 case UPDATE_EVERY_WEEK
:
1371 value
= time (NULL
) + (3600 * 24 * 7);
1373 case UPDATE_MANUALLY
:
1380 eel_gconf_set_integer (CONF_STATE_PODCAST_DOWNLOAD_NEXT_TIME
, value
);
1381 eel_gconf_suggest_sync ();
1382 pd
->priv
->next_time
= value
;
1383 rb_podcast_manager_start_sync (pd
);
1386 static void rb_podcast_manager_config_changed (GConfClient
* client
,
1391 rb_podcast_manager_update_synctime (RB_PODCAST_MANAGER (user_data
));
1396 rb_podcast_manager_set_remove_files (RBPodcastManager
*pd
, gboolean flag
)
1398 pd
->priv
->remove_files
= flag
;
1403 rb_podcast_manager_get_remove_files (RBPodcastManager
*pd
)
1405 return pd
->priv
->remove_files
;
1409 rb_podcast_manager_insert_feed (RBPodcastManager
*pd
, RBPodcastChannel
*data
)
1411 GValue description_val
= { 0, };
1412 GValue title_val
= { 0, };
1413 GValue subtitle_val
= { 0, };
1414 GValue summary_val
= { 0, };
1415 GValue lang_val
= { 0, };
1416 GValue copyright_val
= { 0, };
1417 GValue image_val
= { 0, };
1418 GValue author_val
= { 0, };
1419 GValue status_val
= { 0, };
1420 GValue last_post_val
= { 0, };
1421 GValue last_update_val
= { 0, };
1422 gulong last_post
= 0;
1423 gulong new_last_post
;
1424 gboolean new_feed
, updated
;
1425 RhythmDB
*db
= pd
->priv
->db
;
1427 RhythmDBEntry
*entry
;
1431 if (data
->title
== NULL
) {
1432 g_list_free (data
->posts
);
1439 /* processing podcast head */
1440 entry
= rhythmdb_entry_lookup_by_location (db
, (gchar
* )data
->url
);
1442 if (rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_TYPE
) != RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
)
1445 rb_debug ("Head found");
1446 g_value_init (&status_val
, G_TYPE_ULONG
);
1447 g_value_set_ulong (&status_val
, 1);
1448 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
1449 g_value_unset (&status_val
);
1450 last_post
= rhythmdb_entry_get_ulong (entry
, RHYTHMDB_PROP_POST_TIME
);
1453 rb_debug ("Insert new entry");
1454 entry
= rhythmdb_entry_new (db
,
1455 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED
,
1456 (gchar
*) data
->url
);
1459 rb_debug("New entry create\n");
1461 g_value_init (&title_val
, G_TYPE_STRING
);
1462 g_value_set_string (&title_val
, (gchar
* ) data
->title
);
1463 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_TITLE
, &title_val
);
1464 g_value_unset (&title_val
);
1466 g_value_init (&author_val
, G_TYPE_STRING
);
1468 g_value_set_string (&author_val
, (gchar
* ) data
->author
);
1470 g_value_set_static_string (&author_val
, _("Unknown"));
1471 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_ARTIST
, &author_val
);
1472 g_value_unset (&author_val
);
1475 if (data
->subtitle
) {
1476 g_value_init (&subtitle_val
, G_TYPE_STRING
);
1477 g_value_set_string (&subtitle_val
, (gchar
* ) data
->subtitle
);
1478 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_SUBTITLE
, &subtitle_val
);
1479 g_value_unset (&subtitle_val
);
1482 if (data
->description
) {
1483 g_value_init (&description_val
, G_TYPE_STRING
);
1484 g_value_set_string (&description_val
, (gchar
* ) data
->description
);
1485 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_DESCRIPTION
, &description_val
);
1486 g_value_unset (&description_val
);
1489 if (data
->summary
) {
1490 g_value_init (&summary_val
, G_TYPE_STRING
);
1491 g_value_set_string (&summary_val
, (gchar
* ) data
->summary
);
1492 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_SUMMARY
, &summary_val
);
1493 g_value_unset (&summary_val
);
1497 g_value_init (&lang_val
, G_TYPE_STRING
);
1498 g_value_set_string (&lang_val
, (gchar
* ) data
->lang
);
1499 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_LANG
, &lang_val
);
1500 g_value_unset (&lang_val
);
1503 if (data
->copyright
) {
1504 g_value_init (©right_val
, G_TYPE_STRING
);
1505 g_value_set_string (©right_val
, (gchar
* ) data
->copyright
);
1506 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_COPYRIGHT
, ©right_val
);
1507 g_value_unset (©right_val
);
1511 g_value_init (&image_val
, G_TYPE_STRING
);
1512 g_value_set_string (&image_val
, (gchar
* ) data
->img
);
1513 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_IMAGE
, &image_val
);
1514 g_value_unset (&image_val
);
1517 g_value_init (&status_val
, G_TYPE_ULONG
);
1518 g_value_set_ulong (&status_val
, 1);
1519 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_STATUS
, &status_val
);
1520 g_value_unset (&status_val
);
1522 rb_debug("Podcast head Inserted");
1525 /* insert episodes */
1526 new_last_post
= last_post
;
1529 for (lst_songs
= data
->posts
; lst_songs
!= NULL
; lst_songs
= g_list_next (lst_songs
)) {
1530 RBPodcastItem
*item
= (RBPodcastItem
*) lst_songs
->data
;
1532 if (item
->pub_date
> last_post
|| item
->pub_date
== 0) {
1536 /* last episode gets status RHYTHMDB_PODCAST_STATUS_WAITING, so that it begins downloading */
1537 if (lst_songs
== (g_list_last (data
->posts
)))
1538 status
= RHYTHMDB_PODCAST_STATUS_WAITING
;
1540 status
= RHYTHMDB_PODCAST_STATUS_PAUSED
;
1542 rb_podcast_manager_add_post (db
,
1543 (gchar
*) data
->title
,
1544 (gchar
*) item
->title
,
1546 (gchar
*) (item
->author
? item
->author
: data
->author
),
1548 (gchar
*) item
->description
,
1550 (gulong
) (item
->pub_date
> 0 ? item
->pub_date
: data
->pub_date
),
1551 (gulong
) item
->duration
,
1553 if (item
->pub_date
> new_last_post
)
1554 new_last_post
= item
->pub_date
;
1559 g_signal_emit (pd
, rb_podcast_manager_signals
[FEED_UPDATES_AVALIABLE
],
1562 if (data
->pub_date
> new_last_post
)
1563 new_last_post
= data
->pub_date
;
1565 g_value_init (&last_post_val
, G_TYPE_ULONG
);
1566 g_value_set_ulong (&last_post_val
, new_last_post
);
1569 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &last_post_val
);
1571 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_POST_TIME
, &last_post_val
);
1572 g_value_unset (&last_post_val
);
1574 g_value_init (&last_update_val
, G_TYPE_ULONG
);
1575 g_value_set_ulong (&last_update_val
, time(NULL
));
1578 rhythmdb_entry_set_uninserted (db
, entry
, RHYTHMDB_PROP_LAST_SEEN
, &last_update_val
);
1580 rhythmdb_entry_set (db
, entry
, RHYTHMDB_PROP_LAST_SEEN
, &last_update_val
);
1581 g_value_unset (&last_update_val
);
1583 rhythmdb_commit (db
);
1588 rb_podcast_manager_event_loop (RBPodcastManager
*pd
)
1590 RBPodcastManagerEvent
*event
;
1592 while ((event
= g_async_queue_try_pop (pd
->priv
->event_queue
))) {
1593 switch (event
->type
)
1595 case EVENT_INSERT_FEED
:
1596 rb_podcast_manager_insert_feed (pd
, event
->channel
);
1598 case EVENT_ERROR_FEED
:
1601 error_msg
= g_strdup_printf (_("There was a problem adding this podcast. Please verify the URL: %s"),
1602 (gchar
*) event
->channel
->url
);
1603 g_signal_emit (G_OBJECT (pd
),
1604 rb_podcast_manager_signals
[PROCESS_ERROR
],
1611 rb_podcast_parse_channel_free (event
->channel
);
1615 g_async_queue_unref (pd
->priv
->event_queue
);
1621 rb_podcast_manager_abort_subscribe (RBPodcastManager
*pd
)
1623 RBPodcastManagerEvent
*event
;
1625 /* remove all event processing functions */
1626 while (g_idle_remove_by_data (pd
))
1629 /* purge the event queue */
1630 while ((event
= g_async_queue_try_pop (pd
->priv
->event_queue
))) {
1631 rb_podcast_parse_channel_free (event
->channel
);
1637 rb_podcast_manager_shutdown (RBPodcastManager
*pd
)
1639 rb_podcast_manager_cancel_all (pd
);
1640 rb_podcast_manager_abort_subscribe (pd
);
1644 rb_podcast_manager_get_podcast_dir (RBPodcastManager
*pd
)
1646 gchar
*conf_dir_name
= eel_gconf_get_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
);
1648 if (conf_dir_name
== NULL
|| (strcmp (conf_dir_name
, "") == 0)) {
1649 conf_dir_name
= g_build_filename (g_get_home_dir (),
1652 eel_gconf_set_string (CONF_STATE_PODCAST_DOWNLOAD_DIR
, conf_dir_name
);
1655 return conf_dir_name
;