~ubuntu-branches/ubuntu/quantal/rhythmbox/quantal

« back to all changes in this revision

Viewing changes to sources/rb-ipod-source.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-03-25 23:58:54 UTC
  • Revision ID: james.westby@ubuntu.com-20050325235854-2212vevw1u4074w8
Tags: upstream-0.8.8
ImportĀ upstreamĀ versionĀ 0.8.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  arch-tag: Implementation of ipod source object
 
3
 *
 
4
 *  Copyright (C) 2004 Christophe Fergeau  <teuf@gnome.org>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
#include <gtk/gtktreeview.h>
 
22
#include <string.h>
 
23
#include "itunesdb.h"
 
24
#include "rhythmdb.h"
 
25
#include <libgnome/gnome-i18n.h>
 
26
#include "eel-gconf-extensions.h"
 
27
#include "rb-ipod-source.h"
 
28
#include "rb-stock-icons.h"
 
29
#define DEFAULT_MOUNT_PATH "/mnt/ipod"
 
30
#define GCONF_MOUNT_PATH "/apps/qahog/mount_path"
 
31
 
 
32
 
 
33
static void rb_ipod_source_init (RBiPodSource *source);
 
34
static void rb_ipod_source_finalize (GObject *object);
 
35
static void rb_ipod_source_class_init (RBiPodSourceClass *klass);
 
36
 
 
37
static gboolean ipod_itunesdb_monitor_cb (RBiPodSource *source);
 
38
 
 
39
 
 
40
 
 
41
struct RBiPodSourcePrivate
 
42
{
 
43
        guint ipod_polling_id;
 
44
};
 
45
 
 
46
 
 
47
GType
 
48
rb_ipod_source_get_type (void)
 
49
{
 
50
        static GType rb_ipod_source_type = 0;
 
51
 
 
52
        if (rb_ipod_source_type == 0)
 
53
        {
 
54
                static const GTypeInfo our_info =
 
55
                {
 
56
                        sizeof (RBiPodSourceClass),
 
57
                        NULL,
 
58
                        NULL,
 
59
                        (GClassInitFunc) rb_ipod_source_class_init,
 
60
                        NULL,
 
61
                        NULL,
 
62
                        sizeof (RBiPodSource),
 
63
                        0,
 
64
                        (GInstanceInitFunc) rb_ipod_source_init
 
65
                };
 
66
 
 
67
                rb_ipod_source_type = g_type_register_static (RB_TYPE_LIBRARY_SOURCE,
 
68
                                                              "RBiPodSource",
 
69
                                                              &our_info, 0);
 
70
 
 
71
        }
 
72
 
 
73
        return rb_ipod_source_type;
 
74
}
 
75
 
 
76
static void
 
77
rb_ipod_source_class_init (RBiPodSourceClass *klass)
 
78
{
 
79
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
80
 
 
81
        object_class->finalize = rb_ipod_source_finalize;
 
82
}
 
83
 
 
84
static void
 
85
rb_ipod_source_init (RBiPodSource *source)
 
86
{
 
87
        source->priv = g_new0 (RBiPodSourcePrivate, 1); 
 
88
        source->priv->ipod_polling_id = g_timeout_add (1000, (GSourceFunc)ipod_itunesdb_monitor_cb, source);
 
89
}
 
90
 
 
91
 
 
92
static void 
 
93
rb_ipod_source_finalize (GObject *object)
 
94
{
 
95
        RBiPodSource *source = RB_IPOD_SOURCE (object);
 
96
 
 
97
        if (source->priv->ipod_polling_id) {
 
98
                g_source_remove (source->priv->ipod_polling_id);
 
99
        }
 
100
}
 
101
 
 
102
 
 
103
RBSource *
 
104
rb_ipod_source_new (RBShell *shell, RhythmDB *db, BonoboUIComponent *component)
 
