1/* File : gpod.i.in */
2
3/*
4 Copyright (C) 2007 Nick Piper <nick-gtkpod at nickpiper co uk>
5 Part of the gtkpod project.
6
7 URL: http://www.gtkpod.org/
8 URL: http://gtkpod.sourceforge.net/
9
10 The code contained in this file is free software; you can redistribute
11 it and/or modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either version
13 2.1 of the License, or (at your option) any later version.
14
15 This file is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this code; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24 $Id$
25
26Please send any fixes, improvements or suggestions to
27<nick-gtkpod at nickpiper co uk>.
28
29*/
30
31%define DOCSTRING
32"This module gives access to an iPod's content. It provides an easy to
33use API to retrieve the list of files and playlists stored on an iPod,
34modify them, and save them back to the iPod.
35
36This module implements the libgpod C API as directly as possible in
37Python.  See the main gpod module for a more traditional Python
38interface."
39%enddef
40
41%pythoncode %{
42version = "@PACKAGE_VERSION@"
43version_info = version.split(".")
44%}
45
46%module(docstring=DOCSTRING) gpod
47%{
48#include "@top_builddir@/config.h"
49#include "db-artwork-debug.h"
50#include "db-artwork-parser.h"
51#include "db-image-parser.h"
52#include "db-itunes-parser.h"
53#include "db-parse-context.h"
54#include "itdb.h"
55#include "itdb_device.h"
56#include "itdb_private.h"
57#include <time.h>
58#include <datetime.h>
59#ifdef HAVE_GDKPIXBUF
60#ifdef HAVE_PYGOBJECT
61#include <gdk-pixbuf/gdk-pixbuf.h>
62#include <pygobject.h>
63#endif
64#endif
65
66
67/* include prototypes for all functions so builds using
68 * -Wmissing-prototypes don't fail. */
69PyObject* sw_get_tracks(Itdb_iTunesDB *itdb);
70PyObject* sw_get_track(GList *list, gint index);
71PyObject* sw_get_rule(GList *list, gint index);
72PyObject* sw_get_playlist(GList *list, gint index);
73PyObject* sw_get_list_len(GList *list);
74PyObject* sw_get_playlists(Itdb_iTunesDB *itdb);
75PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl);
76PyObject* sw_set_track_userdata(Itdb_Track *track, PyObject *data);
77PyObject* sw_get_track_userdata(Itdb_Track *track);
78PyObject* sw__track_extra_duplicate (PyObject *data);
79PyObject* sw_get_photoalbums(Itdb_PhotoDB *db);
80PyObject* sw_get_photoalbum(GList *list, gint index);
81PyObject* sw_get_photos(Itdb_PhotoDB *db);
82PyObject* sw_get_photo(GList *list, gint index);
83PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album);
84PyObject* sw_ipod_device_to_dict(Itdb_Device *device);
85void sw__track_extra_destroy (PyObject *data);
86void hash_table_to_pydict(gpointer key, gpointer value, gpointer user_data);
87void SWIG_init(void);
88
89PyObject* sw_get_tracks(Itdb_iTunesDB *itdb) {
90  PyObject    *list;
91  gint        i;
92  GList       *l;
93  list = PyList_New(g_list_length(itdb->tracks));
94  for (l = itdb->tracks, i = 0; l; l = l->next, ++i) {
95    PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), SWIGTYPE_p__Itdb_Track, 0));
96  }
97  return list;
98 }
99
100PyObject* sw_get_track(GList *list, gint index) {
101  GList *position;
102  if ( (index >= g_list_length(list)) || index < 0 ) {
103   PyErr_SetString(PyExc_IndexError, "Value out of range");
104   return NULL;
105  }
106  position = g_list_nth(list, index);
107  return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_Track, 0);
108 }
109
110PyObject* sw_get_rule(GList *list, gint index) {
111  GList *position;
112  if ( (index >= g_list_length(list)) || index < 0 ) {
113   PyErr_SetString(PyExc_IndexError, "Value out of range");
114   return NULL;
115  }
116  position = g_list_nth(list, index);
117  return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_SPLRule, 0);
118 }
119
120PyObject* sw_get_playlist(GList *list, gint index) {
121  GList *position;
122  if ( (index >= g_list_length(list)) || index < 0 ) {
123   PyErr_SetString(PyExc_IndexError, "Value out of range");
124   return NULL;
125  }
126  position = g_list_nth(list, index);
127  return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_Playlist, 0);
128 }
129
130PyObject* sw_get_list_len(GList *list) {
131   return PyInt_FromLong(g_list_length(list));
132 }
133
134PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl) {
135  PyObject    *list;
136  gint        i;
137  GList       *l;
138  list = PyList_New(g_list_length(pl->members));
139  for (l = pl->members, i = 0; l; l = l->next, ++i) {
140    PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), SWIGTYPE_p__Itdb_Track, 0));
141  }
142  return list;
143 }
144
145PyObject* sw_get_playlists(Itdb_iTunesDB *itdb) {
146  PyObject    *list;
147  gint        i;
148  GList       *l;
149  list = PyList_New(g_list_length(itdb->playlists));
150  for (l = itdb->playlists, i = 0; l; l = l->next, ++i) {
151    PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), SWIGTYPE_p__Itdb_Playlist, 0));
152  }
153  return list;
154 }
155
156 void sw__track_extra_destroy (PyObject *data) {
157   Py_XDECREF(data);
158 }
159
160 PyObject *sw__track_extra_duplicate (PyObject *data) {
161   if (data == Py_None) {
162     Py_INCREF(Py_None);
163     return Py_None;
164   } else {
165     return PyDict_Copy(data);
166   }
167 }
168
169 PyObject *sw_set_track_userdata(Itdb_Track *track, PyObject *data) {
170   Py_INCREF(data);
171   if ((PyDict_Check(data)) || (data == Py_None)) {
172     if (track->userdata) {
173       Py_DECREF((PyObject *)track->userdata);
174     }
175     track->userdata = (gpointer) data;
176     track->userdata_duplicate = (ItdbUserDataDuplicateFunc)sw__track_extra_duplicate;
177     track->userdata_destroy   = (ItdbUserDataDestroyFunc)sw__track_extra_destroy;
178     Py_INCREF(Py_None);
179     return Py_None;
180   } else {
181     PyErr_SetString(PyExc_TypeError, "userdata must be a Dictionary");
182     return NULL;
183   }
184 }
185
186 PyObject* sw_get_track_userdata(Itdb_Track *track) {
187   if (track->userdata) {
188     Py_INCREF((PyObject *)track->userdata);
189     return (PyObject *)track->userdata;
190   } else {
191     Py_INCREF(Py_None);
192     return Py_None;
193   }
194 }
195
196 PyObject* sw_get_photoalbums(Itdb_PhotoDB *db) {
197  PyObject    *list;
198  gint        i;
199  GList       *l;
200  list = PyList_New(g_list_length(db->photoalbums));
201  for (l = db->photoalbums, i = 0; l; l = l->next, ++i) {
202    PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data),
203SWIGTYPE_p__Itdb_PhotoAlbum, 0));
204  }
205  return list;
206 }
207
208PyObject* sw_get_photoalbum(GList *list, gint index) {
209  GList *position;
210  if ( (index >= g_list_length(list)) || index < 0 ) {
211   PyErr_SetString(PyExc_IndexError, "Value out of range");
212   return NULL;
213  }
214  position = g_list_nth(list, index);
215  return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_PhotoAlbum, 0);
216 }
217
218 PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album) {
219  PyObject    *list;
220  gint        i;
221  GList       *l;
222  list = PyList_New(g_list_length(album->members));
223  for (l = album->members, i = 0; l; l = l->next, ++i) {
224    gint photo_id = GPOINTER_TO_INT(l->data);
225    PyList_SET_ITEM(list, i, PyInt_FromLong((long)photo_id));
226  }
227  return list;
228 }
229
230 PyObject* sw_get_photos(Itdb_PhotoDB *db) {
231  PyObject    *list;
232  gint        i;
233  GList       *l;
234  list = PyList_New(g_list_length(db->photos));
235  for (l = db->photos, i = 0; l; l = l->next, ++i) {
236    PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data),
237SWIGTYPE_p__Itdb_Artwork, 0));
238  }
239  return list;
240 }
241
242PyObject* sw_get_photo(GList *list, gint index) {
243  GList *position;
244  if ( (index >= g_list_length(list)) || index < 0 ) {
245   PyErr_SetString(PyExc_IndexError, "Value out of range");
246   return NULL;
247  }
248  position = g_list_nth(list, index);
249  return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_Artwork, 0);
250 }
251
252 void hash_table_to_pydict(gpointer key,
253			   gpointer value,
254			   gpointer user_data) {
255   PyDict_SetItemString((PyObject *)user_data,
256			(char *)key,
257			PyString_FromString(value));
258 }
259
260 PyObject* sw_ipod_device_to_dict(Itdb_Device *device) {
261   PyObject* sysinfo;
262   if (device == NULL) {
263     Py_INCREF(Py_None);
264     return Py_None;
265   } else {
266     sysinfo = PyDict_New();
267     g_hash_table_foreach(device->sysinfo,
268			  hash_table_to_pydict,
269			  (gpointer) sysinfo);
270     return Py_BuildValue("{s:s,s:i,s:i,s:O,s:i}",
271			  "mountpoint",
272			  device->mountpoint,
273			  "musicdirs",
274			  device->musicdirs,
275			  "byte_order",
276			  device->byte_order,
277			  "sysinfo",
278			  sysinfo,
279                          "timezone_shift",
280                          device->timezone_shift);
281   }
282 }
283
284%}
285
286%init %{
287#ifdef HAVE_GDKPIXBUF
288#ifdef HAVE_PYGOBJECT
289#if !GLIB_CHECK_VERSION(2, 36, 0)
290   g_type_init ();
291#endif
292   init_pygobject ();
293#endif
294#endif
295   PyDateTime_IMPORT;
296%}
297
298%include "gpod_doc.i"
299%include "@top_builddir@/config.h"
300
301# be nicer to decode these utf8 strings into Unicode objects in the C
302# layer. Here we are leaving it to the Python side, and just giving
303# them utf8 encoded Strings.
304typedef char gchar;
305
306%typemap(in) time_t {
307  struct tm tmvalue;
308  PyObject* pydatetime = NULL;
309  if (PyDateTime_Check($input)) {
310    pydatetime = $input;
311    Py_INCREF(pydatetime);
312  } else if  ((PyInt_Check($input)) || (PyLong_Check($input)) || (PyFloat_Check($input))) {
313    PyObject* pyargs;
314    Py_INCREF($input);
315    pyargs = PyTuple_Pack(1, $input);
316    if ((pydatetime = PyDateTime_FromTimestamp(pyargs)) == NULL) {
317      Py_DECREF(pyargs);
318      Py_DECREF($input);
319      SWIG_fail;
320    }
321    Py_DECREF(pyargs);
322    Py_DECREF($input);
323  } else {
324    PyErr_SetString(PyExc_ValueError, "$symname: Value must be a datetime.datetime, int or float");
325    SWIG_fail;
326  }
327  tmvalue.tm_year = PyDateTime_GET_YEAR(pydatetime)  - 1900;
328  tmvalue.tm_mon  = PyDateTime_GET_MONTH(pydatetime) - 1;
329  tmvalue.tm_mday = PyDateTime_GET_DAY(pydatetime);
330  tmvalue.tm_hour = PyDateTime_DATE_GET_HOUR(pydatetime);
331  tmvalue.tm_min  = PyDateTime_DATE_GET_MINUTE(pydatetime);
332  tmvalue.tm_sec  = PyDateTime_DATE_GET_SECOND(pydatetime);
333
334  Py_DECREF(pydatetime);
335
336  $1 = mktime(&tmvalue);
337  if ($1 == -1) {
338    PyErr_SetString(PyExc_ValueError, "$symname: Failed to parse provided time");
339    SWIG_fail;
340  }
341}
342
343%typemap(out) time_t {
344#ifdef 0
345  /* for libgpod 0.6.x.. maybe ? */
346  struct tm *tmvalue;
347  tmvalue = localtime(&$1);
348  $result = PyDateTime_FromDateAndTime(tmvalue->tm_year + 1900,
349				       tmvalue->tm_mon  + 1,
350				       tmvalue->tm_mday,
351				       tmvalue->tm_hour,
352				       tmvalue->tm_min,
353				       tmvalue->tm_sec,
354				       0);
355#else
356  $result = PyLong_FromUnsignedLong((unsigned long) $1);
357#endif
358}
359
360%typemap(in) guint8 {
361   unsigned long ival;
362   ival = PyInt_AsUnsignedLongMask($input);
363   if (PyErr_Occurred())
364        SWIG_fail;
365   if (ival > 255) {
366      PyErr_SetString(PyExc_ValueError, "$symname: Value must be between 0 and 255");
367      SWIG_fail;
368   } else {
369      $1 = (guint8) ival;
370   }
371}
372
373%typemap(in) gint8 {
374   long ival;
375   ival = PyInt_AsInt($input);
376   if (PyErr_Occurred())
377        SWIG_fail;
378   if ((ival < -128) || (ival > 127)) {
379      PyErr_SetString(PyExc_ValueError, "$symname: Value must be between -128 and 127");
380      SWIG_fail;
381   } else {
382      $1 = (gint8) ival;
383   }
384}
385
386%typemap(in) guint16 {
387   unsigned long ival;
388   ival = PyInt_AsUnsignedLongMask($input);
389   if (PyErr_Occurred())
390        SWIG_fail;
391   if (ival > 65535) {
392      PyErr_SetString(PyExc_ValueError, "$symname: Value must be between 0 and 65535");
393      SWIG_fail;
394   } else {
395      $1 = (guint16) ival;
396   }
397}
398
399%typemap(in) gint16 {
400   long ival;
401   ival = PyInt_AsLong($input);
402   if (PyErr_Occurred())
403        SWIG_fail;
404   if ((ival < -32768) || (ival > 32767)) {
405      PyErr_SetString(PyExc_ValueError, "$symname: Value must be between -32,768 and 32,767");
406      SWIG_fail;
407   } else {
408      $1 = (gint16) ival;
409   }
410}
411
412%typemap(in) guint32 {
413   unsigned long ival;
414   ival = PyInt_AsUnsignedLongMask($input);
415   if (PyErr_Occurred())
416        SWIG_fail;
417   $1 = (guint32) ival;
418}
419
420%typemap(in) gint32 {
421   long ival;
422   ival = PyInt_AsLong($input);
423   if (PyErr_Occurred())
424        SWIG_fail;
425   $1 = (gint32) ival;
426}
427
428%typemap(in) guint64 {
429  if (PyInt_CheckExact($input))
430    $1 = PyInt_AsUnsignedLongLongMask($input);
431  else
432    $1 = PyLong_AsUnsignedLongLong($input);
433  if (PyErr_Occurred())
434    SWIG_fail;
435}
436
437%typemap(in) gint64 {
438  if (PyInt_CheckExact($input))
439    $1 = PyInt_AsLong($input);
440  else
441    $1 = PyLong_AsLongLong($input);
442  if (PyErr_Occurred())
443    SWIG_fail;
444}
445
446%typemap(out) guint64 {
447   $result = PyLong_FromUnsignedLongLong($1);
448}
449
450%typemap(out) gint64 {
451   $result = PyLong_FromLongLong($1);
452}
453
454%typemap(out) guint32 {
455   $result = PyLong_FromUnsignedLong($1);
456}
457
458%typemap(out) gint32 {
459   $result = PyLong_FromLong($1);
460}
461
462%typemap(out) guint16 {
463   $result = PyLong_FromUnsignedLong($1);
464}
465
466%typemap(out) gint16 {
467   $result = PyLong_FromLong($1);
468}
469
470%typemap(out) guint8 {
471   $result = PyInt_FromLong($1);
472}
473
474typedef int gboolean;
475typedef int gint;
476
477#ifdef HAVE_GDKPIXBUF
478#ifdef HAVE_PYGOBJECT
479%typemap(out) gpointer itdb_artwork_get_pixbuf {
480  $result = pygobject_new((GObject *)$1);
481  if ($1) {
482      g_object_unref($1);
483  }
484}
485
486%typemap(in) gpointer pixbuf {
487  $1 = GDK_PIXBUF(pygobject_get($input));
488}
489#endif
490#endif
491
492#define G_BEGIN_DECLS
493#define G_END_DECLS
494
495PyObject* sw_get_tracks(Itdb_iTunesDB *itdb);
496PyObject* sw_get_track(GList *list, gint index);
497PyObject* sw_get_rule(GList *list, gint index);
498PyObject* sw_get_playlist(GList *list, gint index);
499PyObject* sw_get_list_len(GList *list);
500PyObject* sw_get_playlists(Itdb_iTunesDB *itdb);
501PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl);
502PyObject* sw_set_track_userdata(Itdb_Track *track, PyObject *data);
503PyObject* sw_get_track_userdata(Itdb_Track *track);
504PyObject* sw_get_photoalbums(Itdb_PhotoDB *db);
505PyObject* sw_get_photoalbum(GList *list, gint index);
506PyObject* sw_get_photos(Itdb_PhotoDB *db);
507PyObject* sw_get_photo(GList *list, gint index);
508PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album);
509PyObject* sw_ipod_device_to_dict(Itdb_Device *device);
510
511%include "@top_srcdir@/src/itdb.h"
512