Revision: 2232
http://gtkpod.svn.sourceforge.net/gtkpod/?rev=2232&view=rev
Author: teuf
Date: 2009-01-20 21:40:19 +0000 (Tue, 20 Jan 2009)
Log Message:
-----------
Write album IDs and MHLAs to the database
Recent iTunes write a mhsd type 4 containing the list of all albums, this
commit adds an album id member to Itdb_Track and adds the code to generate
that ID and to write mhla/mhia headers to the itunesdb. Not sure what the
ipod uses that information for, but hopefully this will help to write
iTunesDB that the iphone likes, or to improve responsiveness of the album
list when artwork is involved.
Modified Paths:
--------------
libgpod/trunk/ChangeLog
libgpod/trunk/src/itdb_itunesdb.c
libgpod/trunk/src/itdb_private.h
Modified: libgpod/trunk/ChangeLog
===================================================================
--- libgpod/trunk/ChangeLog 2009-01-20 21:39:56 UTC (rev 2231)
+++ libgpod/trunk/ChangeLog 2009-01-20 21:40:19 UTC (rev 2232)
@@ -1,5 +1,11 @@
2009-01-20 Christophe Fergeau <teuf at gnome.org>
+ * src/itdb_itunesdb.c: generate list of albums and write it in a
+ MHLA header in the iTunesDB
+ * src/itdb_private.h: store album list in FExport
+
+2009-01-20 Christophe Fergeau <teuf at gnome.org>
+
* src/itdb_itunesdb.c: add new enum value for MHOD types found as
children of the MHLA header (list of albums)
Modified: libgpod/trunk/src/itdb_itunesdb.c
===================================================================
--- libgpod/trunk/src/itdb_itunesdb.c 2009-01-20 21:39:56 UTC (rev 2231)
+++ libgpod/trunk/src/itdb_itunesdb.c 2009-01-20 21:40:19 UTC (rev 2232)
@@ -3651,7 +3651,9 @@
put32lint (cts, track->unk252);
put16lint (cts, track->gapless_track_flag);
put16lint (cts, track->gapless_album_flag);
- put32_n0 (cts, 23);
+ put32_n0 (cts, 22);
+ put16lint (cts, 0);
+ put16lint (cts, track->album_id);
put32lint (cts, track->mhii_link); /* Needed on fat nanos/ipod classic to
get art
* in the right sidepane (mhii_link) */
put32_n0 (cts, 8); /* padding */
@@ -4350,7 +4352,90 @@
}
}
+static void mk_mhia (gpointer key, gpointer value, gpointer user_data)
+{
+ FExport *fexp;
+ WContents *cts;
+ Itdb_Track *track;
+ MHODData mhod;
+ guint mhod_num;
+ gulong mhia_seek;
+ track = (Itdb_Track *)key;
+ g_return_if_fail (track != NULL);
+
+ fexp = (FExport *)user_data;
+ g_return_if_fail (fexp);
+ g_return_if_fail (fexp->wcontents);
+ cts = fexp->wcontents;
+ mhia_seek = cts->pos;
+
+ put_header (cts, "mhia"); /* header */
+ put32lint (cts, 92); /* size of header */
+ put32lint (cts, -1); /* total size -> later */
+ put32lint (cts, 2); /* number of children mhods */
+ put16lint (cts, 0); /* unknown */
+ put16lint (cts, GPOINTER_TO_UINT (value)); /* album id */
+ put32lint (cts, 0); /* unknown */
+ put32lint (cts, 0); /* unknown */
+ put32lint (cts, 2); /* unknown */
+ put32_n0 (cts, 15); /* padding */
+
+ mhod.valid = TRUE;
+ mhod_num = 0;
+ if (track->album && *track->album) {
+ mhod.type = MHOD_ID_ALBUM_ALBUM;
+ mhod.data.string = track->album;
+ mk_mhod (fexp, &mhod);
+ ++mhod_num;
+ }
+
+ if (track->albumartist && *track->albumartist) {
+ mhod.type = MHOD_ID_ALBUM_ARTIST;
+ mhod.data.string = track->albumartist;
+ mk_mhod (fexp, &mhod);
+ ++mhod_num;
+ } else if (track->artist && *track->artist) {
+ mhod.type = MHOD_ID_ALBUM_ARTIST;
+ mhod.data.string = track->artist;
+ mk_mhod (fexp, &mhod);
+ ++mhod_num;
+ }
+
+ if (track->sort_albumartist && *track->sort_albumartist) {
+ mhod.type = MHOD_ID_ALBUM_SORT_ARTIST;
+ mhod.data.string = track->sort_albumartist;
+ mk_mhod (fexp, &mhod);
+ ++mhod_num;
+ } else if (track->sort_artist && *track->sort_artist) {
+ mhod.type = MHOD_ID_ALBUM_SORT_ARTIST;
+ mhod.data.string = track->sort_artist;
+ mk_mhod (fexp, &mhod);
+ ++mhod_num;
+ }
+ fix_mhit (cts, mhia_seek, mhod_num);
+}
+
+static void mk_mhla (FExport *fexp)
+{
+ WContents *cts;
+
+ g_return_if_fail (fexp);
+ g_return_if_fail (fexp->wcontents);
+ g_return_if_fail (fexp->albums);
+
+ cts = fexp->wcontents;
+
+ put_header (cts, "mhla"); /* header */
+ put32lint (cts, 92); /* size of header */
+ /* albums on iPod (including main!) */
+ put32lint (cts, g_hash_table_size (fexp->albums));
+ put32_n0 (cts, 20); /* dummy space */
+ g_hash_table_foreach (fexp->albums, mk_mhia, fexp);
+ g_hash_table_destroy (fexp->albums);
+ fexp->albums = NULL;
+}
+
/* Write out the mhlp header. Size will be written later */
static void mk_mhlp (FExport *fexp)
{
@@ -4998,7 +5083,23 @@
return TRUE;
}
+static gboolean write_mhsd_albums (FExport *fexp)
+{
+ gulong mhsd_seek;
+ WContents *cts;
+ g_return_val_if_fail (fexp, FALSE);
+ g_return_val_if_fail (fexp->itdb, FALSE);
+ g_return_val_if_fail (fexp->wcontents, FALSE);
+
+ cts = fexp->wcontents;
+ mhsd_seek = cts->pos; /* get position of mhsd header */
+ mk_mhsd (fexp, 4); /* write header */
+ mk_mhla (fexp);
+ fix_header (cts, mhsd_seek);
+ return TRUE;
+}
+
/* create a WContents structure */
static WContents *wcontents_new (const gchar *filename)
{
@@ -5040,14 +5141,41 @@
}
+static guint itdb_track_hash (gconstpointer v)
+{
+ Itdb_Track *track = (Itdb_Track *)v;
+ if (track->album != NULL) {
+ return g_str_hash (track->album);
+ } else if (track->artist != NULL) {
+ return g_str_hash (track->artist);;
+ }
+ g_assert_not_reached ();
+}
+
+static gboolean itdb_track_equal (gconstpointer v1, gconstpointer v2)
+{
+ Itdb_Track *track1 = (Itdb_Track *)v1;
+ Itdb_Track *track2 = (Itdb_Track *)v2;
+
+ if ((track1->albumartist != NULL) && (track2->albumartist != NULL)) {
+ return (g_str_equal (track1->album, track2->album)
+ && g_str_equal (track1->albumartist, track2->albumartist));
+ } else {
+ return (g_str_equal (track1->album, track2->album)
+ && g_str_equal (track1->artist, track2->artist));
+ }
+}
+
/* - reassign the iPod IDs
- make sure the itdb->tracks are in the same order as the mpl
+ - assign album IDs to write the MHLA
*/
static void prepare_itdb_for_write (FExport *fexp)
{
GList *gl;
Itdb_iTunesDB *itdb;
Itdb_Playlist *mpl;
+ guint album_id = 1;
g_return_if_fail (fexp);
itdb = fexp->itdb;
@@ -5076,16 +5204,37 @@
fexp->next_id = FIRST_IPOD_ID;
+ g_assert (fexp->albums == NULL);
+ fexp->albums = g_hash_table_new (itdb_track_hash, itdb_track_equal);
+
/* assign unique IDs and create sort keys */
for (gl=itdb->tracks; gl; gl=gl->next)
{
Itdb_Track *track = gl->data;
+ guint id;
+
g_return_if_fail (track);
track->id = fexp->next_id++;
+
+ if ((track->album == NULL) && (track->artist == NULL)) {
+ /* unknow album name and artist, this entry isn't interesting to
+ * build the list of all albums on the ipod
+ */
+ continue;
+ }
+ /* album ids are used when writing the mhla header */
+ id = GPOINTER_TO_UINT (g_hash_table_lookup (fexp->albums, track));
+ if (id != 0) {
+ track->album_id = id;
+ } else {
+ g_hash_table_insert (fexp->albums, track,
+ GUINT_TO_POINTER (album_id));
+ track->album_id = album_id;
+ album_id++;
+ }
}
}
-
static gboolean write_db_checksum (FExport *fexp, GError **error)
{
guint64 fwid;
@@ -5181,7 +5330,7 @@
}
#endif
- mk_mhbd (fexp, 3); /* three mhsds */
+ mk_mhbd (fexp, 4); /* four mhsds */
/* write tracklist */
if (write_mhsd_tracks (fexp))
{ /* write special podcast version mhsd */
@@ -5189,12 +5338,14 @@
{ /* write standard playlist mhsd */
if (write_mhsd_playlists (fexp, 2))
{
- fix_header (cts, mhbd_seek);
+ if (write_mhsd_albums (fexp)) {
+ fix_header (cts, mhbd_seek);
- /* Set checksum (ipods require it starting from iPod Classic
- * and fat Nanos)
- */
- write_db_checksum (fexp, &fexp->error);
+ /* Set checksum (ipods require it starting from
+ * iPod Classic and fat Nanos)
+ */
+ write_db_checksum (fexp, &fexp->error);
+ }
}
}
}
@@ -5209,6 +5360,9 @@
result = FALSE;
}
wcontents_free (cts);
+ if (fexp->albums != NULL) {
+ g_hash_table_destroy (fexp->albums);
+ }
g_free (fexp);
if (result == TRUE)
{
Modified: libgpod/trunk/src/itdb_private.h
===================================================================
--- libgpod/trunk/src/itdb_private.h 2009-01-20 21:39:56 UTC (rev 2231)
+++ libgpod/trunk/src/itdb_private.h 2009-01-20 21:40:19 UTC (rev 2232)
@@ -120,6 +120,7 @@
Itdb_iTunesDB *itdb;
WContents *wcontents;
guint32 next_id; /* next free ID to use */
+ GHashTable *albums; /* used to build the MHLA */
GError *error; /* where to report errors to */
} FExport;
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2