105
{
 
106
        RBSource *source;
 
107
        GtkWidget *dummy = gtk_tree_view_new ();
 
108
        GdkPixbuf *icon;
 
109
 
 
110
        icon = gtk_widget_render_icon (dummy, RB_STOCK_IPOD,
 
111
                                       GTK_ICON_SIZE_LARGE_TOOLBAR,
 
112
                                       NULL);
 
113
        gtk_widget_destroy (dummy);
 
114
 
 
115
        /* FIXME: need to set icon */
 
116
        source = RB_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
 
117
                                          "name", _("iPod"),
 
118
                                          "entry-type", RHYTHMDB_ENTRY_TYPE_IPOD,
 
119
                                          "internal-name", "<ipod>",
 
120
                                          "icon", icon,
 
121
                                          "db", db,
 
122
                                          "component", component,
 
123
                                          NULL));
 
124
 
 
125
        rb_shell_register_entry_type_for_source (shell, source, 
 
126
                                                 RHYTHMDB_ENTRY_TYPE_IPOD);
 
127
 
 
128
 
 
129
        return source;
 
130
}
 
131
 
 
132
 
 
133
static char *
 
134
ipod_get_mount_path (void)
 
135
{
 
136
        gchar *path;
 
137
 
 
138
        path = eel_gconf_get_string (GCONF_MOUNT_PATH);
 
139
        if (path == NULL || strcmp (path, "") == 0)
 
140
                return g_strdup (DEFAULT_MOUNT_PATH);
 
141
        else
 
142
                return path;
 
143
}
 
144
 
 
145
static char *
 
146
ipod_get_itunesdb_path (void)
 
147
{
 
148
        gchar *result;
 
149
        gchar *mount_path = ipod_get_mount_path ();
 
150
 
 
151
        result = g_build_filename (mount_path,
 
152
                                   "iPod_Control/iTunes/iTunesDB", 
 
153
                                   NULL);
 
154
        g_free (mount_path);
 
155
        return result;
 
156
}
 
157
 
 
158
static void
 
159
entry_set_locked (RhythmDB *db, RhythmDBEntry *entry,
 
160
                  RhythmDBPropType propid, GValue *value) 
 
161
{
 
162
        rhythmdb_write_lock (RHYTHMDB (db));
 
163
        rhythmdb_entry_set (RHYTHMDB (db), entry, propid, value);
 
164
        rhythmdb_write_unlock (RHYTHMDB (db));
 
165
}
 
166
 
 
167
static void 
 
168
entry_set_string_prop (RhythmDB *db, RhythmDBEntry *entry,
 
169
                       RhythmDBPropType propid, const char *str)
 
170
{
 
171
        GValue value = {0,};
 
172
        gchar *tmp;
 
173
 
 
174
        if (str == NULL) {
 
175
                tmp = g_strdup (_("Unknown"));
 
176
        } else {
 
177
                tmp = g_strdup (str);
 
178
        }
 
179
 
 
180
        g_value_init (&value, G_TYPE_STRING);
 
181
        g_value_set_string_take_ownership (&value, tmp);
 
182
        entry_set_locked (RHYTHMDB (db), entry, propid, &value);
 
183
        g_value_unset (&value);
 
184
}
 
185
 
 
186
 
 
187
#define MAX_SONGS_LOADED_AT_ONCE 250
 
188
 
 
189
typedef struct  {
 
190
        RhythmDB *db;
 
191
        iPodParser *parser;
 
192
} RBiPodSongAdderCtxt;
 
193
 
 
194
 
 
195
static gboolean
 
196
load_ipod_db_idle_cb (RBiPodSongAdderCtxt *ctxt)
 
