diff options
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | docs/reference/tmpl/artwork.sgml | 2 | ||||
-rw-r--r-- | docs/reference/tmpl/device.sgml | 4 | ||||
-rw-r--r-- | docs/reference/tmpl/track.sgml | 1 | ||||
-rw-r--r-- | src/db-artwork-parser.c | 190 | ||||
-rw-r--r-- | src/db-artwork-writer.c | 13 | ||||
-rw-r--r-- | src/db-parse-context.c | 1 | ||||
-rw-r--r-- | src/db-parse-context.h | 1 | ||||
-rw-r--r-- | src/itdb.h | 7 | ||||
-rw-r--r-- | src/itdb_artwork.c | 4 | ||||
-rw-r--r-- | src/itdb_device.c | 8 | ||||
-rw-r--r-- | src/itdb_itunesdb.c | 8 | ||||
-rw-r--r-- | src/itdb_track.c | 15 | ||||
-rw-r--r-- | src/ithumb-writer.c | 6 | ||||
-rw-r--r-- | tests/test-covers.c | 4 |
15 files changed, 226 insertions, 74 deletions
@@ -1,3 +1,39 @@ +2008-05-28 Jorg Schuler <jcsjcs at users.sourceforge.net> + + * src/itdb_track.c (itdb_track_set_thumbnails_internal): set + artwork ID to 0 after removing thumbnails. + + * src/db-artwork-parser.c (parse_mhii): move out dbid association + to a separate function. + + (mhfd_associate_itunesdb_artwork): handle dbid and mhii_link + association of artwork to track + + (parse_mhfd): loop over the number of mhsd hunks instead of + hardcoding it. Call mhfd_associate_itunesdb_artwork(). + + * src/itdb_itunesdb.c (get_mhit): read the mhii_link field. + + * src/db-artwork-writer.c (write_mhli): handle unset artwork + correctly. + + (itdb_track_filter_thumbnails): remove thumbnails correctly. + + * src/db-parse-context.c (db_parse_context_get_sub_context): copy + newly introduced artwork field. + + * tests/test-covers.c: print mhii_link. + + * src/itdb.h: (Itdb_Track) added mhii_link. (Itdb_Artwork): added + dbid. + + * src/itdb.h, src/db-artwork-parser.c, src/db-artwork-writer.c, + src/itdb_device.c, src/ithumb-writer.c, src/itdb_artwork.c: + added ITDB_THUMB_CHAPTER_SMALL/LARGE. + + * src/itdb_device.c: ipod_classic_1_artwork_info: correct + ITDB_THUMB_COVER_SMALL/LARGE entries. + 2008-05-25 Christophe Fergeau <teuf at gnome.org> * configure.ac: libxml presence is mandatory unless diff --git a/docs/reference/tmpl/artwork.sgml b/docs/reference/tmpl/artwork.sgml index 3729c83..1f491bd 100644 --- a/docs/reference/tmpl/artwork.sgml +++ b/docs/reference/tmpl/artwork.sgml @@ -78,6 +78,8 @@ album/track artwork. For working with photos, see the @ITDB_THUMB_COVER_MEDIUM: @ITDB_THUMB_COVER_SMEDIUM: @ITDB_THUMB_COVER_XSMALL: +@ITDB_THUMB_CHAPTER_SMALL: +@ITDB_THUMB_CHAPTER_LARGE: <!-- ##### FUNCTION itdb_artwork_new ##### --> <para> diff --git a/docs/reference/tmpl/device.sgml b/docs/reference/tmpl/device.sgml index 6307097..cb5e38f 100644 --- a/docs/reference/tmpl/device.sgml +++ b/docs/reference/tmpl/device.sgml @@ -26,6 +26,7 @@ These functions are for reading and setting information about the iPod. @musicdirs: @byte_order: @sysinfo: +@sysinfo_extended: @sysinfo_changed: @timezone_shift: @@ -247,7 +248,8 @@ These functions are for reading and setting information about the iPod. @type: @width: @height: -@correlation_id: +@format_id: @format: @padding: +@crop: diff --git a/docs/reference/tmpl/track.sgml b/docs/reference/tmpl/track.sgml index 10fb412..c213f41 100644 --- a/docs/reference/tmpl/track.sgml +++ b/docs/reference/tmpl/track.sgml @@ -129,6 +129,7 @@ information about an iPod track. @chapterdata_raw: @chapterdata_raw_length: @artwork: +@mhii_link: @reserved_int1: @reserved_int2: @reserved_int3: diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c index 038d558..064449b 100644 --- a/src/db-artwork-parser.c +++ b/src/db-artwork-parser.c @@ -241,6 +241,7 @@ parse_photo_mhod (DBParseContext *ctx, Itdb_Artwork *artwork, GError *error) return 0; } + static int parse_mhii (DBParseContext *ctx, GError *error) { @@ -248,12 +249,11 @@ parse_mhii (DBParseContext *ctx, GError *error) DBParseContext *mhod_ctx; int num_children; off_t cur_offset; - iPodSong *song = NULL; Itdb_Artwork *artwork; Itdb_PhotoDB *photodb; Itdb_iTunesDB *itunesdb; - guint64 dbid; guint64 mactime; + Itdb_Artwork *artwork_fallback = NULL; Itdb_Device *device = db_get_device (ctx->db); mhii = db_parse_context_get_m_header (ctx, MhiiHeader, "mhii"); @@ -269,23 +269,15 @@ parse_mhii (DBParseContext *ctx, GError *error) case DB_TYPE_PHOTO: photodb = db_get_photodb (ctx->db); g_return_val_if_fail (photodb, -1); - artwork = g_new0 (Itdb_Artwork, 1); + artwork = itdb_artwork_new (); photodb->photos = g_list_append (photodb->photos, artwork); break; case DB_TYPE_ITUNES: itunesdb = db_get_itunesdb (ctx->db); g_return_val_if_fail (itunesdb, -1); - dbid = get_gint64 (mhii->song_id, ctx->byte_order); - song = get_song_by_dbid (itunesdb, dbid); - if (song == NULL) - { - gchar *strval = g_strdup_printf("%" G_GINT64_FORMAT, dbid); - g_print (_("Could not find corresponding track (dbid: %s) for artwork entry.\n"), strval); - g_free (strval); - return -1; - } - artwork = song->artwork; - g_return_val_if_fail (artwork, -1); + artwork_fallback = itdb_artwork_new (); + artwork = artwork_fallback; + artwork->dbid = get_gint64 (mhii->song_id, ctx->byte_order); break; default: g_return_val_if_reached (-1); @@ -301,18 +293,6 @@ parse_mhii (DBParseContext *ctx, GError *error) artwork->digitized_date = device_time_mac_to_time_t (device, mactime); artwork->artwork_size = get_gint32 (mhii->orig_img_size, ctx->byte_order); - if (song) - { - if ((song->artwork_size+song->artwork_count) != - artwork->artwork_size) - { - g_warning (_("iTunesDB and ArtworkDB artwork sizes inconsistent (%d+%d != %d)\n"), - song->artwork_size, - song->artwork_count, - song->artwork->artwork_size); - } - } - cur_offset = ctx->header_len; mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset); num_children = get_gint32 (mhii->num_children, ctx->byte_order); @@ -325,6 +305,17 @@ parse_mhii (DBParseContext *ctx, GError *error) mhod_ctx = db_parse_context_get_sub_context (ctx, cur_offset); } g_free (mhod_ctx); + + /* make a copy of all artwork in ctx->artwork */ + if (ctx->artwork) + { + if (artwork_fallback == NULL) + { + artwork_fallback = itdb_artwork_duplicate (artwork); + } + *ctx->artwork = g_list_prepend (*ctx->artwork, artwork_fallback); + } + return 0; } @@ -499,6 +490,103 @@ parse_mhsd (DBParseContext *ctx, GError **error) return 0; } + +/* Apple introduced a new way to associate artwork. The former way + * used the dbid to link each artwork (mhii) back to the track. The + * new way uses the mhii id to link from each track to the mhii. Above + * we only handled the former way */ +static int +mhfd_associate_itunesdb_artwork (DBParseContext *ctx) +{ + GHashTable *mhii_id_hash; + Itdb_iTunesDB *itdb; + GList *gl; + + g_return_val_if_fail (ctx && ctx->artwork, -1); + itdb = db_get_itunesdb (ctx->db); + g_return_val_if_fail (itdb, -1); + + /* make a hash linking the mhii with the artwork for faster + lookup */ + mhii_id_hash = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)itdb_artwork_free); + + for (gl=*ctx->artwork; gl; gl=gl->next) + { + Itdb_Track *track; + Itdb_Artwork *artwork=gl->data; + g_return_val_if_fail (artwork, -1); + + g_hash_table_insert (mhii_id_hash, GINT_TO_POINTER (artwork->id), artwork); + + /* add Artwork to track indicated by the dbid for backward + compatibility */ + track = get_song_by_dbid (itdb, artwork->dbid); + if (track == NULL) + { + gchar *strval = g_strdup_printf("%" G_GINT64_FORMAT, artwork->dbid); + g_print (_("Could not find corresponding track (dbid: %s) for artwork entry.\n"), strval); + g_free (strval); + } + else + { + if ((track->artwork_size + track->artwork_count) != + artwork->artwork_size) + { + g_warning (_("iTunesDB and ArtworkDB artwork sizes inconsistent (%d+%d != %d)\n"), + track->artwork_size, + track->artwork_count, + track->artwork->artwork_size); + } + itdb_artwork_free (track->artwork); + track->artwork = itdb_artwork_duplicate (artwork); + } + } + /* Now go through all the tracks and add artwork where an + * mhii_link is available */ + for (gl=itdb->tracks; gl; gl=gl->next) + { + Itdb_Track *track = gl->data; + g_return_val_if_fail (track, -1); + if (track->mhii_link) + { + Itdb_Artwork *artwork; + artwork = g_hash_table_lookup (mhii_id_hash, + GINT_TO_POINTER (track->mhii_link)); + if (artwork) + { + g_return_val_if_fail (track->artwork, -1); + if (track->artwork->id != track->mhii_link) + { + itdb_artwork_free (track->artwork); + track->artwork = itdb_artwork_duplicate (artwork); + } + else + { + /* same artwork -- don't copy again */ + } + } + else + { + gchar *strval = g_strdup_printf("%" G_GINT64_FORMAT, track->dbid); + g_print (_("Could not find artwork entry (mhii id: %u) for track (dbid: %s).\n"), track->mhii_link, strval); + g_free (strval); + } + } + } + g_hash_table_destroy (mhii_id_hash); + /* The actual ItdbArtwork data was freed through the GHashTable + value_destroy_func */ + g_list_free (*ctx->artwork); + ctx->artwork = NULL; + + return 0; +} + + + /* Database Object */ static int parse_mhfd (DBParseContext *ctx, GError **error) @@ -507,6 +595,8 @@ parse_mhfd (DBParseContext *ctx, GError **error) DBParseContext *mhsd_context; unsigned int cur_pos; gint total_len; + gint32 i; + GList *artwork_glist = NULL; mhfd = db_parse_context_get_m_header (ctx, MhfdHeader, "mhfd"); if (mhfd == NULL) { @@ -519,38 +609,35 @@ parse_mhfd (DBParseContext *ctx, GError **error) dump_mhfd (mhfd); cur_pos = ctx->header_len; - /* The mhfd record always has 3 mhsd children, so it's hardcoded here. - * It could be replaced with a loop using the nb_children field from - * the mhfd record. [explanation by Christophe] - */ - mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos); - if (mhsd_context == NULL) { - return -1; + if (ctx->db->db_type == DB_TYPE_ITUNES) + { /* we need to collect all artwork in this GList for + iTunesDB (see below) */ + ctx->artwork = &artwork_glist; } - parse_mhsd (mhsd_context, NULL); - cur_pos += mhsd_context->total_len; - g_free (mhsd_context); - mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos); - if (mhsd_context == NULL) { + for (i=0; i<mhfd->num_children; ++i) + { + /* so far all mhfd we know have 3 children, but better be + safe than sorry */ + mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos); + if (mhsd_context == NULL) { return -1; + } + parse_mhsd (mhsd_context, NULL); + cur_pos += mhsd_context->total_len; + g_free (mhsd_context); } - parse_mhsd (mhsd_context, NULL); - cur_pos += mhsd_context->total_len; - g_free (mhsd_context); - mhsd_context = db_parse_context_get_sub_context (ctx, cur_pos); - if (mhsd_context == NULL) { - return -1; + if (ctx->db->db_type == DB_TYPE_ITUNES) + { + return mhfd_associate_itunesdb_artwork (ctx); } - parse_mhsd (mhsd_context, NULL); - cur_pos += mhsd_context->total_len; - g_free (mhsd_context); - + return 0; } + G_GNUC_INTERNAL char * ipod_db_get_artwork_db_path (const char *mount_point) { @@ -622,6 +709,9 @@ ipod_supports_cover_art (Itdb_Device *device) case ITDB_THUMB_COVER_SMEDIUM: case ITDB_THUMB_COVER_XSMALL: break; + case ITDB_THUMB_CHAPTER_SMALL: + case ITDB_THUMB_CHAPTER_LARGE: + break; } formats++; } @@ -660,6 +750,9 @@ ipod_supports_photos (Itdb_Device *device) case ITDB_THUMB_COVER_SMEDIUM: case ITDB_THUMB_COVER_XSMALL: break; + case ITDB_THUMB_CHAPTER_SMALL: + case ITDB_THUMB_CHAPTER_LARGE: + break; } formats++; } @@ -695,6 +788,7 @@ ipod_parse_artwork_db (Itdb_iTunesDB *itdb) ctx = db_parse_context_new_from_file (filename, &db); g_free (filename); + if (ctx == NULL) { goto error; } diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c index 15151bc..b2a0ab4 100644 --- a/src/db-artwork-writer.c +++ b/src/db-artwork-writer.c @@ -564,7 +564,7 @@ write_mhli (Itdb_DB *db, iPodBuffer *buffer ) iPodBuffer *sub_buffer; if (buffer->db_type == DB_TYPE_ITUNES) { song = (Itdb_Track*)it->data; - if (!song->artwork || (song->artwork->id == 0)) { + if (!song->artwork->thumbnails || (song->artwork->id == 0)) { it = it->next; continue; } @@ -753,6 +753,9 @@ itdb_thumb_type_is_valid_for_db (const ItdbThumbType thumb_type, DbType db_type) case ITDB_THUMB_COVER_SMEDIUM: case ITDB_THUMB_COVER_XSMALL: return (db_type == DB_TYPE_ITUNES); + case ITDB_THUMB_CHAPTER_SMALL: + case ITDB_THUMB_CHAPTER_LARGE: + return FALSE; /* not supported yet */ case ITDB_THUMB_PHOTO_SMALL: case ITDB_THUMB_PHOTO_LARGE: case ITDB_THUMB_PHOTO_FULL_SCREEN: @@ -962,8 +965,7 @@ itdb_track_filter_thumbnails (Itdb_iTunesDB *itdb, Itdb_Track *track) formats = itdb_device_get_artwork_formats (itdb->device); if (formats == NULL) { - itdb_artwork_free (track->artwork); - track->artwork = NULL; + itdb_artwork_remove_thumbnails (track->artwork); return; } @@ -983,11 +985,6 @@ itdb_track_filter_thumbnails (Itdb_iTunesDB *itdb, Itdb_Track *track) } } - if (supported_thumbs == NULL) { - itdb_artwork_free (track->artwork); - track->artwork = NULL; - return; - } g_list_free (track->artwork->thumbnails); track->artwork->thumbnails = supported_thumbs; } diff --git a/src/db-parse-context.c b/src/db-parse-context.c index cf5171d..57d913a 100644 --- a/src/db-parse-context.c +++ b/src/db-parse-context.c @@ -116,6 +116,7 @@ db_parse_context_get_sub_context (DBParseContext *ctx, off_t offset) ctx->total_len - offset, ctx->byte_order); sub_ctx->db = ctx->db; + sub_ctx->artwork = ctx->artwork; return sub_ctx; } diff --git a/src/db-parse-context.h b/src/db-parse-context.h index c23c69d..85f40ae 100644 --- a/src/db-parse-context.h +++ b/src/db-parse-context.h @@ -39,6 +39,7 @@ struct _DBParseContext { off_t total_len; guint byte_order; Itdb_DB *db; + GList **artwork; }; typedef struct _DBParseContext DBParseContext; @@ -490,6 +490,8 @@ typedef enum { ITDB_THUMB_COVER_MEDIUM, /* iPhone: cover view */ ITDB_THUMB_COVER_SMEDIUM, /* iPhone: ?? */ ITDB_THUMB_COVER_XSMALL, /* iPhone: ?? */ + ITDB_THUMB_CHAPTER_SMALL, /* classic -- not supported yet */ + ITDB_THUMB_CHAPTER_LARGE, /* classic -- not supported yet */ } ItdbThumbType; @@ -539,6 +541,8 @@ struct _Itdb_Artwork { GList *thumbnails; /* list of Itdb_Thumbs */ guint32 id; /* Artwork id used by photoalbums, starts at * 0x40... libgpod will set this on sync. */ + guint64 dbid; /* dbid of associated track. used + internally by libgpod */ gint32 unk028; guint32 rating; /* Rating from iPhoto * 20 (PhotoDB only) */ gint32 unk036; @@ -995,6 +999,9 @@ struct _Itdb_Track /* This is for Cover Art support */ struct _Itdb_Artwork *artwork; + /* 200805 */ + guint32 mhii_link; + /* reserved for future use */ gint32 reserved_int1; gint32 reserved_int2; diff --git a/src/itdb_artwork.c b/src/itdb_artwork.c index 2d8ce77..acdbc7e 100644 --- a/src/itdb_artwork.c +++ b/src/itdb_artwork.c @@ -1006,6 +1006,10 @@ itdb_thumb_get_gdk_pixbuf (Itdb_Device *device, Itdb_Thumb *thumb) width = 88; height = 88; break; case ITDB_THUMB_COVER_XSMALL: width = 56; height = 56; break; + case ITDB_THUMB_CHAPTER_SMALL: + width = 100; height = 100; break; + case ITDB_THUMB_CHAPTER_LARGE: + width = 200; height = 200; break; } if (width == 0) { diff --git a/src/itdb_device.c b/src/itdb_device.c index 0f86c57..9efd62f 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -326,16 +326,16 @@ static const Itdb_ArtworkFormat ipod_touch_1_artwork_info[] = { static const Itdb_ArtworkFormat ipod_classic_1_artwork_info[] = { /* officially 55x55 -- verify! */ - {ITDB_THUMB_COVER_XSMALL, 56, 56, 1061, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_COVER_SMALL, 56, 56, 1061, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_COVER_MEDIUM, 128, 128, 1055, THUMB_FORMAT_RGB565_LE}, - {ITDB_THUMB_COVER_XLARGE, 320, 320, 1060, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_COVER_LARGE, 320, 320, 1060, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1067, THUMB_FORMAT_I420_LE}, {ITDB_THUMB_PHOTO_FULL_SCREEN,320, 240, 1024, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_SMALL, 64, 64, 1066, THUMB_FORMAT_RGB565_LE}, /* These are the same as for the iPod video... -- labeled by the iPod as "chapter images" */ - {ITDB_THUMB_COVER_SMALL, 100, 100, 1028, THUMB_FORMAT_RGB565_LE}, - {ITDB_THUMB_COVER_LARGE, 200, 200, 1029, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_CHAPTER_SMALL, 100, 100, 1028, THUMB_FORMAT_RGB565_LE}, + {ITDB_THUMB_CHAPTER_LARGE, 200, 200, 1029, THUMB_FORMAT_RGB565_LE}, {-1, -1, -1, -1, -1} }; diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c index be846f4..cab04bb 100644 --- a/src/itdb_itunesdb.c +++ b/src/itdb_itunesdb.c @@ -2353,6 +2353,11 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) track->gapless_track_flag = get16lint (cts, seek+256); track->gapless_album_flag = get16lint (cts, seek+258); } + /* 200805 */ + if (header_len >= 0x184) + { + track->mhii_link = get32lint (cts, seek+352); + } track->transferred = TRUE; /* track is on iPod! */ @@ -3641,8 +3646,7 @@ static void mk_mhit (WContents *cts, Itdb_Track *track) put16lint (cts, track->gapless_album_flag); put32_n0 (cts, 23); put32lint (cts, track->id); /* Needed on fat nanos/ipod classic to get art - * in the right sidepane - */ + * in the right sidepane (mhii_link) */ put32_n0 (cts, 8); /* padding */ } diff --git a/src/itdb_track.c b/src/itdb_track.c index 470f92d..c09b9ae 100644 --- a/src/itdb_track.c +++ b/src/itdb_track.c @@ -395,14 +395,13 @@ static gboolean itdb_track_set_thumbnails_internal (Itdb_Track *track, gpointer *pixbuf, gint rotation, GError **error) -{ - /* FIXME: this looks like it would work, but the problem is that - * gtkpod calls this function mostly with tracks that are not yet - * part of an iTunesDB. This means only the SMALL and LARGE thumbs - * are being added. +{ + /* gtkpod calls this function mostly with tracks that are not yet + * part of an iTunesDB. This means it is not known which + * thumbnails are required. * - * One solution would be to add all kinds of cover thumbs and weed - * out the ones not supported when the ArtworkDB is written. + * Our solution is to add all kinds of cover thumbs and weed out + * the ones not supported when the ArtworkDB is written. * * Suggestions welcome! */ @@ -428,6 +427,8 @@ static gboolean itdb_track_set_thumbnails_internal (Itdb_Track *track, } itdb_artwork_remove_thumbnails (track->artwork); + /* clear artwork id */ + track->artwork->id = 0; for (thumbtype=thumbtypes; *thumbtype!=-1; ++thumbtype) { diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c index 074caa9..5594fe5 100644 --- a/src/ithumb-writer.c +++ b/src/ithumb-writer.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2007-11-04 09:46:51 jcs> +/* Time-stamp: <2008-05-25 23:15:17 jcs> * * Copyright (C) 2005 Christophe Fergeau * @@ -778,6 +778,8 @@ static char *get_ithmb_filename (iThumbWriter *writer, Itdb_Thumb *thumb) case ITDB_THUMB_COVER_MEDIUM: case ITDB_THUMB_COVER_SMEDIUM: case ITDB_THUMB_COVER_XSMALL: + case ITDB_THUMB_CHAPTER_LARGE: + case ITDB_THUMB_CHAPTER_SMALL: return g_strdup_printf (":F%d_%d.ithmb", writer->img_info->format_id, writer->current_file_index); @@ -1225,7 +1227,7 @@ static gboolean ithumb_rearrange_thumbnail_file (gpointer _key, To avoid the need to read large amounts from the iPod and back, or have to large files exist on the iPod (reading from the original - thumbnail fail and writing to the new thumbnail file), the + thumbnail file and writing to the new thumbnail file), the modifications are done in place. It is assumed that all thumbnails have the same data size. If not, diff --git a/tests/test-covers.c b/tests/test-covers.c index 7d22c85..36a87fa 100644 --- a/tests/test-covers.c +++ b/tests/test-covers.c @@ -80,10 +80,10 @@ save_thumbnails (Itdb_iTunesDB *db) Itdb_Track *song; song = (Itdb_Track *)it->data; - g_print ("Track %d (%016"G_GINT64_MODIFIER"x) %s-%s-%s\n", + g_print ("Track %d (%016"G_GINT64_MODIFIER"x) %s-%s-%s (%08x)\n", count++, song->dbid, song->artist, song->album, - song->title); + song->title, song->mhii_link); save_song_thumbnails (song); } } |