commit dc0132609df0c1985c769443745c4ac3f83be581
Author: Nikias Bassen <[email protected]>
Date:   Sat Oct 10 13:01:29 2009 +0200

    write artist list (mhla and mhia)
    
    Newer iTunes versions have a new type of mhsd with type 8. This new
    mhsd contains a list of all artists used by songs on the iPod. This commit
    adds support for writing this mhsd.

 src/itdb_itunesdb.c |  150 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/itdb_private.h  |    2 +
 2 files changed, 146 insertions(+), 6 deletions(-)
---
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index 09d3a39..67464dd 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -222,7 +222,8 @@ enum MHOD_ID {
   MHOD_ID_PLAYLIST = 100,
   MHOD_ID_ALBUM_ALBUM = 200, /* MHODs for the MHIAs */
   MHOD_ID_ALBUM_ARTIST = 201,
-  MHOD_ID_ALBUM_SORT_ARTIST = 202
+  MHOD_ID_ALBUM_SORT_ARTIST = 202,
+  MHOD_ID_ALBUM_ARTIST_MHII = 300,
 };
 
 
@@ -1677,6 +1678,7 @@ static gchar *get_mhod_string (FImport *fimp, glong seek, 
guint32 *ml, gint32 *m
     case MHOD_ID_SORT_TVSHOW:
     case MHOD_ID_ALBUM_ALBUM:
     case MHOD_ID_ALBUM_ARTIST:
+    case MHOD_ID_ALBUM_ARTIST_MHII:
     case MHOD_ID_ALBUM_SORT_ARTIST:
        mhoddata = get_mhod (fimp, seek, ml);
        if ((*ml != -1) && mhoddata.valid)
@@ -2109,6 +2111,7 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek)
          case MHOD_ID_SORT_TVSHOW:
          case MHOD_ID_ALBUM_ALBUM:
          case MHOD_ID_ALBUM_ARTIST:
+         case MHOD_ID_ALBUM_ARTIST_MHII:
          case MHOD_ID_ALBUM_SORT_ARTIST:
          case MHOD_ID_LIBPLAYLISTJUMPTABLE:
              /* these are not expected here */
@@ -2447,6 +2450,7 @@ static glong get_mhit (FImport *fimp, glong mhit_seek)
          case MHOD_ID_CHAPTERDATA:
          case MHOD_ID_ALBUM_ALBUM:
          case MHOD_ID_ALBUM_ARTIST:
+         case MHOD_ID_ALBUM_ARTIST_MHII:
          case MHOD_ID_ALBUM_SORT_ARTIST:
              g_free (entry_utf8);
              break;
@@ -3757,7 +3761,8 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
   /* +0x170 */
   put32_n0 (cts, 28);
   /* +0x1E0 */
-  put32_n0 (cts, 5);
+  put32lint (cts, track->priv->artist_id);
+  put32_n0 (cts, 4);
   /* +0x1F4 */
   put32lint (cts, 0); /* FIXME: this is another ID for something, composer?! */
   put32_n0 (cts, 20); /* padding */
@@ -4102,6 +4107,7 @@ static void mk_mhod (FExport *fexp, MHODData *mhod)
   case MHOD_ID_ALBUM_ALBUM:
   case MHOD_ID_ALBUM_ARTIST:
   case MHOD_ID_ALBUM_SORT_ARTIST:
+  case MHOD_ID_ALBUM_ARTIST_MHII:
       g_return_if_fail (mhod->data.string);
       /* normal iTunesDBs seem to take utf16 strings), endian-inversed
         iTunesDBs seem to take utf8 strings */
@@ -4567,6 +4573,69 @@ static void mk_mhlp (FExport *fexp)
   put32_n0 (cts, 20);               /* dummy space              */
 }
 