197
{
 
198
        RhythmDBTreeEntry *entry;
 
199
        int i;
 
200
 
 
201
        for (i = 0; i < MAX_SONGS_LOADED_AT_ONCE; i++) {
 
202
                gchar *pc_path;
 
203
                gchar *mount_path;
 
204
                iPodItem *item;
 
205
                iPodSong *song;
 
206
                
 
207
                item = ipod_get_next_item (ctxt->parser);
 
208
                if ((item == NULL) || (item->type != IPOD_ITEM_SONG)) {
 
209
                        ipod_item_destroy (item);
 
210
                        return FALSE;
 
211
                }
 
212
                song = (iPodSong *)item->data;
 
213
                                
 
214
                /* Set URI */
 
215
                mount_path = ipod_get_mount_path ();
 
216
                pc_path = itunesdb_get_track_name_on_ipod (mount_path, song);
 
217
                g_free (mount_path);
 
218
                rhythmdb_write_lock (RHYTHMDB (ctxt->db));
 
219
                entry = rhythmdb_entry_new (RHYTHMDB (ctxt->db), 
 
220
                                            RHYTHMDB_ENTRY_TYPE_IPOD,
 
221
                                            pc_path);
 
222
                rhythmdb_write_unlock (RHYTHMDB (ctxt->db));
 
223
                g_free (pc_path);
 
224
 
 
225
                /* Set track number */
 
226
                if (song->track_nr != 0) {
 
227
                        GValue value = {0, };
 
228
                        g_value_init (&value, G_TYPE_INT);
 
229
                        g_value_set_int (&value, song->track_nr);
 
230
                        entry_set_locked (RHYTHMDB (ctxt->db), entry, 
 
231
                                          RHYTHMDB_PROP_TRACK_NUMBER, 
 
232
                                          &value);
 
233
                        g_value_unset (&value);
 
234
                }
 
235
 
 
236
                /* Set disc number */
 
237
                if (song->cd_nr != 0) {
 
238
                        GValue value = {0, };
 
239
                        g_value_init (&value, G_TYPE_ULONG);
 
240
                        g_value_set_ulong (&value, song->cd_nr);
 
241
                        rhythmdb_entry_set (RHYTHMDB (ctxt->db), entry, 
 
242
                                            RHYTHMDB_PROP_DISC_NUMBER, 
 
243
                                            &value);
 
244
                        g_value_unset (&value);
 
245
                }
 
246
                
 
247
                /* Set bitrate */
 
248
                if (song->bitrate != 0) {
 
249
                        GValue value = {0, };
 
250
                        g_value_init (&value, G_TYPE_INT);
 
251
                        g_value_set_int (&value, song->bitrate);
 
252
                        entry_set_locked (RHYTHMDB (ctxt->db), entry, 
 
253
                                          RHYTHMDB_PROP_BITRATE, 
 
254
                                          &value);
 
255
                        g_value_unset (&value);
 
256
                }
 
257
                
 
258
                /* Set length */
 
259
                if (song->tracklen != 0) {
 
260
                        GValue value = {0, };
 
261
                        g_value_init (&value, G_TYPE_LONG);
 
262
                        g_value_set_long (&value, song->tracklen/1000);
 
263
                        entry_set_locked (RHYTHMDB (ctxt->db), entry, 
 
264
                                          RHYTHMDB_PROP_DURATION, 
 
265
                                          &value);
 
266
                        g_value_unset (&value);
 
267
                }
 
268
                
 
269
                /* Set file size */
 
270
                if (song->size != 0) {
 
271
                        GValue value = {0, };
 
272
                        g_value_init (&value, G_TYPE_UINT64);
 
273
                        g_value_set_uint64 (&value, song->size);
 
274
                        entry_set_locked (RHYTHMDB (ctxt->db), entry, 
 
275
                                          RHYTHMDB_PROP_FILE_SIZE, 
 
276
                                          &value);
 
277
                        g_value_unset (&value);
 
278
                }
 
279
                
 
280
                /* Set title */
 
281
                
 
282
                entry_set_string_prop (RHYTHMDB (ctxt->db), entry, 
 
283
                                       RHYTHMDB_PROP_TITLE, song->title);
 
284
                
 
285
                /* Set album, artist and genre from iTunesDB */
 
286
                entry_set_string_prop (RHYTHMDB (ctxt->db), entry, 
 
287
                                       RHYTHMDB_PROP_ARTIST, song->artist);
 
288
                
 
289
                entry_set_string_prop (RHYTHMDB (ctxt->db), entry, 
 
290
                                       RHYTHMDB_PROP_ALBUM, song->album);
 
291
                
 
292
                entry_set_string_prop (RHYTHMDB (ctxt->db), entry, 
 
293
                                       RHYTHMDB_PROP_GENRE, song->genre);
 
294
                
 
295
                ipod_item_destroy (item);
 
296
        }
 
297
        /* FIXME: item is leaked */
 
298
        return TRUE;
 
299
}
 
