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/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
|