diff options
author | Jorg Schuler <jcsjcs@users.sourceforge.net> | 2006-10-29 08:43:28 +0000 |
---|---|---|
committer | Jorg Schuler <jcsjcs@users.sourceforge.net> | 2006-10-29 08:43:28 +0000 |
commit | e6d6143818172892e9a667cca4f3a37639586605 (patch) | |
tree | 1a7a2a4aac1a5fd450f57fa3da44d6200bb58594 | |
parent | 344770dd26661ef37f7b7974a6b42bb16fe5d8fa (diff) | |
download | libgpod-e6d6143818172892e9a667cca4f3a37639586605.tar.gz libgpod-e6d6143818172892e9a667cca4f3a37639586605.tar.xz libgpod-e6d6143818172892e9a667cca4f3a37639586605.zip |
Major rework of picture support.
* src/db-artwork-parser.c, src/db-artwork-writer.c, src/itdb.h,
src/db-itunes-parser.h: renamed 'master' to 'album_type' in
MhbaHeader and Itdb_PhotoAlbum.
* src/db-artwork-parser.c, src/db-artwork-writer.c,
src/itdb_photoalbum.c: Itdb_Photoalbum->members are now pointers
to the corresponding Itdb_Artwork instead of image_ids.
* src/itdb_photoalbum.c: album_ids and image_ids are set just
before writing the PhotoDB in itdb_photodb_write().
* src/itdb_photoalbum.c: new interface, basically use as follows:
itdb_photodb_parse():
Read an existing PhotoDB.
itdb_photodb_create():
Create a new Itdb_PhotoDB structure. The Photo Library Album is
(first album) is created automatically.
itdb_photodb_add_photo(), itdb_photodb_add_photo_from_data():
Add a photo to the PhotoDB (from file or from a chunk of
memory). It is automatically added to the Photo Library Album
(first album), which is created if it does not exist already.
itdb_photodb_photoalbum_craete():
Create and add a new photoalbum.
itdb_photodb_photoalbum_add_photo():
Add a photo (Itdb_Artwork) to an existing photoalbum.
itdb_photodb_photoalbum_remove():
Remove an existing photoalbum. Pictures can be kept in the
Photo Library or automatically removed as well.
itdb_photodb_remove_photo():
Remove a photo either from a photoalbum or completely from the
database.
itdb_photodb_write():
Write out your PhotoDB.
itdb_photodb_free():
Free all memory taken by the PhotoDB.
itdb_photodb_photoalbum_by_name():
Find the first photoalbum with a given name.
* src/itdb_playlist.c (itdb_playlist_add, itdb_playlist_add_track):
src/itdb_track.c (itdb_track_add): simplify code by using
g_list_insert().
* tests/test-photos.c: change to new interface, add new commands
'list' to list photo IDs in the database, 'remove' to remove IDs
from an album or the iPod, or remove entire photoalbums from the
iPod.
* src/db-itunes-parser.h: added comments to _MhbaHeader definition.
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1329 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r-- | ChangeLog | 59 | ||||
-rw-r--r-- | src/db-artwork-parser.c | 38 | ||||
-rw-r--r-- | src/db-artwork-writer.c | 7 | ||||
-rw-r--r-- | src/db-itunes-parser.h | 38 | ||||
-rw-r--r-- | src/itdb.h | 215 | ||||
-rw-r--r-- | src/itdb_photoalbum.c | 559 | ||||
-rw-r--r-- | tests/test-photos.c | 351 |
7 files changed, 947 insertions, 320 deletions
@@ -1,9 +1,66 @@ -2006-10-02 Jorg Schuler <jcsjcs at users.sourceforge.net> +2006-10-29 Jorg Schuler <jcsjcs at users.sourceforge.net> + + Major rework of picture support. + + * src/db-artwork-parser.c, src/db-artwork-writer.c, src/itdb.h, + src/db-itunes-parser.h: renamed 'master' to 'album_type' in + MhbaHeader and Itdb_PhotoAlbum. + + * src/db-artwork-parser.c, src/db-artwork-writer.c, + src/itdb_photoalbum.c: Itdb_Photoalbum->members are now pointers + to the corresponding Itdb_Artwork instead of image_ids. + + * src/itdb_photoalbum.c: album_ids and image_ids are set just + before writing the PhotoDB in itdb_photodb_write(). + + * src/itdb_photoalbum.c: new interface, basically use as follows: + + itdb_photodb_parse(): + Read an existing PhotoDB. + + itdb_photodb_create(): + Create a new Itdb_PhotoDB structure. The Photo Library Album is + (first album) is created automatically. + + itdb_photodb_add_photo(), itdb_photodb_add_photo_from_data(): + Add a photo to the PhotoDB (from file or from a chunk of + memory). It is automatically added to the Photo Library Album + (first album), which is created if it does not exist already. + + itdb_photodb_photoalbum_craete(): + Create and add a new photoalbum. + + itdb_photodb_photoalbum_add_photo(): + Add a photo (Itdb_Artwork) to an existing photoalbum. + + itdb_photodb_photoalbum_remove(): + Remove an existing photoalbum. Pictures can be kept in the + Photo Library or automatically removed as well. + + itdb_photodb_remove_photo(): + Remove a photo either from a photoalbum or completely from the + database. + + itdb_photodb_write(): + Write out your PhotoDB. + + itdb_photodb_free(): + Free all memory taken by the PhotoDB. + + itdb_photodb_photoalbum_by_name(): + Find the first photoalbum with a given name. * src/itdb_playlist.c (itdb_playlist_add, itdb_playlist_add_track): src/itdb_track.c (itdb_track_add): simplify code by using g_list_insert(). + * tests/test-photos.c: change to new interface, add new commands + 'list' to list photo IDs in the database, 'remove' to remove IDs + from an album or the iPod, or remove entire photoalbums from the + iPod. + + * src/db-itunes-parser.h: added comments to _MhbaHeader definition. + 2006-10-02 Jorg Schuler <jcsjcs at users.sourceforge.net> * tests/Makefile.am diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c index 4a848ce..51d81fa 100644 --- a/src/db-artwork-parser.c +++ b/src/db-artwork-parser.c @@ -79,7 +79,7 @@ static int parse_mhia (DBParseContext *ctx, Itdb_PhotoAlbum *photo_album, GError *error) { MhiaHeader *mhia; - gint image_id; + guint32 image_id; mhia = db_parse_context_get_m_header (ctx, MhiaHeader, "mhia"); if (mhia == NULL) { @@ -88,7 +88,7 @@ parse_mhia (DBParseContext *ctx, Itdb_PhotoAlbum *photo_album, GError *error) dump_mhia (mhia); image_id = get_gint32 (mhia->image_id, ctx->byte_order); photo_album->members = g_list_append (photo_album->members, - GINT_TO_POINTER(image_id)); + GUINT_TO_POINTER(image_id)); db_parse_context_set_total_len (ctx, get_gint32_db (ctx->db, mhia->total_len)); return 0; @@ -402,7 +402,7 @@ parse_mhba (DBParseContext *ctx, GError *error) photo_album = g_new0 (Itdb_PhotoAlbum, 1); photo_album->num_images = get_gint32( mhba->num_mhias, ctx->byte_order); photo_album->album_id = get_gint32( mhba->playlist_id, ctx->byte_order); - photo_album->master = get_gint32( mhba->master, ctx->byte_order); + photo_album->album_type = get_gint32( mhba->album_type, ctx->byte_order); photo_album->prev_album_id = get_gint32( mhba->prev_playlist_id, ctx->byte_order); cur_offset = ctx->header_len; @@ -766,6 +766,9 @@ ipod_parse_photo_db (Itdb_PhotoDB *photodb) char *filename; Itdb_DB db; + GList *gl; + GHashTable *hash; + db.db.photodb = photodb; db.db_type = DB_TYPE_PHOTO; @@ -784,6 +787,35 @@ ipod_parse_photo_db (Itdb_PhotoDB *photodb) parse_mhfd (ctx, NULL); db_parse_context_destroy (ctx, TRUE); + /* Now we need to replace references to artwork_ids in the + * photo albums with references to the actual artwork + * structure. Since we cannot guarantee that the list with the + * photos is read before the album list, we cannot safely do + * this at the time of reading the ids. */ + + /* Create a hash for faster lookup */ + hash = g_hash_table_new (g_int_hash, g_int_equal); + for (gl=photodb->photos; gl; gl=gl->next) + { + Itdb_Artwork *photo = gl->data; + g_return_val_if_fail (photo, -1); + g_hash_table_insert (hash, &photo->id, photo); +/* printf ("id: %d, photo: %p\n", photo->id, photo);*/ + } + for (gl=photodb->photoalbums; gl; gl=gl->next) + { + GList *glp; + Itdb_PhotoAlbum *album = gl->data; + g_return_val_if_fail (album, -1); + for (glp=album->members; glp; glp=glp->next) + { + guint image_id = GPOINTER_TO_UINT (glp->data); + Itdb_Artwork *photo = g_hash_table_lookup (hash, &image_id); +/* printf ("id: %d, photo: %p\n", image_id, photo);*/ + glp->data = photo; + } + } + g_hash_table_destroy (hash); return 0; } diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c index f072059..80ab33f 100644 --- a/src/db-artwork-writer.c +++ b/src/db-artwork-writer.c @@ -685,7 +685,7 @@ write_mhba (Itdb_PhotoAlbum *photo_album, iPodBuffer *buffer) } mhba->num_mhods = get_gint32(1, buffer->byte_order); mhba->playlist_id = get_gint32(photo_album->album_id, buffer->byte_order); - mhba->master = get_gint32(photo_album->master, buffer->byte_order); + mhba->album_type = get_gint32(photo_album->album_type, buffer->byte_order); mhba->prev_playlist_id = get_gint32(photo_album->prev_album_id, buffer->byte_order); mhba->num_mhias = get_gint32(photo_album->num_images, buffer->byte_order); total_bytes = get_gint32 (mhba->header_len, buffer->byte_order); @@ -704,13 +704,14 @@ write_mhba (Itdb_PhotoAlbum *photo_album, iPodBuffer *buffer) total_bytes += bytes_written; for (it = photo_album->members; it != NULL; it = it->next) { - gint image_id = GPOINTER_TO_INT(it->data); + Itdb_Artwork *photo = it->data; + g_return_val_if_fail (photo, -1); sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } - bytes_written = write_mhia (image_id, sub_buffer); + bytes_written = write_mhia (photo->id, sub_buffer); ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; diff --git a/src/db-itunes-parser.h b/src/db-itunes-parser.h index 344efa4..1b2cfff 100644 --- a/src/db-itunes-parser.h +++ b/src/db-itunes-parser.h @@ -612,22 +612,26 @@ struct _MhbaHeader { unsigned char header_id[4]; gint32 header_len; gint32 total_len; - gint32 num_mhods; /* number of Data Objects in the List, probably always 1 */ - gint32 num_mhias; /* number of pictures in the album */ - gint32 playlist_id; /* starts out at $64 and increments by 1 */ - gint32 unknown2; /* unknown, seems to be always 0 */ - gint16 unknown3; /* unknown, seems to be always 0 */ - gchar master; - /* FIXME: not sure if I have these right; iPod doesn't seem to listen to them */ - guint8 playmusic; - guint8 repeat; - guint8 random; - guint8 show_titles; - guint8 transition_direction; - gint32 slide_duration; - gint32 transition_duration; - gint32 unknown4; - gint32 unknown5; + gint32 num_mhods; /* number of Data Objects in the List, + probably always 1 */ + gint32 num_mhias; /* number of pictures in the album */ + gint32 playlist_id;/* starts out at $64 and increments by 1 */ + gint32 unknown2; /* unknown, seems to be always 0 */ + gint16 unknown3; /* unknown, seems to be always 0 */ + gchar album_type; /* 1 = master photo list ("Photo Library"), + 2 = normal album, sometimes 4 and 5 */ + guint8 playmusic; /* play music during slideshow (from iPhoto setting) */ + guint8 repeat; /* repeat the slideshow (from iPhoto setting) */ + guint8 random; /* show the slides in random order (from iPhoto + setting) */ + guint8 show_titles;/* show slide captions (from iPhoto setting) */ + guint8 transition_direction; /* 0=none, 1=left-to-right, + 2=right-to-left, 3=top-to-bottom, + 4=bottom-to-top (from iPhoto setting) */ + gint32 slide_duration; /* in seconds (from iPhoto setting) */ + gint32 transition_duration; /* in milliseconds (from iPhoto setting) */ + gint32 unk044; + gint32 unk048; gint64 song_id; gint32 prev_playlist_id; /* the id of the previous playlist */ unsigned char padding[]; @@ -656,7 +660,7 @@ struct _MhiaHeader { gint32 total_len; /* probably the size of the header and all child records; * as there aren't any child records this is equal to header length */ gint32 unknown1; /* seems to be zero */ - gint32 image_id; /* the id of the mhii record this mhia refers to */ + guint32 image_id; /* the id of the mhii record this mhia refers to */ unsigned char padding[]; }; @@ -1,4 +1,4 @@ -/* Time-stamp: <2006-09-23 21:25:40 jcs> +/* Time-stamp: <2006-10-29 15:03:21 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -70,74 +70,6 @@ typedef struct _Itdb_IpodInfo Itdb_IpodInfo; /* ------------------------------------------------------------ *\ * - * Thumbnail-relevant definitions - * -\* ------------------------------------------------------------ */ - -/* Types of thumbnails in Itdb_Image */ -typedef enum { - ITDB_THUMB_COVER_SMALL, - ITDB_THUMB_COVER_LARGE, - ITDB_THUMB_PHOTO_SMALL, - ITDB_THUMB_PHOTO_LARGE, - ITDB_THUMB_PHOTO_FULL_SCREEN, - ITDB_THUMB_PHOTO_TV_SCREEN -} ItdbThumbType; - - -/* The Itdb_Thumb structure can represent two slightly different - thumbnails: - - a) a thumbnail before it's transferred to the iPod. - - offset and size are 0 - - width and height, if unequal 0, will indicate the size on the - iPod. width and height are set the first time a pixbuf is - requested for this thumbnail. - - type is set according to the type this thumbnail represents - - filename point to a 'real' image file OR image_data and - image_data_len are set. - - b) a thumbnail (big or small) stored on a database in the iPod. In - these cases, id corresponds to the ID originally used in the - database, filename points to a .ithmb file on the iPod - */ -struct _Itdb_Thumb { - ItdbThumbType type; - gchar *filename; - guchar *image_data; /* holds the thumbnail data of - non-transfered thumbnails when - filename == NULL */ - gsize image_data_len; /* length of data */ - guint32 offset; - guint32 size; - gint16 width; - gint16 height; - gint16 horizontal_padding; - gint16 vertical_padding; -}; - -struct _Itdb_Artwork { - GList *thumbnails; /* list of Itdb_Thumbs */ - guint32 artwork_size; /* Size in bytes of the original source image */ - guint32 id; /* Artwork id used by photoalbums, starts at - * 0x40... libgpod will set this on sync. */ - gint32 creation_date; /* Date the image was created */ - /* below is for use by application */ - guint64 usertype; - gpointer userdata; - /* function called to duplicate userdata */ - ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ - ItdbUserDataDestroyFunc userdata_destroy; -}; - - -/* ------------------------------------------------------------ *\ - * * iPod model-relevant definitions * \* ------------------------------------------------------------ */ @@ -459,24 +391,84 @@ struct _SPLRules /* ------------------------------------------------------------ *\ * - * iTunesDB, Playlists, Tracks + * iTunesDB, Playlists, Tracks, PhotoDB, Artwork, Thumbnails * \* ------------------------------------------------------------ */ /* one star is how much (track->rating) */ #define ITDB_RATING_STEP 20 +/* Types of thumbnails in Itdb_Image */ +typedef enum { + ITDB_THUMB_COVER_SMALL, + ITDB_THUMB_COVER_LARGE, + ITDB_THUMB_PHOTO_SMALL, + ITDB_THUMB_PHOTO_LARGE, + ITDB_THUMB_PHOTO_FULL_SCREEN, + ITDB_THUMB_PHOTO_TV_SCREEN +} ItdbThumbType; + + +/* The Itdb_Thumb structure can represent two slightly different + thumbnails: + + a) a thumbnail before it's transferred to the iPod. + + offset and size are 0 + + width and height, if unequal 0, will indicate the size on the + iPod. width and height are set the first time a pixbuf is + requested for this thumbnail. + + type is set according to the type this thumbnail represents + + filename point to a 'real' image file OR image_data and + image_data_len are set. + + b) a thumbnail (big or small) stored on a database in the iPod. In + these cases, id corresponds to the ID originally used in the + database, filename points to a .ithmb file on the iPod + */ +struct _Itdb_Thumb { + ItdbThumbType type; + gchar *filename; + guchar *image_data; /* holds the thumbnail data of + non-transfered thumbnails when + filename == NULL */ + gsize image_data_len; /* length of data */ + guint32 offset; + guint32 size; + gint16 width; + gint16 height; + gint16 horizontal_padding; + gint16 vertical_padding; +}; + +struct _Itdb_Artwork { + GList *thumbnails; /* list of Itdb_Thumbs */ + guint32 artwork_size; /* Size in bytes of the original source image */ + guint32 id; /* Artwork id used by photoalbums, starts at + * 0x40... libgpod will set this on sync. */ + gint32 creation_date; /* Date the image was created */ + /* below is for use by application */ + guint64 usertype; + gpointer userdata; + /* functions called to duplicate/free userdata */ + ItdbUserDataDuplicateFunc userdata_duplicate; + ItdbUserDataDestroyFunc userdata_destroy; +}; + + struct _Itdb_PhotoDB { - GList *photos; - GList *photoalbums; + GList *photos; /* (Itdb_Artwork *) */ + GList *photoalbums; /* (Itdb_PhotoAlbum *) */ Itdb_Device *device;/* iPod device info */ /* below is for use by application */ guint64 usertype; gpointer userdata; - /* function called to duplicate userdata */ + /* functions called to duplicate/free userdata */ ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ ItdbUserDataDestroyFunc userdata_destroy; }; @@ -491,26 +483,26 @@ struct _Itdb_iTunesDB /* below is for use by application */ guint64 usertype; gpointer userdata; - /* function called to duplicate userdata */ + /* functions called to duplicate/free userdata */ ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ ItdbUserDataDestroyFunc userdata_destroy; }; struct _Itdb_PhotoAlbum { gchar *name; /* name of photoalbum in UTF8 */ - GList *members; /* photos in album (Track *) */ + GList *members; /* photos in album (Itdb_Artwork *) */ gint num_images; /* number of photos in album */ - gint master; /* 0x01 for master, 0x00 otherwise */ - gint album_id; - gint prev_album_id; + gint album_type; /* 0x01 for master (Photo Library), + 0x02 otherwise */ + /* set automatically at time of writing the PhotoDB */ + gint32 album_id; + gint32 prev_album_id; /* below is for use by application */ guint64 usertype; gpointer userdata; - /* function called to duplicate userdata */ + /* functions called to duplicate/free userdata */ ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ ItdbUserDataDestroyFunc userdata_destroy; }; @@ -550,9 +542,8 @@ struct _Itdb_Playlist /* below is for use by application */ guint64 usertype; gpointer userdata; - /* function called to duplicate userdata */ + /* functions called to duplicate/free userdata */ ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ ItdbUserDataDestroyFunc userdata_destroy; }; @@ -732,7 +723,7 @@ struct _Itdb_Track 0x000c, AAC songs are always 0x0033, Audible files are 0x0029, WAV files are 0x0. itdb will attempt to set this value when adding a - track. */ + track. */ guint16 unk146; /* unknown, but appears to be 1 if played at least once in iTunes and 0 otherwise. */ guint32 unk148; /* unknown - used for Apple Store DRM songs @@ -791,9 +782,8 @@ struct _Itdb_Track /* below is for use by application */ guint64 usertype; gpointer userdata; - /* function called to duplicate userdata */ + /* functions called to duplicate/free userdata */ ItdbUserDataDuplicateFunc userdata_duplicate; - /* function called to free userdata */ ItdbUserDataDestroyFunc userdata_destroy; }; /* (gtkpod note: don't forget to add fields read from the file to @@ -939,7 +929,7 @@ void itdb_spl_update (Itdb_Playlist *spl); void itdb_spl_update_all (Itdb_iTunesDB *itdb); void itdb_spl_update_live (Itdb_iTunesDB *itdb); -/* thumbnails functions */ +/* thumbnails functions for coverart */ /* itdb_track_... */ gboolean itdb_track_set_thumbnails (Itdb_Track *track, const gchar *filename); @@ -948,25 +938,38 @@ gboolean itdb_track_set_thumbnails_from_data (Itdb_Track *track, gsize image_data_len); void itdb_track_remove_thumbnails (Itdb_Track *track); -/* photoalbum functions */ +/* photoalbum functions -- see itdb_photoalbum.c for instructions on + * how to use. */ Itdb_PhotoDB *itdb_photodb_parse (const gchar *mp, GError **error); -gboolean itdb_photodb_add_photo (Itdb_PhotoDB *db, - const gchar *albumname, - const gchar *filename); -gboolean itdb_photodb_add_photo_from_data (Itdb_PhotoDB *db, - const gchar *albumname, - const guchar *image_data, - gsize image_data_len); -Itdb_PhotoAlbum *itdb_photodb_photoalbum_new (Itdb_PhotoDB *db, - const gchar *album_name); -Itdb_PhotoDB *itdb_photodb_new (void); +Itdb_Artwork *itdb_photodb_add_photo (Itdb_PhotoDB *db, const gchar *filename, + GError **error); +Itdb_Artwork *itdb_photodb_add_photo_from_data (Itdb_PhotoDB *db, + const guchar *image_data, + gsize image_data_len, + GError **error); +void itdb_photodb_photoalbum_add_photo (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + Itdb_Artwork *photo); +Itdb_PhotoAlbum *itdb_photodb_photoalbum_create (Itdb_PhotoDB *db, + const gchar *albumname, + gint pos); +Itdb_PhotoDB *itdb_photodb_create (const gchar *mountpoint); void itdb_photodb_free (Itdb_PhotoDB *photodb); gboolean itdb_photodb_write (Itdb_PhotoDB *db, GError **error); -void itdb_photodb_photoalbum_free (Itdb_PhotoAlbum *pa); -gboolean itdb_photodb_remove_photo (Itdb_PhotoDB *db, - const gint photo_id ); - -/* itdb_artwork_... */ +void itdb_photodb_remove_photo (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + Itdb_Artwork *photo); +void itdb_photodb_photoalbum_remove (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + gboolean remove_pics); +Itdb_PhotoAlbum *itdb_photodb_photoalbum_by_name(Itdb_PhotoDB *db, + const gchar *albumname ); + +/* itdb_artwork_... -- you probably won't need many of these (probably + * with the exception of itdb_artwork_get_thumb_by_type() and + * itdb_thumb_get_gdk_pixbuf() probably). Use the itdb_photodb_...() + * functions when adding photos, and the itdb_track_...() functions + * when adding coverart to audio. */ Itdb_Artwork *itdb_artwork_new (void); Itdb_Artwork *itdb_artwork_duplicate (Itdb_Artwork *artwork); void itdb_artwork_free (Itdb_Artwork *artwork); @@ -983,7 +986,7 @@ void itdb_artwork_remove_thumbnail (Itdb_Artwork *artwork, Itdb_Thumb *thumb); void itdb_artwork_remove_thumbnails (Itdb_Artwork *artwork); /* itdb_thumb_... */ -/* the following funciton returns a pointer to a GdkPixbuf if +/* the following function returns a pointer to a GdkPixbuf if gdk-pixbuf is installed -- a NULL pointer otherwise. */ gpointer itdb_thumb_get_gdk_pixbuf (Itdb_Device *device, Itdb_Thumb *thumb); @@ -997,7 +1000,7 @@ guint64 itdb_time_get_mac_time (void); time_t itdb_time_mac_to_host (guint64 mactime); guint64 itdb_time_host_to_mac (time_t time); -/* Initialise a blank ipod */ +/* Initialize a blank ipod */ gboolean itdb_init_ipod (const gchar *mountpoint, const gchar *model_number, const gchar *ipod_name, diff --git a/src/itdb_photoalbum.c b/src/itdb_photoalbum.c index 003222d..4a06a28 100644 --- a/src/itdb_photoalbum.c +++ b/src/itdb_photoalbum.c @@ -1,3 +1,31 @@ +/* Time-stamp: <2006-10-22 20:19:45 jcs> +| +| Copyright (C) 2002-2006 Jorg Schuler <jcsjcs at users sourceforge net> +| Part of the gtkpod project. +| +| URL: http://www.gtkpod.org/ +| URL: http://gtkpod.sourceforge.net/ +| +| The code contained in this file is free software; you can redistribute +| it and/or modify it under the terms of the GNU Lesser General Public +| License as published by the Free Software Foundation; either version +| 2.1 of the License, or (at your option) any later version. +| +| This file is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +| Lesser General Public License for more details. +| +| You should have received a copy of the GNU Lesser General Public +| License along with this code; if not, write to the Free Software +| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +| +| iTunes and iPod are trademarks of Apple +| +| This product is not supported/written/published by Apple! +| +| $Id$ +*/ #include <config.h> #include "itdb_private.h" @@ -9,6 +37,59 @@ #include <glib/gi18n-lib.h> +/* Short summary: + + itdb_photodb_parse(): + Read an existing PhotoDB. + + itdb_photodb_create(): + Create a new Itdb_PhotoDB structure. The Photo Library Album is + (first album) is created automatically. + + itdb_photodb_add_photo(), itdb_photodb_add_photo_from_data(): + Add a photo to the PhotoDB (from file or from a chunk of + memory). It is automatically added to the Photo Library Album + (first album), which is created if it does not exist already. + + itdb_photodb_photoalbum_craete(): + Create and add a new photoalbum. + + itdb_photodb_photoalbum_add_photo(): + Add a photo (Itdb_Artwork) to an existing photoalbum. + + itdb_photodb_photoalbum_remove(): + Remove an existing photoalbum. Pictures can be kept in the + Photo Library or automatically removed as well. + + itdb_photodb_remove_photo(): + Remove a photo either from a photoalbum or completely from the database. + + itdb_photodb_write(): + Write out your PhotoDB. + + itdb_photodb_free(): + Free all memory taken by the PhotoDB. + + itdb_photodb_photoalbum_by_name(): + Find the first photoalbum with a given name. + + + If you cannot add photos because your iPod is not recognized, you + may have to set the iPod model by calling + + itdb_device_set_sysinfo (db->device, "ModelNumStr", model); + + For example, "MA450" would stand for an 80 GB 6th generation iPod + Video. See itdb_device.c for a list of supported models. + + This information will be written to the iPod when the PhotoDB is + saved (itdb_device_write_sysinfo() is called). +*/ + + +static Itdb_PhotoDB *itdb_photodb_new (void); +static void itdb_photodb_photoalbum_free (Itdb_PhotoAlbum *pa); + /* Set @error with standard error message */ static void error_no_photos_dir (const gchar *mp, GError **error) { @@ -146,14 +227,36 @@ Itdb_PhotoDB *itdb_photodb_parse (const gchar *mp, GError **error) /** - * itdb_photodb_new: + * itdb_photodb_create: * - * Creates a new Itdb_PhotoDB + * @mountpoint: mountpoint or NULL. + * + * Creates a new Itdb_PhotoDB. If mountpoint is NULL, you will have to + * set it manually later by calling itdb_device_set_mountpoint(). * * Return value: a newly created Itdb_PhotoDB to be freed with - * itdb_photodb_free() when it's no longer needed + * itdb_photodb_free() when it's no longer needed. The Photo Library + * Album is created automatically. **/ -Itdb_PhotoDB *itdb_photodb_new (void) +Itdb_PhotoDB *itdb_photodb_create (const gchar *mountpoint) +{ + Itdb_PhotoDB *photodb = itdb_photodb_new (); + Itdb_PhotoAlbum *album; + + album = itdb_photodb_photoalbum_create (photodb, _("Photo Libarary"), -1); + album->album_type = 1; /* Photo Library */ + + if (mountpoint) + { + itdb_device_set_mountpoint (photodb->device, mountpoint); + } + + return photodb; +} + + + +static Itdb_PhotoDB *itdb_photodb_new (void) { Itdb_PhotoDB *photodb; @@ -164,6 +267,7 @@ Itdb_PhotoDB *itdb_photodb_new (void) } + /** * itdb_photodb_free: * @photodb: an #Itdb_PhotoDB @@ -207,181 +311,353 @@ G_GNUC_INTERNAL gint itdb_get_free_photo_id ( Itdb_PhotoDB *db ) return photo_id + 1; } -static gint itdb_get_free_photoalbum_id ( Itdb_PhotoDB *db ) +static void itdb_photodb_photoalbum_free (Itdb_PhotoAlbum *album) { - gint album_id = 0; - GList *it; + if (album) + { + g_free (album->name); + g_list_free (album->members); - for (it = db->photoalbums; it != NULL; it = it->next) { - Itdb_PhotoAlbum *album; + if (album->userdata && album->userdata_destroy) + (*album->userdata_destroy) (album->userdata); - album = (Itdb_PhotoAlbum *)it->data; - if( album->album_id > album_id ) - album_id = album->album_id; - } - return album_id + 1; + g_free (album); + } } -static Itdb_PhotoAlbum *itdb_get_photoalbum ( Itdb_PhotoDB *db, const gchar *albumname ) + +/* called by itdb_photodb_add_photo() and + itdb_photodb_add_photo_from_data() */ +static Itdb_Artwork *itdb_photodb_add_photo_internal (Itdb_PhotoDB *db, + const gchar *filename, + const guchar *image_data, + gsize image_data_len, + GError **error) { - GList *it; +#ifdef HAVE_GDKPIXBUF + gboolean result; + Itdb_Artwork *artwork; + Itdb_PhotoAlbum *album; + const Itdb_ArtworkFormat *format; - if( strcmp( albumname, "master" ) == 0 ) - return g_list_nth_data (db->photoalbums, 0); + g_return_val_if_fail (db, NULL); + g_return_val_if_fail (db->device, NULL); + g_return_val_if_fail (filename || image_data, NULL); + g_return_val_if_fail (!(image_data && (image_data_len == 0)), NULL); - for (it = db->photoalbums; it != NULL; it = it->next) { - Itdb_PhotoAlbum *album; + if (!ipod_supports_photos (db->device)) + { + const Itdb_IpodInfo *ipodinfo = itdb_device_get_ipod_info (db->device); + const gchar *model, *generation; - album = (Itdb_PhotoAlbum *)it->data; - if( strcmp(album->name, albumname) == 0 ) - return album; + if (!ipodinfo) + { + g_set_error (error, 0, -1, + _("You need to specify the iPod model used before photos can be added.")); + return NULL; + /* For information: The model is set by calling the rather + unintuitive function itdb_device_set_sysinfo as + follows: + + itdb_device_set_sysinfo (db->device, "ModelNumStr", model); + + For example, "MA450" would stand for an 80 GB 6th + generation iPod Video. See itdb_device.c for a list of + supported models. + + This information will be written to the iPod when the + PhotoDB is saved (itdb_device_write_sysinfo() is called). + */ } - return (Itdb_PhotoAlbum *)NULL; -} + model = itdb_info_get_ipod_model_name_string (ipodinfo->ipod_model); + generation = itdb_info_get_ipod_generation_string (ipodinfo->ipod_generation); + g_return_val_if_fail (model && generation, NULL); + g_set_error (error, 0, -1, + _("Your iPod does not seem to support photos. Maybe you need to specify the correct iPod model number? It is currently set to 'x%s' (%s/%s)."), + ipodinfo->model_number, generation, model); + return NULL; + } -void itdb_photodb_photoalbum_free (Itdb_PhotoAlbum *pa) -{ - if (pa) + /* check if filename is valid */ + if (filename) { - g_free (pa->name); - g_list_free (pa->members); - - if (pa->userdata && pa->userdata_destroy) - (*pa->userdata_destroy) (pa->userdata); - - g_free (pa); + struct stat statbuf; + if (g_stat (filename, &statbuf) != 0) + { + g_set_error (error, 0, -1, + _("Could not access file '%s'. Photo not added.")); + return NULL; + } } -} - -static gboolean itdb_photodb_add_photo_internal (Itdb_PhotoDB *db, - const gchar *albumname, - const gchar *filename, - const guchar *image_data, - gsize image_data_len) -{ - gboolean result; - Itdb_Artwork *artwork; - Itdb_PhotoAlbum *photoalbum; - const Itdb_ArtworkFormat *format; - gint photo_id; - g_return_val_if_fail (db, FALSE); + artwork = itdb_artwork_new (); - artwork = itdb_artwork_new (); + /* Add a thumbnail for every supported format */ + format = itdb_device_get_artwork_formats (db->device); + g_return_val_if_fail (format, NULL); - photo_id = itdb_get_free_photo_id( db ); - artwork->id = photo_id; - - /* Add a thumbnail for every supported format */ - format = itdb_device_get_artwork_formats(db->device); - for( result = TRUE; format->type != -1 && result == TRUE; format++) + for(result = TRUE; format->type != -1 && result == TRUE; format++) + { + if((format->type == ITDB_THUMB_COVER_SMALL) || + (format->type == ITDB_THUMB_COVER_LARGE)) + continue; + if (filename) { - if((format->type == ITDB_THUMB_COVER_SMALL) || - (format->type == ITDB_THUMB_COVER_LARGE)) - continue; - if (filename) - { - result = itdb_artwork_add_thumbnail (artwork, - format->type, - filename); - } - if (image_data) - { - result = itdb_artwork_add_thumbnail_from_data (artwork, - format->type, - image_data, - image_data_len); - } + result = itdb_artwork_add_thumbnail (artwork, + format->type, + filename); } - - if (result != TRUE) + if (image_data) { - itdb_artwork_remove_thumbnails (artwork); - return result; + result = itdb_artwork_add_thumbnail_from_data (artwork, + format->type, + image_data, + image_data_len); } - db->photos = g_list_append (db->photos, artwork); + } - photoalbum = itdb_get_photoalbum( db, albumname ); - if( photoalbum == NULL ) - photoalbum = itdb_photodb_photoalbum_new( db, albumname ); - photoalbum->num_images++; - photoalbum->members = g_list_append (photoalbum->members, GINT_TO_POINTER(photo_id)); + if (result != TRUE) + { + itdb_artwork_free (artwork); + g_set_error (error, 0, -1, + _("Unexpected error in itdb_photodb_add_photo_internal() while adding photo, please report.")); + return NULL; + } - return result; + /* Add artwork to the list of photos */ + db->photos = g_list_append (db->photos, artwork); + + /* Add artwork to the first playlist */ + album = itdb_photodb_photoalbum_by_name (db, NULL); + if (!album) + { + album = itdb_photodb_photoalbum_create (db, _("Photo Libarary"), -1); + album->album_type = 1; /* Photo Library */ + } + itdb_photodb_photoalbum_add_photo (db, album, artwork); + + return artwork; +#else + g_set_error (error, 0, -1, + _("Library compiled without gkdpixbuf support. Picture support is disabled.")); + return NULL; +#endif } -gboolean itdb_photodb_add_photo (Itdb_PhotoDB *db, - const gchar *albumname, - const gchar *filename) + +/** + * itdb_photodb_add_photo: + * @db: the #Itdb_PhotoDB to add the photo to. + * @filename: file with the photo to add. + * @error: return location for a #GError or NULL + * + * Add a photo to the PhotoDB. The photo is automatically added to the + * first Photoalbum, which by default contains a list of all photos in + * the database. If no Photoalbums exist one is created automatically. + * + * Return value: a pointer to the added photo. + **/ +Itdb_Artwork *itdb_photodb_add_photo (Itdb_PhotoDB *db, + const gchar *filename, + GError **error) { g_return_val_if_fail (db, FALSE); g_return_val_if_fail (filename, FALSE); - return itdb_photodb_add_photo_internal (db, albumname, filename, - NULL, 0); + return itdb_photodb_add_photo_internal (db, filename, NULL, 0, error); } -gboolean itdb_photodb_add_photo_from_data (Itdb_PhotoDB *db, - const gchar *albumname, - const guchar *image_data, - gsize image_data_len) +/** + * itdb_photodb_add_photo_from_data: + * @db: the #Itdb_PhotoDB to add the photo to. + * @filename: file with the photo to add. + * @error: return location for a #GError or NULL + * + * Add a photo to the PhotoDB. The photo is automatically added to the + * first Photoalbum, which by default contains a list of all photos in + * the database. If no Photoalbums exist one is created automatically. + **/ +Itdb_Artwork *itdb_photodb_add_photo_from_data (Itdb_PhotoDB *db, + const guchar *image_data, + gsize image_data_len, + GError **error) { g_return_val_if_fail (db, FALSE); g_return_val_if_fail (image_data, FALSE); - return itdb_photodb_add_photo_internal (db, albumname, NULL, - image_data, image_data_len); + return itdb_photodb_add_photo_internal (db, NULL, image_data, image_data_len, + error); } -gboolean itdb_photodb_remove_photo (Itdb_PhotoDB *db, - const gint photo_id ) +/** + * itdb_photodb_remove_photo: + * @db: the #Itdb_PhotoDB to remove the photo from + * @album: the album to remove the photo from. If album is NULL, then + * it will first be removed from all photoalbums and then from the + * photo database as well. + * @photo: #Itdb_Artwork (photo) to remove. + * + * Remove photo. If @album is not the first photoalbum, the photo will + * be removed from that album only. If @album is NULL or the first + * photoalbum (Photo Library), the photo will be removed from all + * albums and the #Itdb_PhotoDB. + * + * @photo will be freed and can no longer be used if removed from the + * first photoalbum. + */ +void itdb_photodb_remove_photo (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + Itdb_Artwork *photo) { - gboolean result = TRUE; - GList *it; + GList *it; - g_return_val_if_fail (db, FALSE); + g_return_if_fail (db); - /* Remove the photo from the image list */ - for (it = db->photos; it != NULL; it = it->next) { - Itdb_Artwork *artwork; + /* If album==NULL, or album is the master album, remove from all + * albums */ + if ((album == NULL) || (album == g_list_nth_data (db->photoalbums, 0))) + { + /* Remove the photo from any albums containing it */ + for (it = db->photoalbums; it != NULL; it = it->next) + { + Itdb_PhotoAlbum *_album = it->data; + while (g_list_find (_album->members, photo)) + { + _album->members = g_list_remove (_album->members, photo); + --_album->num_images; + } + } + /* Remove the photo from the image list */ + db->photos = g_list_remove (db->photos, photo); + /* Free the photo */ + itdb_artwork_free (photo); + } + /* If album is specified, only remove it from that album */ + else + { + album->members = g_list_remove (album->members, photo); + --album->num_images; + } +} - artwork = (Itdb_Artwork *)it->data; - if( artwork->id == photo_id ) { - db->photos = g_list_remove (db->photos, artwork); - break; - } - } +/** + * itdb_photodb_photoalbum_by_name: + * Return a pointer to the first photoalbum named @albumname + * + * @db: the #Itdb_PhotoDB to retrieve the album from + * @albumname: the name of the photoalbum to get or NULL for the + * master photoalbum. + * + * Returns the photoalbum if found, else NULL + */ +Itdb_PhotoAlbum *itdb_photodb_photoalbum_by_name (Itdb_PhotoDB *db, const gchar *albumname) +{ + GList *it; + + if( albumname == NULL ) + return g_list_nth_data (db->photoalbums, 0); - /* Remove the photo from any albums containing it */ for (it = db->photoalbums; it != NULL; it = it->next) { Itdb_PhotoAlbum *album; album = (Itdb_PhotoAlbum *)it->data; - album->members = g_list_remove (album->members, GINT_TO_POINTER(photo_id)); - album->num_images = g_list_length( album->members ); + if( strcmp(album->name, albumname) == 0 ) + return album; } - return result; + return NULL; +} + +/** + * itdb_photodb_remove_photoalbum: + * @db: the #Itdb_PhotoDB to apply changes to + * @album: the album to be removed from the database + * @remove_pics: TRUE to remove pics in that album permanently from + * the database. + * + * Remove @album from the Photo Database. If remove_pics is TRUE, + * remove all photos contained in @album from the Photo Database. + * + * Memory used by the removed album will be freed and the album cannot + * be accessed any more. + **/ +void itdb_photodb_photoalbum_remove (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + gboolean remove_pics) +{ + GList *it; + + g_return_if_fail (db); + g_return_if_fail (album); + + /* if remove_pics, iterate over the photos within that album + * and remove them from the database */ + if (remove_pics) + { + for (it = album->members; it != NULL; it = it->next ) + { + Itdb_Artwork *photo = it->data; + itdb_photodb_remove_photo (db, NULL, photo); + } + } + db->photoalbums = g_list_remove (db->photoalbums, album); + itdb_photodb_photoalbum_free (album); +} + +/** + * itdb_photodb_photoalbum_add_photo: + * @db: the #Itdb_PhotoDB to act on + * @album: the #Itdb_PhotoAlbum to add the photo to + * @photo: a pointer to the photo (#Itdb_Artwork) to add to the album + * + * Adds a photo already in the library to the specified album + * @album. Photos are automatically added to the first album (Photo + * Library) when calling itdb_photodb_add_photo() or + * itdb_photodb_add_photo_from_data(), so you don't have to use this + * function to add them there. + * + */ + +void itdb_photodb_photoalbum_add_photo (Itdb_PhotoDB *db, + Itdb_PhotoAlbum *album, + Itdb_Artwork *photo) +{ + g_return_if_fail (db); + g_return_if_fail (album); + g_return_if_fail (photo); + + album->members = g_list_append (album->members, photo); + ++album->num_images; } -Itdb_PhotoAlbum *itdb_photodb_photoalbum_new (Itdb_PhotoDB *db, - const gchar *album_name) + +/** + * itdb_photodb_photoalbum_create: + * @db: The database to create a new album in + * @album_name: the name of the new album + * @pos: position where to insert the newly created album (-1 for + * append to end). + * + * Return value: the album which was created and added. + */ +Itdb_PhotoAlbum *itdb_photodb_photoalbum_create (Itdb_PhotoDB *db, + const gchar *albumname, + gint pos) { - Itdb_PhotoAlbum *photoalbum; + Itdb_PhotoAlbum *album; - g_return_val_if_fail (db, FALSE); - g_return_val_if_fail (album_name, FALSE); + g_return_val_if_fail (db, NULL); + g_return_val_if_fail (albumname, NULL); - photoalbum = g_new0 (Itdb_PhotoAlbum, 1); - photoalbum->album_id = itdb_get_free_photoalbum_id( db ); - photoalbum->prev_album_id = photoalbum->album_id - 1; - photoalbum->name = g_strdup( album_name ); - db->photoalbums = g_list_append (db->photoalbums, photoalbum); + album = g_new0 (Itdb_PhotoAlbum, 1); + album->album_type = 2; /* normal album, set to 1 for Photo Library */ + album->name = g_strdup(albumname); + db->photoalbums = g_list_insert (db->photoalbums, album, pos); - return photoalbum; + return album; } /** @@ -398,7 +674,9 @@ Itdb_PhotoAlbum *itdb_photodb_photoalbum_new (Itdb_PhotoDB *db, **/ gboolean itdb_photodb_write (Itdb_PhotoDB *photodb, GError **error) { - gboolean result; + gint result; + GList *gl; + gint32 id, prev_id; g_return_val_if_fail (photodb, FALSE); g_return_val_if_fail (photodb->device, FALSE); @@ -406,12 +684,41 @@ gboolean itdb_photodb_write (Itdb_PhotoDB *photodb, GError **error) if (photodb->device->byte_order == 0) itdb_device_autodetect_endianess (photodb->device); + /* set up photo_ids */ + id = 0x40; + for (gl=photodb->photos; gl; gl=gl->next) + { + Itdb_Artwork *photo = gl->data; + g_return_val_if_fail (photo, FALSE); + photo->id = id; + ++id; + } + /* set up album_ids -- this is how my iPod Nano does it... */ + prev_id = 0x64; + id = prev_id + g_list_length (photodb->photos); + for (gl=photodb->photoalbums; gl; gl=gl->next) + { + Itdb_PhotoAlbum *album = gl->data; + g_return_val_if_fail (album, FALSE); + album->album_id = id; + album->prev_album_id = prev_id; + ++id; + ++prev_id; + if (gl != photodb->photoalbums) + { /* except for the first album */ + prev_id += g_list_length (album->members); + } + } + result = ipod_write_photo_db (photodb); /* Write SysInfo file if it has changed */ - if (!(*error) && photodb->device->sysinfo_changed) + if (!error || !(*error)) { - itdb_device_write_sysinfo (photodb->device, error); + if (photodb->device->sysinfo_changed) + { + itdb_device_write_sysinfo (photodb->device, error); + } } if (result == -1) diff --git a/tests/test-photos.c b/tests/test-photos.c index a63d51b..36c3bf5 100644 --- a/tests/test-photos.c +++ b/tests/test-photos.c @@ -31,6 +31,34 @@ #include <gdk-pixbuf/gdk-pixbuf.h> #include <glib/gi18n-lib.h> +static void usage (int argc, char **argv) +{ +/* gchar *name = argv[0];*/ + gchar *name = "test-photos"; + + g_print (_("Usage to add photos:\n %s add <mountpoint> <albumname> [<filename(s)>]\n <albumname> should be set to 'NULL' to add photos to the master photo album\n (Photo Library) only. If you don't specify any filenames an empty album will\n be created.\n"), name); + g_print (_("Usage to dump all photos to <output_dir>:\n %s dump <mountpoint> <output_dir>\n"), name); + g_print (_("Usage to list all photos IDs to stdout:\n %s list <mountpoint>\n"), name); + g_print (_("Usage to remove photo IDs from Photo Library:\n %s remove <mountpoint> <albumname> [<ID(s)>]\n <albumname> should be set to 'NULL' to to remove photos from the iPod\n altogether. If you don't specify any IDs, the photoalbum will be removed\n instead.\n WARNING: IDs may change when writing the PhotoDB file.\n"), name); +} + +/* Retrieve the photo whose ID is @id */ +static Itdb_Artwork *get_photo_by_id (Itdb_PhotoDB *db, guint32 id) +{ + GList *gl; + + g_return_val_if_fail (db, NULL); + + for (gl=db->photos; gl; gl=gl->next) + { + Itdb_Artwork *photo = gl->data; + g_return_val_if_fail (photo, NULL); + + if (photo->id == id) return photo; + } + return NULL; +} + static void save_itdb_thumb (Itdb_PhotoDB *itdb, Itdb_Thumb *thumb, const gchar *filename) @@ -69,24 +97,6 @@ dump_thumbs (Itdb_PhotoDB *db, Itdb_Artwork *artwork, } static void -dump_artwork (Itdb_PhotoDB *db, gint photo_id, - const gchar *album_name, const gchar *dir) -{ - GList *it; - - for (it = db->photos; it != NULL; it = it->next) { - Itdb_Artwork *artwork; - - artwork = (Itdb_Artwork *)it->data; - g_return_if_fail (artwork); - if( artwork->id == photo_id ) { - dump_thumbs (db, artwork, album_name, dir); - break; - } - } -} - -static void dump_albums (Itdb_PhotoDB *db, const gchar *dir) { GList *it; @@ -99,91 +109,304 @@ dump_albums (Itdb_PhotoDB *db, const gchar *dir) g_return_if_fail (album); for (it2 = album->members; it2 != NULL; it2 = it2->next) { - gint photo_id = GPOINTER_TO_INT(it2->data); - dump_artwork (db, photo_id, album->name, dir); + Itdb_Artwork *photo = it2->data; + dump_thumbs (db, photo, album->name, dir); } } } -int -main (int argc, char **argv) + +static int do_dump (int argc, char **argv) +{ + GError *error = NULL; + Itdb_PhotoDB *db; + + if (argc != 4) + { + g_print (_("Wrong number of command line arguments.\n")); + usage (argc, argv); + return 1; + } + + if (!g_file_test (argv[3], G_FILE_TEST_EXISTS)) + { + if (mkdir (argv[3], 0777) == -1) + { + g_print (_("Error creating '%s' (mkdir)\n"), argv[3]); + return 1; + } + } + if (!g_file_test (argv[3], G_FILE_TEST_IS_DIR)) + { + g_print (_("Error: '%s' is not a directory\n"), argv[3]); + return 1; + } + + db = itdb_photodb_parse (argv[2], &error); + if (db == NULL) + { + if (error) + { + g_print (_("Error reading iPod photo database (%s).\n"), error->message); + g_error_free (error); + error = NULL; + } + else + { + g_print (_("Error reading iPod photo database.\n")); + } + return 1; + } + dump_albums (db, argv[3]); + itdb_photodb_free (db); + return 0; +} + +static int do_list (int argc, char **argv) +{ + GError *error = NULL; + Itdb_PhotoDB *db; + GList *gl_album; + + + if (argc != 3) + { + g_print (_("Insufficient number of command line arguments.\n")); + usage (argc, argv); + return 1; + } + + db = itdb_photodb_parse (argv[2], &error); + if (db == NULL) + { + if (error) + { + g_print (_("Error reading iPod photo database (%s).\n"), error->message); + g_error_free (error); + error = NULL; + } + else + { + g_print (_("Error reading iPod photo database.\n")); + } + return 1; + } + + for (gl_album=db->photoalbums; gl_album; gl_album=gl_album->next) + { + GList *gl_photo; + Itdb_PhotoAlbum *album = gl_album->data; + g_return_val_if_fail (album, 1); + + g_print ("%s: ", album->name?album->name:_("<Unnamed>")); + + for (gl_photo=album->members; gl_photo; gl_photo=gl_photo->next) + { + Itdb_Artwork *photo = gl_photo->data; + g_return_val_if_fail (photo, 1); + + g_print ("%d ", photo->id); + } + if (g_list_length (album->members) > 0) + { + g_print ("\n"); + } + else + { + g_print (_("<No members>\n")); + } + } + itdb_photodb_free (db); + return 0; +} + + +static int do_add (int argc, char **argv) { GError *error = NULL; + Itdb_PhotoAlbum *album = NULL; Itdb_PhotoDB *db; gint i; - if (argc < 4) { - g_print (_("Usage to add photos:\n")); - g_print (_("%s <mountpoint> <albumname> <filename(s)>\n"), argv[0]); - g_print (_("albumname should be set to 'master' to add photos to the master photo album\n")); - g_print (_("\n")); - g_print (_("Usage to dump all photos to <output_dir>:\n")); - g_print (_("%s dump <mountpoint> <output_dir>\n"), argv[0]); - return 1; + if (argc < 4) + { + g_print (_("Insufficient number of command line arguments.\n")); + usage (argc, argv); + return 1; } - setlocale (LC_ALL, ""); - g_type_init (); - if (strcmp (argv[1], "dump") == 0) + db = itdb_photodb_parse (argv[2], &error); + if (db == NULL) { - if (!g_file_test (argv[3], G_FILE_TEST_EXISTS)) + if (error) { - if (mkdir (argv[3], 0777) == -1) - { - g_print (_("Error creating '%s' (mkdir)\n"), argv[3]); - return 1; - } + g_print (_("Error reading iPod photo database (%s).\nWill attempt to create a new database.\n"), error->message); + g_error_free (error); + error = NULL; } - if (!g_file_test (argv[3], G_FILE_TEST_IS_DIR)) + else { - g_print (_("Error: '%s' is not a directory\n"), argv[3]); - return 1; + g_print (_("Error reading iPod photo database, will attempt to create a new database\n")); + } + db = itdb_photodb_create (argv[2]); + } + + /* Find or create specified photoalbum */ + if (strcmp (argv[3], "NULL") != 0) + { + album = itdb_photodb_photoalbum_by_name (db, argv[3]); + if (!album) + { + album = itdb_photodb_photoalbum_create (db, argv[3], -1); } + } - db = itdb_photodb_parse (argv[2], &error); - if (db == NULL) + for (i=4; i<argc; ++i) + { + Itdb_Artwork *photo; + + photo = itdb_photodb_add_photo (db, argv[i], &error); + if (photo == NULL) { if (error) { - g_print (_("Error reading iPod photo database (%s).\n"), error->message); + g_print (_("Error adding photo (%s) to photo database: %s\n"), + argv[i], error->message); g_error_free (error); error = NULL; } - else + } + else + { + if (album) { - g_print (_("Error reading iPod photo database.\n")); + itdb_photodb_photoalbum_add_photo (db, album, photo); } + } + } + + itdb_photodb_write (db, NULL); + itdb_photodb_free (db); + return 0; +} + + +static int do_remove (int argc, char **argv) +{ + GError *error = NULL; + Itdb_PhotoDB *db; + Itdb_PhotoAlbum *album = NULL; + + if (argc < 4) + { + g_print (_("Insufficient number of command line arguments.\n")); + usage (argc, argv); + return 1; + } + + db = itdb_photodb_parse (argv[2], &error); + if (db == NULL) + { + if (error) + { + g_print (_("Error reading iPod photo database (%s).\n"), + error->message); + g_error_free (error); + error = NULL; + } + else + { + g_print (_("Error reading iPod photo database")); + } + return 1; + } + + /* Find specified photoalbum */ + if (strcmp (argv[3], "NULL") != 0) + { + album = itdb_photodb_photoalbum_by_name (db, argv[3]); + if (!album) + { + g_print (_("Specified album '%s' not found. Aborting.\n"), + argv[3]); + itdb_photodb_free (db); + return 1; + } + } + + if (argc == 4) + { + /* Remove photoalbum altogether, but preserve pics */ + if (album == NULL) + { + g_print (_("Cannot remove Photo Libarary playlist. Aborting.\n")); + itdb_photodb_free (db); return 1; } - dump_albums (db, argv[3]); - itdb_photodb_free (db); + itdb_photodb_photoalbum_remove (db, album, FALSE); } else { - db = itdb_photodb_parse (argv[1], &error); - if (db == NULL) + /* Remove specified pictures */ + int i; + for (i=4; i<argc; ++i) { - if (error) + Itdb_Artwork *photo; + guint32 id; + + id = g_strtod (argv[i], NULL); + + photo = get_photo_by_id (db, id); + + if (photo == NULL) { - g_print (_("Error reading iPod photo database (%s).\nWill attempt to create a new database.\n"), error->message); - g_error_free (error); - error = NULL; + g_print (_("Error: could not find photo with ID <%d>. Skipping...\n"), + id); } else { - g_print (_("Error reading iPod photo database, will attempt to create a new database\n")); + itdb_photodb_remove_photo (db, album, photo); } - db = itdb_photodb_new (); - itdb_device_set_mountpoint (db->device, argv[1]); - } - for (i=3; i<argc; ++i) - { - itdb_photodb_add_photo (db, argv[2], argv[i]); } + } + + itdb_photodb_write (db, NULL); + itdb_photodb_free (db); + return 0; +} + + - itdb_photodb_write (db, NULL); - itdb_photodb_free (db); +int +main (int argc, char **argv) +{ + if (argc < 2) + { + g_print (_("Insufficient number of command line arguments.\n")); + usage (argc, argv); + return 1; + } + setlocale (LC_ALL, ""); + g_type_init (); + + if (strcmp (argv[1], "dump") == 0) + { + return do_dump (argc, argv); + } + if (strcmp (argv[1], "add") == 0) + { + return do_add (argc, argv); + } + if (strcmp (argv[1], "list") == 0) + { + return do_list (argc, argv); + } + if (strcmp (argv[1], "remove") == 0) + { + return do_remove (argc, argv); } + g_print (_("Unknown command '%s'\n"), argv[1]); + usage (argc, argv); return 0; } |