300
 
 
301
static void
 
302
context_free (gpointer data)
 
303
{
 
304
        RBiPodSongAdderCtxt *ctxt = (RBiPodSongAdderCtxt *)data;
 
305
        if (ctxt == NULL) {
 
306
                return;
 
307
        }
 
308
        if (ctxt->parser != NULL) {
 
309
                ipod_parser_destroy (ctxt->parser);
 
310
        }
 
311
        g_free (ctxt);
 
312
}
 
313
 
 
314
/* We need to be locked to use this function */
 
315
static GnomeVFSResult
 
316
add_ipod_songs_to_db (RhythmDB *db)
 
317
{
 
318
        char *path;
 
319
        iPodParser *parser;
 
320
        RBiPodSongAdderCtxt *ctxt;
 
321
 
 
322
        ctxt = g_new0 (RBiPodSongAdderCtxt, 1);
 
323
        if (ctxt == NULL) {
 
324
                return GNOME_VFS_ERROR_NO_MEMORY;
 
325
        }
 
326
 
 
327
        path = ipod_get_mount_path ();
 
328
        parser = ipod_parser_new (path);
 
329
        g_free (path);
 
330
 
 
331
        ctxt->db = db;
 
332
        ctxt->parser = parser;
 
333
 
 
334
        g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, 
 
335
                         (GSourceFunc)load_ipod_db_idle_cb,
 
336
                         ctxt, context_free);
 
337
 
 
338
        return GNOME_VFS_OK;
 
339
}
 
340
 
 
341
 
 
342
static void
 
343
ipod_load_songs (RhythmDB *rdb)
 
344
{
 
345
        GnomeVFSResult res;
 
346
 
 
347
        res = add_ipod_songs_to_db (rdb);
 
348
 
 
349
        if (res != GNOME_VFS_OK) {
 
350
                g_warning ("Error loading iPod database");
 
351
        }
 
352
}
 
353
 
 
354
static void
 
355
ipod_unload_songs (RhythmDB *db)
 
356
{
 
357
        rhythmdb_write_lock (db);
 
358
        rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_IPOD);
 
359
        rhythmdb_write_unlock (db);
 
360
}
 
361
 
 
362
static gboolean
 
363
ipod_itunesdb_monitor_cb (RBiPodSource *source)
 
364
{
 
365
        gboolean is_present;
 
366
        gchar *itunesdb_path;
 
367
        static gboolean was_present = FALSE;
 
368
 
 
369
        itunesdb_path = ipod_get_itunesdb_path ();
 
370
        g_assert (itunesdb_path != NULL);
 
371
        is_present = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
 
372
 
 
373
        if (is_present && !was_present) {
 
374
                RhythmDB *db;
 
375
 
 
376
                g_print ("iPod plugged\n");
 
377
                was_present = TRUE;
 
378
                g_object_get (G_OBJECT (source), "db", &db, NULL);
 
379
                ipod_load_songs (db);
 
380
                /* FIXME: should we suspend this monitor until the iPod 
 
381
                 * database has been read and fed to rhythmbox?
 
382
                 */
 
383
        } else if (!is_present && was_present) {
 
384
                RhythmDB *db;
 
385
 
 
386
                g_print ("iPod unplugged\n");
 
387
                was_present = FALSE;
 
388
                g_object_get (G_OBJECT (source), "db", &db, NULL);
 
389
                ipod_unload_songs (db);
 
390
        }
 
391
        g_free (itunesdb_path);
 
392
        return TRUE;
 
393
}
 
394
 
 
395
RhythmDBEntryType rhythmdb_entry_ipod_get_type (void) 
 
396
{
 
397
        static RhythmDBEntryType ipod_type = -1;
 
398
       
 
399
        if (ipod_type == -1) {
 
400
                ipod_type = rhythmdb_entry_register_type ();
 
401
        }
 
402
 
 
403
        return ipod_type;
 
404
}