rbpod 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/rbpod/track.c CHANGED
@@ -1,115 +1,203 @@
1
1
  /* track.c */
2
2
 
3
3
  #include "rbpod.h"
4
- #include "track.h"
5
4
 
6
- /*
7
- * call-seq:
8
- * transferred?() -> Boolean
9
- *
10
- * Returns true or false if this track has been transferred to the device.
11
- */
12
- static VALUE rbpod_track_transferred_p(VALUE self)
5
+ ID sMEDIA_TYPE_AUDIO_VIDEO;
6
+ ID sMEDIA_TYPE_AUDIO;
7
+ ID sMEDIA_TYPE_VIDEO;
8
+ ID sMEDIA_TYPE_PODCAST;
9
+ ID sMEDIA_TYPE_VIDEO_PODCAST;
10
+ ID sMEDIA_TYPE_AUDIO_BOOK;
11
+ ID sMEDIA_TYPE_MUSIC_VIDEO;
12
+ ID sMEDIA_TYPE_TV_SHOW_EXCL;
13
+ ID sMEDIA_TYPE_TV_SHOW;
14
+
15
+ typedef enum {
16
+ MEDIA_TYPE_AUDIO_VIDEO = 0x00000000,
17
+ MEDIA_TYPE_AUDIO = 0x00000001,
18
+ MEDIA_TYPE_VIDEO = 0x00000002,
19
+ MEDIA_TYPE_PODCAST = 0x00000004,
20
+ MEDIA_TYPE_VIDEO_PODCAST = 0x00000006,
21
+ MEDIA_TYPE_AUDIO_BOOK = 0x00000008,
22
+ MEDIA_TYPE_MUSIC_VIDEO = 0x00000020,
23
+ MEDIA_TYPE_TV_SHOW_EXCL = 0x00000040,
24
+ MEDIA_TYPE_TV_SHOW = 0x00000060,
25
+ } media_type;
26
+
27
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, title);
28
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, album);
29
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, artist);
30
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, genre);
31
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, filetype);
32
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, comment);
33
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, category);
34
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, composer);
35
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, grouping);
36
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, description);
37
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, podcasturl);
38
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, podcastrss);
39
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, subtitle);
40
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, tvshow);
41
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, tvepisode);
42
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, tvnetwork);
43
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, albumartist);
44
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, keywords);
45
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_artist);
46
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_title);
47
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_album);
48
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_albumartist);
49
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_composer);
50
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, STRING, sort_tvshow);
51
+
52
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, id);
53
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, size);
54
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, tracklen);
55
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, cd_nr);
56
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, cds);
57
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, track_nr);
58
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, tracks);
59
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, bitrate);
60
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, samplerate);
61
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, year);
62
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, volume);
63
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, soundcheck);
64
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, rating);
65
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, playcount);
66
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, recent_playcount);
67
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, BPM);
68
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, starttime);
69
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, stoptime);
70
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, skipcount);
71
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, recent_skipcount);
72
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, pregap);
73
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, samplecount);
74
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, postgap);
75
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, season_nr);
76
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, FIXNUM, episode_nr);
77
+
78
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, transferred);
79
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, compilation);
80
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, visible);
81
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, explicit_flag);
82
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, skip_when_shuffling);
83
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, remember_playback_position);
84
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, lyrics_flag);
85
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, movie_flag);
86
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, gapless_track_flag);
87
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, BOOLEAN, gapless_album_flag);
88
+
89
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, time_added);
90
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, time_modified);
91
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, time_played);
92
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, bookmark_time);
93
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, time_released);
94
+ DEF_ATTR_ACCESSOR(Itdb_Track, track, DATETIME, last_skipped);
95
+
96
+ static VALUE rbpod_track_ipod_path_get(VALUE self)
13
97
  {
14
98
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
15
- return BooleanValue(track->transferred);
99
+ gchar *buffer = NULL;
100
+
101
+ if (track->ipod_path == NULL)
102
+ return Qnil;
103
+
104
+ buffer = g_strdup(track->ipod_path);
105
+
106
+ itdb_filename_ipod2fs(buffer);
107
+
108
+ return rb_str_new2(buffer);
16
109
  }
17
110
 
