summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog59
-rw-r--r--src/db-artwork-parser.c38
-rw-r--r--src/db-artwork-writer.c7
-rw-r--r--src/db-itunes-parser.h38
-rw-r--r--src/itdb.h215
-rw-r--r--src/itdb_photoalbum.c559
-rw-r--r--tests/test-photos.c351
7 files changed, 947 insertions, 320 deletions
diff --git a/ChangeLog b/ChangeLog
index f9ed363..c454056 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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[];
};
diff --git a/src/itdb.h b/src/itdb.h
index d51fac0..e04a74a 100644
--- a/src/itdb.h
+++ b/src/itdb.h
@@ -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;
}