+static void mk_mhii (gpointer key, gpointer value, gpointer user_data)
+{
+  FExport *fexp;
+  WContents *cts;
+  Itdb_Track *track;
+  Itdb_Item_Id *id;
+  MHODData mhod;
+  guint mhod_num;
+  gulong mhii_seek;
+
+  track = (Itdb_Track *)key;
+  g_return_if_fail (track != NULL);
+
+  id = (Itdb_Item_Id *)value;
+  g_return_if_fail (id != NULL);
+
+  fexp = (FExport *)user_data;
+  g_return_if_fail (fexp);
+  g_return_if_fail (fexp->wcontents);
+  cts = fexp->wcontents;
+  mhii_seek = cts->pos;
+
+  put_header (cts, "mhii");                    /* header                   */
+  put32lint (cts, 80);                         /* size of header           */
+  put32lint (cts, -1);                         /* total size -> later */
+  put32lint (cts, 1);                          /* number of children mhods */
+  put32lint (cts, id->id);                     /* artist id */
+  put64lint (cts, id->sql_id);                 /* artist SQL id */
+  put32lint (cts, 2);                          /* unknown */
+  put32_n0 (cts, 12);                          /* padding */
+
+  mhod.valid = TRUE;
+  mhod_num = 0;
+
+  if (track->artist && *track->artist) {
+      mhod.type = MHOD_ID_ALBUM_ARTIST_MHII;
+      mhod.data.string = track->artist;
+      mk_mhod (fexp, &mhod);
+      ++mhod_num;
+  }
+
+  fix_mhit (cts, mhii_seek, mhod_num);
+}
+
+static void mk_mhli (FExport *fexp)
+{
+  WContents *cts;
+
+  g_return_if_fail (fexp);
+  g_return_if_fail (fexp->wcontents);
+  g_return_if_fail (fexp->artists);
+
+  cts = fexp->wcontents;
+
+  put_header (cts, "mhli");        /* header                   */
+  put32lint (cts, 92);             /* size of header           */
+  /* albums on iPod (including main!) */
+  put32lint (cts, g_hash_table_size (fexp->artists));
+  put32_n0 (cts, 20);               /* dummy space              */
+  g_hash_table_foreach (fexp->artists, mk_mhii, fexp);
+  g_hash_table_destroy (fexp->artists);
+  fexp->artists = NULL;
+}
 
 /* Write out the long MHOD_ID_PLAYLIST mhod header.
    This seems to be an itunespref thing.. dunno know this
@@ -5228,6 +5297,23 @@ static gboolean write_mhsd_albums (FExport *fexp)
     return TRUE;
 }
 
+static gboolean write_mhsd_artists (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, 8);                 /* write header */
+    mk_mhli (fexp);
+    fix_header (cts, mhsd_seek);
+    return TRUE;
+}
+
 static gboolean write_mhsd_type6 (FExport *fexp)
 {
     gulong mhsd_seek;
@@ -5313,15 +5399,35 @@ static gboolean itdb_album_equal (gconstpointer v1, 
gconstpointer v2)
   }
 }
 
