1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of Rhythmbox playlist management object
5 * Copyright (C) 2003,2004 Colin Walters <walters@gnome.org>
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.
26 #include <stdio.h> /* rename() */
27 #include <unistd.h> /* unlink() */
29 #include <libxml/tree.h>
30 #include <glib/gi18n.h>
32 #include <libgnomevfs/gnome-vfs.h>
33 #include <libgnomevfs/gnome-vfs-mime-utils.h>
35 #include "rb-playlist-manager.h"
36 #include "rb-playlist-source.h"
37 #include "rb-static-playlist-source.h"
38 #include "rb-auto-playlist-source.h"
39 #include "rb-play-queue-source.h"
40 #include "rb-sourcelist.h"
41 #include "rb-sourcelist-model.h"
42 #include "rb-query-creator.h"
43 #include "totem-pl-parser.h"
45 #include "rb-file-helpers.h"
47 #include "rb-dialog.h"
49 #include "rb-stock-icons.h"
50 #include "eel-gconf-extensions.h"
51 #include "rb-glade-helpers.h"
54 #define RB_PLAYLIST_MGR_VERSION (xmlChar *) "1.0"
55 #define RB_PLAYLIST_MGR_PL (xmlChar *) "rhythmdb-playlists"
57 static void rb_playlist_manager_class_init (RBPlaylistManagerClass
*klass
);
58 static void rb_playlist_manager_init (RBPlaylistManager
*mgr
);
59 static void rb_playlist_manager_dispose (GObject
*object
);
60 static void rb_playlist_manager_finalize (GObject
*object
);
61 static void rb_playlist_manager_set_property (GObject
*object
,
65 static void rb_playlist_manager_get_property (GObject
*object
,
69 static void rb_playlist_manager_cmd_load_playlist (GtkAction
*action
,
70 RBPlaylistManager
*mgr
);
71 static void rb_playlist_manager_cmd_save_playlist (GtkAction
*action
,
72 RBPlaylistManager
*mgr
);
73 static void rb_playlist_manager_cmd_new_playlist (GtkAction
*action
,
74 RBPlaylistManager
*mgr
);
75 static void rb_playlist_manager_cmd_new_automatic_playlist (GtkAction
*action
,
76 RBPlaylistManager
*mgr
);
77 static void rb_playlist_manager_cmd_rename_playlist (GtkAction
*action
,
78 RBPlaylistManager
*mgr
);
79 static void rb_playlist_manager_cmd_delete_playlist (GtkAction
*action
,
80 RBPlaylistManager
*mgr
);
81 static void rb_playlist_manager_cmd_edit_automatic_playlist (GtkAction
*action
,
82 RBPlaylistManager
*mgr
);
83 static void rb_playlist_manager_cmd_queue_playlist (GtkAction
*action
,
84 RBPlaylistManager
*mgr
);
86 struct RBPlaylistManagerPrivate
90 RBSource
*selected_source
;
94 RBSourceList
*sourcelist
;
96 GtkActionGroup
*actiongroup
;
97 GtkUIManager
*uimanager
;
101 RBStaticPlaylistSource
*loading_playlist
;
105 GMutex
*saving_mutex
;
122 PLAYLIST_LOAD_FINISH
,
126 static guint rb_playlist_manager_signals
[LAST_SIGNAL
] = { 0 };
128 static GtkActionEntry rb_playlist_manager_actions
[] =
130 /* Submenu of Music */
131 { "Playlist", NULL
, N_("_Playlist") },
133 { "MusicPlaylistNewPlaylist", GNOME_MEDIA_PLAYLIST
, N_("_New Playlist"), "<control>N",
134 N_("Create a new playlist"),
135 G_CALLBACK (rb_playlist_manager_cmd_new_playlist
) },
136 { "MusicPlaylistNewAutomaticPlaylist", GNOME_MEDIA_AUTO_PLAYLIST
, N_("New _Automatic Playlist..."), NULL
,
137 N_("Create a new automatically updating playlist"),
138 G_CALLBACK (rb_playlist_manager_cmd_new_automatic_playlist
) },
139 { "MusicPlaylistLoadPlaylist", NULL
, N_("_Load from File..."), NULL
,
140 N_("Choose a playlist to be loaded"),
141 G_CALLBACK (rb_playlist_manager_cmd_load_playlist
) },
142 { "MusicPlaylistSavePlaylist", GTK_STOCK_SAVE_AS
, N_("_Save to File..."), NULL
,
143 N_("Save a playlist to a file"),
144 G_CALLBACK (rb_playlist_manager_cmd_save_playlist
) },
145 { "MusicPlaylistRenamePlaylist", NULL
, N_("_Rename"), NULL
,
146 N_("Rename playlist"),
147 G_CALLBACK (rb_playlist_manager_cmd_rename_playlist
) },
148 { "MusicPlaylistDeletePlaylist", GTK_STOCK_REMOVE
, N_("_Delete"), NULL
,
149 N_("Delete playlist"),
150 G_CALLBACK (rb_playlist_manager_cmd_delete_playlist
) },
151 { "EditAutomaticPlaylist", GTK_STOCK_PROPERTIES
, N_("_Edit..."), NULL
,
152 N_("Change this automatic playlist"),
153 G_CALLBACK (rb_playlist_manager_cmd_edit_automatic_playlist
) },
154 { "QueuePlaylist", NULL
, N_("_Queue All Tracks"), NULL
,
155 N_("Add all tracks in this playlist to the queue"),
156 G_CALLBACK (rb_playlist_manager_cmd_queue_playlist
) },
158 static guint rb_playlist_manager_n_actions
= G_N_ELEMENTS (rb_playlist_manager_actions
);
160 G_DEFINE_TYPE (RBPlaylistManager
, rb_playlist_manager
, G_TYPE_OBJECT
)
163 rb_playlist_manager_class_init (RBPlaylistManagerClass
*klass
)
165 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
167 object_class
->dispose
= rb_playlist_manager_dispose
;
168 object_class
->finalize
= rb_playlist_manager_finalize
;
170 object_class
->set_property
= rb_playlist_manager_set_property
;
171 object_class
->get_property
= rb_playlist_manager_get_property
;
173 g_object_class_install_property (object_class
,
175 g_param_spec_string ("playlists_file",
181 g_object_class_install_property (object_class
,
183 g_param_spec_object ("source",
189 g_object_class_install_property (object_class
,
191 g_param_spec_object ("shell",
197 g_object_class_install_property (object_class
,
199 g_param_spec_object ("sourcelist",
203 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
204 rb_playlist_manager_signals
[PLAYLIST_ADDED
] =
205 g_signal_new ("playlist_added",
206 RB_TYPE_PLAYLIST_MANAGER
,
208 G_STRUCT_OFFSET (RBPlaylistManagerClass
, playlist_added
),
210 g_cclosure_marshal_VOID__OBJECT
,
214 rb_playlist_manager_signals
[PLAYLIST_CREATED
] =
215 g_signal_new ("playlist_created",
216 RB_TYPE_PLAYLIST_MANAGER
,
218 G_STRUCT_OFFSET (RBPlaylistManagerClass
, playlist_created
),
220 g_cclosure_marshal_VOID__OBJECT
,
224 rb_playlist_manager_signals
[PLAYLIST_LOAD_START
] =
225 g_signal_new ("load_start",
226 RB_TYPE_PLAYLIST_MANAGER
,
228 G_STRUCT_OFFSET (RBPlaylistManagerClass
, load_start
),
230 g_cclosure_marshal_VOID__VOID
,
233 rb_playlist_manager_signals
[PLAYLIST_LOAD_FINISH
] =
234 g_signal_new ("load_finish",
235 RB_TYPE_PLAYLIST_MANAGER
,
237 G_STRUCT_OFFSET (RBPlaylistManagerClass
, load_finish
),
239 g_cclosure_marshal_VOID__VOID
,
243 g_type_class_add_private (klass
, sizeof (RBPlaylistManagerPrivate
));
247 rb_playlist_manager_init (RBPlaylistManager
*mgr
)
249 mgr
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (mgr
,
250 RB_TYPE_PLAYLIST_MANAGER
,
251 RBPlaylistManagerPrivate
);
253 mgr
->priv
->saving_mutex
= g_mutex_new ();
254 mgr
->priv
->dirty
= 0;
255 mgr
->priv
->saving
= 0;
259 rb_playlist_manager_shutdown (RBPlaylistManager
*mgr
)
261 g_return_if_fail (RB_IS_PLAYLIST_MANAGER (mgr
));
263 g_mutex_lock (mgr
->priv
->saving_mutex
);
264 g_mutex_unlock (mgr
->priv
->saving_mutex
);
268 rb_playlist_manager_dispose (GObject
*object
)
270 RBPlaylistManager
*mgr
;
272 g_return_if_fail (object
!= NULL
);
273 g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object
));
275 rb_debug ("Disposing playlist manager");
277 mgr
= RB_PLAYLIST_MANAGER (object
);
279 g_return_if_fail (mgr
->priv
!= NULL
);
281 if (mgr
->priv
->db
!= NULL
) {
282 g_object_unref (mgr
->priv
->db
);
283 mgr
->priv
->db
= NULL
;
286 if (mgr
->priv
->uimanager
!= NULL
) {
287 g_object_unref (mgr
->priv
->uimanager
);
288 mgr
->priv
->uimanager
= NULL
;
291 if (mgr
->priv
->sourcelist
!= NULL
) {
292 g_object_unref (mgr
->priv
->sourcelist
);
293 mgr
->priv
->sourcelist
= NULL
;
296 if (mgr
->priv
->selected_source
!= NULL
) {
297 g_object_unref (mgr
->priv
->selected_source
);
298 mgr
->priv
->selected_source
= NULL
;
301 G_OBJECT_CLASS (rb_playlist_manager_parent_class
)->dispose (object
);
305 rb_playlist_manager_finalize (GObject
*object
)
307 RBPlaylistManager
*mgr
;
309 g_return_if_fail (object
!= NULL
);
310 g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object
));
312 rb_debug ("Finalizing playlist manager");
314 mgr
= RB_PLAYLIST_MANAGER (object
);
316 g_return_if_fail (mgr
->priv
!= NULL
);
318 g_mutex_free (mgr
->priv
->saving_mutex
);
320 g_free (mgr
->priv
->playlists_file
);
322 G_OBJECT_CLASS (rb_playlist_manager_parent_class
)->finalize (object
);
326 rb_playlist_manager_set_uimanager (RBPlaylistManager
*mgr
,
327 GtkUIManager
*uimanager
)
329 if (mgr
->priv
->uimanager
!= NULL
) {
330 if (mgr
->priv
->actiongroup
!= NULL
) {
331 gtk_ui_manager_remove_action_group (mgr
->priv
->uimanager
,
332 mgr
->priv
->actiongroup
);
334 g_object_unref (mgr
->priv
->uimanager
);
337 mgr
->priv
->uimanager
= uimanager
;
339 if (mgr
->priv
->actiongroup
== NULL
) {
340 mgr
->priv
->actiongroup
= gtk_action_group_new ("PlaylistActions");
341 gtk_action_group_set_translation_domain (mgr
->priv
->actiongroup
,
343 gtk_action_group_add_actions (mgr
->priv
->actiongroup
,
344 rb_playlist_manager_actions
,
345 rb_playlist_manager_n_actions
,
349 gtk_ui_manager_insert_action_group (mgr
->priv
->uimanager
,
350 mgr
->priv
->actiongroup
,
355 rb_playlist_manager_set_source (RBPlaylistManager
*mgr
,
358 gboolean playlist_active
;
359 gboolean playlist_local
= FALSE
;
367 party_mode
= rb_shell_get_party_mode (mgr
->priv
->shell
);
369 if (mgr
->priv
->selected_source
!= NULL
) {
370 g_object_unref (mgr
->priv
->selected_source
);
372 mgr
->priv
->selected_source
= g_object_ref (source
);
374 playlist_active
= RB_IS_PLAYLIST_SOURCE (mgr
->priv
->selected_source
);
375 if (playlist_active
) {
376 g_object_get (mgr
->priv
->selected_source
, "is-local", &playlist_local
, NULL
);
379 can_save
= playlist_local
&& !party_mode
;
380 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
381 "MusicPlaylistSavePlaylist");
382 gtk_action_set_visible (action
, can_save
);
384 can_delete
= (playlist_local
&& !party_mode
&&
385 !RB_IS_PLAY_QUEUE_SOURCE (mgr
->priv
->selected_source
));
386 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
387 "MusicPlaylistDeletePlaylist");
388 gtk_action_set_visible (action
, can_delete
);
390 can_edit
= (playlist_local
&& RB_IS_AUTO_PLAYLIST_SOURCE (mgr
->priv
->selected_source
) &&
392 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
393 "EditAutomaticPlaylist");
394 gtk_action_set_visible (action
, can_edit
);
396 can_rename
= playlist_local
&& rb_source_can_rename (mgr
->priv
->selected_source
);
397 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
398 "MusicPlaylistRenamePlaylist");
399 gtk_action_set_visible (action
, can_rename
);
403 rb_playlist_manager_set_shell_internal (RBPlaylistManager
*mgr
,
406 GtkUIManager
*uimanager
= NULL
;
409 if (mgr
->priv
->db
!= NULL
) {
410 g_object_unref (mgr
->priv
->db
);
413 mgr
->priv
->shell
= shell
;
415 if (mgr
->priv
->shell
!= NULL
) {
416 g_object_get (mgr
->priv
->shell
,
417 "ui-manager", &uimanager
,
423 rb_playlist_manager_set_uimanager (mgr
, uimanager
);
427 rb_playlist_manager_set_property (GObject
*object
,
432 RBPlaylistManager
*mgr
= RB_PLAYLIST_MANAGER (object
);
435 case PROP_PLAYLIST_NAME
:
436 g_free (mgr
->priv
->playlists_file
);
437 mgr
->priv
->playlists_file
= g_strdup (g_value_get_string (value
));
440 rb_playlist_manager_set_source (mgr
, g_value_get_object (value
));
443 rb_playlist_manager_set_shell_internal (mgr
, g_value_get_object (value
));
445 case PROP_SOURCELIST
:
446 mgr
->priv
->sourcelist
= g_value_get_object (value
);
447 g_object_ref (mgr
->priv
->sourcelist
);
448 mgr
->priv
->window
= GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (mgr
->priv
->sourcelist
)));
451 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
457 rb_playlist_manager_get_property (GObject
*object
,
462 RBPlaylistManager
*mgr
= RB_PLAYLIST_MANAGER (object
);
465 case PROP_PLAYLIST_NAME
:
466 g_value_set_string (value
, mgr
->priv
->playlists_file
);
469 g_value_set_object (value
, mgr
->priv
->selected_source
);
472 g_value_set_object (value
, mgr
->priv
->shell
);
474 case PROP_SOURCELIST
:
475 g_value_set_object (value
, mgr
->priv
->sourcelist
);
478 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
484 rb_playlist_manager_new (RBShell
*shell
,
485 RBSourceList
*sourcelist
,
486 const char *playlists_file
)
488 return g_object_new (RB_TYPE_PLAYLIST_MANAGER
,
490 "sourcelist", sourcelist
,
491 "playlists_file", playlists_file
,
496 rb_playlist_manager_error_quark (void)
498 static GQuark quark
= 0;
500 quark
= g_quark_from_static_string ("rb_playlist_manager_error");
506 handle_playlist_entry_cb (TotemPlParser
*playlist
,
507 const char *uri_maybe
,
510 RBPlaylistManager
*mgr
)
514 uri
= rb_canonicalise_uri (uri_maybe
);
515 g_return_if_fail (uri
!= NULL
);
517 rb_debug ("adding uri %s (title %s, genre %s) from playlist",
519 if (!rb_shell_add_uri (mgr
->priv
->shell
,
526 if (!mgr
->priv
->loading_playlist
) {
527 mgr
->priv
->loading_playlist
=
528 RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr
, NULL
, FALSE
));
530 if (rb_source_want_uri (RB_SOURCE (mgr
->priv
->loading_playlist
), uri
) > 0) {
531 rb_debug ("adding uri %s to playlist", uri
);
532 rb_static_playlist_source_add_location (mgr
->priv
->loading_playlist
, uri
, -1);
539 playlist_load_start_cb (TotemPlParser
*parser
, const char *title
, RBPlaylistManager
*mgr
)
541 rb_debug ("loading new playlist %s", title
);
543 mgr
->priv
->loading_playlist
=
544 RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr
, title
, FALSE
));
548 playlist_load_end_cb (TotemPlParser
*parser
, const char *title
, RBPlaylistManager
*mgr
)
550 rb_debug ("finished loading playlist %s", title
);
553 g_object_set (mgr
->priv
->loading_playlist
, "name", title
, NULL
);
554 mgr
->priv
->loading_playlist
= NULL
;
559 * rb_playlist_manager_parse_file:
560 * @mgr: the #RBPlaylistManager
561 * @uri: URI of the playlist to load
562 * @error: returns a GError in case of error
564 * Parses a playlist file, adding entries to the database and to a new
565 * static playlist. If the playlist file includes a title, the static
566 * playlist created will have the same title.
568 * Returns TRUE on success
571 rb_playlist_manager_parse_file (RBPlaylistManager
*mgr
, const char *uri
, GError
**error
)
573 rb_debug ("loading playlist from %s", uri
);
575 g_signal_emit (mgr
, rb_playlist_manager_signals
[PLAYLIST_LOAD_START
], 0);
578 TotemPlParser
*parser
= totem_pl_parser_new ();
580 g_signal_connect_object (parser
, "entry",
581 G_CALLBACK (handle_playlist_entry_cb
),
584 g_signal_connect_object (parser
, "playlist-start",
585 G_CALLBACK (playlist_load_start_cb
),
588 g_signal_connect_object (parser
, "playlist-end",
589 G_CALLBACK (playlist_load_end_cb
),
592 if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser
), "recurse"))
593 g_object_set (parser
, "recurse", FALSE
, NULL
);
595 if (totem_pl_parser_parse (parser
, uri
, TRUE
) != TOTEM_PL_PARSER_RESULT_SUCCESS
) {
597 RB_PLAYLIST_MANAGER_ERROR
,
598 RB_PLAYLIST_MANAGER_ERROR_PARSE
,
600 _("The playlist file may be in an unknown format or corrupted."));
603 if (mgr
->priv
->loading_playlist
!= NULL
) {
606 /* totem-plparser may not have given us the playlist name */
607 g_object_get (mgr
->priv
->loading_playlist
, "name", &name
, NULL
);
608 if (name
== NULL
|| name
[0] == '\0') {
611 rb_debug ("setting playlist name from file name");
612 path
= g_filename_from_uri (uri
, NULL
, NULL
);
614 name
= g_path_get_basename (path
);
615 g_object_set (mgr
->priv
->loading_playlist
, "name", name
, NULL
);
621 mgr
->priv
->loading_playlist
= NULL
;
624 g_object_unref (parser
);
627 g_signal_emit (mgr
, rb_playlist_manager_signals
[PLAYLIST_LOAD_FINISH
], 0);
632 append_new_playlist_source (RBPlaylistManager
*mgr
, RBPlaylistSource
*source
)
634 g_signal_emit (mgr
, rb_playlist_manager_signals
[PLAYLIST_ADDED
], 0,
639 * rb_playlist_manager_load_playlists
640 * @mgr: the #RBPlaylistManager
642 * Loads the user's playlists, or if the playlist file does not exists,
643 * reads the default playlist file. Should be called only once on startup.
646 rb_playlist_manager_load_playlists (RBPlaylistManager
*mgr
)
655 file
= g_strdup (mgr
->priv
->playlists_file
);
657 /* block saves until the playlists have loaded */
658 g_mutex_lock (mgr
->priv
->saving_mutex
);
660 exists
= g_file_test (file
, G_FILE_TEST_EXISTS
);
662 rb_debug ("personal playlists not found, loading defaults");
664 /* try global playlists */
666 file
= g_strdup (rb_file ("playlists.xml"));
667 exists
= g_file_test (file
, G_FILE_TEST_EXISTS
);
671 rb_debug ("default playlists file not found");
675 doc
= xmlParseFile (file
);
679 root
= xmlDocGetRootElement (doc
);
681 for (child
= root
->children
; child
; child
= child
->next
) {
684 if (xmlNodeIsText (child
))
687 playlist
= rb_playlist_source_new_from_xml (mgr
->priv
->shell
,
690 append_new_playlist_source (mgr
, RB_PLAYLIST_SOURCE (playlist
));
695 g_mutex_unlock (mgr
->priv
->saving_mutex
);
700 rb_playlist_manager_set_dirty (RBPlaylistManager
*mgr
, gboolean dirty
)
702 g_atomic_int_compare_and_exchange (&mgr
->priv
->dirty
, dirty
== FALSE
, dirty
== TRUE
);
705 /* returns TRUE if a playlist has been created, modified, or deleted since last save */
707 rb_playlist_manager_is_dirty (RBPlaylistManager
*mgr
)
709 gboolean dirty
= FALSE
;
710 GtkTreeModel
*fmodel
;
714 g_object_get (mgr
->priv
->sourcelist
, "model", &fmodel
, NULL
);
715 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
716 g_object_unref (fmodel
);
718 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
723 gtk_tree_model_get (model
,
725 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
728 if (source
== NULL
) {
731 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
) {
732 g_object_unref (source
);
736 g_object_get (source
,
740 g_object_get (source
, "dirty", &dirty
, NULL
);
744 g_object_unref (source
);
745 } while (gtk_tree_model_iter_next (model
, &iter
));
749 dirty
= g_atomic_int_get (&mgr
->priv
->dirty
);
754 struct RBPlaylistManagerSaveData
756 RBPlaylistManager
*mgr
;
761 rb_playlist_manager_save_data (struct RBPlaylistManagerSaveData
*data
)
766 g_mutex_lock (data
->mgr
->priv
->saving_mutex
);
768 file
= g_strdup (data
->mgr
->priv
->playlists_file
);
769 tmpname
= g_strconcat (file
, ".tmp", NULL
);
771 if (xmlSaveFormatFile (tmpname
, data
->doc
, 1) != -1) {
772 rename (tmpname
, file
);
774 rb_debug ("error in xmlSaveFormatFile(), not saving");
776 rb_playlist_manager_set_dirty (data
->mgr
, TRUE
);
778 xmlFreeDoc (data
->doc
);
782 g_atomic_int_compare_and_exchange (&data
->mgr
->priv
->saving
, 1, 0);
783 g_mutex_unlock (data
->mgr
->priv
->saving_mutex
);
785 g_object_unref (data
->mgr
);
792 * rb_playlist_manager_save_playlists
793 * @mgr: the #RBPlaylistManager
794 * @force: if TRUE, save playlists synchronously and unconditionally
796 * Saves the user's playlists. If the force flag is
797 * TRUE, the playlists will always be saved. Otherwise, the playlists
798 * will only be saved if a playlist has been created, modified, or deleted
799 * since the last time the playlists were saved, and no save operation is
800 * currently taking place.
802 * Returns TRUE if a playlist save operation has been started
805 rb_playlist_manager_save_playlists (RBPlaylistManager
*mgr
, gboolean force
)
808 struct RBPlaylistManagerSaveData
*data
;
810 GtkTreeModel
*fmodel
;
813 if (!force
&& !rb_playlist_manager_is_dirty (mgr
)) {
814 /* playlists already in sync, so don't bother */
818 if (!g_atomic_int_compare_and_exchange (&mgr
->priv
->saving
, 0, 1) && !force
) {
819 /* already saving, so don't bother */
823 data
= g_new0 (struct RBPlaylistManagerSaveData
, 1);
825 data
->doc
= xmlNewDoc (RB_PLAYLIST_MGR_VERSION
);
828 root
= xmlNewDocNode (data
->doc
, NULL
, RB_PLAYLIST_MGR_PL
, NULL
);
829 xmlDocSetRootElement (data
->doc
, root
);
831 g_object_get (mgr
->priv
->sourcelist
, "model", &fmodel
, NULL
);
832 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
833 g_object_unref (fmodel
);
835 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
840 gtk_tree_model_get (model
,
842 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
845 if (source
== NULL
) {
848 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
) {
849 g_object_unref (source
);
853 g_object_get (source
, "is-local", &local
, NULL
);
855 rb_playlist_source_save_to_xml (RB_PLAYLIST_SOURCE (source
), root
);
857 g_object_unref (source
);
858 } while (gtk_tree_model_iter_next (model
, &iter
));
861 /* mark clean here. if the save fails, we'll mark it dirty again */
862 rb_playlist_manager_set_dirty (data
->mgr
, FALSE
);
865 rb_playlist_manager_save_data (data
);
867 g_thread_create ((GThreadFunc
) rb_playlist_manager_save_data
, data
, FALSE
, NULL
);
873 * rb_playlist_manager_new_playlist
874 * @mgr: the #RBPlaylistManager
875 * @suggested_name: optional name to use for the new playlist
876 * @automatic: if TRUE, create an auto playlist
878 * Creates a new playlist and adds it to the source list.
880 * Returns the new playlist object.
883 rb_playlist_manager_new_playlist (RBPlaylistManager
*mgr
,
884 const char *suggested_name
,
889 playlist
= rb_auto_playlist_source_new (mgr
->priv
->shell
,
893 playlist
= rb_static_playlist_source_new (mgr
->priv
->shell
,
896 RHYTHMDB_ENTRY_TYPE_SONG
);
898 append_new_playlist_source (mgr
, RB_PLAYLIST_SOURCE (playlist
));
899 rb_sourcelist_edit_source_name (mgr
->priv
->sourcelist
, playlist
);
900 rb_playlist_manager_set_dirty (mgr
, TRUE
);
902 g_signal_emit (mgr
, rb_playlist_manager_signals
[PLAYLIST_CREATED
], 0,
909 create_name_from_selection_data (RBPlaylistManager
*mgr
,
910 GtkSelectionData
*data
)
915 if (data
->type
== gdk_atom_intern ("text/uri-list", TRUE
) ||
916 data
->type
== gdk_atom_intern ("application/x-rhythmbox-entry", TRUE
)) {
918 list
= rb_uri_list_parse ((const char *)data
->data
);
919 is_id
= (data
->type
== gdk_atom_intern ("application/x-rhythmbox-entry", TRUE
));
925 gboolean mixed_artists
;
926 gboolean mixed_albums
;
930 mixed_artists
= FALSE
;
931 mixed_albums
= FALSE
;
932 for (l
= list
; l
!= NULL
; l
= g_list_next (l
)) {
933 RhythmDBEntry
*entry
;
934 const char *e_artist
;
937 entry
= rhythmdb_entry_lookup_from_string (mgr
->priv
->db
,
938 (const char *)l
->data
,
944 e_artist
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ARTIST
);
945 e_album
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
);
947 /* get value of first non-NULL artist */
948 if (e_artist
!= NULL
&& artist
== NULL
) {
949 artist
= g_strdup (e_artist
);
952 /* get value of first non-NULL album */
953 if (e_album
!= NULL
&& album
== NULL
) {
954 album
= g_strdup (e_album
);
957 /* pretend that NULL fields always match */
958 if (artist
!= NULL
&& e_artist
!= NULL
959 && strcmp (artist
, e_artist
) != 0) {
960 mixed_artists
= TRUE
;
963 /* pretend that NULL fields always match */
964 if (album
!= NULL
&& e_album
!= NULL
965 && strcmp (album
, e_album
) != 0) {
969 /* if there is a mix of both then stop */
970 if (mixed_artists
&& mixed_albums
) {
975 if (! mixed_artists
&& ! mixed_albums
) {
976 name
= g_strdup_printf ("%s - %s", artist
, album
);
977 } else if (! mixed_artists
) {
978 name
= g_strdup_printf ("%s", artist
);
979 } else if (! mixed_albums
) {
980 name
= g_strdup_printf ("%s", album
);
985 rb_list_deep_free (list
);
991 names
= g_strsplit ((char *)data
->data
, "\r\n", 0);
992 name
= g_strjoinv (", ", names
);
997 name
= g_strdup (_("Untitled Playlist"));
1004 * rb_playlist_manager_new_playlist_from_selection_data
1005 * @mgr: the #RBPlaylistManager
1006 * @data: the #GtkSelectionData from which to create a playlist
1008 * Creates a new playlist based on selection data from gtk.
1009 * Used to implement playlist creation through drag and drop
1010 * to the source list.
1012 * Returns the new playlist.
1015 rb_playlist_manager_new_playlist_from_selection_data (RBPlaylistManager
*mgr
,
1016 GtkSelectionData
*data
)
1019 gboolean automatic
= TRUE
;
1020 char *suggested_name
;
1022 if (data
->type
== gdk_atom_intern ("text/uri-list", TRUE
) ||
1023 data
->type
== gdk_atom_intern ("application/x-rhythmbox-entry", TRUE
))
1025 suggested_name
= create_name_from_selection_data (mgr
, data
);
1027 playlist
= rb_playlist_manager_new_playlist (mgr
,
1030 g_free (suggested_name
);
1036 rb_playlist_manager_cmd_new_playlist (GtkAction
*action
,
1037 RBPlaylistManager
*mgr
)
1039 rb_playlist_manager_new_playlist (mgr
, NULL
, FALSE
);
1043 rb_playlist_manager_set_automatic_playlist (RBPlaylistManager
*mgr
,
1044 RBAutoPlaylistSource
*playlist
,
1045 RBQueryCreator
*creator
)
1047 RhythmDBQueryModelLimitType limit_type
;
1048 GValueArray
*limit_value
= NULL
;
1049 const char *sort_key
;
1050 gint sort_direction
;
1053 rb_query_creator_get_limit (creator
, &limit_type
, &limit_value
);
1054 rb_query_creator_get_sort_order (creator
,
1058 query
= rb_query_creator_get_query (creator
);
1059 rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (playlist
),
1065 rhythmdb_query_free (query
);
1069 rb_playlist_manager_cmd_new_automatic_playlist (GtkAction
*action
,
1070 RBPlaylistManager
*mgr
)
1072 RBQueryCreator
*creator
= RB_QUERY_CREATOR (rb_query_creator_new (mgr
->priv
->db
));
1075 switch (gtk_dialog_run (GTK_DIALOG (creator
))) {
1076 case GTK_RESPONSE_NONE
:
1077 case GTK_RESPONSE_CLOSE
:
1078 gtk_widget_destroy (GTK_WIDGET (creator
));
1082 playlist
= rb_playlist_manager_new_playlist (mgr
, NULL
, TRUE
);
1084 rb_playlist_manager_set_automatic_playlist (mgr
, RB_AUTO_PLAYLIST_SOURCE (playlist
), creator
);
1086 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1088 gtk_widget_destroy (GTK_WIDGET (creator
));
1092 RBAutoPlaylistSource
*playlist
;
1093 RBPlaylistManager
*mgr
;
1094 RBQueryCreator
*creator
;
1095 gint playlist_deleted_id
;
1096 gint creator_response_id
;
1097 } EditAutoPlaylistData
;
1100 cleanup_edit_data (EditAutoPlaylistData
*data
)
1102 g_signal_handler_disconnect (data
->playlist
, data
->playlist_deleted_id
);
1103 g_signal_handler_disconnect (data
->creator
, data
->creator_response_id
);
1104 gtk_widget_destroy (GTK_WIDGET (data
->creator
));
1109 edit_auto_playlist_response_cb (RBQueryCreator
*dialog
,
1111 EditAutoPlaylistData
*data
)
1113 rb_playlist_manager_set_automatic_playlist (data
->mgr
, data
->playlist
, dialog
);
1114 g_object_set_data (G_OBJECT (data
->playlist
), "rhythmbox-playlist-editor", NULL
);
1116 cleanup_edit_data (data
);
1120 edit_auto_playlist_deleted_cb (RBAutoPlaylistSource
*playlist
, EditAutoPlaylistData
*data
)
1122 g_object_set_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor", NULL
);
1124 cleanup_edit_data (data
);
1128 rb_playlist_manager_cmd_edit_automatic_playlist (GtkAction
*action
,
1129 RBPlaylistManager
*mgr
)
1131 RBQueryCreator
*creator
;
1132 RBAutoPlaylistSource
*playlist
;
1134 playlist
= RB_AUTO_PLAYLIST_SOURCE (mgr
->priv
->selected_source
);
1135 creator
= g_object_get_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor");
1136 if (creator
== NULL
) {
1137 RhythmDBQueryModelLimitType limit_type
;
1138 GValueArray
*limit_value
= NULL
;
1141 gint sort_direction
;
1142 EditAutoPlaylistData
*data
;
1145 rb_auto_playlist_source_get_query (playlist
,
1152 creator
= RB_QUERY_CREATOR (rb_query_creator_new_from_query (mgr
->priv
->db
,
1158 if (limit_value
!= NULL
) {
1159 g_value_array_free (limit_value
);
1161 rhythmdb_query_free (query
);
1164 data
= g_new0 (EditAutoPlaylistData
, 1);
1166 data
->playlist
= playlist
;
1167 data
->creator
= creator
;
1168 data
->creator_response_id
=
1169 g_signal_connect (creator
,
1171 G_CALLBACK (edit_auto_playlist_response_cb
),
1174 g_object_set_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor", creator
);
1175 data
->playlist_deleted_id
=
1176 g_signal_connect (playlist
,
1178 G_CALLBACK (edit_auto_playlist_deleted_cb
),
1181 gtk_window_present (GTK_WINDOW (creator
));
1185 _queue_track_cb (RhythmDBQueryModel
*model
,
1188 RBStaticPlaylistSource
*queue_source
)
1190 RhythmDBEntry
*entry
;
1192 entry
= rhythmdb_query_model_iter_to_entry (model
, iter
);
1193 rb_static_playlist_source_add_entry (queue_source
, entry
, -1);
1194 rhythmdb_entry_unref (entry
);
1200 rb_playlist_manager_cmd_queue_playlist (GtkAction
*action
,
1201 RBPlaylistManager
*mgr
)
1203 RBSource
*queue_source
;
1204 RhythmDBQueryModel
*model
;
1206 g_object_get (mgr
->priv
->shell
, "queue-source", &queue_source
, NULL
);
1207 g_object_get (mgr
->priv
->selected_source
, "query-model", &model
, NULL
);
1209 gtk_tree_model_foreach (GTK_TREE_MODEL (model
),
1210 (GtkTreeModelForeachFunc
) _queue_track_cb
,
1213 g_object_unref (queue_source
);
1214 g_object_unref (model
);
1218 rb_playlist_manager_cmd_rename_playlist (GtkAction
*action
,
1219 RBPlaylistManager
*mgr
)
1221 rb_debug ("Renaming playlist %p", mgr
->priv
->selected_source
);
1223 rb_sourcelist_edit_source_name (mgr
->priv
->sourcelist
, mgr
->priv
->selected_source
);
1224 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1228 rb_playlist_manager_cmd_delete_playlist (GtkAction
*action
,
1229 RBPlaylistManager
*mgr
)
1231 rb_debug ("Deleting playlist %p", mgr
->priv
->selected_source
);
1233 rb_source_delete_thyself (mgr
->priv
->selected_source
);
1234 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1238 load_playlist_response_cb (GtkDialog
*dialog
,
1240 RBPlaylistManager
*mgr
)
1242 char *escaped_file
= NULL
;
1243 GError
*error
= NULL
;
1245 if (response_id
!= GTK_RESPONSE_ACCEPT
) {
1246 gtk_widget_destroy (GTK_WIDGET (dialog
));
1250 escaped_file
= gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog
));
1252 gtk_widget_destroy (GTK_WIDGET (dialog
));
1254 if (escaped_file
== NULL
)
1257 if (!rb_playlist_manager_parse_file (mgr
, escaped_file
, &error
)) {
1258 rb_error_dialog (NULL
, _("Couldn't read playlist"),
1259 "%s", error
->message
);
1260 g_error_free (error
);
1263 g_free (escaped_file
);
1264 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1268 rb_playlist_manager_cmd_load_playlist (GtkAction
*action
,
1269 RBPlaylistManager
*mgr
)
1273 dialog
= rb_file_chooser_new (_("Load Playlist"),
1274 GTK_WINDOW (mgr
->priv
->window
),
1275 GTK_FILE_CHOOSER_ACTION_OPEN
,
1278 g_signal_connect_object (dialog
, "response",
1279 G_CALLBACK (load_playlist_response_cb
), mgr
, 0);
1283 const gchar
*description
;
1284 /* NULL terminated array of extensions for this file format. The first
1285 * one is the prefered extension for files of this type. */
1286 const gchar
**extensions
;
1287 const RBPlaylistExportType type
;
1288 } RBPlaylistExportFilter
;
1290 static const char *m3u_extensions
[] = {"m3u", NULL
};
1291 static const char *pls_extensions
[] = {"pls", NULL
};
1293 static RBPlaylistExportFilter playlist_export_formats
[] = {
1294 {N_("MPEG Version 3.0 URL"), m3u_extensions
, RB_PLAYLIST_EXPORT_TYPE_M3U
},
1295 {N_("Shoutcast playlist"), pls_extensions
, RB_PLAYLIST_EXPORT_TYPE_PLS
},
1299 save_playlist_response_cb (GtkDialog
*dialog
,
1301 RBPlaylistManager
*mgr
)
1306 RBPlaylistExportType export_type
= RB_PLAYLIST_EXPORT_TYPE_UNKNOWN
;
1308 if (response_id
!= GTK_RESPONSE_OK
) {
1309 gtk_widget_destroy (GTK_WIDGET (dialog
));
1313 file
= gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog
));
1314 if (file
== NULL
|| file
[0] == '\0')
1317 menu
= g_object_get_data (G_OBJECT(dialog
), "export-menu");
1318 index
= gtk_combo_box_get_active (GTK_COMBO_BOX (menu
));
1320 /* by extension selected */
1324 for (i
= 0; i
< G_N_ELEMENTS (playlist_export_formats
); i
++) {
1327 /* determine the playlist type from the extension */
1328 for (j
= 0; playlist_export_formats
[i
].extensions
[j
] != NULL
; j
++) {
1329 if (g_str_has_suffix (file
, playlist_export_formats
[i
].extensions
[j
])) {
1330 export_type
= playlist_export_formats
[i
].type
;
1336 export_type
= playlist_export_formats
[index
-1].type
;
1339 if (export_type
== RB_PLAYLIST_EXPORT_TYPE_UNKNOWN
) {
1340 rb_error_dialog (NULL
, _("Couldn't save playlist"), _("Unsupported file extension given."));
1342 rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr
->priv
->selected_source
),
1343 file
, (export_type
== RB_PLAYLIST_EXPORT_TYPE_M3U
));
1344 gtk_widget_destroy (GTK_WIDGET (dialog
));
1351 export_set_extension_cb (GtkWidget
* widget
, GtkDialog
*dialog
)
1356 const char *extension
;
1358 GString
*basename_str
;
1360 index
= gtk_combo_box_get_active (GTK_COMBO_BOX (widget
));
1364 extension
= playlist_export_formats
[index
-1].extensions
[0];
1365 if (extension
== NULL
)
1368 text
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
1369 if (text
== NULL
|| text
[0] == '\0') {
1374 basename
= g_path_get_basename (text
);
1375 basename_str
= g_string_new (basename
);
1376 last_dot
= g_utf8_strrchr (basename
, -1, '.');
1378 g_string_truncate (basename_str
, (last_dot
-basename
));
1382 g_string_append_printf (basename_str
, ".%s", extension
);
1383 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), basename_str
->str
);
1384 g_string_free (basename_str
, TRUE
);
1388 filter_get_export_filter_label (RBPlaylistExportFilter
*efilter
)
1393 str
= g_string_new (_(efilter
->description
));
1394 for (ext
= 0; efilter
->extensions
[ext
] != NULL
; ext
++) {
1396 g_string_append (str
, " (*.");
1398 g_string_append (str
, ", *.");
1399 g_string_append (str
, efilter
->extensions
[ext
]);
1403 g_string_append (str
, ")");
1405 return g_string_free (str
, FALSE
);
1409 setup_format_menu (GtkWidget
* menu
, GtkWidget
*dialog
)
1411 GtkTreeModel
*model
;
1414 model
= gtk_combo_box_get_model (GTK_COMBO_BOX (menu
));
1415 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu
), rb_combo_box_hyphen_separator_func
,
1418 for (i
= 0; i
< G_N_ELEMENTS (playlist_export_formats
); i
++) {
1419 gchar
*filter_label
;
1422 filter_label
= filter_get_export_filter_label (&playlist_export_formats
[i
]);
1423 gtk_list_store_insert_with_values (GTK_LIST_STORE (model
), &iter
, -1,
1424 0, filter_label
, -1);
1426 g_free (filter_label
);
1429 g_signal_connect_object (menu
,
1430 "changed", G_CALLBACK (export_set_extension_cb
),
1435 rb_playlist_manager_cmd_save_playlist (GtkAction
*action
,
1436 RBPlaylistManager
*mgr
)
1439 GtkWidget
*dialog
, *menu
;
1442 xml
= rb_glade_xml_new ("playlist-save.glade",
1443 "playlist_save_dialog",
1445 dialog
= glade_xml_get_widget (xml
, "playlist_save_dialog");
1447 menu
= glade_xml_get_widget (xml
, "playlist_format_menu");
1448 setup_format_menu (menu
, dialog
);
1449 g_object_set_data (G_OBJECT (dialog
), "export-menu", menu
);
1451 g_object_get (mgr
->priv
->selected_source
, "name", &name
, NULL
);
1452 tmp
= g_strconcat (name
, ".pls", NULL
);
1453 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), tmp
);
1457 /* FIXME: always has "by extension" as default (it should probably remember the last selection) */
1458 gtk_combo_box_set_active (GTK_COMBO_BOX (menu
), 0);
1459 g_signal_connect_object (dialog
, "response",
1460 G_CALLBACK (save_playlist_response_cb
),
1463 g_object_unref (xml
);
1467 * rb_playlist_manager_get_playlists
1468 * @mgr: the #RBPlaylistManager
1470 * Returns a #GList containing all local playlist source objects.
1473 rb_playlist_manager_get_playlists (RBPlaylistManager
*mgr
)
1475 GList
*playlists
= NULL
;
1477 GtkTreeModel
*fmodel
;
1478 GtkTreeModel
*model
;
1480 g_object_get (mgr
->priv
->sourcelist
, "model", &fmodel
, NULL
);
1481 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1482 g_object_unref (fmodel
);
1484 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
1489 gtk_tree_model_get (model
,
1491 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1494 if (source
== NULL
) {
1497 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
1498 || RB_IS_PLAY_QUEUE_SOURCE (source
) == TRUE
) {
1499 g_object_unref (source
);
1503 g_object_get (source
, "is-local", &local
,
1506 playlists
= g_list_prepend (playlists
, source
);
1509 g_object_unref (source
);
1510 } while (gtk_tree_model_iter_next (model
, &iter
));
1517 * rb_playlist_manager_get_playlist_names
1518 * @mgr: the #RBPlaylistManager
1519 * @playlists: holds the array of playlist names on reutrn
1520 * @error: holds a #GError on return on failure
1522 * Allocates and returns an array containing the names of all local
1523 * playlists. This is part of the playlist manager dbus interface.
1525 * Returns TRUE if successful.
1528 rb_playlist_manager_get_playlist_names (RBPlaylistManager
*mgr
,
1533 GtkTreeModel
*fmodel
;
1534 GtkTreeModel
*model
;
1537 g_object_get (mgr
->priv
->sourcelist
, "model", &fmodel
, NULL
);
1538 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1539 g_object_unref (fmodel
);
1541 if (!gtk_tree_model_get_iter_first (model
, &iter
)) {
1546 *playlists
= g_new0 (char *, gtk_tree_model_iter_n_children (model
, NULL
) + 1);
1555 gtk_tree_model_get (model
, &iter
,
1556 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1559 if (source
== NULL
) {
1562 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
1563 || RB_IS_PLAY_QUEUE_SOURCE (source
) == TRUE
) {
1564 g_object_unref (source
);
1568 g_object_get (source
, "name", &source_name
, NULL
);
1569 (*playlists
)[i
++] = source_name
;
1571 g_object_unref (source
);
1573 } while (gtk_tree_model_iter_next (model
, &iter
));
1579 _get_playlist_by_name (RBPlaylistManager
*mgr
,
1583 GtkTreeModel
*fmodel
;
1584 GtkTreeModel
*model
;
1585 RBSource
*playlist
= NULL
;
1587 g_object_get (mgr
->priv
->sourcelist
, "model", &fmodel
, NULL
);
1588 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1589 g_object_unref (fmodel
);
1591 if (!gtk_tree_model_get_iter_first (model
, &iter
))
1598 gtk_tree_model_get (model
, &iter
,
1599 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1602 if (source
== NULL
) {
1605 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
) {
1606 g_object_unref (source
);
1609 g_object_get (source
, "name", &source_name
, NULL
);
1610 if (strcmp (name
, source_name
) == 0)
1613 g_free (source_name
);
1614 g_object_unref (source
);
1615 } while (gtk_tree_model_iter_next (model
, &iter
) && playlist
== NULL
);
1621 * rb_playlist_manager_create_static_playlist
1622 * @mgr: the #RBPlaylistManager
1623 * @name: name of the new playlist
1624 * @error: holds a #GError on return on failure
1626 * Creates a new static playlist source with the given name.
1627 * Will fail if a playlist with that name already exists.
1628 * This is part of the playlist manager dbus interface.
1630 * Returns TRUE if successful.
1633 rb_playlist_manager_create_static_playlist (RBPlaylistManager
*mgr
,
1637 if (_get_playlist_by_name (mgr
, name
)) {
1639 RB_PLAYLIST_MANAGER_ERROR
,
1640 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_EXISTS
,
1641 _("Playlist %s already exists"),
1646 rb_playlist_manager_new_playlist (mgr
, name
, FALSE
);
1651 * rb_playlist_manager_delete_playlist
1652 * @mgr: the #RBPlaylistManager
1653 * @name: name of the playlist to delete
1654 * @error: holds a #GError on return on failure
1656 * Deletes the specified playlist. Will fail if no playlist with
1657 * that name exists. This is part of the playlist manager dbus interface.
1659 * Returns TRUE if successful.
1662 rb_playlist_manager_delete_playlist (RBPlaylistManager
*mgr
,
1666 RBSource
*playlist
= _get_playlist_by_name (mgr
, name
);
1669 RB_PLAYLIST_MANAGER_ERROR
,
1670 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1671 _("Unknown playlist: %s"),
1675 rb_source_delete_thyself (playlist
);
1676 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1681 * rb_playlist_manager_add_to_playlist
1682 * @mgr: the #RBPlaylistManager
1683 * @name: name of the playlist to add to
1684 * @uri: URI of the entry to add to the playlist
1685 * @error: holds a #GError on return on failure
1687 * Adds an entry to the specified playlist.
1688 * Fails if no playlist with that name exists.
1689 * This is part of the playlist manager dbus interface.
1691 * Returns TRUE if successful.
1694 rb_playlist_manager_add_to_playlist (RBPlaylistManager
*mgr
,
1695 const gchar
*playlist
,
1699 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);;
1702 RB_PLAYLIST_MANAGER_ERROR
,
1703 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1704 _("Unknown playlist: %s"),
1708 if (RB_IS_AUTO_PLAYLIST_SOURCE (source
)) {
1710 RB_PLAYLIST_MANAGER_ERROR
,
1711 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1712 _("Playlist %s is an automatic playlist"),
1716 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (source
), uri
, -1);
1721 * rb_playlist_manager_remove_from_playlist
1722 * @mgr: the #RBPlaylistManager
1723 * @name: name of the playlist to remove from
1724 * @uri: URI of the entry to remove from the playlist
1725 * @error: holds a #GError on return on failure
1727 * Removes an entry from the specified playlist.
1728 * Fails if no playlist with that name exists.
1729 * This is part of the playlist manager dbus interface.
1731 * Returns TRUE if successful.
1734 rb_playlist_manager_remove_from_playlist (RBPlaylistManager
*mgr
,
1735 const gchar
*playlist
,
1739 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);;
1742 RB_PLAYLIST_MANAGER_ERROR
,
1743 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1744 _("Unknown playlist: %s"),
1748 if (RB_IS_AUTO_PLAYLIST_SOURCE (source
)) {
1750 RB_PLAYLIST_MANAGER_ERROR
,
1751 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1752 _("Playlist %s is an automatic playlist"),
1757 if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (source
), uri
))
1758 rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (source
), uri
);
1763 * rb_playlist_manager_export_playlist
1764 * @mgr: the #RBPlaylistManager
1765 * @name: name of the playlist to export
1766 * @uri: playlist save location
1767 * @m3u_format: if TRUE, save in M3U format, otherwise save in PLS format
1768 * @error: holds a #GError on return on failure
1770 * Saves the specified playlist to a file in either M3U or PLS format.
1771 * This is part of the playlist manager dbus interface.
1773 * Returns TRUE if successful.
1776 rb_playlist_manager_export_playlist (RBPlaylistManager
*mgr
,
1777 const gchar
*playlist
,
1779 gboolean m3u_format
,
1782 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);
1785 RB_PLAYLIST_MANAGER_ERROR
,
1786 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1787 _("Unknown playlist: %s"),
1792 rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (source
),