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/README.md +13 -2
- data/ext/rbpod/collection.c +0 -1
- data/ext/rbpod/database.c +16 -19
- data/ext/rbpod/device.c +22 -17
- data/ext/rbpod/error.c +0 -1
- data/ext/rbpod/extconf.rb +7 -2
- data/ext/rbpod/macros.h +99 -0
- data/ext/rbpod/playlist.c +52 -21
- data/ext/rbpod/playlist_collection.c +94 -8
- data/ext/rbpod/rbpod.c +0 -34
- data/ext/rbpod/rbpod.h +36 -10
- data/ext/rbpod/track.c +255 -83
- data/ext/rbpod/track_collection.c +108 -5
- data/ext/rbpod/utilities.c +27 -0
- data/lib/rbpod/version.rb +1 -1
- data/spec/rbpod/playlist_collection_spec.rb +20 -0
- data/spec/rbpod/playlist_spec.rb +58 -1
- metadata +6 -12
- data/ext/rbpod/collection.h +0 -10
- data/ext/rbpod/database.h +0 -10
- data/ext/rbpod/device.h +0 -10
- data/ext/rbpod/error.h +0 -12
- data/ext/rbpod/playlist.h +0 -10
- data/ext/rbpod/playlist_collection.h +0 -10
- data/ext/rbpod/track.h +0 -10
- data/ext/rbpod/track_collection.h +0 -10
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
29
|
-
const gchar *ipod_path = NULL;
|
114
|
+
gchar *new_path = StringValueCStr(value);
|
115
|
+
gchar *buffer = NULL;
|
30
116
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
117
|
+
if (track->ipod_path != NULL)
|
118
|
+
g_free(track);
|
119
|
+
|
120
|
+
buffer = g_strdup(new_path);
|
35
121
|
|
36
|
-
|
37
|
-
ipod_path = (const gchar *) &track->ipod_path[1];
|
122
|
+
itdb_filename_fs2ipod(buffer);
|
38
123
|
|
39
|
-
|
40
|
-
mount_point = rb_str_new2(itdb_get_mountpoint(database));
|
124
|
+
track->ipod_path = buffer;
|
41
125
|
|
42
|
-
|
43
|
-
|
126
|
+
return Qnil;
|
127
|
+
}
|
44
128
|
|
45
|
-
|
46
|
-
|
129
|
+
static VALUE rbpod_track_mediatype_get(VALUE self)
|
130
|
+
{
|
131
|
+
Itdb_Track *track = TYPED_DATA_PTR(self, Itdb_Track);
|
47
132
|
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
180
|
+
return (track->has_artwork == 0x01) ? Qtrue : Qfalse;
|
101
181
|
}
|
102
182
|
|
103
|
-
|
104
|
-
|
105
|
-
*
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
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
|
-
|
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
@@ -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
|
data/spec/rbpod/playlist_spec.rb
CHANGED
@@ -1,3 +1,60 @@
|
|
1
1
|
describe RbPod::Playlist do
|
2
|
-
|
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
|