rbpod 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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