-static void add_new_id (GHashTable *album_ids, Itdb_Track *track, guint 
album_id)
+static void add_new_id (GHashTable *ids, Itdb_Track *track, guint new_id)
 {
     Itdb_Item_Id *id;
 
     id  = g_new0 (Itdb_Item_Id, 1);
-    id->id = album_id;
+    id->id = new_id;
     id->sql_id = ((guint64)g_random_int () << 32) | ((guint64)g_random_int 
()); 
 
-    g_hash_table_insert (album_ids, track, id);
+    g_hash_table_insert (ids, track, id);
+}
+
+static guint itdb_artist_hash (gconstpointer v)
+{
+  Itdb_Track *track = (Itdb_Track *)v;
+  if (track->artist != NULL) {
+    return g_str_hash (track->artist);
+  }
+  g_assert_not_reached ();
+}
+
+static gboolean itdb_artist_equal (gconstpointer v1, gconstpointer v2)
+{
+  Itdb_Track *track1 = (Itdb_Track *)v1;
+  Itdb_Track *track2 = (Itdb_Track *)v2;
+
+  g_assert (track1->artist != NULL);
+  g_assert (track2->artist != NULL);
+
+  return g_str_equal (track1->artist, track2->artist);
 }
 
 /* - reassign the iPod IDs
@@ -5334,6 +5440,7 @@ static void prepare_itdb_for_write (FExport *fexp)
     Itdb_iTunesDB *itdb;
     Itdb_Playlist *mpl;
     guint album_id = 1;
+    guint artist_id = 1;
 
     g_return_if_fail (fexp);
     itdb = fexp->itdb;
@@ -5366,6 +5473,10 @@ static void prepare_itdb_for_write (FExport *fexp)
     fexp->albums = g_hash_table_new_full (itdb_album_hash, itdb_album_equal,
                                          NULL, g_free);
 
+    g_assert (fexp->artists == NULL);
+    fexp->artists = g_hash_table_new_full (itdb_artist_hash, itdb_artist_equal,
+                                          NULL, g_free);
+
     /* assign unique IDs and create sort keys */
     for (gl=itdb->tracks; gl; gl=gl->next)
     {
@@ -5390,6 +5501,22 @@ static void prepare_itdb_for_write (FExport *fexp)
            track->priv->album_id = album_id;
            album_id++;
        }
+
+       if (track->artist == NULL) {    
+           /* unknown artist name, this entry isn't interesting to
+            * build the list of all artists on the ipod
+            */
+           continue;
+       }
+       /* artist ids are used when writing the mhli header */
+       id = g_hash_table_lookup (fexp->artists, track);
+       if (id != NULL) {
+           track->priv->artist_id = id->id;
+       } else {        
+           add_new_id (fexp->artists, track, artist_id);
+           track->priv->artist_id = id->id;
+           artist_id++;
+       }
     }
 }
 
@@ -5436,7 +5563,7 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB 
*itdb,
     }
 #endif
 
-    mk_mhbd (fexp, 6);  /* six mhsds */
+    mk_mhbd (fexp, 7);  /* seven mhsds */
 
     /* write albums (mhsd type 4) */
     if (!write_mhsd_albums (fexp)) {
@@ -5446,6 +5573,14 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB 
*itdb,
                     _("Error writing list of albums (mhsd type 4)"));
        goto err;
     }
+    /* write artists (mhsd type 8) */
+    if (!fexp->error && !write_mhsd_artists (fexp)) {
+       g_set_error (&fexp->error,
+                    ITDB_FILE_ERROR,
+                    ITDB_FILE_ERROR_ITDB_CORRUPT,
+                    _("Error writing list of artists (mhsd type 8)"));
+       goto err;
+    }
 
     /* write tracklist (mhsd type 1) */
     if (!fexp->error && !write_mhsd_tracks (fexp)) {
@@ -5529,6 +5664,9 @@ err:
     if (fexp->albums != NULL) {
        g_hash_table_destroy (fexp->albums);
     }
+    if (fexp->artists != NULL) {
+       g_hash_table_destroy (fexp->artists);
+    }
     g_free (fexp);
     if (result == TRUE)
     {
diff --git a/src/itdb_private.h b/src/itdb_private.h
index 67bec7c..424d76f 100644
--- a/src/itdb_private.h
+++ b/src/itdb_private.h
@@ -133,6 +133,7 @@ typedef struct
     WContents *wcontents;
     guint32 next_id;     /* next free ID to use       */
     GHashTable *albums;  /* used to build the MHLA    */
+    GHashTable *artists; /* used to build the MHLI    */
     GError *error;       /* where to report errors to */
 } FExport;
 
@@ -172,6 +173,7 @@ struct _Itdb_iTunesDB_Private
 /* private data for Itdb_Track */
 struct _Itdb_Track_Private {
        guint32 album_id;
+       guint32 artist_id;
 };
 
 G_GNUC_INTERNAL gboolean itdb_spl_action_known (ItdbSPLAction action);

------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2

Reply via email to