18
- /*
19
- * call-seq:
20
- * path() -> String
21
- *
22
- * Returns the full path to the file backing this track on the device.
23
- */
24
- static VALUE rbpod_track_path_get(VALUE self)
111
+ static VALUE rbpod_track_ipod_path_set(VALUE self, VALUE value)
25
112
  {
26
113
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
27
- VALUE mount_point, path_parts, file_path, full_path;
28
- Itdb_iTunesDB *database = track->itdb;
29
- const gchar *ipod_path = NULL;
114
+ gchar *new_path = StringValueCStr(value);
115
+ gchar *buffer = NULL;
30
116
 
31
- /* Never hurts to be careful, right? */
32
- if (database == NULL || track->ipod_path == NULL) {
33
- return Qnil;
34
- }
117
+ if (track->ipod_path != NULL)
118
+ g_free(track);
119
+
120
+ buffer = g_strdup(new_path);
35
121
 
36
- /* Skip the prepended directory separator. */
37
- ipod_path = (const gchar *) &track->ipod_path[1];
122
+ itdb_filename_fs2ipod(buffer);
38
123
 
39
- /* Extract the iPod mount point from the database pointer. */
40
- mount_point = rb_str_new2(itdb_get_mountpoint(database));
124
+ track->ipod_path = buffer;
41
125
 
42
- /* Split the track's ipod_path by ':' character. */
43
- path_parts = rb_str_split(rb_str_new2(ipod_path), ":");
126
+ return Qnil;
127
+ }
44
128
 
45
- /* Use File.join to rejoin the path safely. */
46
- file_path = rb_funcall2(rb_cFile, rb_intern("join"), 1, &path_parts);
129
+ static VALUE rbpod_track_mediatype_get(VALUE self)
130
+ {
131
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
47
132
 
48
- /* Retrieve the expanded absolute path name. */
49
- full_path = rb_file_expand_path(file_path, mount_point);
133
+ switch(track->mediatype) {
134
+ case MEDIA_TYPE_AUDIO_VIDEO:
135
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_AUDIO_VIDEO);
136
+ case MEDIA_TYPE_AUDIO:
137
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_AUDIO);
138
+ case MEDIA_TYPE_VIDEO:
139
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_VIDEO);
140
+ case MEDIA_TYPE_PODCAST:
141
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_PODCAST);
142
+ case MEDIA_TYPE_VIDEO_PODCAST:
143
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_VIDEO_PODCAST);
144
+ case MEDIA_TYPE_AUDIO_BOOK:
145
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_AUDIO_BOOK);
146
+ case MEDIA_TYPE_MUSIC_VIDEO:
147
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_MUSIC_VIDEO);
148
+ case MEDIA_TYPE_TV_SHOW_EXCL:
149
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_TV_SHOW_EXCL);
150
+ case MEDIA_TYPE_TV_SHOW:
151
+ return rb_const_get(cRbPodTrack, sMEDIA_TYPE_TV_SHOW);
152
+ }
50
153
 
51
- /* Return a Pathname instance for the resolved path. */
52
- return rb_class_new_instance(1, &full_path, rb_cPathname);
154
+ return Qnil;
53
155
  }
54
156
 
55
- /*
56
- * call-seq:
57
- * type() -> String
58
- *
59
- * Returns a human-readable string describing the content of the track.
60
- */
61
- static VALUE rbpod_track_type_get(VALUE self)
157
+ static VALUE rbpod_track_mediatype_set(VALUE self, VALUE value)
62
158
  {
63
159
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
64
- return rb_str_new2(track->filetype);
160
+ track->mediatype = NUM2INT(value);
161
+ return Qnil;
65
162
  }
66
163
 
67
- /*
68
- * call-seq:
69
- * artist() -> String
70
- *
71
- * Returns the artist for the track.
72
- */
73
- static VALUE rbpod_track_artist_get(VALUE self)
164
+ static VALUE rbpod_track_checked_get(VALUE self)
74
165
  {
75
166
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
76
- return rb_str_new2(track->artist);
167
+ return (track->checked == 0x0) ? Qtrue : Qfalse;
77
168
  }
78
169
 
79
- /*
80
- * call-seq:
81
- * album() -> String
82
- *
83
- * Returns the album for the track.
84
- */
85
- static VALUE rbpod_track_album_get(VALUE self)
170
+ static VALUE rbpod_track_checked_set(VALUE self, VALUE value)
86
171
  {
87
172
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
88
- return rb_str_new2(track->album);
173
+ track->checked = RTEST(value) ? 0x0 : 0x1;
174
+ return Qnil;
89
175
  }
90
176
 
91
- /*
92
- * call-seq:
93
- * title() -> String
94
- *
95
- * Returns the title of the track.
96
- */
97
- static VALUE rbpod_track_title_get(VALUE self)
177
+ static VALUE rbpod_track_has_artwork_get(VALUE self)
98
178
  {
99
179
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
100
- return rb_str_new2(track->title);
180
+ return (track->has_artwork == 0x01) ? Qtrue : Qfalse;
101
181
  }
102
182
 
103
- /*
104
- * call-seq:
105
- * id() -> Fixnum
106
- *
107
- * Returns the internal ID number for this track. Do not use this method.
108
- */
109
- static VALUE rbpod_track_id_get(VALUE self)
183
+ static VALUE rbpod_track_has_artwork_set(VALUE self, VALUE value)
184
+ {
185
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
186
+ track->has_artwork = RTEST(value) ? 0x1 : 0x2;
187
+ return Qnil;
188
+ }
189
+
190
+ static VALUE rbpod_track_mark_unplayed_get(VALUE self)
110
191
  {
111
192
  Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
112
- return INT2NUM(track->id);
193
+ return (track->mark_unplayed == 0x2) ? Qtrue : Qfalse;
194
+ }
195
+
196
+ static VALUE rbpod_track_mark_unplayed_set(VALUE self, VALUE value)
197
+ {
198
+ Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
199
+ track->mark_unplayed = RTEST(value) ? 0x2 : 0x1;
200
+ return Qnil;
113
201
  }
114
202
 
115
203
  /*
@@ -128,7 +216,7 @@ static void rbpod_track_deallocate(void *handle)
128
216
  Itdb_Track *track = (Itdb_Track *) handle;
129
217
 
130
218
  /* Don't free tracks that are assigned to a playlist/database. */
131
- if (track->itdb == NULL || track->id == 0) {
219
+ if (track->itdb == NULL) {
132
220
  itdb_track_free((Itdb_Track *) handle);
133
221
  }
134
222
 
@@ -152,15 +240,99 @@ void Init_rbpod_track(void)
152
240
 
153
241
  rb_define_method(cRbPodTrack, "initialize", rbpod_track_initialize, 0);
154
242
 
155
- rb_define_private_method(cRbPodTrack, "id", rbpod_track_id_get, 0);
243
+ sMEDIA_TYPE_AUDIO_VIDEO = rb_intern("MEDIA_TYPE_AUDIO_VIDEO");
244
+ sMEDIA_TYPE_AUDIO = rb_intern("MEDIA_TYPE_AUDIO");
245
+ sMEDIA_TYPE_VIDEO = rb_intern("MEDIA_TYPE_VIDEO");
246
+ sMEDIA_TYPE_PODCAST = rb_intern("MEDIA_TYPE_PODCAST");
247
+ sMEDIA_TYPE_VIDEO_PODCAST = rb_intern("MEDIA_TYPE_VIDEO_PODCAST");
248
+ sMEDIA_TYPE_AUDIO_BOOK = rb_intern("MEDIA_TYPE_AUDIO_BOOK");
249
+ sMEDIA_TYPE_MUSIC_VIDEO = rb_intern("MEDIA_TYPE_MUSIC_VIDEO");
250
+ sMEDIA_TYPE_TV_SHOW_EXCL = rb_intern("MEDIA_TYPE_TV_SHOW_EXCL");
251
+ sMEDIA_TYPE_TV_SHOW = rb_intern("MEDIA_TYPE_TV_SHOW");
252
+
253
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_AUDIO_VIDEO, UINT2NUM(MEDIA_TYPE_AUDIO_VIDEO));
254
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_AUDIO, UINT2NUM(MEDIA_TYPE_AUDIO));
255
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_VIDEO, UINT2NUM(MEDIA_TYPE_VIDEO));
256
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_PODCAST, UINT2NUM(MEDIA_TYPE_PODCAST));
257
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_VIDEO_PODCAST, UINT2NUM(MEDIA_TYPE_VIDEO_PODCAST));
258
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_AUDIO_BOOK, UINT2NUM(MEDIA_TYPE_AUDIO_BOOK));
259
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_MUSIC_VIDEO, UINT2NUM(MEDIA_TYPE_MUSIC_VIDEO));
260
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_TV_SHOW_EXCL, UINT2NUM(MEDIA_TYPE_TV_SHOW_EXCL));
261
+ rb_const_set(cRbPodTrack, sMEDIA_TYPE_TV_SHOW, UINT2NUM(MEDIA_TYPE_TV_SHOW));
262
+
263
+ DCL_ATTR(cRbPodTrack, track, title, title);
264
+ DCL_ATTR(cRbPodTrack, track, ipod_path, ipod_path);
265
+ DCL_ATTR(cRbPodTrack, track, album, album);
266
+ DCL_ATTR(cRbPodTrack, track, artist, artist);
267
+ DCL_ATTR(cRbPodTrack, track, genre, genre);
268
+ DCL_ATTR(cRbPodTrack, track, file_type, filetype);
269
+ DCL_ATTR(cRbPodTrack, track, comment, comment);
270
+ DCL_ATTR(cRbPodTrack, track, category, category);
271
+ DCL_ATTR(cRbPodTrack, track, composer, composer);
272
+ DCL_ATTR(cRbPodTrack, track, grouping, grouping);
273
+ DCL_ATTR(cRbPodTrack, track, description, description);
274
+ DCL_ATTR(cRbPodTrack, track, podcast_url, podcasturl);
275
+ DCL_ATTR(cRbPodTrack, track, podcast_rss, podcastrss);
276
+ DCL_ATTR(cRbPodTrack, track, subtitle, subtitle);
277
+ DCL_ATTR(cRbPodTrack, track, tv_show, tvshow);
278
+ DCL_ATTR(cRbPodTrack, track, tv_episode, tvepisode);
279
+ DCL_ATTR(cRbPodTrack, track, tv_network, tvnetwork);
280
+ DCL_ATTR(cRbPodTrack, track, album_artist, albumartist);
281
+ DCL_ATTR(cRbPodTrack, track, keywords, keywords);
282
+ DCL_ATTR(cRbPodTrack, track, sort_artist, sort_artist);
283
+ DCL_ATTR(cRbPodTrack, track, sort_title, sort_title);
284
+ DCL_ATTR(cRbPodTrack, track, sort_album, sort_album);
285
+ DCL_ATTR(cRbPodTrack, track, sort_albumartist, sort_albumartist);
286
+ DCL_ATTR(cRbPodTrack, track, sort_composer, sort_composer);
287
+ DCL_ATTR(cRbPodTrack, track, sort_tvshow, sort_tvshow);
288
+
289
+ DCL_ATTR(cRbPodTrack, track, id, id);
290
+ DCL_ATTR(cRbPodTrack, track, size, size);
291
+ DCL_ATTR(cRbPodTrack, track, length, tracklen);
292
+ DCL_ATTR(cRbPodTrack, track, cd_number, cd_nr);
293
+ DCL_ATTR(cRbPodTrack, track, cd_total, cds);
294
+ DCL_ATTR(cRbPodTrack, track, track_number, track_nr);
295
+ DCL_ATTR(cRbPodTrack, track, track_total, tracks);
296
+ DCL_ATTR(cRbPodTrack, track, bitrate, bitrate);
297
+ DCL_ATTR(cRbPodTrack, track, samplerate, samplerate);
298
+ DCL_ATTR(cRbPodTrack, track, year, year);
299
+ DCL_ATTR(cRbPodTrack, track, volume, volume);
300
+ DCL_ATTR(cRbPodTrack, track, soundcheck, soundcheck);
301
+ DCL_ATTR(cRbPodTrack, track, bookmark, bookmark_time);
302
+ DCL_ATTR(cRbPodTrack, track, rating, rating);
303
+ DCL_ATTR(cRbPodTrack, track, play_count, playcount);
304
+ DCL_ATTR(cRbPodTrack, track, recent_play_count, recent_playcount);
305
+ DCL_ATTR(cRbPodTrack, track, BPM, BPM);
306
+ DCL_ATTR(cRbPodTrack, track, start_offset, starttime);
307
+ DCL_ATTR(cRbPodTrack, track, stop_offset, stoptime);
308
+ DCL_ATTR(cRbPodTrack, track, skip_count, skipcount);
309
+ DCL_ATTR(cRbPodTrack, track, recent_skip_count, recent_skipcount);
310
+ DCL_ATTR(cRbPodTrack, track, pregap, pregap);
311
+ DCL_ATTR(cRbPodTrack, track, sample_count, samplecount);
312
+ DCL_ATTR(cRbPodTrack, track, postgap, postgap);
313
+ DCL_ATTR(cRbPodTrack, track, media_type, mediatype);
314
+ DCL_ATTR(cRbPodTrack, track, season_number, season_nr);
315
+ DCL_ATTR(cRbPodTrack, track, episode_number, episode_nr);
156
316
 
157
- rb_define_method(cRbPodTrack, "title", rbpod_track_title_get, 0);
158
- rb_define_method(cRbPodTrack, "album", rbpod_track_album_get, 0);
159
- rb_define_method(cRbPodTrack, "artist", rbpod_track_artist_get, 0);
160
- rb_define_method(cRbPodTrack, "type", rbpod_track_type_get, 0);
161
- rb_define_method(cRbPodTrack, "path", rbpod_track_path_get, 0);
317
+ DCL_ATTR_P(cRbPodTrack, track, transferred, transferred);
318
+ DCL_ATTR_P(cRbPodTrack, track, compilation, compilation);
319
+ DCL_ATTR_P(cRbPodTrack, track, checked, checked);
320
+ DCL_ATTR_P(cRbPodTrack, track, visible, visible);
321
+ DCL_ATTR_P(cRbPodTrack, track, explicit, explicit_flag);
322
+ DCL_ATTR_P(cRbPodTrack, track, has_artwork, has_artwork);
323
+ DCL_ATTR_P(cRbPodTrack, track, skip_when_shuffling, skip_when_shuffling);
324
+ DCL_ATTR_P(cRbPodTrack, track, remember_position, remember_playback_position);
325
+ DCL_ATTR_P(cRbPodTrack, track, has_lyrics, lyrics_flag);
326
+ DCL_ATTR_P(cRbPodTrack, track, movie, movie_flag);
327
+ DCL_ATTR_P(cRbPodTrack, track, unplayed, mark_unplayed);
328
+ DCL_ATTR_P(cRbPodTrack, track, gapless, gapless_track_flag);
329
+ DCL_ATTR_P(cRbPodTrack, track, has_gapless_album, gapless_album_flag);
162
330
 
163
- rb_define_method(cRbPodTrack, "transferred?", rbpod_track_transferred_p, 0);
331
+ DCL_ATTR(cRbPodTrack, track, added_on, time_added);
332
+ DCL_ATTR(cRbPodTrack, track, modified_on, time_modified);
333
+ DCL_ATTR(cRbPodTrack, track, last_played_on, time_played);
334
+ DCL_ATTR(cRbPodTrack, track, released_on, time_released);
335
+ DCL_ATTR(cRbPodTrack, track, last_skipped_on, last_skipped);
164
336
 
165
337
  return;
166
338
  }
@@ -1,10 +1,6 @@
1
1
  /* track_collection.c */
2
2
 
3
3
  #include "rbpod.h"
4
- #include "track.h"
5
- #include "playlist.h"
6
- #include "collection.h"
7
- #include "track_collection.h"
8
4
 
9
5
  /*
10
6
  * call-seq:
@@ -14,7 +10,103 @@
14
10
  */
15
11
  static VALUE rbpod_track_collection_playlist(VALUE self)
16
12
  {
17
- return rb_iv_get(self, "@playlist");
13
+ VALUE playlist = rb_iv_get(self, "@playlist");
14
+
15
+ if (rb_obj_is_instance_of(playlist, cRbPodPlaylist) == FALSE) {
16
+ rb_raise(eRbPodError, "Invalid Arguments: Expected RbPod::Playlist, got %s", StringValueCStr(playlist));
17
+ return Qnil;
18
+ }
19
+
20
+ return playlist;
21
+ }
22
+
23
+ /*
24
+ * call-seq:
25
+ * include?(track) -> boolean
26
+ *
27
+ * Determines if the given RbPod::Track +track+ is within this playlist.
28
+ */
29
+ static VALUE rbpod_track_collection_include(VALUE self, VALUE track)
30
+ {
31
+ VALUE playlist = rbpod_track_collection_playlist(self);
32
+ Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
33
+ Itdb_Track *_track = TYPED_DATA_PTR(track, Itdb_Track);
34
+
35
+ if (rb_obj_is_instance_of(track, cRbPodTrack) == FALSE) {
36
+ rb_raise(eRbPodError, "Invalid Arguments: Expected RbPod::Track, got %s", StringValueCStr(playlist));
37
+ return Qnil;
38
+ }
39
+
40
+ return BooleanValue(itdb_playlist_contains_track(_playlist, _track));
41
+ }
42
+
43
+ /*
44
+ * call-seq:
45
+ * remove(track) -> nil
46
+ *
47
+ * Removes a given RbPod::Track +track+ from the playlist.
48
+ */
49
+ static VALUE rbpod_track_collection_remove(VALUE self, VALUE track)
50
+ {
51
+ VALUE playlist = rbpod_track_collection_playlist(self);
52
+ Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
53
+ Itdb_Track *_track = TYPED_DATA_PTR(track, Itdb_Track);
54
+
55
+ if (rb_obj_is_instance_of(track, cRbPodTrack) == FALSE) {
56
+ rb_raise(eRbPodError, "Invalid Arguments: Expected RbPod::Track, got %s", StringValueCStr(playlist));
57
+ return Qnil;
58
+ }
59
+
60
+ itdb_playlist_remove_track(_playlist, _track);
61
+
62
+ return Qnil;
63
+ }
64
+
65
+ /*
66
+ * call-seq:
67
+ * insert(track, position = -1) -> nil
68
+ *
69
+ * Adds a given RbPod::Track +track+ to the playlist at +position+. If +position+
70
+ * was not supplied, +track+ will be appended to the end of the playlist.
71
+ */
72
+ static VALUE rbpod_track_collection_insert(int argc, VALUE *argv, VALUE self)
73
+ {
74
+ VALUE playlist = rbpod_track_collection_playlist(self);
75
+ Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
76
+ VALUE track = Qnil, position = Qnil;
77
+ Itdb_Track *_track = NULL;
78
+ gint32 _position = 0;
79
+
80
+ if (rb_scan_args(argc, argv, "11", &track, &position) < 1) {
81
+ rb_raise(eRbPodError, "Invalid arguments: Expected >= 1 argument!");
82
+ return Qnil;
83
+ }
84
+
85
+ _track = TYPED_DATA_PTR(track, Itdb_Track);
86
+ _position = NIL_P(position) ? -1 : NUM2INT(position);
87
+
88
+ /* We we given a track? */
89
+ if (rb_obj_is_instance_of(track, cRbPodTrack) == FALSE) {
90
+ rb_raise(eRbPodError, "Invalid argument: expected RbPod::Track, got %s", StringValueCStr(playlist));
91
+ return Qnil;
92
+ }
93
+
94
+ itdb_playlist_add_track(_playlist, _track, _position);
95
+
96
+ return Qnil;
97
+ }
98
+
99
+ /*
100
+ * call-seq:
101
+ * size() -> integer
102
+ *
103
+ * Returns the total number of tracks in this playlist.
104
+ */
105
+ static VALUE rbpod_track_collection_size(VALUE self)
106
+ {
107
+ VALUE playlist = rbpod_track_collection_playlist(self);
108
+ Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
109
+ return INT2NUM(itdb_playlist_tracks_number(_playlist));
18
110
  }
19
111
 
20
112
  /*
@@ -62,6 +154,17 @@ void Init_rbpod_track_collection(void)
62
154
 
63
155
  rb_define_method(cRbPodTrackCollection, "playlist", rbpod_track_collection_playlist, 0);
64
156
 
157
+ rb_define_method(cRbPodTrackCollection, "size", rbpod_track_collection_size, 0);
158
+
159
+ rb_define_method(cRbPodTrackCollection, "insert", rbpod_track_collection_insert, -1);
160
+
161
+ rb_define_method(cRbPodTrackCollection, "remove", rbpod_track_collection_remove, 1);
162
+
163
+ rb_define_method(cRbPodTrackCollection, "include?", rbpod_track_collection_include, 1);
164
+
165
+ /* Syntactic sugar for adding a track. */
166
+ rb_define_alias(cRbPodTrackCollection, "<<", "insert");
167
+
65
168
  return;
66
169
  }
67
170
 
@@ -0,0 +1,27 @@
1
+ /* utilities.c */
2
+
3
+ #include "rbpod.h"
4
+
5
+ /*
6
+ * This is a hack used to inject a pointer from the data of one class instance into another.
7
+ */
8
+ inline VALUE rb_class_new_instance_with_data(int argc, VALUE *argv, VALUE class, void *handle)
9
+ {
10
+ /* Create a new instance of this class. */
11
+ VALUE instance = rb_class_new_instance(argc, argv, class);
12
+ /* Assign it's DATA pointer to the given handle. */
13
+ DATA_PTR(instance) = handle;
14
+ /* Return the instance. */
15
+ return instance;
16
+ }
17
+
18
+ /*
19
+ * This is a hack so that including a module will trigger the +included+ singleton method.
20
+ */
21
+ inline void rb_real_include_module(VALUE klass, VALUE module)
22
+ {
23
+ ID included = rb_intern("included");
24
+ rb_include_module(klass, module);
25
+ rb_funcall(mRbPodCollection, included, 1, klass);
26
+ }
27
+
data/lib/rbpod/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RbPod # :nodoc:
2
- VERSION = "0.0.5" # :nodoc:
2
+ VERSION = "0.0.6" # :nodoc:
3
3
  end
@@ -41,4 +41,24 @@ describe RbPod::PlaylistCollection do
41
41
  collection.include?(anonymous_playlist).should be_false
42
42
  end
43
43
  end
44
+
45
+ let (:playlist) { RbPod::Playlist.new() }
46
+
47
+ describe '#insert' do
48
+ it 'should add a playlist to the database' do
49
+ collection.insert(playlist)
50
+ collection.database.save!
51
+ collection.include?(playlist).should be_true
52
+ end
53
+ end
54
+
55
+ describe '#remove' do
56
+ it 'should remove a playlist from the database' do
57
+ collection.insert(playlist)
58
+ collection.database.save!
59
+ collection.remove(playlist)
60
+ collection.database.save!
61
+ collection.include?(playlist).should be_false
62
+ end
63
+ end
44
64
  end
@@ -1,3 +1,60 @@
1
1
  describe RbPod::Playlist do
2
- # Nothing yet.
2
+ context 'with a new playlist' do
3
+ let (:playlist) { RbPod::Playlist.new }
4
+
5
+ describe '#initialize' do
6
+ it 'should return a new playlist' do
7
+ playlist.should be_instance_of(RbPod::Playlist)
8
+ end
9
+ end
10
+
11
+ describe '#name' do
12
+ it 'should be "New Playlist"' do
13
+ playlist.name.should be_kind_of(String)
14
+ playlist.name.should eq('New Playlist')
15
+ end
16
+ end
17
+
18
+ describe '#created_on' do
19
+ it 'should have a creation date' do
20
+ playlist.created_on.should be_kind_of(Time)
21
+ end
22
+ end
23
+
24
+ describe '#length' do
25
+ it 'should contain zero tracks' do
26
+ playlist.length.should be_kind_of(Integer)
27
+ playlist.length.should eq(0)
28
+ end
29
+ end
30
+
31
+ describe '#tracks' do
32
+ it 'should return a collection of tracks' do
33
+ playlist.tracks.should be_instance_of(RbPod::TrackCollection)
34
+ end
35
+
36
+ it 'should have zero tracks within it' do
37
+ playlist.tracks.size.should be_kind_of(Integer)
38
+ playlist.tracks.size.should eq(0)
39
+ end
40
+ end
41
+
42
+ describe '#smart?' do
43
+ it 'should not be a smart playlist' do
44
+ playlist.should_not be_smart
45
+ end
46
+ end
47
+
48
+ describe '#master?' do
49
+ it 'should not be the master playlist' do
50
+ playlist.should_not be_master
51
+ end
52
+ end
53
+
54
+ describe '#podcast?' do
55
+ it 'should not be the podcast playlist' do
56
+ playlist.should_not be_podcast
57
+ end
58
+ end
59
+ end
3
60
  end