diff options
-rw-r--r-- | ChangeLog | 40 | ||||
-rw-r--r-- | docs/reference/tmpl/device.sgml | 19 | ||||
-rw-r--r-- | docs/reference/tmpl/itunesdb-time.sgml | 7 | ||||
-rw-r--r-- | docs/reference/tmpl/libgpod-unused.sgml | 16 | ||||
-rw-r--r-- | docs/reference/tmpl/track.sgml | 2 | ||||
-rw-r--r-- | src/db-artwork-parser.c | 14 | ||||
-rw-r--r-- | src/db-artwork-writer.c | 17 | ||||
-rw-r--r-- | src/db-itunes-parser.h | 5 | ||||
-rw-r--r-- | src/itdb.h | 28 | ||||
-rw-r--r-- | src/itdb_device.c | 80 | ||||
-rw-r--r-- | src/itdb_device.h | 9 | ||||
-rw-r--r-- | src/itdb_itunesdb.c | 330 | ||||
-rw-r--r-- | src/itdb_private.h | 13 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/test-ls.c | 32 |
15 files changed, 435 insertions, 181 deletions
@@ -1,3 +1,43 @@ +2007-04-27 Jorg Schuler <jcsjcs at users.sourceforge.net> + + * docs/reference/tmpl/device.sgml + docs/reference/tmpl/itunesdb-time.sgml + docs/reference/tmpl/libgpod-unused.sgml + docs/reference/tmpl/track.sgml + src/db-artwork-parser.c + src/db-artwork-writer.c + src/db-itunes-parser.h + src/itdb.h + src/itdb_device.c + src/itdb_device.h + src/itdb_itunesdb.c + src/itdb_private.h + tests/Makefile.am: + + Christophe's patch for automatic correction of timestamps + depending on which timezone the iPod is set to. + + ATTENTION DEVELOPERS: as a consequence all exported timestamps + are no longer guint32 mac-type timestamps but standard time_t + timestamps. This also includes the 64 bit timestamps in smart + playlists. The following functions are therefore no longer + needed and are deprecated: + + itdb_time_mac_to_host(), itdb_time_host_to_mac(): simply return + the argument without changing it. Argument and return value are + now both of type 'time_t'. + + itunesdb_time_get_mac_time(): returns the seconds passed since + Epoch in seconds and is equivalent to time(NULL). + + These functions may be removed in a future version of + libgpod. Programs linking to libgpod may need to be changed + slightly if they made any assumptions on the type of timestamps + used. This should be obvious through compile-time warnings. + + tests/test-ls.c: print a list of recently played tracks. + + 2007-04-15 Todd Zullinger <tmzullinger at users.sourceforge.net> * bindings/python/ipod.py: use the mac-style path for diff --git a/docs/reference/tmpl/device.sgml b/docs/reference/tmpl/device.sgml index 6ca9191..4323e53 100644 --- a/docs/reference/tmpl/device.sgml +++ b/docs/reference/tmpl/device.sgml @@ -27,6 +27,7 @@ These functions are for reading and setting information about the iPod. @byte_order: @sysinfo: @sysinfo_changed: +@timezone_shift: <!-- ##### FUNCTION itdb_device_new ##### --> <para> @@ -101,24 +102,6 @@ These functions are for reading and setting information about the iPod. @Returns: -<!-- ##### FUNCTION itdb_device_supports_artwork ##### --> -<para> - -</para> - -@device: -@Returns: - - -<!-- ##### FUNCTION itdb_device_supports_photo ##### --> -<para> - -</para> - -@device: -@Returns: - - <!-- ##### FUNCTION itdb_info_get_ipod_info_table ##### --> <para> diff --git a/docs/reference/tmpl/itunesdb-time.sgml b/docs/reference/tmpl/itunesdb-time.sgml index 3f75abb..aeee4fb 100644 --- a/docs/reference/tmpl/itunesdb-time.sgml +++ b/docs/reference/tmpl/itunesdb-time.sgml @@ -6,7 +6,10 @@ Helper functions to convert between Epoch time and Mac (iPod) time <!-- ##### SECTION Long_Description ##### --> <para> -The functions provide conversion between Epoch time and Mac (iPod) time +The functions provide conversion between Epoch time and Mac (iPod) time. These +functions are now obsolete and should no longer be used, libgpod automatically +converts to/from Epoch time and iPod time when writing/reading the iPod +databases </para> <!-- ##### SECTION See_Also ##### --> @@ -30,7 +33,7 @@ The functions provide conversion between Epoch time and Mac (iPod) time </para> -@mactime: +@time: @Returns: diff --git a/docs/reference/tmpl/libgpod-unused.sgml b/docs/reference/tmpl/libgpod-unused.sgml index aaf7c7f..ebb16c4 100644 --- a/docs/reference/tmpl/libgpod-unused.sgml +++ b/docs/reference/tmpl/libgpod-unused.sgml @@ -153,6 +153,22 @@ iTunesDB </para> +<!-- ##### FUNCTION itdb_device_supports_artwork ##### --> +<para> + +</para> + +@device: +@Returns: + +<!-- ##### FUNCTION itdb_device_supports_photo ##### --> +<para> + +</para> + +@device: +@Returns: + <!-- ##### FUNCTION itdb_file_error_quark ##### --> <para> diff --git a/docs/reference/tmpl/track.sgml b/docs/reference/tmpl/track.sgml index 658d51e..95c2550 100644 --- a/docs/reference/tmpl/track.sgml +++ b/docs/reference/tmpl/track.sgml @@ -59,8 +59,8 @@ information about an iPod track. @volume: @soundcheck: @time_added: -@time_played: @time_modified: +@time_played: @bookmark_time: @rating: @playcount: diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c index ecb4ce1..5474458 100644 --- a/src/db-artwork-parser.c +++ b/src/db-artwork-parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Christophe Fergeau + * Copyright (C) 2005-2007 Christophe Fergeau * * * The code contained in this file is free software; you can redistribute @@ -237,6 +237,8 @@ parse_mhii (DBParseContext *ctx, GError *error) Itdb_PhotoDB *photodb; Itdb_iTunesDB *itunesdb; guint64 dbid; + guint64 mactime; + Itdb_iTunesDB *itdb = db_get_itunesdb (ctx->db); mhii = db_parse_context_get_m_header (ctx, MhiiHeader, "mhii"); if (mhii == NULL) @@ -277,11 +279,11 @@ parse_mhii (DBParseContext *ctx, GError *error) artwork->unk028 = get_gint32 (mhii->unknown4, ctx->byte_order); artwork->rating = get_gint32 (mhii->rating, ctx->byte_order); artwork->unk036 = get_gint32 (mhii->unknown6, ctx->byte_order); - artwork->creation_date = get_gint32 (mhii->orig_date, ctx->byte_order); - artwork->digitized_date = get_gint32 (mhii->digitized_date, - ctx->byte_order); - artwork->artwork_size = get_gint32 (mhii->orig_img_size, - ctx->byte_order); + mactime = get_gint32 (mhii->orig_date, ctx->byte_order); + artwork->creation_date = itdb_time_mac_to_time_t (itdb, mactime); + mactime = get_gint32 (mhii->digitized_date, ctx->byte_order); + artwork->digitized_date = itdb_time_mac_to_time_t (itdb, mactime); + artwork->artwork_size = get_gint32 (mhii->orig_img_size, ctx->byte_order); if (song) { diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c index ed1e012..f84915a 100644 --- a/src/db-artwork-writer.c +++ b/src/db-artwork-writer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Christophe Fergeau + * Copyright (C) 2005-2007 Christophe Fergeau * * * The code contained in this file is free software; you can redistribute @@ -531,6 +531,8 @@ write_mhii (Itdb_DB *db, void *data, iPodBuffer *buffer) GList *it = NULL; Itdb_Track *song; Itdb_Artwork *artwork; + guint64 mactime; + Itdb_iTunesDB *itdb = db_get_itunesdb (db); mhii = (MhiiHeader *)init_header (buffer, "mhii", sizeof (MhiiHeader)); if (mhii == NULL) { @@ -555,11 +557,14 @@ write_mhii (Itdb_DB *db, void *data, iPodBuffer *buffer) mhii->unknown4 = get_gint32 (artwork->unk028, buffer->byte_order); mhii->rating = get_gint32 (artwork->rating, buffer->byte_order); mhii->unknown6 = get_gint32 (artwork->unk036, buffer->byte_order); - mhii->orig_date = get_guint32 (artwork->creation_date, buffer->byte_order); - mhii->digitized_date = get_guint32 (artwork->digitized_date, - buffer->byte_order); - mhii->orig_img_size = get_gint32 (artwork->artwork_size, - buffer->byte_order); + + mactime = itdb_time_time_t_to_mac (itdb, artwork->creation_date); + mhii->orig_date = get_guint32 (mactime, buffer->byte_order); + + mactime = itdb_time_time_t_to_mac (itdb, artwork->digitized_date); + mhii->digitized_date = get_guint32 (mactime, buffer->byte_order); + + mhii->orig_img_size = get_gint32 (artwork->artwork_size, buffer->byte_order); it = artwork->thumbnails; num_children = 0; while (it != NULL) { diff --git a/src/db-itunes-parser.h b/src/db-itunes-parser.h index f32b452..74fdd03 100644 --- a/src/db-itunes-parser.h +++ b/src/db-itunes-parser.h @@ -1,6 +1,5 @@ -/* Time-stamp: <2007-02-24 21:36:04 jcs> - * - * Copyright (C) 2005 Christophe Fergeau +/* + * Copyright (C) 2005-2007 Christophe Fergeau * * * The code contained in this file is free software; you can redistribute @@ -1,5 +1,5 @@ /* -| Copyright (C) 2002-2006 Jorg Schuler <jcsjcs at users sourceforge net> +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. | | URL: http://www.gtkpod.org/ @@ -461,10 +461,10 @@ struct _Itdb_Artwork { gint32 unk028; guint32 rating; /* Rating from iPhoto * 20 (PhotoDB only) */ gint32 unk036; - guint32 creation_date; /* Date the image file was created + time_t creation_date; /* Date the image file was created (creation date of image file (Mac type, PhotoDB only) */ - guint32 digitized_date;/* Date the image was taken (EXIF + time_t digitized_date;/* Date the image was taken (EXIF information, Mac type, PhotoDB only) */ guint32 artwork_size; /* Size in bytes of the original source image (PhotoDB only -- don't touch in @@ -554,7 +554,7 @@ struct _Itdb_Playlist gint num; /* number of tracks in playlist */ GList *members; /* tracks in playlist (Track *) */ gboolean is_spl; /* smart playlist? */ - guint32 timestamp; /* timestamp of playlist creation */ + time_t timestamp; /* timestamp of playlist creation */ guint64 id; /* playlist ID */ guint32 sortorder; /* How to sort playlist -- see below */ guint32 podcastflag; /* ITDB_PL_FLAG_NORM/_PODCAST */ @@ -694,9 +694,9 @@ struct _Itdb_Track gint32 year; /* year */ gint32 volume; /* volume adjustment */ guint32 soundcheck; /* volume adjustment "soundcheck" */ - guint32 time_added; /* time when added (Mac type) */ - guint32 time_played; /* time of last play (Mac type) */ - guint32 time_modified; /* time of last modification (Mac type)*/ + time_t time_added; /* time when added (Mac type) */ + time_t time_modified; /* time of last modification (Mac type)*/ + time_t time_played; /* time of last play (Mac type) */ guint32 bookmark_time; /* bookmark set for (AudioBook) in ms */ guint32 rating; /* star rating (stars * RATING_STEP (20)) */ guint32 playcount; /* number of times track was played */ @@ -756,11 +756,9 @@ struct _Itdb_Track (like WAVE format), 0x1 for Audible. itdb will try to set this when adding a new track */ guint32 unk132; /* unknown */ - guint32 time_released;/* date/time added to music store? definitely a - timestamp, always appears to be a time of - 0700 GMT. For podcasts: release date as - displayed next to the title in the Podcast - playlist */ + time_t time_released;/* date/time added to music store? + For podcasts: release date as displayed next to the + title in the Podcast playlist */ guint16 unk144; /* unknown, but MP3 songs appear to be always 0x000c, AAC songs are always 0x0033, Audible files are 0x0029, WAV files are 0x0. itdb @@ -1111,9 +1109,9 @@ Itdb_Thumb *itdb_thumb_new (void); gchar *itdb_thumb_get_filename (Itdb_Device *device, Itdb_Thumb *thumb); /* time functions */ -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); +time_t itdb_time_get_mac_time (void); +time_t itdb_time_mac_to_host (time_t time); +time_t itdb_time_host_to_mac (time_t time); /* Initialize a blank ipod */ gboolean itdb_init_ipod (const gchar *mountpoint, diff --git a/src/itdb_device.c b/src/itdb_device.c index 35836fb..8c5b9fb 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -1,6 +1,5 @@ -/* Time-stamp: <27-mar-2007 10:09:48 teuf> -| -| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> +/* +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. | | URL: http://www.gtkpod.org/ @@ -268,6 +267,8 @@ static const Itdb_ArtworkFormat *ipod_artwork_info_table[] = { }; +static void itdb_device_set_timezone_info (Itdb_Device *device); + /* Reset or create the SysInfo hash table */ static void itdb_device_reset_sysinfo (Itdb_Device *device) { @@ -328,8 +329,10 @@ void itdb_device_set_mountpoint (Itdb_Device *device, const gchar *mp) g_free (device->mountpoint); device->mountpoint = g_strdup (mp); - if (mp) + if (mp) { itdb_device_read_sysinfo (device); + itdb_device_set_timezone_info (device); + } } @@ -834,3 +837,72 @@ gboolean itdb_device_supports_photo (Itdb_Device *device) return (it->type != -1); } + + +/* This function reads the timezone information from the iPod and sets it in + * the Itdb_Device structure. If an error occurs, the function returns silently + * and the timezone shift is set to 0 + */ +static void itdb_device_set_timezone_info (Itdb_Device *device) +{ + const gchar *p_preferences[] = {"Preferences", NULL}; + char *dev_path; + char *prefs_filename; + FILE *f; + gint32 timezone; + const int GMT_OFFSET = 0x19; + int result; + + device->timezone_shift = 0; + + if (device->mountpoint == NULL) { + /* Assumes the iPod is in the UTC timezone for those cases */ + return; + } + + dev_path = itdb_get_device_dir (device->mountpoint); + + if (dev_path == NULL) { + return ; + } + + prefs_filename = itdb_resolve_path (dev_path, p_preferences); + g_free (dev_path); + + f = fopen (prefs_filename, "r"); + if (f == NULL) { + g_free (prefs_filename); + return; + } + + result = fseek (f, 0xB10, SEEK_SET); + if (result != 0) { + fclose (f); + g_free (prefs_filename); + return; + } + + result = fread (&timezone, sizeof (timezone), 1, f); + if (result != 1) { + fclose (f); + g_free (prefs_filename); + return; + } + + fclose (f); + g_free (prefs_filename); + + timezone = GINT32_FROM_LE (timezone); + if ((timezone < 0) || (timezone > (2*12) << 1)) { + /* invalid timezone */ + return; + } + + timezone -= GMT_OFFSET; + + device->timezone_shift = (timezone >> 1) * 3600; + if (timezone & 1) { + /* Adjust for DST */ + device->timezone_shift += 3600; + } +} diff --git a/src/itdb_device.h b/src/itdb_device.h index 0601ea4..bba6f48 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -1,6 +1,5 @@ -/* Time-stamp: <2006-11-12 23:03:35 jcs> -| -| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> +/* +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. | | URL: http://www.gtkpod.org/ @@ -71,6 +70,10 @@ struct _Itdb_Device * in Device/SysInfo */ gboolean sysinfo_changed; /* Has the sysinfo hash been changed by the user (itdb_set_sysinfo) */ + gint timezone_shift; /* difference in seconds between the current + * timezone and UTC + */ + }; struct _Itdb_ArtworkFormat diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c index c2f9bcd..61bfb71 100644 --- a/src/itdb_itunesdb.c +++ b/src/itdb_itunesdb.c @@ -1,6 +1,5 @@ -/* Time-stamp: <27-mar-2007 10:06:21 teuf> -| -| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> +/* +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. | | URL: http://www.gtkpod.org/ @@ -271,7 +270,6 @@ typedef struct _MHODData MHODData; /* Declarations */ static gboolean itdb_create_directories (Itdb_Device *device, GError **error); - /* ID for error domain */ GQuark itdb_file_error_quark (void) { @@ -939,6 +937,7 @@ static gboolean playcounts_read (FImport *fimp, FContents *cts) CHECK_ERROR (fimp, FALSE); for (i=0; i<entry_num; ++i) { + gint32 mac_time; struct playcount *playcount = g_new0 (struct playcount, 1); glong seek = header_length + i*entry_length; @@ -946,18 +945,10 @@ static gboolean playcounts_read (FImport *fimp, FContents *cts) CHECK_ERROR (fimp, FALSE); fimp->playcounts = g_list_append (fimp->playcounts, playcount); - playcount->playcount = get32lint (cts, seek); - playcount->time_played = get32lint (cts, seek+4); + playcount->playcount = get32lint (cts, seek); + mac_time = get32lint (cts, seek+4); + playcount->time_played = itdb_time_mac_to_time_t (fimp->itdb, mac_time); playcount->bookmark_time = get32lint (cts, seek+8); - /* NOTE: - * - * The iPod (firmware 1.3, 2.0, ...?) doesn't seem to use the - * timezone information correctly -- no matter what you set - * iPod's timezone to, it will always record as if it were set - * to UTC -- we need to subtract the difference between - * current timezone and UTC to get a correct - * display. -- this should be done by the application were - * necessary */ /* rating only exists if the entry length is at least 0x10 */ if (entry_length >= 0x10) @@ -978,7 +969,10 @@ static gboolean playcounts_read (FImport *fimp, FContents *cts) if (entry_length >= 0x1c) { playcount->skipcount = get32lint (cts, seek+20); - playcount->last_skipped = get32lint (cts, seek+24); + mac_time = get32lint (cts, seek+24); + playcount->last_skipped = itdb_time_mac_to_time_t (fimp->itdb, + mac_time); + } } return TRUE; @@ -1297,7 +1291,7 @@ static gint32 get_mhod_type (FContents *cts, glong seek, guint32 *ml) .playlist_id/.string/.chapterdata/.splp/.splrs */ -static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml) +static MHODData get_mhod (FImport *fimp, glong mhod_seek, guint32 *ml) { gunichar2 *entry_utf16 = NULL; MHODData result; @@ -1306,7 +1300,10 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml) gint32 header_length; guint32 string_type; gulong seek; - + FContents *cts; + + cts = fimp->fcontents; + result.valid = FALSE; result.type = -1; g_return_val_if_fail (ml, result); @@ -1517,6 +1514,19 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml) splr->unk060 = get32bint (cts, seek+60); splr->unk064 = get32bint (cts, seek+64); splr->unk068 = get32bint (cts, seek+68); + + if (ft == splft_date) { + SPLActionType at; + at = itdb_splr_get_action_type (splr); + if ((at == splat_range_date) || (at == splat_date)) { + Itdb_iTunesDB *itdb = fimp->itdb; + splr->fromvalue = itdb_time_mac_to_time_t (itdb, + splr->fromvalue); + splr->tovalue = itdb_time_mac_to_time_t (itdb, + splr->tovalue); + } + } + break; } seek += length+4; @@ -1557,9 +1567,12 @@ static MHODData get_mhod (FContents *cts, glong mhod_seek, guint32 *ml) UTF8). After use you must free the string with g_free(). Returns NULL if no string is avaible. *ml is set to -1 in case of error and cts->error is set appropriately. */ -static gchar *get_mhod_string (FContents *cts, glong seek, guint32 *ml, gint32 *mty) +static gchar *get_mhod_string (FImport *fimp, glong seek, guint32 *ml, gint32 *mty) { MHODData mhoddata; + FContents *cts; + + cts = fimp->fcontents; *mty = get_mhod_type (cts, seek, ml); if (cts->error) return NULL; @@ -1585,7 +1598,7 @@ static gchar *get_mhod_string (FContents *cts, glong seek, guint32 *ml, gint32 * case MHOD_ID_TVNETWORK: case MHOD_ID_ALBUMARTIST: case MHOD_ID_KEYWORDS: - mhoddata = get_mhod (cts, seek, ml); + mhoddata = get_mhod (fimp, seek, ml); if ((*ml != -1) && mhoddata.valid) return mhoddata.data.string; else @@ -1850,7 +1863,7 @@ static glong get_mhip (FImport *fimp, Itdb_Playlist *plitem, if (mhod_type == MHOD_ID_PLAYLIST) { MHODData mhod; - mhod = get_mhod (cts, mhod_seek, &mhod_len); + mhod = get_mhod (fimp, mhod_seek, &mhod_len); CHECK_ERROR (fimp, -1); pos = -1; if (mhod.valid && first_entry) @@ -1973,6 +1986,7 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek) plitem->flag2 = get8int (cts, mhyp_seek+22); plitem->flag3 = get8int (cts, mhyp_seek+23); plitem->timestamp = get32lint (cts, mhyp_seek+24); + plitem->timestamp = itdb_time_mac_to_time_t (fimp->itdb, plitem->timestamp); plitem->id = get64lint (cts, mhyp_seek+28); /* plitem->mhodcount = get32lint (cts, mhyp_seek+36); */ /* plitem->libmhodcount = get16lint (cts, mhyp_seek+40);*/ @@ -1996,7 +2010,7 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek) /* here we could do something about the playlist settings */ break; case MHOD_ID_TITLE: - mhod = get_mhod (cts, mhod_seek, &header_len); + mhod = get_mhod (fimp, mhod_seek, &header_len); CHECK_ERROR (fimp, -1); if (mhod.valid && mhod.data.string) { @@ -2007,7 +2021,7 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek) } break; case MHOD_ID_SPLPREF: - mhod = get_mhod (cts, mhod_seek, &header_len); + mhod = get_mhod (fimp, mhod_seek, &header_len); CHECK_ERROR (fimp, -1); if (mhod.valid && mhod.data.splpref) { @@ -2019,7 +2033,7 @@ static glong get_playlist (FImport *fimp, glong mhyp_seek) } break; case MHOD_ID_SPLRULES: - mhod = get_mhod (cts, mhod_seek, &header_len); + mhod = get_mhod (fimp, mhod_seek, &header_len); CHECK_ERROR (fimp, -1); if (mhod.valid && mhod.data.splrules) { @@ -2178,6 +2192,8 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) track->compilation = get8int (cts, seek+30); track->rating = get8int (cts, seek+31); track->time_modified = get32lint(cts, seek+32); /* time added */ + track->time_modified = itdb_time_mac_to_time_t (fimp->itdb, + track->time_modified); track->size = get32lint(cts, seek+36); /* file size */ track->tracklen = get32lint(cts, seek+40); /* time */ track->track_nr = get32lint(cts, seek+44); /* track number */ @@ -2194,12 +2210,16 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) track->playcount = get32lint (cts, seek+80); /* playcount */ track->playcount2 = get32lint (cts, seek+84); track->time_played = get32lint(cts, seek+88);/* last time played */ + track->time_played = itdb_time_mac_to_time_t (fimp->itdb, + track->time_played); track->cd_nr = get32lint(cts, seek+92); /* CD nr */ track->cds = get32lint(cts, seek+96); /* CD nr of.. */ /* Apple Store/Audible User ID (for DRM'ed files only, set to 0 otherwise). */ track->drm_userid = get32lint (cts, seek+100); track->time_added = get32lint(cts, seek+104);/* last mod. time */ + track->time_added = itdb_time_mac_to_time_t (fimp->itdb, + track->time_added); track->bookmark_time = get32lint (cts, seek+108);/*time bookmarked*/ track->dbid = get64lint (cts, seek+112); track->checked = get8int (cts, seek+120); /*Checked/Unchecked: 0/1*/ @@ -2213,6 +2233,8 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) track->unk132 = get32lint (cts, seek+132); track->samplerate2 = get32lfloat (cts, seek+136); track->time_released = get32lint (cts, seek+140); + track->time_released = itdb_time_mac_to_time_t (fimp->itdb, + track->time_released); track->unk144 = get16lint (cts, seek+144); track->unk146 = get16lint (cts, seek+146); track->unk148 = get32lint (cts, seek+148); @@ -2222,6 +2244,8 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) { track->skipcount = get32lint (cts, seek+156); track->last_skipped = get32lint (cts, seek+160); + track->last_skipped = itdb_time_mac_to_time_t (fimp->itdb, + track->last_skipped); track->has_artwork = get8int (cts, seek+164); track->skip_when_shuffling = get8int (cts, seek+165); track->remember_playback_position = get8int (cts, seek+166); @@ -2263,7 +2287,7 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) for (i=0; i<mhod_nums; ++i) { - entry_utf8 = get_mhod_string (cts, seek, &zip, &type); + entry_utf8 = get_mhod_string (fimp, seek, &zip, &type); CHECK_ERROR (fimp, -1); if (entry_utf8 != NULL) { @@ -2343,7 +2367,7 @@ static glong get_mhit (FImport *fimp, glong mhit_seek) case MHOD_ID_CHAPTERDATA: /* we just read the entire chapterdata info until we have a better way to parse and represent it */ - mhod = get_mhod (cts, seek, &zip); + mhod = get_mhod (fimp, seek, &zip); if (mhod.valid && mhod.data.chapterdata_raw) { track->chapterdata_raw = mhod.data.chapterdata_raw; @@ -2804,6 +2828,42 @@ static void error_no_control_dir (const gchar *mp, GError **error) } #endif + +static gboolean +itdb_parse_internal (Itdb_iTunesDB *itdb, GError **error) +{ + FImport *fimp; + gboolean success; + + g_return_val_if_fail (itdb->filename != NULL, FALSE); + + fimp = g_new0 (FImport, 1); + fimp->itdb = itdb; + + fimp->fcontents = fcontents_read (itdb->filename, error); + + if (fimp->fcontents) + { + if (playcounts_init (fimp)) + { + if (parse_fimp (fimp)) + { + if (read_OTG_playlists (fimp)) + { + success = TRUE; + } + } + } + } + + if (fimp->error) + g_propagate_error (error, fimp->error); + + itdb_free_fimp (fimp); + + return success; +} + /** * itdb_parse: * @mp: mount point of the iPod (eg "/mnt/ipod) in local encoding @@ -2823,6 +2883,7 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error) Itdb_iTunesDB *itdb = NULL; const gchar *db[] = {"iTunesDB", NULL}; + itunes_dir = itdb_get_itunes_dir (mp); if (!itunes_dir) @@ -2832,13 +2893,24 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error) } filename = itdb_resolve_path (itunes_dir, db); + if (itdb != NULL) { + itdb_set_mountpoint (itdb, mp); + } if (filename) { - itdb = itdb_parse_file (filename, error); + itdb = itdb_new (); + if (itdb) { - itdb_set_mountpoint (itdb, mp); + gboolean success; + itdb_set_mountpoint (itdb, mp); + itdb->filename = filename; + success = itdb_parse_internal (itdb, error); + if (!success) { + itdb_free (itdb); + itdb = NULL; + } /* We don't test the return value of ipod_parse_artwork_db * since the database content will be consistent even if * we fail to get the various thumbnails, we ignore the @@ -2863,7 +2935,6 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error) ipod_parse_artwork_db (itdb); } - g_free (filename); } else { @@ -2879,6 +2950,7 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error) return itdb; } + /** * itdb_parse_file: * @filename: path to a file in iTunesDB format @@ -2887,47 +2959,26 @@ Itdb_iTunesDB *itdb_parse (const gchar *mp, GError **error) * Same as itunesdb_parse(), but filename is specified directly. * * Return value: a newly allocated #Itdb_iTunesDB struct holding the tracks and - * the playlists present on the iPod at @mp, NULL if @mp isn't an iPod mount - * point. If non-NULL, the #Itdb_iTunesDB is to be freed with itdb_free() when - * it's no longer needed + * the playlists present in @filename, NULL if @filename isn't a parsable + * iTunesDB file. If non-NULL, the #Itdb_iTunesDB is to be freed with + * itdb_free() when it's no longer needed **/ Itdb_iTunesDB *itdb_parse_file (const gchar *filename, GError **error) { - FImport *fimp; Itdb_iTunesDB *itdb; - gboolean success = FALSE; + gboolean success; g_return_val_if_fail (filename, NULL); - fimp = g_new0 (FImport, 1); itdb = itdb_new (); itdb->filename = g_strdup (filename); - fimp->itdb = itdb; - - fimp->fcontents = fcontents_read (filename, error); - - if (fimp->fcontents) - { - if (playcounts_init (fimp)) - { - if (parse_fimp (fimp)) - { - if (read_OTG_playlists (fimp)) - { - success = TRUE; - } - } - } - } + success = itdb_parse_internal (itdb, error); if (!success) { itdb_free (itdb); itdb = NULL; - if (fimp->error) - g_propagate_error (error, fimp->error); } - itdb_free_fimp (fimp); return itdb; } @@ -3388,6 +3439,7 @@ static void mk_mhlt (FExport *fexp, guint32 num) /* Write out the mhit header. Size will be written later */ static void mk_mhit (WContents *cts, Itdb_Track *track) { + gint32 mac_time; g_return_if_fail (cts); g_return_if_fail (track); @@ -3403,7 +3455,8 @@ static void mk_mhit (WContents *cts, Itdb_Track *track) put8int (cts, track->type2); put8int (cts, track->compilation); put8int (cts, track->rating); - put32lint (cts, track->time_modified); /* timestamp */ + mac_time = itdb_time_time_t_to_mac (track->itdb, track->time_modified); + put32lint (cts, mac_time); /* timestamp */ put32lint (cts, track->size); /* filesize */ put32lint (cts, track->tracklen);/* length of track in ms */ put32lint (cts, track->track_nr);/* track number */ @@ -3419,11 +3472,13 @@ static void mk_mhit (WContents *cts, Itdb_Track *track) put32lint (cts, track->playcount);/* playcount */ track->playcount2 = track->playcount; put32lint (cts, track->playcount2); - put32lint (cts, track->time_played); /* last time played */ + mac_time = itdb_time_time_t_to_mac (track->itdb, track->time_played); + put32lint (cts, mac_time); /* last time played */ put32lint (cts, track->cd_nr); /* CD number */ put32lint (cts, track->cds); /* number of CDs */ put32lint (cts, track->drm_userid); - put32lint (cts, track->time_added); /* timestamp */ + mac_time = itdb_time_time_t_to_mac (track->itdb, track->time_added); + put32lint (cts, mac_time); /* timestamp */ put32lint (cts, track->bookmark_time); put64lint (cts, track->dbid); if (track->checked) put8int (cts, 1); @@ -3435,14 +3490,16 @@ static void mk_mhit (WContents *cts, Itdb_Track *track) put32lint (cts, track->artwork_size); put32lint (cts, track->unk132); put32lfloat (cts, track->samplerate2); - put32lint (cts, track->time_released); + mac_time = itdb_time_time_t_to_mac (track->itdb, track->time_released); + put32lint (cts, mac_time); put16lint (cts, track->unk144); put16lint (cts, track->unk146); put32lint (cts, track->unk148); put32lint (cts, track->unk152); /* since iTunesDB version 0x0c */ put32lint (cts, track->skipcount); - put32lint (cts, track->last_skipped); + mac_time = itdb_time_time_t_to_mac (track->itdb, track->last_skipped); + put32lint (cts, mac_time); put8int (cts, track->has_artwork); put8int (cts, track->skip_when_shuffling); put8int (cts, track->remember_playback_position); @@ -3626,8 +3683,10 @@ static void mhod52_free_collate_keys (GList *coltracks) position indicator for MHOD_ID_PLAYLIST SPLPref for MHOD_ID_SPLPREF SPLRules for MHOD_ID_SPLRULES */ -static void mk_mhod (WContents *cts, MHODData *mhod) +static void mk_mhod (FExport *fexp, MHODData *mhod) { + WContents *cts = fexp->wcontents; + g_return_if_fail (cts); g_return_if_fail (mhod->valid); @@ -3785,7 +3844,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod) itdb_splr_validate (splr); put32bint (cts, splr->field); put32bint (cts, splr->action); - put32_n0 (cts, 11); /* unknown */ + put32_n0 (cts, 11); /* unknown */ switch (ft) { case splft_string: @@ -3801,19 +3860,36 @@ static void mk_mhod (WContents *cts, MHODData *mhod) put_data (cts, (gchar *)entry_utf16, 2*len); g_free (entry_utf16); break; - case splft_int: case splft_date: + case splft_int: case splft_boolean: case splft_playlist: case splft_unknown: - case splft_binary_and: + case splft_binary_and: { + guint64 fromvalue; + guint64 tovalue; + + fromvalue = splr->fromvalue; + tovalue = splr->tovalue; + + if (ft == splft_date) { + SPLActionType at; + at = itdb_splr_get_action_type (splr); + if ((at == splat_range_date) || (at == splat_date)) { + Itdb_iTunesDB *itdb = fexp->itdb; + fromvalue = itdb_time_time_t_to_mac (itdb, + fromvalue); + tovalue = itdb_time_time_t_to_mac (itdb, tovalue); + } + } + /* write non-string-type rule */ put32bint (cts, 0x44); /* length of data */ /* data */ - put64bint (cts, splr->fromvalue); + put64bint (cts, fromvalue); put64bint (cts, splr->fromdate); put64bint (cts, splr->fromunits); - put64bint (cts, splr->tovalue); + put64bint (cts, tovalue); put64bint (cts, splr->todate); put64bint (cts, splr->tounits); put32bint (cts, splr->unk052); @@ -3823,6 +3899,7 @@ static void mk_mhod (WContents *cts, MHODData *mhod) put32bint (cts, splr->unk068); break; } + } } /* insert length of mhod junk */ fix_header (cts, header_seek); @@ -3977,6 +4054,7 @@ static void mk_mhip (FExport *fexp, put32lint (cts, podcastgroupflag); /* 16 */ put32lint (cts, podcastgroupid); /* 20 */ put32lint (cts, trackid); /* 24 */ + timestamp = itdb_time_time_t_to_mac (fexp->itdb, timestamp); put32lint (cts, timestamp); /* 28 */ put32lint (cts, podcastgroupref); /* 32 */ put32_n0 (cts, 10); /* 36 */ @@ -4017,140 +4095,140 @@ static gboolean write_mhsd_tracks (FExport *fexp) { mhod.type = MHOD_ID_TITLE; mhod.data.string = track->title; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->ipod_path && *track->ipod_path) { mhod.type = MHOD_ID_PATH; mhod.data.string = track->ipod_path; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->album && *track->album) { mhod.type = MHOD_ID_ALBUM; mhod.data.string = track->album; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->artist && *track->artist) { mhod.type = MHOD_ID_ARTIST; mhod.data.string = track->artist; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->genre && *track->genre) { mhod.type = MHOD_ID_GENRE; mhod.data.string = track->genre; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->filetype && *track->filetype) { mhod.type = MHOD_ID_FILETYPE; mhod.data.string = track->filetype; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->comment && *track->comment) { mhod.type = MHOD_ID_COMMENT; mhod.data.string = track->comment; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->category && *track->category) { mhod.type = MHOD_ID_CATEGORY; mhod.data.string = track->category; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->composer && *track->composer) { mhod.type = MHOD_ID_COMPOSER; mhod.data.string = track->composer; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->grouping && *track->grouping) { mhod.type = MHOD_ID_GROUPING; mhod.data.string = track->grouping; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->description && *track->description) { mhod.type = MHOD_ID_DESCRIPTION; mhod.data.string = track->description; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->subtitle && *track->subtitle) { mhod.type = MHOD_ID_SUBTITLE; mhod.data.string = track->subtitle; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->tvshow && *track->tvshow) { mhod.type = MHOD_ID_TVSHOW; mhod.data.string = track->tvshow; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->tvepisode && *track->tvepisode) { mhod.type = MHOD_ID_TVEPISODE; mhod.data.string = track->tvepisode; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->tvnetwork && *track->tvnetwork) { mhod.type = MHOD_ID_TVNETWORK; mhod.data.string = track->tvnetwork; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->albumartist && *track->albumartist) { mhod.type = MHOD_ID_ALBUMARTIST; mhod.data.string = track->albumartist; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->keywords && *track->keywords) { mhod.type = MHOD_ID_KEYWORDS; mhod.data.string = track->keywords; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->podcasturl && *track->podcasturl) { mhod.type = MHOD_ID_PODCASTURL; mhod.data.string = track->podcasturl; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->podcastrss && *track->podcastrss) { mhod.type = MHOD_ID_PODCASTRSS; mhod.data.string = track->podcastrss; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } if (track->chapterdata_raw && track->chapterdata_raw_length) { mhod.type = MHOD_ID_CHAPTERDATA; mhod.data.chapterdata_track = track; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); ++mhod_num; } /* Fill in the missing items of the mhit header */ @@ -4191,7 +4269,7 @@ static gboolean write_playlist_mhips (FExport *fexp, mhod.valid = TRUE; mhod.type = MHOD_ID_PLAYLIST; mhod.data.track_pos = i; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); /* note: with iTunes 4.9 the mhod is counted as a child to mhip, so we have put the total length of the mhip and mhod into the mhip header */ @@ -4247,7 +4325,7 @@ void write_one_podcast_group (gpointer key, gpointer value, mhod.valid = TRUE; mhod.type = MHOD_ID_TITLE; mhod.data.string = album; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); fix_header (cts, mhip_seek); /* write members */ @@ -4263,7 +4341,7 @@ void write_one_podcast_group (gpointer key, gpointer value, mk_mhip (fexp, 1, 0, mhip_id, track->id, 0, groupid); mhod.type = MHOD_ID_PLAYLIST; mhod.data.track_pos = mhip_id; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); fix_header (cts, mhip_seek); } } @@ -4340,6 +4418,7 @@ static gboolean write_playlist (FExport *fexp, gboolean result = TRUE; MHODData mhod; gint mhodnum; + guint32 mac_time; g_return_val_if_fail (fexp, FALSE); g_return_val_if_fail (fexp->itdb, FALSE); @@ -4375,7 +4454,8 @@ static gboolean write_playlist (FExport *fexp, put8int (cts, pl->flag1); /* unknown */ put8int (cts, pl->flag2); /* unknown */ put8int (cts, pl->flag3); /* unknown */ - put32lint (cts, pl->timestamp);/* some timestamp */ + mac_time = itdb_time_time_t_to_mac (fexp->itdb, pl->timestamp); + put32lint (cts, mac_time); /* some timestamp */ put64lint (cts, pl->id); /* 64 bit ID */ put32lint (cts, 0); /* unknown, always 0? */ put16lint (cts, 1); /* string mhod count (1) */ @@ -4386,7 +4466,7 @@ static gboolean write_playlist (FExport *fexp, mhod.valid = TRUE; mhod.type = MHOD_ID_TITLE; mhod.data.string = pl->name; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mk_long_mhod_id_playlist (fexp, pl); if ((pl->type == ITDB_PL_TYPE_MPL) && pl->members) @@ -4398,26 +4478,26 @@ static gboolean write_playlist (FExport *fexp, mhod.type = MHOD_ID_LIBPLAYLISTINDEX; mhod.data.mhod52coltracks = mhod52_make_collate_keys (pl->members); mhod.data2.mhod52sorttype = MHOD52_SORTTYPE_TITLE; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod.data2.mhod52sorttype = MHOD52_SORTTYPE_ALBUM; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod.data2.mhod52sorttype = MHOD52_SORTTYPE_ARTIST; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod.data2.mhod52sorttype = MHOD52_SORTTYPE_GENRE; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod.data2.mhod52sorttype = MHOD52_SORTTYPE_COMPOSER; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod52_free_collate_keys (mhod.data.mhod52coltracks); } else if (pl->is_spl) { /* write the smart rules */ mhod.type = MHOD_ID_SPLPREF; mhod.data.splpref = &pl->splpref; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); mhod.type = MHOD_ID_SPLRULES; mhod.data.splrules = &pl->splrules; - mk_mhod (cts, &mhod); + mk_mhod (fexp, &mhod); } if (itdb_playlist_is_podcasts(pl) && (mhsd_type == 3)) @@ -5820,17 +5900,21 @@ gchar *itdb_get_artworkdb_path (const gchar *mountpoint) /** * itdb_time_get_mac_time: * - * Gets the current time expressed in 'Mac' unit (ie in number of seconds since - * 1/1/1904). + * Gets the current time in a format appropriate for storing in the libgpod + * data structures * - * Return value: current time in 'Mac' unit. + * Return value: current time + * + * Deprecated: kept for compatibility with older code, directly use + * g_get_current_time() or time(NULL) instead **/ -guint64 itdb_time_get_mac_time (void) +time_t itdb_time_get_mac_time (void) { GTimeVal time; g_get_current_time (&time); - return itdb_time_host_to_mac (time.tv_sec); + + return time.tv_sec; } @@ -5838,33 +5922,45 @@ guint64 itdb_time_get_mac_time (void) * itdb_time_mac_to_host: * @mactime: time expressed in 'Mac' unit * - * Convert a Mac timestamp to host system time stamp -- modify - * this function if necessary to port to host systems with different - * start of Epoch. - * A "0" time will not be converted. + * Converts a timestamp from libgpod format to host system timestamp. * * Return value: timestamp for the host system + * + * Deprecated: It's been kept for compatibility with older code, but this + * function is now a no-op **/ -time_t itdb_time_mac_to_host (guint64 mactime) +time_t itdb_time_mac_to_host (time_t mactime) { - if (mactime != 0) return (time_t)(mactime - 2082844800); - else return (time_t)mactime; + return mactime; } - /** * itdb_time_host_to_mac: * @time: time expressed in host unit * - * Convert host system timestamp to Mac time stamp -- modify - * this function if necessary to port to host systems with different - * start of Epoch + * Convert host system timestamp to libgpod format timestamp + * + * Return value: a libgpod timestamp * - * Return value: a Mac timestamp + * Deprecated: It's been kept for compatibility with older code, but this + * function is now a no-op **/ -guint64 itdb_time_host_to_mac (time_t time) +time_t itdb_time_host_to_mac (time_t timet) +{ + return timet; +} + +time_t itdb_time_mac_to_time_t (Itdb_iTunesDB *db, guint64 mactime) +{ + if (mactime != 0) return (time_t)(mactime - 2082844800 - db->device->timezone_shift); + else return (time_t)mactime; +} + +guint64 itdb_time_time_t_to_mac (Itdb_iTunesDB *db, time_t timet) { - return (guint64)(((gint64)time) + 2082844800); + if (timet != 0) + return ((guint64)timet) + 2082844800 + db->device->timezone_shift; + else return 0; } diff --git a/src/itdb_private.h b/src/itdb_private.h index 1695f22..8fcbcea 100644 --- a/src/itdb_private.h +++ b/src/itdb_private.h @@ -1,6 +1,5 @@ -/* Time-stamp: <2007-01-06 20:46:59 jcs> -| -| Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> +/* +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. | | URL: http://www.gtkpod.org/ @@ -83,12 +82,12 @@ typedef struct struct playcount { guint32 playcount; guint32 skipped; /* skipped (only for Shuffle's iTunesStats */ - guint32 time_played; + time_t time_played; guint32 bookmark_time; gint32 rating; gint32 pc_unk16; /* unknown field in Play Counts file */ guint32 skipcount; - guint32 last_skipped; + time_t last_skipped; gint32 st_unk06; /* unknown field in iTunesStats file */ gint32 st_unk09; /* unknown field in iTunesStats file */ }; @@ -152,4 +151,8 @@ G_GNUC_INTERNAL gint itdb_get_free_photo_id ( Itdb_PhotoDB *db ); G_GNUC_INTERNAL Itdb_iTunesDB *db_get_itunesdb (Itdb_DB *db); G_GNUC_INTERNAL Itdb_PhotoDB *db_get_photodb (Itdb_DB *db); G_GNUC_INTERNAL gint itdb_thumb_get_byteorder (ItdbThumbFormat format); +G_GNUC_INTERNAL time_t itdb_time_mac_to_time_t (Itdb_iTunesDB *db, + guint64 mactime); +G_GNUC_INTERNAL guint64 itdb_time_time_t_to_mac (Itdb_iTunesDB *db, + time_t timet); #endif diff --git a/tests/Makefile.am b/tests/Makefile.am index e77f83b..4d3e89f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ if HAVE_GDKPIXBUF -TESTTHUMBS=test-thumbnails test-write-thumbnails test-photos +TESTTHUMBS=test-thumbnails test-write-thumbnails test-photos get-timezone test_thumbnails_SOURCES = test-covers.c test_thumbnails_CFLAGS = $(AM_CFLAGS) @@ -33,6 +33,8 @@ test_ls_LDADD = test_init_ipod_SOURCES = test-init-ipod.c test_init_ipod_LDADD = +get_timezone_SOURCES = get-timezone.c + noinst_PROGRAMS=test-itdb test-ls $(TESTTHUMBS) $(TESTTAGLIB) $(TESTMISC) INCLUDES=$(LIBGPOD_CFLAGS) -I$(top_srcdir)/src -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" diff --git a/tests/test-ls.c b/tests/test-ls.c index f37bc43..635ce44 100644 --- a/tests/test-ls.c +++ b/tests/test-ls.c @@ -37,6 +37,36 @@ #define LOCALDB "/.gtkpod/local_0.itdb" static void +display_recently_played (Itdb_iTunesDB *db) +{ + Itdb_Playlist *mpl = itdb_playlist_mpl (db); + GList *it; + + g_print ("Recently played:\n"); + for (it = mpl->members; it != NULL; it = it->next) { + Itdb_Track *track = (Itdb_Track*)it->data; + + if (track->recent_playcount != 0) { + char date[30]; + time_t track_time = itdb_time_mac_to_host (track->time_played); + + g_print ("%s - %s - %s:\n", + track->artist, track->album, track->title); + strftime (date, sizeof (date), "%D %H:%M:%S", + gmtime (&track_time)); + g_print ("\tUTC: %s\n", date); + strftime (date, sizeof (date), "%D %H:%M:%S", + localtime (&track_time)); + g_print ("\tlocal: %s\n", date); + g_print ("track: %ld ", track_time); + time (&track_time); + g_print ("current: %ld\n", track_time); + g_print ("\n"); + } + } +} + +static void display_track (Itdb_Track *track, const char *prefix) { g_print ("%s%s - %s - %s\n", prefix, @@ -131,6 +161,8 @@ main (int argc, char *argv[]) g_error_free (error); error = NULL; } + + display_recently_played (itdb); } itdb_free (itdb); |