229
233
case RHYTHMDB_TREE_PARSER_STATE_START:
231
if (!strcmp (name, "rhythmdb"))
235
if (!strcmp (name, "rhythmdb")) {
232
236
ctx->state = RHYTHMDB_TREE_PARSER_STATE_RHYTHMDB;
237
for (; *attrs; attrs +=2) {
238
if (!strcmp (*attrs, "version")) {
239
const char *version = *(attrs+1);
241
if (!strcmp (version, "1.0") || !strcmp (version, "1.1")) {
242
ctx->canonicalise_uris = TRUE;
243
rb_debug ("old version of rhythmdb, performing URI canonicalisation for all entries");
244
} else if (!strcmp (version, "1.2")) {
248
g_assert_not_reached ();
251
g_assert_not_reached ();
234
256
ctx->in_unknown_elt = TRUE;
237
261
case RHYTHMDB_TREE_PARSER_STATE_RHYTHMDB:
239
263
if (!strcmp (name, "entry")) {
240
RhythmDBEntryType type = -1;
264
RhythmDBEntryType type = RHYTHMDB_ENTRY_TYPE_INVALID;
241
265
gboolean type_set = FALSE;
242
266
for (; *attrs; attrs +=2) {
243
267
if (!strcmp (*attrs, "type")) {
244
268
const char *typename = *(attrs+1);
245
if (!strcmp (typename, "song"))
246
type = RHYTHMDB_ENTRY_TYPE_SONG;
247
else if (!strcmp (typename, "iradio"))
248
type = RHYTHMDB_ENTRY_TYPE_IRADIO_STATION;
249
else if (!strcmp (typename, "podcast-post"))
250
type = RHYTHMDB_ENTRY_TYPE_PODCAST_POST;
251
else if (!strcmp (typename, "podcast-feed"))
252
type = RHYTHMDB_ENTRY_TYPE_PODCAST_FEED;
269
type = rhythmdb_entry_type_get_by_name (typename);
322
328
rb_debug ("pre-Date entry found, causing re-read");
323
329
ctx->entry->mtime = 0;
325
if (ctx->entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED && ctx->entry->podcast->post_time == 0) {
331
if (ctx->entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
332
RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (ctx->entry, RhythmDBPodcastFields);
326
333
/* Handle upgrades from 0.9.2.
327
334
* Previously, last-seen for podcast feeds was the time of the last post,
328
335
* and post-time was unused. Now, we want last-seen to be the time we
329
336
* last updated the feed, and post-time to be the time of the last post.
331
ctx->entry->podcast->post_time = ctx->entry->last_seen;
338
if (podcast->post_time == 0) {
339
podcast->post_time = ctx->entry->last_seen;
334
343
if (ctx->entry->location != NULL) {
335
rhythmdb_tree_entry_new (RHYTHMDB (ctx->db), ctx->entry);
336
rhythmdb_entry_insert (RHYTHMDB (ctx->db), ctx->entry);
337
rhythmdb_commit (RHYTHMDB (ctx->db));
344
RhythmDBEntry *entry;
346
entry = g_hash_table_lookup (ctx->db->priv->entries, ctx->entry->location);
348
rhythmdb_tree_entry_new (RHYTHMDB (ctx->db), ctx->entry);
349
rhythmdb_entry_insert (RHYTHMDB (ctx->db), ctx->entry);
350
if (++ctx->batch_count == RHYTHMDB_QUERY_MODEL_SUGGESTED_UPDATE_CHUNK) {
351
rhythmdb_commit (RHYTHMDB (ctx->db));
352
ctx->batch_count = 0;
355
rb_debug ("found entry with duplicate location %s. merging metadata", ctx->entry->location);
356
entry->play_count += ctx->entry->play_count;
358
if (entry->rating < 0.01)
359
entry->rating = ctx->entry->rating;
360
else if (ctx->entry->rating > 0.01)
361
entry->rating = (entry->rating + ctx->entry->rating) / 2;
363
if (ctx->entry->last_played > entry->last_played)
364
entry->last_played = ctx->entry->last_played;
366
if (ctx->entry->first_seen < entry->first_seen)
367
entry->first_seen = ctx->entry->first_seen;
369
if (ctx->entry->last_seen > entry->last_seen)
370
entry->last_seen = ctx->entry->last_seen;
372
rhythmdb_entry_unref (RHYTHMDB (ctx->db), ctx->entry);
339
375
rb_debug ("found entry without location");
340
376
rhythmdb_entry_unref (RHYTHMDB (ctx->db), ctx->entry);
345
381
case RHYTHMDB_TREE_PARSER_STATE_ENTRY_PROPERTY:
347
/* Handle indexed properties. */
350
case RHYTHMDB_PROP_TYPE:
351
g_assert_not_reached ();
353
case RHYTHMDB_PROP_TITLE:
354
ctx->entry->title = rb_refstring_new (ctx->buf->str);
356
case RHYTHMDB_PROP_GENRE:
357
ctx->entry->genre = rb_refstring_new (ctx->buf->str);
359
case RHYTHMDB_PROP_ARTIST:
360
ctx->entry->artist = rb_refstring_new (ctx->buf->str);
362
case RHYTHMDB_PROP_ALBUM:
363
ctx->entry->album = rb_refstring_new (ctx->buf->str);
365
case RHYTHMDB_PROP_TRACK_NUMBER:
366
ctx->entry->tracknum = parse_ulong (ctx->buf->str);
368
case RHYTHMDB_PROP_DISC_NUMBER:
369
ctx->entry->discnum = parse_ulong (ctx->buf->str);
384
gboolean set = FALSE;
385
gboolean skip = FALSE;
387
/* special case some properties for upgrade handling etc. */
388
switch (ctx->propid) {
371
389
case RHYTHMDB_PROP_DATE:
373
gulong value = parse_ulong (ctx->buf->str);
376
ctx->entry->date = g_date_new_julian (value);
379
390
ctx->has_date = TRUE;
382
case RHYTHMDB_PROP_DURATION:
383
ctx->entry->duration = parse_ulong (ctx->buf->str);
385
case RHYTHMDB_PROP_FILE_SIZE:
386
ctx->entry->file_size = parse_ulong (ctx->buf->str);
388
392
case RHYTHMDB_PROP_LOCATION:
389
ctx->entry->location = g_strdup (ctx->buf->str);
393
if (ctx->canonicalise_uris) {
394
char *canon = rb_canonicalise_uri (ctx->buf->str);
396
g_value_init (&value, G_TYPE_STRING);
397
g_value_take_string (&value, canon);
391
401
case RHYTHMDB_PROP_MOUNTPOINT:
392
/* remove this from old podcast-post entries */
393
if (!g_str_has_prefix (ctx->buf->str, "http://"))
394
ctx->entry->mountpoint = rb_refstring_new (ctx->buf->str);
396
case RHYTHMDB_PROP_MTIME:
397
ctx->entry->mtime = parse_ulong (ctx->buf->str);
399
case RHYTHMDB_PROP_FIRST_SEEN:
400
ctx->entry->first_seen = parse_ulong (ctx->buf->str);
402
case RHYTHMDB_PROP_LAST_SEEN:
403
ctx->entry->last_seen = parse_ulong (ctx->buf->str);
405
case RHYTHMDB_PROP_RATING:
406
ctx->entry->rating = g_ascii_strtod (ctx->buf->str, NULL);
408
case RHYTHMDB_PROP_PLAY_COUNT:
409
ctx->entry->play_count = parse_ulong (ctx->buf->str);
411
case RHYTHMDB_PROP_LAST_PLAYED:
412
ctx->entry->last_played = parse_ulong (ctx->buf->str);
414
case RHYTHMDB_PROP_BITRATE:
415
ctx->entry->bitrate = parse_ulong (ctx->buf->str);
417
case RHYTHMDB_PROP_TRACK_GAIN:
418
ctx->entry->track_gain = g_ascii_strtod (ctx->buf->str, NULL);
420
case RHYTHMDB_PROP_TRACK_PEAK:
421
ctx->entry->track_peak = g_ascii_strtod (ctx->buf->str, NULL);
423
case RHYTHMDB_PROP_ALBUM_GAIN:
424
ctx->entry->album_gain = g_ascii_strtod (ctx->buf->str, NULL);
426
case RHYTHMDB_PROP_ALBUM_PEAK:
427
ctx->entry->album_peak = g_ascii_strtod (ctx->buf->str, NULL);
429
case RHYTHMDB_PROP_MIMETYPE:
430
ctx->entry->mimetype = rb_refstring_new (ctx->buf->str);
432
case RHYTHMDB_PROP_STATUS:
433
ctx->entry->podcast->status = parse_ulong (ctx->buf->str);
435
case RHYTHMDB_PROP_DESCRIPTION:
436
ctx->entry->podcast->description = rb_refstring_new (ctx->buf->str);
438
case RHYTHMDB_PROP_SUBTITLE:
439
ctx->entry->podcast->subtitle = rb_refstring_new (ctx->buf->str);
441
case RHYTHMDB_PROP_SUMMARY:
442
ctx->entry->podcast->summary = rb_refstring_new (ctx->buf->str);
444
case RHYTHMDB_PROP_LANG:
445
ctx->entry->podcast->lang = rb_refstring_new (ctx->buf->str);
447
case RHYTHMDB_PROP_COPYRIGHT:
448
ctx->entry->podcast->copyright = rb_refstring_new (ctx->buf->str);
450
case RHYTHMDB_PROP_IMAGE:
451
ctx->entry->podcast->image = rb_refstring_new (ctx->buf->str);
453
case RHYTHMDB_PROP_POST_TIME:
454
ctx->entry->podcast->post_time = parse_ulong (ctx->buf->str);
456
case RHYTHMDB_PROP_TITLE_SORT_KEY:
457
case RHYTHMDB_PROP_GENRE_SORT_KEY:
458
case RHYTHMDB_PROP_ARTIST_SORT_KEY:
459
case RHYTHMDB_PROP_ALBUM_SORT_KEY:
460
case RHYTHMDB_PROP_TITLE_FOLDED:
461
case RHYTHMDB_PROP_GENRE_FOLDED:
462
case RHYTHMDB_PROP_ARTIST_FOLDED:
463
case RHYTHMDB_PROP_ALBUM_FOLDED:
464
case RHYTHMDB_PROP_LAST_PLAYED_STR:
465
case RHYTHMDB_PROP_HIDDEN:
466
case RHYTHMDB_PROP_PLAYBACK_ERROR:
467
case RHYTHMDB_PROP_FIRST_SEEN_STR:
468
case RHYTHMDB_PROP_SEARCH_MATCH:
469
case RHYTHMDB_NUM_PROPERTIES:
470
g_assert_not_reached ();
474
rhythmdb_entry_sync_mirrored (RHYTHMDB (ctx->db), ctx->entry, ctx->propid);
402
/* fix old podcast posts */
403
if (g_str_has_prefix (ctx->buf->str, "http://"))
412
rhythmdb_read_encoded_property (RHYTHMDB (ctx->db), ctx->buf->str, ctx->propid, &value);
415
rhythmdb_entry_set_internal (RHYTHMDB (ctx->db), ctx->entry, FALSE, ctx->propid, &value);
416
g_value_unset (&value);
476
419
ctx->state = RHYTHMDB_TREE_PARSER_STATE_ENTRY;
775
736
case RHYTHMDB_PROP_LAST_PLAYED:
776
737
save_entry_ulong (ctx, elt_name, entry->last_played, FALSE);
739
case RHYTHMDB_PROP_HIDDEN:
741
gboolean hidden = ((entry->flags & RHYTHMDB_ENTRY_HIDDEN) != 0);
742
save_entry_boolean (ctx, elt_name, hidden);
778
745
case RHYTHMDB_PROP_STATUS:
780
save_entry_ulong (ctx, elt_name, entry->podcast->status, FALSE);
747
save_entry_ulong (ctx, elt_name, podcast->status, FALSE);
782
749
case RHYTHMDB_PROP_DESCRIPTION:
783
if (entry->podcast && entry->podcast->description)
784
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->description));
750
if (podcast && podcast->description)
751
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->description));
786
753
case RHYTHMDB_PROP_SUBTITLE:
787
if (entry->podcast && entry->podcast->subtitle)
788
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->subtitle));
754
if (podcast && podcast->subtitle)
755
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->subtitle));
790
757
case RHYTHMDB_PROP_SUMMARY:
791
if (entry->podcast && entry->podcast->summary)
792
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->summary));
758
if (podcast && podcast->summary)
759
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->summary));
794
761
case RHYTHMDB_PROP_LANG:
795
if (entry->podcast && entry->podcast->lang)
796
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->lang));
762
if (podcast && podcast->lang)
763
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->lang));
798
765
case RHYTHMDB_PROP_COPYRIGHT:
799
if (entry->podcast && entry->podcast->copyright)
800
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->copyright));
766
if (podcast && podcast->copyright)
767
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->copyright));
802
769
case RHYTHMDB_PROP_IMAGE:
803
if (entry->podcast && entry->podcast->image)
804
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->image));
770
if (podcast && podcast->image)
771
save_entry_string(ctx, elt_name, rb_refstring_get (podcast->image));
806
773
case RHYTHMDB_PROP_POST_TIME:
808
save_entry_ulong (ctx, elt_name, entry->podcast->post_time, FALSE);
775
save_entry_ulong (ctx, elt_name, podcast->post_time, FALSE);
810
777
case RHYTHMDB_PROP_TITLE_SORT_KEY:
811
778
case RHYTHMDB_PROP_GENRE_SORT_KEY:
854
822
ctx.error = NULL;
855
823
RHYTHMDB_FWRITE_STATICSTR ("<?xml version=\"1.0\" standalone=\"yes\"?>\n"
856
"<rhythmdb version=\"" RHYTHMDB_TREE_XML_VERSION "\">",
824
"<rhythmdb version=\"" RHYTHMDB_TREE_XML_VERSION "\">\n",
857
825
ctx.handle, ctx.error);
859
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_SONG,
860
(RBTreeEntryItFunc)save_entry,
861
NULL, NULL, NULL, &ctx);
862
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_IRADIO_STATION,
863
(RBTreeEntryItFunc)save_entry,
864
NULL, NULL, NULL, &ctx);
865
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
866
(RBTreeEntryItFunc)save_entry,
867
NULL, NULL, NULL, &ctx);
868
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED,
869
(RBTreeEntryItFunc)save_entry,
827
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_SONG,
828
(RBTreeEntryItFunc)save_entry,
829
NULL, NULL, NULL, &ctx);
830
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_IRADIO_STATION,
831
(RBTreeEntryItFunc)save_entry,
832
NULL, NULL, NULL, &ctx);
833
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
834
(RBTreeEntryItFunc)save_entry,
835
NULL, NULL, NULL, &ctx);
836
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED,
837
(RBTreeEntryItFunc)save_entry,
838
NULL, NULL, NULL, &ctx);
839
rhythmdb_hash_tree_foreach (rdb, RHYTHMDB_ENTRY_TYPE_IGNORE,
840
(RBTreeEntryItFunc)save_entry,
870
841
NULL, NULL, NULL, &ctx);
872
843
RHYTHMDB_FWRITE_STATICSTR ("</rhythmdb>\n", ctx.handle, ctx.error);
1440
1428
relative_time = g_value_get_ulong (data->val);
1441
1429
g_get_current_time (¤t_time);
1443
if (data->type == RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN)
1444
return (rhythmdb_entry_get_ulong (entry, data->propid) >= (current_time.tv_sec - relative_time));
1446
return (rhythmdb_entry_get_ulong (entry, data->propid) < (current_time.tv_sec - relative_time));
1431
if (data->type == RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN) {
1432
if (!(rhythmdb_entry_get_ulong (entry, data->propid) >= (current_time.tv_sec - relative_time)))
1435
if (!(rhythmdb_entry_get_ulong (entry, data->propid) < (current_time.tv_sec - relative_time)))
1440
case RHYTHMDB_QUERY_PROP_PREFIX:
1441
case RHYTHMDB_QUERY_PROP_SUFFIX:
1443
const char *value_s;
1444
const char *entry_s;
1446
g_assert (rhythmdb_get_property_type (db, data->propid) == G_TYPE_STRING);
1448
value_s = g_value_get_string (data->val);
1449
entry_s = rhythmdb_entry_get_string (entry, data->propid);
1451
if (data->type == RHYTHMDB_QUERY_PROP_PREFIX && !g_str_has_prefix (entry_s, value_s))
1453
if (data->type == RHYTHMDB_QUERY_PROP_SUFFIX && !g_str_has_suffix (entry_s, value_s))
1450
1458
case RHYTHMDB_QUERY_PROP_LIKE: