2
* arch-tag: Implementation of generic audio player source object
4
* Copyright (C) 2004 James Livingston <jrl@ids.org.au>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24
#include <gtk/gtktreeview.h>
27
#include <libgnome/gnome-i18n.h>
30
#include <dbus/dbus.h>
32
#include <libgnomevfs/gnome-vfs-volume.h>
33
#include <libgnomevfs/gnome-vfs-volume-monitor.h>
34
#include <totem-pl-parser.h>
36
#include "eel-gconf-extensions.h"
37
#include "rb-static-playlist-source.h"
38
#include "rb-generic-player-source.h"
41
#include "rb-file-helpers.h"
43
#include "rb-dialog.h"
44
#include "rb-plugin.h"
46
static GObject *rb_generic_player_source_constructor (GType type, guint n_construct_properties,
47
GObjectConstructParam *construct_properties);
48
static void rb_generic_player_source_dispose (GObject *object);
50
static gboolean rb_generic_player_source_load_playlists (RBGenericPlayerSource *source);
51
static void rb_generic_player_source_load_songs (RBGenericPlayerSource *source);
53
static gboolean impl_show_popup (RBSource *source);
54
static void impl_delete_thyself (RBSource *source);
55
static gboolean impl_can_move_to_trash (RBSource *source);
57
static gchar *default_get_mount_path (RBGenericPlayerSource *source);
58
static void default_load_playlists (RBGenericPlayerSource *source);
59
static char * default_transform_playlist_uri (RBGenericPlayerSource *source,
70
gboolean handles_trash;
72
} RBGenericPlayerSourcePrivate;
75
RB_PLUGIN_DEFINE_TYPE(RBGenericPlayerSource, rb_generic_player_source, RB_TYPE_REMOVABLE_MEDIA_SOURCE)
76
#define GENERIC_PLAYER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_GENERIC_PLAYER_SOURCE, RBGenericPlayerSourcePrivate))
79
rb_generic_player_source_class_init (RBGenericPlayerSourceClass *klass)
81
GObjectClass *object_class = G_OBJECT_CLASS (klass);
82
RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
84
object_class->constructor = rb_generic_player_source_constructor;
85
object_class->dispose = rb_generic_player_source_dispose;
87
source_class->impl_show_popup = impl_show_popup;
88
source_class->impl_delete_thyself = impl_delete_thyself;
89
source_class->impl_can_move_to_trash = impl_can_move_to_trash;
91
klass->impl_get_mount_path = default_get_mount_path;
92
klass->impl_load_playlists = default_load_playlists;
93
klass->impl_transform_playlist_uri = default_transform_playlist_uri;
95
g_type_class_add_private (klass, sizeof (RBGenericPlayerSourcePrivate));
99
rb_generic_player_source_init (RBGenericPlayerSource *source)
105
rb_generic_player_source_constructor (GType type, guint n_construct_properties,
106
GObjectConstructParam *construct_properties)
108
RBGenericPlayerSource *source;
109
RBGenericPlayerSourcePrivate *priv;
110
GnomeVFSVolume *volume;
113
source = RB_GENERIC_PLAYER_SOURCE (G_OBJECT_CLASS (rb_generic_player_source_parent_class)->
114
constructor (type, n_construct_properties, construct_properties));
116
priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
118
g_object_get (G_OBJECT (source), "shell", &shell, NULL);
120
g_object_get (G_OBJECT (shell), "db", &priv->db, NULL);
121
g_object_unref (G_OBJECT (shell));
123
g_object_get (G_OBJECT (source), "volume", &volume, NULL);
124
priv->handles_trash = gnome_vfs_volume_handles_trash (volume);
125
priv->read_only = gnome_vfs_volume_is_read_only (volume);
126
g_object_unref (G_OBJECT (volume));
128
rb_generic_player_source_load_songs (source);
130
g_idle_add ((GSourceFunc)rb_generic_player_source_load_playlists, source);
132
return G_OBJECT (source);
136
rb_generic_player_source_dispose (GObject *object)
138
RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (object);
140
if (priv->mount_path) {
141
g_free (priv->mount_path);
142
priv->mount_path = NULL;
145
g_object_unref (G_OBJECT (priv->db));
149
G_OBJECT_CLASS (rb_generic_player_source_parent_class)->dispose (object);
152
RBRemovableMediaSource *
153
rb_generic_player_source_new (RBShell *shell, GnomeVFSVolume *volume)
155
RBGenericPlayerSource *source;
156
RhythmDBEntryType entry_type;
158
g_assert (rb_generic_player_is_volume_player (volume));
160
entry_type = rhythmdb_entry_register_type (NULL);
162
source = RB_GENERIC_PLAYER_SOURCE (g_object_new (RB_TYPE_GENERIC_PLAYER_SOURCE,
163
"entry-type", entry_type,
166
"sourcelist-group", RB_SOURCELIST_GROUP_REMOVABLE,
169
rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
171
return RB_REMOVABLE_MEDIA_SOURCE (source);
175
impl_delete_thyself (RBSource *source)
178
RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
180
for (p = priv->playlists; p != NULL; p = p->next) {
181
RBSource *playlist = RB_SOURCE (p->data);
182
rb_source_delete_thyself (playlist);
184
g_list_free (priv->playlists);
185
priv->playlists = NULL;
187
RB_SOURCE_CLASS (rb_generic_player_source_parent_class)->impl_delete_thyself (source);
191
rb_generic_player_source_load_songs (RBGenericPlayerSource *source)
193
RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
194
RhythmDBEntryType entry_type;
196
priv->mount_path = rb_generic_player_source_get_mount_path (source);
197
g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
199
rhythmdb_add_uri_with_type (priv->db, priv->mount_path, entry_type);
203
rb_generic_player_source_get_mount_path (RBGenericPlayerSource *source)
205
RBGenericPlayerSourceClass *klass = RB_GENERIC_PLAYER_SOURCE_GET_CLASS (source);
207
return klass->impl_get_mount_path (source);
211
default_get_mount_path (RBGenericPlayerSource *source)
214
GnomeVFSVolume *volume;
216
g_object_get (G_OBJECT (source), "volume", &volume, NULL);
217
uri = gnome_vfs_volume_get_activation_uri (volume);
218
g_object_unref (G_OBJECT (volume));
225
rb_generic_player_is_volume_player (GnomeVFSVolume *volume)
227
gboolean result = FALSE;
229
gchar *udi = gnome_vfs_volume_get_hal_udi (volume);
232
LibHalContext *ctx = NULL;
233
DBusConnection *conn = NULL;
237
dbus_error_init (&error);
238
ctx = libhal_ctx_new ();
242
conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
243
if (conn == NULL || dbus_error_is_set (&error))
245
libhal_ctx_set_dbus_connection (ctx, conn);
246
if (!libhal_ctx_init (ctx, &error) || dbus_error_is_set (&error))
249
/* find the udi of the player itself */
250
while (!libhal_device_query_capability (ctx, udi, "portable_audio_player", &error) &&
251
!dbus_error_is_set (&error)) {
252
char *new_udi = libhal_device_get_property_string (ctx, udi, "info.parent", &error);
253
if (dbus_error_is_set (&error))
256
if ((new_udi == NULL) || strcmp (new_udi, "/") == 0) {
257
rb_debug ("device is not audio player");
262
udi = g_strdup (new_udi);
263
libhal_free_string (new_udi);
265
if (dbus_error_is_set (&error))
268
/* check that it can be accessed as mass-storage */
269
prop = libhal_device_get_property_string (ctx, udi, "portable_audio_player.access_method", &error);
270
if (prop == NULL || strcmp (prop, "storage") != 0 || dbus_error_is_set (&error)) {
271
rb_debug ("device cannot be accessed via storage");
275
/* the device has passed all tests, so it should be a usable player */
278
if (dbus_error_is_set (&error)) {
279
rb_debug ("Error: %s\n", error.message);
280
dbus_error_free (&error);
281
dbus_error_init (&error);
285
libhal_free_string (prop);
288
libhal_ctx_shutdown (ctx, &error);
289
libhal_ctx_free (ctx);
291
dbus_error_free (&error);
295
#endif /* HAVE_HAL_0_5 */
297
/* treat as audio player if ".is_audio_player" exists in the root of the volume */
299
char *path = gnome_vfs_volume_get_activation_uri (volume);
300
char *file = g_build_filename (path, ".is_audio_player", NULL);
302
if (rb_uri_is_local (file) && rb_uri_exists (file))
313
impl_show_popup (RBSource *source)
315
_rb_source_show_popup (RB_SOURCE (source), "/GenericPlayerSourcePopup");
320
impl_can_move_to_trash (RBSource *source)
322
RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
323
return priv->handles_trash;
326
/* code for playlist loading */
329
rb_generic_player_source_add_playlist (RBGenericPlayerSource *source,
333
RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
334
priv->playlists = g_list_prepend (priv->playlists, playlist);
336
rb_shell_append_source (shell, playlist, RB_SOURCE (source));
340
rb_generic_player_source_load_playlists (RBGenericPlayerSource *source)
342
RBGenericPlayerSourceClass *klass = RB_GENERIC_PLAYER_SOURCE_GET_CLASS (source);
344
if (klass->impl_load_playlists)
345
klass->impl_load_playlists (source);
351
rb_generic_player_source_transform_playlist_uri (RBGenericPlayerSource *source, const char *uri)
353
RBGenericPlayerSourceClass *klass = RB_GENERIC_PLAYER_SOURCE_GET_CLASS (source);
355
return klass->impl_transform_playlist_uri (source, uri);
360
RBGenericPlayerSource *player_source;
361
RBStaticPlaylistSource *source;
362
} HandlePlaylistEntryData;
365
handle_playlist_entry_cb (TotemPlParser *playlist, const char *uri,
367
const char *genre, HandlePlaylistEntryData *data)
372
local_uri = rb_generic_player_source_transform_playlist_uri (data->player_source, uri);
373
if (local_uri == NULL)
376
g_object_get (G_OBJECT (data->source), "name", &name, NULL);
377
rb_debug ("adding '%s' as '%s' to playlist '%s'", uri, local_uri, name);
378
rb_static_playlist_source_add_location (data->source, local_uri, -1);
383
visit_playlist_dirs (const gchar *rel_path,
384
GnomeVFSFileInfo *info,
385
gboolean recursing_will_loop,
386
RBGenericPlayerSource *source,
390
RhythmDBEntryType entry_type;
393
TotemPlParser *parser;
394
RBStaticPlaylistSource *playlist;
395
HandlePlaylistEntryData *data;
400
main_path = rb_generic_player_source_get_mount_path (source);
401
playlist_path = rb_uri_append_path (main_path, rel_path);
404
if (!g_str_has_suffix (playlist_path, ".m3u") &&
405
!g_str_has_suffix (playlist_path, ".pls")) {
406
g_free (playlist_path);
410
g_object_get (G_OBJECT (source),
412
"entry-type", &entry_type,
415
playlist = RB_STATIC_PLAYLIST_SOURCE (
416
rb_static_playlist_source_new (shell,
421
data = g_new0 (HandlePlaylistEntryData, 1);
422
data->source = playlist;
423
data->player_source = source;
425
parser = totem_pl_parser_new ();
427
g_signal_connect (parser,
428
"entry", G_CALLBACK (handle_playlist_entry_cb),
430
if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser), "recurse"))
431
g_object_set (G_OBJECT (parser), "recurse", FALSE, NULL);
433
if (totem_pl_parser_parse (parser, playlist_path, TRUE) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
434
rb_debug ("unable to parse %s as playlist", playlist_path);
435
g_object_unref (G_OBJECT (playlist));
437
rb_generic_player_source_add_playlist (source, shell, RB_SOURCE (playlist));
440
g_object_unref (G_OBJECT (parser));
441
g_free (playlist_path);
444
g_object_unref (G_OBJECT (shell));
450
default_load_playlists (RBGenericPlayerSource *source)
454
mount_path = rb_generic_player_source_get_mount_path (source);
455
gnome_vfs_directory_visit (mount_path,
456
GNOME_VFS_FILE_INFO_DEFAULT,
457
GNOME_VFS_DIRECTORY_VISIT_DEFAULT,
458
(GnomeVFSDirectoryVisitFunc) visit_playlist_dirs,
464
default_transform_playlist_uri (RBGenericPlayerSource *source, const char *uri)
469
mount_uri = rb_generic_player_source_get_mount_path (source);
470
full_uri = rb_uri_append_uri (mount_uri, uri);