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/README.md
CHANGED
@@ -104,10 +104,21 @@ playlist.podcast? # => false
|
|
104
104
|
|
105
105
|
playlist.tracks # => #<RbPod::TrackCollection:0xdeadbeef>
|
106
106
|
```
|
107
|
+
### RbPod::TrackCollection
|
107
108
|
|
108
|
-
|
109
|
+
All playlists contain a `tracks` method which returns an `RbPod::TrackCollection`:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
tracks = database.playlists.master.tracks
|
113
|
+
|
114
|
+
tracks.playlist # => #<RbPod::Playlist:0xdeadbeef>
|
115
|
+
tracks.length # => 400
|
109
116
|
|
110
|
-
|
117
|
+
tracks.first # => #<RbPod::Track:0xdeadbeef>
|
118
|
+
tracks[0] # => #<RbPod::Track:0xdeadbeef>
|
119
|
+
```
|
120
|
+
|
121
|
+
### RbPod::Track
|
111
122
|
|
112
123
|
```ruby
|
113
124
|
track = database.playlists.master.tracks.first
|
data/ext/rbpod/collection.c
CHANGED
data/ext/rbpod/database.c
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
/* database.c */
|
2
2
|
|
3
3
|
#include "rbpod.h"
|
4
|
-
#include "error.h"
|
5
|
-
#include "device.h"
|
6
|
-
#include "database.h"
|
7
|
-
#include "playlist.h"
|
8
|
-
#include "track_collection.h"
|
9
|
-
#include "playlist_collection.h"
|
10
4
|
|
11
5
|
/*
|
12
6
|
* call-seq:
|
@@ -71,7 +65,9 @@ static VALUE rbpod_database_tracks_get(VALUE self)
|
|
71
65
|
*/
|
72
66
|
static VALUE rbpod_database_device_get(VALUE self)
|
73
67
|
{
|
74
|
-
|
68
|
+
Itdb_iTunesDB *database = TYPED_DATA_PTR(self, Itdb_iTunesDB);
|
69
|
+
VALUE mount_point = rb_str_new2(itdb_get_mountpoint(database));
|
70
|
+
return rb_class_new_instance(1, &mount_point, cRbPodDevice);
|
75
71
|
}
|
76
72
|
|
77
73
|
/*
|
@@ -203,34 +199,35 @@ static VALUE rbpod_database_create(int argc, VALUE *argv, VALUE self)
|
|
203
199
|
return Qnil;
|
204
200
|
}
|
205
201
|
|
206
|
-
/* If
|
207
|
-
if (RTEST(device_name)
|
208
|
-
device_name
|
209
|
-
}
|
202
|
+
/* If a device name was given, ensure it's a string. */
|
203
|
+
if (RTEST(device_name)) {
|
204
|
+
Check_Type(device_name, T_STRING);
|
210
205
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
206
|
+
if (RSTRING_LEN(device_name) < 4) {
|
207
|
+
rb_raise(eRbPodError, "Device name must be a string of at least four characters.");
|
208
|
+
return Qnil;
|
209
|
+
}
|
215
210
|
}
|
216
211
|
|
217
212
|
/* If a model number was given, ensure it's a string. */
|
218
213
|
if (RTEST(model_number)) {
|
219
|
-
Check_Type(
|
214
|
+
Check_Type(model_number, T_STRING);
|
220
215
|
|
221
|
-
model_matcher = rb_str_new2("/
|
216
|
+
model_matcher = rb_str_new2("/[xM]?[A-Z][0-9]{3}/");
|
222
217
|
ignorecase = rb_const_get(rb_cRegexp, rb_intern("IGNORECASE"));
|
223
218
|
model_regexp = rb_reg_new_str(model_matcher, ignorecase);
|
224
219
|
|
225
220
|
if (RTEST(rb_reg_match(model_regexp, model_number)) == FALSE) {
|
226
|
-
rb_raise(eRbPodError, "Model number must be a string matching: /
|
221
|
+
rb_raise(eRbPodError, "Model number must be a string matching: /[xM]?[A-Z][0-9]{3}/i");
|
227
222
|
return Qnil;
|
228
223
|
}
|
229
224
|
}
|
230
225
|
|
231
226
|
/* Extract pointers for glib use. */
|
232
227
|
_mount_point = StringValueCStr(mount_point);
|
233
|
-
|
228
|
+
|
229
|
+
/* GPod will use 'iPod' as the device name if it wasn't specified. */
|
230
|
+
_device_name = !NIL_P(device_name) ? StringValueCStr(device_name) : NULL;
|
234
231
|
|
235
232
|
/* GPod can function with a NULL model number, however, artwork may not function properly. */
|
236
233
|
_model_number = !NIL_P(model_number) ? StringValueCStr(model_number) : NULL;
|
data/ext/rbpod/device.c
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
/* device.c */
|
2
2
|
|
3
3
|
#include "rbpod.h"
|
4
|
-
#include "error.h"
|
5
|
-
#include "device.h"
|
6
|
-
#include "database.h"
|
7
4
|
|
8
5
|
/*
|
9
6
|
* call-seq:
|
@@ -189,32 +186,38 @@ static VALUE rbpod_device_sysinfo_save(VALUE self)
|
|
189
186
|
|
190
187
|
/*
|
191
188
|
* call-seq:
|
192
|
-
* initialize(
|
189
|
+
* initialize(mount_point) -> RbPod::Device
|
193
190
|
*
|
194
|
-
* Creates an RbPod::Device
|
191
|
+
* Creates an RbPod::Device mapped to a given device mount point.
|
195
192
|
*/
|
196
|
-
static VALUE rbpod_device_initialize(VALUE self, VALUE
|
193
|
+
static VALUE rbpod_device_initialize(VALUE self, VALUE mount_point)
|
197
194
|
{
|
198
|
-
|
195
|
+
Itdb_Device *device = TYPED_DATA_PTR(self, Itdb_Device);
|
199
196
|
|
200
|
-
/*
|
201
|
-
if (
|
202
|
-
rb_raise(eRbPodError, "
|
197
|
+
/* Check if the mount point is a directory. */
|
198
|
+
if (rb_file_directory_p(rb_cFile, mount_point) != Qtrue) {
|
199
|
+
rb_raise(eRbPodError, "The mount point must be a directory!");
|
203
200
|
return Qnil;
|
204
201
|
}
|
205
202
|
|
206
|
-
|
207
|
-
if (_database == NULL || _database->device == NULL) {
|
208
|
-
rb_raise(eRbPodError, "Given database and/or device was NULL.");
|
209
|
-
return Qnil;
|
210
|
-
}
|
203
|
+
itdb_device_set_mountpoint(device, StringValueCStr(mount_point));
|
211
204
|
|
212
|
-
|
213
|
-
DATA_PTR(self) = _database->device;
|
205
|
+
DATA_PTR(self) = device;
|
214
206
|
|
215
207
|
return self;
|
216
208
|
}
|
217
209
|
|
210
|
+
static void rbpod_device_deallocate(void *handle)
|
211
|
+
{
|
212
|
+
itdb_device_free((Itdb_Device *) handle);
|
213
|
+
}
|
214
|
+
|
215
|
+
static VALUE rbpod_device_allocate(VALUE self)
|
216
|
+
{
|
217
|
+
Itdb_Device *device = itdb_device_new();
|
218
|
+
return Data_Wrap_Struct(cRbPodDevice, NULL, rbpod_device_deallocate, (void *) device);
|
219
|
+
}
|
220
|
+
|
218
221
|
void Init_rbpod_device(void)
|
219
222
|
{
|
220
223
|
#if RDOC_CAN_PARSE_DOCUMENTATION
|
@@ -222,6 +225,8 @@ void Init_rbpod_device(void)
|
|
222
225
|
#endif
|
223
226
|
cRbPodDevice = rb_define_class_under(mRbPod, "Device", rb_cObject);
|
224
227
|
|
228
|
+
rb_define_alloc_func(cRbPodDevice, rbpod_device_allocate);
|
229
|
+
|
225
230
|
rb_define_method(cRbPodDevice, "initialize", rbpod_device_initialize, 1);
|
226
231
|
|
227
232
|
rb_define_method(cRbPodDevice, "[]", rbpod_device_sysinfo_get, 1);
|
data/ext/rbpod/error.c
CHANGED
data/ext/rbpod/extconf.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'mkmf'
|
4
2
|
|
3
|
+
# Fail immediately if we don't have libgpod-1.0 installed here.
|
5
4
|
abort "Please install libgpod-1.0" unless pkg_config('libgpod-1.0')
|
6
5
|
|
7
6
|
# Unfortunately, rdoc isn't capable of a lot of things.
|
8
7
|
$defs.push("-DRDOC_CAN_PARSE_DOCUMENTATION=0")
|
9
8
|
|
9
|
+
# Provide HAVE_STDDEF_H to the pre-processor.
|
10
|
+
have_header('stddef.h')
|
11
|
+
|
12
|
+
# Provide HAVE_GPOD_ITDB_H to the pre-processor.
|
13
|
+
have_header('gpod/itdb.h')
|
14
|
+
|
10
15
|
create_makefile('rbpod/rbpod')
|
data/ext/rbpod/macros.h
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
/* macros.h */
|
2
|
+
|
3
|
+
#ifndef RBPOD_MACROS_H
|
4
|
+
#define RBPOD_MACROS_H
|
5
|
+
|
6
|
+
#define BooleanValue(value) (value) ? Qtrue : Qfalse
|
7
|
+
|
8
|
+
#define TYPED_DATA_PTR(self, type) ((type *) DATA_PTR(self))
|
9
|
+
|
10
|
+
#define DEF_ATTR_READER_STRING(c_type, prefix, field) \
|
11
|
+
static VALUE rbpod_##prefix##_##field##_get(VALUE self) \
|
12
|
+
{ \
|
13
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
14
|
+
return (ptr->field == NULL) ? Qnil : rb_str_new2(ptr->field); \
|
15
|
+
}
|
16
|
+
|
17
|
+
#define DEF_ATTR_WRITER_STRING(c_type, prefix, field) \
|
18
|
+
static VALUE rbpod_##prefix##_##field##_set(VALUE self, VALUE value) \
|
19
|
+
{ \
|
20
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
21
|
+
gchar *previous = (gchar *) ptr->field; \
|
22
|
+
ptr->field = StringValueCStr(value); \
|
23
|
+
if (previous != NULL) { \
|
24
|
+
g_free(previous); \
|
25
|
+
} \
|
26
|
+
return Qnil; \
|
27
|
+
}
|
28
|
+
|
29
|
+
#define DEF_ATTR_READER_FIXNUM(c_type, prefix, field) \
|
30
|
+
static VALUE rbpod_##prefix##_##field##_get(VALUE self) \
|
31
|
+
{ \
|
32
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
33
|
+
return INT2NUM(ptr->field); \
|
34
|
+
}
|
35
|
+
|
36
|
+
#define DEF_ATTR_WRITER_FIXNUM(c_type, prefix, field) \
|
37
|
+
static VALUE rbpod_##prefix##_##field##_set(VALUE self, VALUE value) \
|
38
|
+
{ \
|
39
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
40
|
+
ptr->field = NUM2INT(value); \
|
41
|
+
return Qnil; \
|
42
|
+
}
|
43
|
+
|
44
|
+
#define DEF_ATTR_READER_BOOLEAN(c_type, prefix, field) \
|
45
|
+
static VALUE rbpod_##prefix##_##field##_get(VALUE self) \
|
46
|
+
{ \
|
47
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
48
|
+
return (ptr->field == 0) ? Qfalse : Qtrue; \
|
49
|
+
}
|
50
|
+
|
51
|
+
#define DEF_ATTR_WRITER_BOOLEAN(c_type, prefix, field) \
|
52
|
+
static VALUE rbpod_##prefix##_##field##_set(VALUE self, VALUE value) \
|
53
|
+
{ \
|
54
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
55
|
+
ptr->field = (RTEST(value)) ? 1 : 0; \
|
56
|
+
return Qnil; \
|
57
|
+
}
|
58
|
+
|
59
|
+
#define DEF_ATTR_READER_DATETIME(c_type, prefix, field) \
|
60
|
+
static VALUE rbpod_##prefix##_##field##_get(VALUE self) \
|
61
|
+
{ \
|
62
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
63
|
+
VALUE timestamp = INT2NUM(ptr->field); \
|
64
|
+
if (ptr->field == 0) { \
|
65
|
+
return Qnil; \
|
66
|
+
} \
|
67
|
+
return rb_funcall(rb_cTime, rb_intern("at"), 1, timestamp); \
|
68
|
+
}
|
69
|
+
|
70
|
+
#define DEF_ATTR_WRITER_DATETIME(c_type, prefix, field) \
|
71
|
+
static VALUE rbpod_##prefix##_##field##_set(VALUE self, VALUE value) \
|
72
|
+
{ \
|
73
|
+
c_type *ptr = TYPED_DATA_PTR(self, c_type); \
|
74
|
+
ptr->field = rb_funcall(value, rb_intern("to_i"), 0); \
|
75
|
+
return Qnil; \
|
76
|
+
}
|
77
|
+
|
78
|
+
#define DEF_ATTR_ACCESSOR(c_type, prefix, ruby_type, field) \
|
79
|
+
DEF_ATTR_READER_##ruby_type(c_type, prefix, field); \
|
80
|
+
DEF_ATTR_WRITER_##ruby_type(c_type, prefix, field)
|
81
|
+
|
82
|
+
#define DCL_ATTR_WRITER(ruby_class, prefix, name, field) \
|
83
|
+
rb_define_method(ruby_class, #name "=", rbpod_##prefix##_##field##_set, 1)
|
84
|
+
|
85
|
+
#define DCL_ATTR_PREDICATE(ruby_class, prefix, name, field) \
|
86
|
+
rb_define_method(ruby_class, #name "?", rbpod_##prefix##_##field##_get, 0)
|
87
|
+
|
88
|
+
#define DCL_ATTR_READER(ruby_class, prefix, name, field) \
|
89
|
+
rb_define_method(ruby_class, #name, rbpod_##prefix##_##field##_get, 0)
|
90
|
+
|
91
|
+
#define DCL_ATTR_P(ruby_class, prefix, name, field) \
|
92
|
+
DCL_ATTR_PREDICATE(ruby_class, prefix, name, field); \
|
93
|
+
DCL_ATTR_WRITER(ruby_class, prefix, name, field)
|
94
|
+
|
95
|
+
#define DCL_ATTR(ruby_class, prefix, name, field) \
|
96
|
+
DCL_ATTR_READER(ruby_class, prefix, name, field); \
|
97
|
+
DCL_ATTR_WRITER(ruby_class, prefix, name, field)
|
98
|
+
|
99
|
+
#endif /* RBPOD_MACROS_H */
|
data/ext/rbpod/playlist.c
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
/* playlist.c */
|
2
2
|
|
3
3
|
#include "rbpod.h"
|
4
|
-
#include "playlist.h"
|
5
|
-
#include "track_collection.h"
|
6
4
|
|
7
5
|
/*
|
8
6
|
* call-seq:
|
@@ -42,7 +40,21 @@ static VALUE rbpod_playlist_smart_p(VALUE self)
|
|
42
40
|
|
43
41
|
/*
|
44
42
|
* call-seq:
|
45
|
-
*
|
43
|
+
* smart=(flag) -> nil
|
44
|
+
*
|
45
|
+
* Set this playlist to a smart playlist.
|
46
|
+
*/
|
47
|
+
static VALUE rbpod_playlist_smart_set(VALUE self, VALUE flag)
|
48
|
+
{
|
49
|
+
Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
|
50
|
+
|
51
|
+
playlist->is_spl = (RTEST(flag)) ? TRUE : FALSE;
|
52
|
+
|
53
|
+
return Qnil;
|
54
|
+
}
|
55
|
+
|
56
|
+
/*
|
57
|
+
* call-seq:
|
46
58
|
* created_on() -> Time
|
47
59
|
*
|
48
60
|
* Returns a Time object representing the time that this playlist was created.
|
@@ -89,6 +101,27 @@ static VALUE rbpod_playlist_length_get(VALUE self)
|
|
89
101
|
return INT2NUM(itdb_playlist_tracks_number(playlist));
|
90
102
|
}
|
91
103
|
|
104
|
+
/*
|
105
|
+
* call-seq:
|
106
|
+
* name=(string) -> nil
|
107
|
+
*
|
108
|
+
* Sets the name of this playlist.
|
109
|
+
*/
|
110
|
+
static VALUE rbpod_playlist_name_set(VALUE self, VALUE name)
|
111
|
+
{
|
112
|
+
Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
|
113
|
+
gchar *new_name = StringValueCStr(name);
|
114
|
+
gchar *old_name = playlist->name;
|
115
|
+
|
116
|
+
/* Free up the old name. */
|
117
|
+
g_free(old_name);
|
118
|
+
|
119
|
+
/* Attach the new name. */
|
120
|
+
playlist->name = new_name;
|
121
|
+
|
122
|
+
return Qnil;
|
123
|
+
}
|
124
|
+
|
92
125
|
/*
|
93
126
|
* call-seq:
|
94
127
|
* name() -> String
|
@@ -116,24 +149,23 @@ static VALUE rbpod_playlist_compare(VALUE self, VALUE other)
|
|
116
149
|
return Qnil;
|
117
150
|
}
|
118
151
|
|
152
|
+
/* If this is the master playlist, it always comes first. */
|
153
|
+
if (rbpod_playlist_master_p(self) == Qtrue) {
|
154
|
+
return NUM2INT(-1);
|
155
|
+
}
|
156
|
+
|
157
|
+
/* If we're comparing against the master playlist, it comes first. */
|
158
|
+
if (rbpod_playlist_master_p(other) == Qtrue) {
|
159
|
+
return NUM2INT(1);
|
160
|
+
}
|
161
|
+
|
119
162
|
this_playlist_name = rbpod_playlist_name_get(self);
|
120
163
|
other_playlist_name = rbpod_playlist_name_get(other);
|
121
164
|
|
165
|
+
/* Otherwise, compare by playlist name. */
|
122
166
|
return rb_str_cmp(this_playlist_name, other_playlist_name);
|
123
167
|
}
|
124
168
|
|
125
|
-
/*
|
126
|
-
* call-seq:
|
127
|
-
* id() -> Fixnum
|
128
|
-
*
|
129
|
-
* Returns the internal ID number for this playlist. Do not use this method.
|
130
|
-
*/
|
131
|
-
static VALUE rbpod_playlist_id_get(VALUE self)
|
132
|
-
{
|
133
|
-
Itdb_Playlist *playlist = TYPED_DATA_PTR(self, Itdb_Playlist);
|
134
|
-
return INT2NUM(playlist->id);
|
135
|
-
}
|
136
|
-
|
137
169
|
/*
|
138
170
|
* call-seq:
|
139
171
|
* initialize() -> RbPod::Playlist
|
@@ -175,23 +207,22 @@ void Init_rbpod_playlist(void)
|
|
175
207
|
|
176
208
|
rb_define_method(cRbPodPlaylist, "initialize", rbpod_playlist_initialize, 0);
|
177
209
|
|
178
|
-
rb_define_private_method(cRbPodPlaylist, "id", rbpod_playlist_id_get, 0);
|
179
|
-
|
180
210
|
rb_define_method(cRbPodPlaylist, "<=>", rbpod_playlist_compare, 1);
|
181
211
|
|
182
212
|
rb_define_method(cRbPodPlaylist, "name", rbpod_playlist_name_get, 0);
|
183
213
|
rb_define_method(cRbPodPlaylist, "length", rbpod_playlist_length_get, 0);
|
184
214
|
rb_define_method(cRbPodPlaylist, "tracks", rbpod_playlist_tracks_get, 0);
|
185
|
-
rb_define_method(cRbPodPlaylist, "
|
186
|
-
rb_define_method(cRbPodPlaylist, "timestamp", rbpod_playlist_timestamp_get, 0);
|
215
|
+
rb_define_method(cRbPodPlaylist, "created_on", rbpod_playlist_timestamp_get, 0);
|
187
216
|
|
188
|
-
|
189
|
-
|
217
|
+
rb_define_method(cRbPodPlaylist, "name=", rbpod_playlist_name_set, 1);
|
218
|
+
rb_define_method(cRbPodPlaylist, "smart=", rbpod_playlist_smart_set, 1);
|
190
219
|
|
191
220
|
rb_define_method(cRbPodPlaylist, "smart?", rbpod_playlist_smart_p, 0);
|
192
221
|
rb_define_method(cRbPodPlaylist, "master?", rbpod_playlist_master_p, 0);
|
193
222
|
rb_define_method(cRbPodPlaylist, "podcast?", rbpod_playlist_podcast_p, 0);
|
194
223
|
|
224
|
+
rb_define_method(cRbPodPlaylist, "shuffle!", rbpod_playlist_shuffle_bang, 0);
|
225
|
+
|
195
226
|
return;
|
196
227
|
}
|
197
228
|
|
@@ -1,10 +1,6 @@
|
|
1
1
|
/* playlist_collection.c */
|
2
2
|
|
3
3
|
#include "rbpod.h"
|
4
|
-
#include "database.h"
|
5
|
-
#include "playlist.h"
|
6
|
-
#include "collection.h"
|
7
|
-
#include "playlist_collection.h"
|
8
4
|
|
9
5
|
/*
|
10
6
|
* call-seq:
|
@@ -19,24 +15,106 @@ static VALUE rbpod_playlist_collection_database(VALUE self)
|
|
19
15
|
|
20
16
|
/*
|
21
17
|
* call-seq:
|
22
|
-
*
|
18
|
+
* insert(playlist, position = -1) -> nil
|
19
|
+
*
|
20
|
+
* Adds the given RbPod::Playlist +playlist+ to the database.
|
21
|
+
*/
|
22
|
+
static VALUE rbpod_playlist_collection_insert(int argc, VALUE *argv, VALUE self)
|
23
|
+
{
|
24
|
+
VALUE database = rbpod_playlist_collection_database(self);
|
25
|
+
VALUE playlist = Qnil, position = Qnil;
|
26
|
+
Itdb_iTunesDB *_database = NULL;
|
27
|
+
Itdb_Playlist *_playlist = NULL;
|
28
|
+
gint32 _position = 0;
|
29
|
+
|
30
|
+
if (rb_scan_args(argc, argv, "11", &playlist, &position) < 1) {
|
31
|
+
rb_raise(eRbPodError, "Invalid arguments: Expected >= 1 argument!");
|
32
|
+
return Qnil;
|
33
|
+
}
|
34
|
+
|
35
|
+
_database = TYPED_DATA_PTR(database, Itdb_iTunesDB);
|
36
|
+
_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
|
37
|
+
_position = NIL_P(position) ? -1 : NUM2INT(position);
|
38
|
+
|
39
|
+
/* We we given a playlist? */
|
40
|
+
if (rb_obj_is_instance_of(playlist, cRbPodPlaylist) == FALSE) {
|
41
|
+
rb_raise(eRbPodError, "Invalid argument: expected RbPod::Playlist, got %s", StringValueCStr(playlist));
|
42
|
+
return Qnil;
|
43
|
+
}
|
44
|
+
|
45
|
+
/* Does this playlist already exist in the database? */
|
46
|
+
if (itdb_playlist_exists(_database, _playlist) == TRUE) {
|
47
|
+
rb_raise(eRbPodError, "Invalid argument: this playlist already exists in the database!");
|
48
|
+
return Qnil;
|
49
|
+
}
|
50
|
+
|
51
|
+
itdb_playlist_add(_database, _playlist, _position);
|
52
|
+
|
53
|
+
return Qnil;
|
54
|
+
}
|
55
|
+
|
56
|
+
/*
|
57
|
+
* call-seq:
|
58
|
+
* remove(playlist) -> nil
|
59
|
+
*
|
60
|
+
* Removes the given RbPod::Playlist +playlist+ from the database.
|
61
|
+
*/
|
62
|
+
static VALUE rbpod_playlist_collection_remove(VALUE self, VALUE playlist)
|
63
|
+
{
|
64
|
+
VALUE database = rbpod_playlist_collection_database(self);
|
65
|
+
Itdb_iTunesDB *_database = TYPED_DATA_PTR(database, Itdb_iTunesDB);
|
66
|
+
Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
|
67
|
+
|
68
|
+
/* We we given a playlist? */
|
69
|
+
if (rb_obj_is_instance_of(playlist, cRbPodPlaylist) == FALSE) {
|
70
|
+
rb_raise(eRbPodError, "Invalid argument: Expected RbPod::Playlist, got %s", StringValueCStr(playlist));
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Does this playlist already exist in the database? */
|
75
|
+
if (itdb_playlist_exists(_database, _playlist) == FALSE) {
|
76
|
+
rb_raise(eRbPodError, "Invalid argument: This playlist does not exist in the database!");
|
77
|
+
return Qnil;
|
78
|
+
}
|
79
|
+
|
80
|
+
itdb_playlist_remove(_playlist);
|
81
|
+
|
82
|
+
return Qnil;
|
83
|
+
}
|
84
|
+
|
85
|
+
/*
|
86
|
+
* call-seq:
|
87
|
+
* include?(playlist) -> boolean
|
23
88
|
*
|
24
89
|
* Returns true or false if the given RbPod::Playlist +playlist+ exists within the database.
|
25
90
|
*/
|
26
|
-
static VALUE
|
91
|
+
static VALUE rbpod_playlist_collection_include(VALUE self, VALUE playlist)
|
27
92
|
{
|
28
93
|
VALUE database = rbpod_playlist_collection_database(self);
|
29
94
|
Itdb_iTunesDB *_database = TYPED_DATA_PTR(database, Itdb_iTunesDB);
|
30
95
|
Itdb_Playlist *_playlist = TYPED_DATA_PTR(playlist, Itdb_Playlist);
|
31
96
|
|
32
97
|
if (rb_obj_is_instance_of(playlist, cRbPodPlaylist) == FALSE) {
|
33
|
-
rb_raise(eRbPodError, "Invalid argument:
|
98
|
+
rb_raise(eRbPodError, "Invalid argument: Expected RbPod::Playlist, got %s", StringValueCStr(playlist));
|
34
99
|
return Qfalse;
|
35
100
|
}
|
36
101
|
|
37
102
|
return BooleanValue(itdb_playlist_exists(_database, _playlist));
|
38
103
|
}
|
39
104
|
|
105
|
+
/*
|
106
|
+
* call-seq:
|
107
|
+
* size() -> integer
|
108
|
+
*
|
109
|
+
* Returns the total number of playlists in this database.
|
110
|
+
*/
|
111
|
+
static VALUE rbpod_playlist_collection_size(VALUE self)
|
112
|
+
{
|
113
|
+
VALUE database = rbpod_playlist_collection_database(self);
|
114
|
+
Itdb_iTunesDB *_database = TYPED_DATA_PTR(database, Itdb_iTunesDB);
|
115
|
+
return INT2NUM(itdb_playlists_number(_database));
|
116
|
+
}
|
117
|
+
|
40
118
|
/*
|
41
119
|
* call-seq:
|
42
120
|
* master() -> RbPod::Playlist
|
@@ -122,11 +200,19 @@ void Init_rbpod_playlist_collection(void)
|
|
122
200
|
|
123
201
|
rb_define_method(cRbPodPlaylistCollection, "database", rbpod_playlist_collection_database, 0);
|
124
202
|
|
125
|
-
rb_define_method(cRbPodPlaylistCollection, "include?",
|
203
|
+
rb_define_method(cRbPodPlaylistCollection, "include?", rbpod_playlist_collection_include, 1);
|
126
204
|
|
127
205
|
rb_define_method(cRbPodPlaylistCollection, "master", rbpod_playlist_collection_master, 0);
|
128
206
|
rb_define_method(cRbPodPlaylistCollection, "podcast", rbpod_playlist_collection_podcast, 0);
|
129
207
|
|
208
|
+
rb_define_method(cRbPodPlaylistCollection, "size", rbpod_playlist_collection_size, 0);
|
209
|
+
|
210
|
+
rb_define_method(cRbPodPlaylistCollection, "insert", rbpod_playlist_collection_insert, -1);
|
211
|
+
rb_define_method(cRbPodPlaylistCollection, "remove", rbpod_playlist_collection_remove, 1);
|
212
|
+
|
213
|
+
/* Syntactic sugar for adding a playlist. */
|
214
|
+
rb_define_alias(cRbPodPlaylistCollection, "<<", "insert");
|
215
|
+
|
130
216
|
return;
|
131
217
|
}
|
132
218
|
|
data/ext/rbpod/rbpod.c
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
/* rbpod.c */
|
2
2
|
|
3
3
|
#include "rbpod.h"
|
4
|
-
#include "error.h"
|
5
|
-
#include "track.h"
|
6
|
-
#include "device.h"
|
7
|
-
#include "playlist.h"
|
8
|
-
#include "database.h"
|
9
|
-
#include "collection.h"
|
10
|
-
#include "track_collection.h"
|
11
|
-
#include "playlist_collection.h"
|
12
4
|
|
13
5
|
VALUE mRbPod;
|
14
6
|
VALUE eRbPodError;
|
@@ -38,32 +30,6 @@ static VALUE rbpod_load_database(VALUE self, VALUE mount_point)
|
|
38
30
|
return rb_class_new_instance(1, &mount_point, cRbPodDatabase);
|
39
31
|
}
|
40
32
|
|
41
|
-
/*
|
42
|
-
* This is a hack used to inject a pointer from the data of one class instance into another.
|
43
|
-
*/
|
44
|
-
inline VALUE rb_class_new_instance_with_data(int argc, VALUE *argv, VALUE class, void *handle)
|
45
|
-
{
|
46
|
-
/* Create a new instance of this class. */
|
47
|
-
VALUE instance = rb_class_new_instance(argc, argv, class);
|
48
|
-
|
49
|
-
/* Assign it's DATA pointer to the given handle. */
|
50
|
-
DATA_PTR(instance) = handle;
|
51
|
-
|
52
|
-
return instance;
|
53
|
-
}
|
54
|
-
|
55
|
-
/*
|
56
|
-
* This is a hack so that including a module will trigger the +included+ singleton method.
|
57
|
-
*/
|
58
|
-
inline void rb_real_include_module(VALUE klass, VALUE module)
|
59
|
-
{
|
60
|
-
ID included = rb_intern("included");
|
61
|
-
|
62
|
-
rb_include_module(klass, module);
|
63
|
-
|
64
|
-
rb_funcall(mRbPodCollection, included, 1, klass);
|
65
|
-
}
|
66
|
-
|
67
33
|
void Init_rbpod(void)
|
68
34
|
{
|
69
35
|
/* This is the wrapper for all RbPod related classes. */
|
data/ext/rbpod/rbpod.h
CHANGED
@@ -4,19 +4,45 @@
|
|
4
4
|
#define RBPOD_H
|
5
5
|
|
6
6
|
#include <ruby.h>
|
7
|
-
#include <gpod/itdb.h>
|
8
|
-
|
9
|
-
#define BooleanValue(value) (value) ? Qtrue : Qfalse
|
10
7
|
|
11
|
-
#
|
8
|
+
#ifdef HAVE_STDDEF_H
|
9
|
+
#include <stddef.h>
|
10
|
+
#endif
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
#ifdef HAVE_GPOD_ITDB_H
|
13
|
+
#include <gpod/itdb.h>
|
14
|
+
#endif
|
15
|
+
|
16
|
+
/* Pre-processor macros. */
|
17
|
+
#include "macros.h"
|
18
|
+
|
19
|
+
/* Initialization function prototypes. */
|
20
|
+
RUBY_EXTERN void Init_rbpod(void); /* rbpod.c */
|
21
|
+
RUBY_EXTERN void Init_rbpod_error(void); /* error.c */
|
22
|
+
RUBY_EXTERN void Init_rbpod_database(void); /* database.c */
|
23
|
+
RUBY_EXTERN void Init_rbpod_device(void); /* device.c */
|
24
|
+
RUBY_EXTERN void Init_rbpod_track(void); /* track.c */
|
25
|
+
RUBY_EXTERN void Init_rbpod_playlist(void); /* playlist.c */
|
26
|
+
RUBY_EXTERN void Init_rbpod_collection(void); /* collection.c */
|
27
|
+
RUBY_EXTERN void Init_rbpod_track_collection(void); /* track_collection.c */
|
28
|
+
RUBY_EXTERN void Init_rbpod_playlist_collection(void); /* playlist_collection.c */
|
29
|
+
|
30
|
+
/* Helper function prototypes. */
|
31
|
+
RUBY_EXTERN inline VALUE rbpod_raise_error(GError *error);
|
32
|
+
RUBY_EXTERN inline VALUE rb_class_new_instance_with_data(int argc, VALUE *argv, VALUE class, void *handle);
|
33
|
+
RUBY_EXTERN inline void rb_real_include_module(VALUE klass, VALUE module);
|
34
|
+
|
35
|
+
/* Global variables. */
|
36
|
+
RUBY_EXTERN VALUE mRbPod; /* rbpod.c */
|
37
|
+
RUBY_EXTERN VALUE eRbPodError; /* error.c */
|
38
|
+
RUBY_EXTERN VALUE cRbPodDatabase; /* database.c */
|
39
|
+
RUBY_EXTERN VALUE cRbPodDevice; /* device.c */
|
40
|
+
RUBY_EXTERN VALUE cRbPodTrack; /* track.c */
|
41
|
+
RUBY_EXTERN VALUE cRbPodPlaylist; /* playlist.c */
|
42
|
+
RUBY_EXTERN VALUE mRbPodCollection; /* collection.c */
|
43
|
+
RUBY_EXTERN VALUE cRbPodTrackCollection; /* track_collection.c */
|
44
|
+
RUBY_EXTERN VALUE cRbPodPlaylistCollection; /* playlist_collection.c */
|
15
45
|
|
16
46
|
RUBY_EXTERN VALUE rb_cPathname;
|
17
47
|
|
18
|
-
inline VALUE rb_class_new_instance_with_data(int argc, VALUE *argv, VALUE class, void *handle);
|
19
|
-
|
20
|
-
inline void rb_real_include_module(VALUE klass, VALUE module);
|
21
|
-
|
22
48
|
#endif /* RBPOD_H */
|