No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2010 Jonathan Matthew <jonathan@d14n.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * The Rhythmbox authors hereby grant permission for non-GPL compatible
11 * GStreamer plugins to be used and distributed together with GStreamer
12 * and Rhythmbox. This permission is above and beyond the permissions granted
13 * by the GPL license by which Rhythmbox is covered. If you modify this code
14 * you may extend this exception to your version of the code, but you are not
15 * obligated to do so. If you do not wish to do so, delete this exception
16 * statement from your version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
29 #include "config.h"
30
31 #include "rhythmdb-entry-type.h"
32 #include "rhythmdb-private.h"
33 #include "rb-util.h"
34 #include "rb-debug.h"
35
36 static RhythmDBEntryType *song_entry_type = NULL;
37 static RhythmDBEntryType *error_entry_type = NULL;
38 static RhythmDBEntryType *ignore_entry_type = NULL;
39
40
41 typedef struct _RhythmDBEntryType RhythmDBSongEntryType;
42 typedef struct _RhythmDBEntryTypeClass RhythmDBSongEntryTypeClass;
43
44 static void rhythmdb_song_entry_type_class_init (RhythmDBSongEntryTypeClass *klass);
45 static void rhythmdb_song_entry_type_init (RhythmDBSongEntryType *etype);
46 GType rhythmdb_song_entry_type_get_type (void);
47 G_DEFINE_TYPE (RhythmDBSongEntryType, rhythmdb_song_entry_type, RHYTHMDB_TYPE_ENTRY_TYPE);
48
49
50 typedef struct _RhythmDBEntryType RhythmDBErrorEntryType;
51 typedef struct _RhythmDBEntryTypeClass RhythmDBErrorEntryTypeClass;
52
53 static void rhythmdb_error_entry_type_class_init (RhythmDBErrorEntryTypeClass *klass);
54 static void rhythmdb_error_entry_type_init (RhythmDBErrorEntryType *etype);
55 GType rhythmdb_error_entry_type_get_type (void);
56 G_DEFINE_TYPE (RhythmDBErrorEntryType, rhythmdb_error_entry_type, RHYTHMDB_TYPE_ENTRY_TYPE);
57
58
59 typedef struct _RhythmDBEntryType RhythmDBIgnoreEntryType;
60 typedef struct _RhythmDBEntryTypeClass RhythmDBIgnoreEntryTypeClass;
61
62 static void rhythmdb_ignore_entry_type_class_init (RhythmDBIgnoreEntryTypeClass *klass);
63 static void rhythmdb_ignore_entry_type_init (RhythmDBIgnoreEntryType *etype);
64 GType rhythmdb_ignore_entry_type_get_type (void);
65 G_DEFINE_TYPE (RhythmDBIgnoreEntryType, rhythmdb_ignore_entry_type, RHYTHMDB_TYPE_ENTRY_TYPE);
66
67 static void
68 update_entry_last_seen (RhythmDB *db, RhythmDBEntry *entry)
69 {
70 GTimeVal time;
71 GValue val = {0, };
72
73 g_get_current_time (&time);
74 g_value_init (&val, G_TYPE_ULONG);
75 g_value_set_ulong (&val, time.tv_sec);
76 rhythmdb_entry_set_internal (db, entry, FALSE, RHYTHMDB_PROP_LAST_SEEN, &val);
77 g_value_unset (&val);
78 }
79
80 static gboolean
81 check_entry_grace_period (RhythmDB *db, RhythmDBEntry *entry)
82 {
83 GTimeVal time;
84 gulong last_seen;
85 gulong grace_period;
86 GError *error;
87
88 error = NULL;
89 grace_period = g_settings_get_int (db->priv->settings, "grace-period");
90 if (error != NULL) {
91 g_error_free (error);
92 return FALSE;
93 }
94
95 /* This is a bit silly, but I prefer to make sure we won't
96 * overflow in the following calculations
97 */
98 if ((grace_period <= 0) || (grace_period > 20000)) {
99 return FALSE;
100 }
101
102 /* Convert from days to seconds */
103 grace_period = grace_period * 60 * 60 * 24;
104 g_get_current_time (&time);
105 last_seen = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_LAST_SEEN);
106
107 return (last_seen + grace_period < time.tv_sec);
108 }
109
110 static void
111 song_sync_metadata (RhythmDBEntryType *entry_type,
112 RhythmDBEntry *entry,
113 GSList *changes,
114 GError **error)
115 {
116 RhythmDB *db;
117
118 g_object_get (entry_type, "db", &db, NULL);
119 rhythmdb_entry_write_metadata_changes (db, entry, changes, error);
120 g_object_unref (db);
121 }
122
123
124 static gboolean
125 song_can_sync_metadata (RhythmDBEntryType *entry_type,
126 RhythmDBEntry *entry)
127 {
128 const char *media_type;
129 gboolean can_sync;
130 RhythmDB *db;
131
132 g_object_get (entry_type, "db", &db, NULL);
133
134 media_type = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MEDIA_TYPE);
135 can_sync = rb_metadata_can_save (db->priv->metadata, media_type);
136
137 g_object_unref (db);
138 return can_sync;
139 }
140
141 static void
142 song_update_availability (RhythmDBEntryType *entry_type,
143 RhythmDBEntry *entry,
144 RhythmDBEntryAvailability avail)
145 {
146 RhythmDB *db;
147
148 g_object_get (entry_type, "db", &db, NULL);
149 switch (avail) {
150 case RHYTHMDB_ENTRY_AVAIL_MOUNTED:
151 rhythmdb_entry_set_visibility (db, entry, TRUE);
152 break;
153
154 case RHYTHMDB_ENTRY_AVAIL_CHECKED:
155 update_entry_last_seen (db, entry);
156 rhythmdb_entry_set_visibility (db, entry, TRUE);
157 break;
158
159 case RHYTHMDB_ENTRY_AVAIL_UNMOUNTED:
160 /* update the last-seen time if the entry is currently visible */
161 if (rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN) == FALSE) {
162 update_entry_last_seen (db, entry);
163 }
164 rhythmdb_entry_set_visibility (db, entry, FALSE);
165 break;
166
167 case RHYTHMDB_ENTRY_AVAIL_NOT_FOUND:
168 if (check_entry_grace_period (db, entry)) {
169 rb_debug ("deleting entry %s; not seen for too long",
170 rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
171 rhythmdb_entry_delete (db, entry);
172 } else {
173 rhythmdb_entry_set_visibility (db, entry, FALSE);
174 }
175 break;
176
177 default:
178 g_assert_not_reached ();
179 }
180 g_object_unref (db);
181 }
182
183 static void
184 import_error_update_availability (RhythmDBEntryType *entry_type,
185 RhythmDBEntry *entry,
186 RhythmDBEntryAvailability avail)
187 {
188 RhythmDB *db;
189
190 switch (avail) {
191 case RHYTHMDB_ENTRY_AVAIL_MOUNTED:
192 case RHYTHMDB_ENTRY_AVAIL_CHECKED:
193 /* do nothing; should never happen anyway */
194 break;
195 case RHYTHMDB_ENTRY_AVAIL_UNMOUNTED:
196 case RHYTHMDB_ENTRY_AVAIL_NOT_FOUND:
197 /* no need to keep error entries if the file is unavailable */
198 g_object_get (entry_type, "db", &db, NULL);
199 rhythmdb_entry_delete (db, entry);
200 g_object_unref (db);
201 break;
202
203 default:
204 g_assert_not_reached ();
205 }
206 }
207
208
209 /**
210 * rhythmdb_get_song_entry_type:
211 *
212 * Returns the #RhythmDBEntryType for normal songs.
213 *
214 * Returns: (transfer none): the entry type for normal songs
215 */
216 RhythmDBEntryType *
217 rhythmdb_get_song_entry_type (void)
218 {
219 return song_entry_type;
220 }
221
222 /**
223 * rhythmdb_get_ignore_entry_type:
224 *
225 * Returns the #RhythmDBEntryType for ignored files
226 *
227 * Return value: (transfer none): the entry type for ignored files
228 */
229 RhythmDBEntryType *
230 rhythmdb_get_ignore_entry_type (void)
231 {
232 return ignore_entry_type;
233 }
234
235 /**
236 * rhythmdb_get_error_entry_type:
237 *
238 * Returns the #RhythmDBEntryType for import errors
239 *
240 * Return value: (transfer none): the entry type for import errors
241 */
242 RhythmDBEntryType *
243 rhythmdb_get_error_entry_type (void)
244 {
245 return error_entry_type;
246 }
247
248
249 static void
250 rhythmdb_song_entry_type_class_init (RhythmDBSongEntryTypeClass *klass)
251 {
252 RhythmDBEntryTypeClass *etype_class = RHYTHMDB_ENTRY_TYPE_CLASS (klass);
253
254 etype_class->can_sync_metadata = song_can_sync_metadata;
255 etype_class->sync_metadata = song_sync_metadata;
256 etype_class->update_availability = song_update_availability;
257 }
258
259 static void
260 rhythmdb_song_entry_type_init (RhythmDBSongEntryType *etype)
261 {
262 }
263
264 static void
265 rhythmdb_error_entry_type_class_init (RhythmDBErrorEntryTypeClass *klass)
266 {
267 RhythmDBEntryTypeClass *etype_class = RHYTHMDB_ENTRY_TYPE_CLASS (klass);
268
269 etype_class->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
270 etype_class->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
271 etype_class->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
272 etype_class->update_availability = import_error_update_availability;
273 }
274
275 static void
276 rhythmdb_error_entry_type_init (RhythmDBErrorEntryType *etype)
277 {
278 }
279
280 static void
281 rhythmdb_ignore_entry_type_class_init (RhythmDBIgnoreEntryTypeClass *klass)
282 {
283 RhythmDBEntryTypeClass *etype_class = RHYTHMDB_ENTRY_TYPE_CLASS (klass);
284
285 etype_class->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
286 etype_class->update_availability = song_update_availability;
287 }
288
289 static void
290 rhythmdb_ignore_entry_type_init (RhythmDBIgnoreEntryType *etype)
291 {
292 }
293
294
295 void
296 rhythmdb_register_song_entry_types (RhythmDB *db)
297 {
298 g_assert (song_entry_type == NULL);
299 g_assert (error_entry_type == NULL);
300 g_assert (ignore_entry_type == NULL);
301
302 song_entry_type = g_object_new (rhythmdb_song_entry_type_get_type (),
303 "db", db,
304 "name", "song",
305 "save-to-disk", TRUE,
306 "has-playlists", TRUE,
307 NULL);
308
309 ignore_entry_type = g_object_new (rhythmdb_ignore_entry_type_get_type (),
310 "db", db,
311 "name", "ignore",
312 "save-to-disk", TRUE,
313 "category", RHYTHMDB_ENTRY_VIRTUAL,
314 NULL);
315
316 error_entry_type = g_object_new (rhythmdb_error_entry_type_get_type (),
317 "db", db,
318 "name", "import-error",
319 "category", RHYTHMDB_ENTRY_VIRTUAL,
320 NULL);
321
322 rhythmdb_register_entry_type (db, song_entry_type);
323 rhythmdb_register_entry_type (db, error_entry_type);
324 rhythmdb_register_entry_type (db, ignore_entry_type);
325 }