summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJorg Schuler <jcsjcs@users.sourceforge.net>2007-03-23 11:58:04 +0000
committerJorg Schuler <jcsjcs@users.sourceforge.net>2007-03-23 11:58:04 +0000
commit981d62180356fe0393c49564db37e8e6551da349 (patch)
tree121729837c9480a3f9f83271e68318664ec8cce0
parent381a8506b44322399e05452f88d1ef3ae9f0b58f (diff)
downloadlibgpod-981d62180356fe0393c49564db37e8e6551da349.tar.gz
libgpod-981d62180356fe0393c49564db37e8e6551da349.tar.xz
libgpod-981d62180356fe0393c49564db37e8e6551da349.zip
* src/itdb_itunesdb.c: Write out MHOD52 hunks after master
playlist. This speeds up the iPod interface when browsing titles or albums etc. because the iPod won't have to sort through the track list. git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1408 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r--ChangeLog7
-rw-r--r--src/itdb_itunesdb.c266
2 files changed, 266 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 83c08c7..a355850 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2007-03-23 Jorg Schuler <jcsjcs at users.sourceforge.net>
+
+ * src/itdb_itunesdb.c: Write out MHOD52 hunks after master
+ playlist. This speeds up the iPod interface when browsing titles
+ or albums etc. because the iPod won't have to sort through the
+ track list.
+
2007-03-22 Jorg Schuler <jcsjcs at users.sourceforge.net>
* src/itdb_itunesdb.c (write_playlist): corrected what is written
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index d08644e..e0b2c0c 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -1,4 +1,4 @@
-/* Time-stamp: <2007-03-22 22:53:36 jcs>
+/* Time-stamp: <2007-03-23 20:49:29 jcs>
|
| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net>
| Part of the gtkpod project.
@@ -220,6 +220,32 @@ enum MHOD_ID {
};
+/* Used as first iPod ID when renumbering (re-assigning) the iPod
+ (track) IDs before writing out the iTunesDB. */
+static const gint FIRST_IPOD_ID=52;
+
+
+enum MHOD52_SORTTYPE {
+ MHOD52_SORTTYPE_TITLE = 0x03,
+ MHOD52_SORTTYPE_ALBUM = 0x04,
+ MHOD52_SORTTYPE_ARTIST = 0x05,
+ MHOD52_SORTTYPE_GENRE = 0x07,
+ MHOD52_SORTTYPE_COMPOSER = 0x12
+};
+
+struct mhod52track
+{
+ gchar *album;
+ gchar *title;
+ gchar *artist;
+ gchar *genre;
+ gchar *composer;
+ gint track_nr;
+ gint cd_nr;
+ gint index;
+ gint numtracks;
+};
+
struct _MHODData
{
gboolean valid;
@@ -232,7 +258,12 @@ struct _MHODData
Itdb_Track *chapterdata_track; /* for writing chapterdata */
SPLPref *splpref;
SPLRules *splrules;
+ GList *mhod52info;
} data;
+ union
+ {
+ enum MHOD52_SORTTYPE mhod52sorttype;
+ } data2;
};
typedef struct _MHODData MHODData;
@@ -3667,7 +3698,29 @@ static void mk_mhod (WContents *cts, MHODData *mhod)
}
break;
case MHOD_ID_LIBPLAYLISTINDEX:
- g_warning (_("Cannot write mhod of type %d\n"), mhod->type);
+ g_return_if_fail (mhod->data.mhod52info);
+ g_return_if_fail (mhod->data.mhod52info->data);
+ {
+ struct mhod52track *ct = mhod->data.mhod52info->data;
+ gint numtracks = ct->numtracks;
+ GList *gl;
+
+ put_header (cts, "mhod"); /* header */
+ put32lint (cts, 24); /* size of header */
+ put32lint (cts, 4*numtracks+72); /* size of header + body */
+ put32lint (cts, mhod->type); /* type of the mhod */
+ put32_n0 (cts, 2); /* unknown */
+ /* end of header, start of data */
+ put32lint (cts, mhod->data2.mhod52sorttype); /* sort type */
+ put32lint (cts, numtracks); /* number of entries */
+ put32_n0 (cts, 10); /* unknown */
+ for (gl=mhod->data.mhod52info; gl; gl=gl->next)
+ {
+ ct = gl->data;
+ g_return_if_fail (ct);
+ put32lint (cts, ct->index);
+ }
+ }
break;
}
}
@@ -4118,6 +4171,182 @@ static gboolean write_podcast_mhips (FExport *fexp,
}
+static gint mhod52_sort_title (const struct mhod52track *a, const struct mhod52track *b)
+{
+ return strcmp (a->title, b->title);
+}
+
+
+static gint mhod52_sort_album (const struct mhod52track *a, const struct mhod52track *b)
+{
+ gint result;
+
+ result = strcmp (a->album, b->album);
+ if (result == 0)
+ result = a->cd_nr - b->cd_nr;
+ if (result == 0)
+ result = a->track_nr - b->track_nr;
+ if (result == 0)
+ result = strcmp (a->title, b->title);
+ return result;
+}
+
+static gint mhod52_sort_artist (struct mhod52track *a, struct mhod52track *b)
+{
+ gint result;
+
+ result = strcmp (a->artist, b->artist);
+ if (result == 0)
+ result = strcmp (a->album, b->album);
+ if (result == 0)
+ result = a->cd_nr - b->cd_nr;
+ if (result == 0)
+ result = a->track_nr - b->track_nr;
+ if (result == 0)
+ result = strcmp (a->title, b->title);
+ return result;
+}
+
+static gint mhod52_sort_genre (struct mhod52track *a, struct mhod52track *b)
+{
+ gint result;
+
+ result = strcmp (a->genre, b->genre);
+ if (result == 0)
+ result = strcmp (a->artist, b->artist);
+ if (result == 0)
+ result = strcmp (a->album, b->album);
+ if (result == 0)
+ result = a->cd_nr - b->cd_nr;
+ if (result == 0)
+ result = a->track_nr - b->track_nr;
+ if (result == 0)
+ result = strcmp (a->title, b->title);
+ return result;
+}
+
+static gint mhod52_sort_composer (struct mhod52track *a, struct mhod52track *b)
+{
+ gint result;
+
+ result = strcmp (a->composer, b->composer);
+ if (result == 0)
+ result = strcmp (a->title, b->title);
+ return result;
+}
+
+
+/* Create a new list containing all tracks but with collate keys
+ instead of the actual strings (title, artist, album, genre,
+ composer) */
+static GList *mhod52_make_collate_keys (GList *tracks)
+{
+ gint numtracks = g_list_length (tracks);
+ GList *gl, *coltracks = NULL;
+ gint index=0;
+
+ for (gl=tracks; gl; gl=gl->next)
+ {
+ struct mhod52track *ct;
+ Itdb_Track *tr = gl->data;
+ g_return_val_if_fail (tr, NULL);
+
+ ct = g_new0 (struct mhod52track, 1);
+ coltracks = g_list_prepend (coltracks, ct);
+
+ if (tr->album)
+ ct->album = g_utf8_collate_key (tr->album, -1);
+ else
+ ct->album = g_strdup ("");
+ if (tr->title)
+ ct->title = g_utf8_collate_key (tr->title, -1);
+ else
+ ct->title = g_strdup ("");
+ if (tr->artist)
+ ct->artist = g_utf8_collate_key (tr->artist, -1);
+ else
+ ct->artist = g_strdup ("");
+ if (tr->genre)
+ ct->genre = g_utf8_collate_key (tr->genre, -1);
+ else
+ ct->genre = g_strdup ("");
+ if (tr->composer)
+ ct->composer = g_utf8_collate_key (tr->composer, -1);
+ else
+ ct->composer = g_strdup ("");
+ ct->track_nr = tr->track_nr;
+ ct->cd_nr = tr->cd_nr;
+ ct->numtracks = numtracks;
+ ct->index = index++;
+ }
+ return coltracks;
+}
+
+
+/* Free all memory used up by the collate keys */
+static void mhod52_free_collate_keys (GList *coltracks)
+{
+ GList *gl;
+
+ for (gl=coltracks; gl; gl=gl->next)
+ {
+ struct mhod52track *ct = gl->data;
+ g_return_if_fail (ct);
+ g_free (ct->album);
+ g_free (ct->title);
+ g_free (ct->artist);
+ g_free (ct->genre);
+ g_free (ct->composer);
+ g_free (ct);
+ }
+ g_list_free (coltracks);
+}
+
+
+/* Write a MHOD52 containing a sorted list of all tracks. Will change
+ the order of @coltracks and return the new list! */
+static GList *mk_mhod52 (WContents *cts, GList *coltracks,
+ enum MHOD52_SORTTYPE sorttype)
+{
+ MHODData mhod;
+
+ gpointer compfunc = NULL;
+
+ g_return_val_if_fail (cts, coltracks);
+
+ switch (sorttype)
+ {
+ case MHOD52_SORTTYPE_TITLE:
+ compfunc = mhod52_sort_title;
+ break;
+ case MHOD52_SORTTYPE_ALBUM:
+ compfunc = mhod52_sort_album;
+ break;
+ case MHOD52_SORTTYPE_ARTIST:
+ compfunc = mhod52_sort_artist;
+ break;
+ case MHOD52_SORTTYPE_GENRE:
+ compfunc = mhod52_sort_genre;
+ break;
+ case MHOD52_SORTTYPE_COMPOSER:
+ compfunc = mhod52_sort_composer;
+ break;
+ }
+ g_return_val_if_fail (compfunc, coltracks);
+
+ /* sort the tracks */
+ coltracks = g_list_sort (coltracks, compfunc);
+
+ /* Write the mhod52 */
+ mhod.valid = TRUE;
+ mhod.type = MHOD_ID_LIBPLAYLISTINDEX;
+ mhod.data.mhod52info = coltracks;
+ mhod.data2.mhod52sorttype = sorttype;
+ mk_mhod (cts, &mhod);
+
+ return coltracks;
+}
+
/* corresponds to mk_mhyp */
/* mhsd_type: 2: write normal playlists
@@ -4130,6 +4359,7 @@ static gboolean write_playlist (FExport *fexp,
WContents *cts;
gboolean result = TRUE;
MHODData mhod;
+ gint mhodnum;
g_return_val_if_fail (fexp, FALSE);
g_return_val_if_fail (fexp->itdb, FALSE);
@@ -4146,10 +4376,19 @@ static gboolean write_playlist (FExport *fexp,
put_header (cts, "mhyp"); /* header */
put32lint (cts, 108); /* length */
put32lint (cts, -1); /* size -> later */
+ mhodnum = 2;
if (pl->is_spl)
- put32lint (cts, 4); /* nr of mhods */
+ { /* 2 more SPL MHODs */
+ mhodnum += 2;
+ }
else
- put32lint (cts, 2); /* nr of mhods */
+ {
+ if ((pl->type == ITDB_PL_TYPE_MPL) && pl->members)
+ { /* 5 more MHOD 52 lists */
+ mhodnum += 5;
+ }
+ }
+ put32lint (cts, mhodnum); /* nr of mhods */
/* number of tracks in plist */
put32lint (cts, -1); /* number of mhips -> later */
put8int (cts, pl->type); /* 1 = main, 0 = visible */
@@ -4170,7 +4409,20 @@ static gboolean write_playlist (FExport *fexp,
mk_mhod (cts, &mhod);
mk_long_mhod_id_playlist (fexp, pl);
- if (pl->is_spl)
+ if ((pl->type == ITDB_PL_TYPE_MPL) && pl->members)
+ { /* write out the MHOD 52 lists */
+ /* We have to sort all tracks five times. To speed this up,
+ translate the utf8 keys into collate_keys and use the
+ faster strcmp() for comparison */
+ GList *coltracks = mhod52_make_collate_keys (pl->members);
+ coltracks = mk_mhod52 (cts, coltracks, MHOD52_SORTTYPE_TITLE);
+ coltracks = mk_mhod52 (cts, coltracks, MHOD52_SORTTYPE_ALBUM);
+ coltracks = mk_mhod52 (cts, coltracks, MHOD52_SORTTYPE_ARTIST);
+ coltracks = mk_mhod52 (cts, coltracks, MHOD52_SORTTYPE_GENRE);
+ coltracks = mk_mhod52 (cts, coltracks, MHOD52_SORTTYPE_COMPOSER);
+ mhod52_free_collate_keys (coltracks);
+ }
+ else if (pl->is_spl)
{ /* write the smart rules */
mhod.type = MHOD_ID_SPLPREF;
mhod.data.splpref = &pl->splpref;
@@ -4213,7 +4465,7 @@ static gboolean write_mhsd_playlists (FExport *fexp, guint32 mhsd_type)
mk_mhsd (fexp, mhsd_type); /* write header */
/* write header with nr. of playlists */
mk_mhlp (fexp);
- for(gl=fexp->itdb->playlists; gl; gl=gl->next)
+ for (gl=fexp->itdb->playlists; gl; gl=gl->next)
{
Itdb_Playlist *pl = gl->data;
g_return_val_if_fail (pl, FALSE);
@@ -4330,7 +4582,7 @@ static void reassign_ids (FExport *fexp)
itdb->tracks = g_list_prepend (itdb->tracks, track);
}
- fexp->next_id = 52;
+ fexp->next_id = FIRST_IPOD_ID;
/* assign unique IDs */
for (gl=itdb->tracks; gl; gl=gl->next)