rbpod 0.0.1
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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +69 -0
- data/Rakefile +1 -0
- data/bin/rbpod +3 -0
- data/ext/rbpod/collection.c +104 -0
- data/ext/rbpod/collection.h +12 -0
- data/ext/rbpod/database.c +173 -0
- data/ext/rbpod/database.h +12 -0
- data/ext/rbpod/device.c +136 -0
- data/ext/rbpod/device.h +12 -0
- data/ext/rbpod/extconf.rb +7 -0
- data/ext/rbpod/playlist.c +85 -0
- data/ext/rbpod/playlist.h +12 -0
- data/ext/rbpod/rbpod.c +34 -0
- data/ext/rbpod/rbpod.h +13 -0
- data/ext/rbpod/track.c +84 -0
- data/ext/rbpod/track.h +12 -0
- data/lib/rbpod/version.rb +3 -0
- data/lib/rbpod.rb +2 -0
- data/rbpod.gemspec +29 -0
- metadata +119 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Joshua M. Keyes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# RbPod
|
2
|
+
|
3
|
+
A Ruby interface to the libgpod library.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rbpod'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rbpod
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Functional for most read-only purposes.
|
22
|
+
|
23
|
+
#!/usr/bin/env ruby
|
24
|
+
|
25
|
+
require 'rbpod'
|
26
|
+
|
27
|
+
# Explicitly load a database from the filesystem -- can be a mount point to an iPod.
|
28
|
+
database = RbPod::Database.new('/mnt/ipod/') # => #<RbPod::Database:0x8733fa4>
|
29
|
+
|
30
|
+
database.version # => 42
|
31
|
+
database.mountpoint # => "/mnt/ipod/"
|
32
|
+
database.filename # => "/mnt/ipod/iPod_Control/iTunes/iTunesDB"
|
33
|
+
database.synchronized? # => true
|
34
|
+
|
35
|
+
# Device information, including model name, number, and capacity.
|
36
|
+
database.device.capacity # => 4.0
|
37
|
+
database.device.generation # => "Nano Video (3rd Gen.)"
|
38
|
+
database.device.model_name # => "Nano (Silver)"
|
39
|
+
database.device.model_number # => "A978"
|
40
|
+
|
41
|
+
# Device feature support detection.
|
42
|
+
database.device.supports_photos? # => true
|
43
|
+
database.device.supports_videos? # => true
|
44
|
+
database.device.supports_artwork? # => true
|
45
|
+
database.device.supports_podcasts? # => true
|
46
|
+
database.device.supports_chapter_images? # => true
|
47
|
+
|
48
|
+
# Device SysInfo read/write.
|
49
|
+
database.device['ModelNumStr'] # => "xA978"
|
50
|
+
database.device['PotsdamConf45'] = "Kilroy Was Here"
|
51
|
+
database.device.save!
|
52
|
+
|
53
|
+
# Playlists (includes enumerable)
|
54
|
+
database.playlists.map(&:name) # => ["iPod", "Podcasts", "Recently Added"]
|
55
|
+
|
56
|
+
# Track Listing (also enumerable)
|
57
|
+
database.tracks.count # => 400
|
58
|
+
database.tracks.first.artist # => "Steppenwolf"
|
59
|
+
database.tracks.first.title # => "Born To Be Wild"
|
60
|
+
|
61
|
+
It's alpha quality -- many pieces still need to be implemented. Patches welcome.
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/rbpod
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
/* collection.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "collection.h"
|
5
|
+
|
6
|
+
VALUE cRbPodCollection;
|
7
|
+
|
8
|
+
struct collection { VALUE klass; GList *list; };
|
9
|
+
|
10
|
+
static inline struct collection *rbpod_collection_unwrap(VALUE self) {
|
11
|
+
struct collection *collection = NULL;
|
12
|
+
Data_Get_Struct(self, struct collection, collection);
|
13
|
+
return collection;
|
14
|
+
}
|
15
|
+
|
16
|
+
static VALUE rbpod_collection_get(VALUE self, VALUE key) {
|
17
|
+
struct collection *collection = rbpod_collection_unwrap(self);
|
18
|
+
GList *current = NULL;
|
19
|
+
|
20
|
+
if (FIXNUM_P(key) == FALSE)
|
21
|
+
return Qnil;
|
22
|
+
|
23
|
+
current = g_list_nth(collection->list, FIX2INT(key));
|
24
|
+
|
25
|
+
return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);;
|
26
|
+
}
|
27
|
+
|
28
|
+
static VALUE rbpod_collection_last(VALUE self) {
|
29
|
+
struct collection *collection = rbpod_collection_unwrap(self);
|
30
|
+
GList *current = g_list_last(collection->list);
|
31
|
+
return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
|
32
|
+
}
|
33
|
+
|
34
|
+
static VALUE rbpod_collection_first(VALUE self) {
|
35
|
+
struct collection *collection = rbpod_collection_unwrap(self);
|
36
|
+
GList *current = g_list_first(collection->list);
|
37
|
+
return Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE rbpod_collection_count(VALUE self) {
|
41
|
+
struct collection *collection = rbpod_collection_unwrap(self);
|
42
|
+
return INT2NUM(g_list_length(collection->list));
|
43
|
+
}
|
44
|
+
|
45
|
+
static VALUE rbpod_collection_each(VALUE self) {
|
46
|
+
struct collection *collection = rbpod_collection_unwrap(self);
|
47
|
+
GList *current = NULL;
|
48
|
+
VALUE item;
|
49
|
+
|
50
|
+
if (rb_block_given_p() == TRUE) {
|
51
|
+
/* If we were supplied a block, enumerate the entire list. */
|
52
|
+
for (current = collection->list; current != NULL; current = current->next) {
|
53
|
+
item = Data_Wrap_Struct(collection->klass, NULL, NULL, (void *) current->data);
|
54
|
+
rb_yield(item);
|
55
|
+
}
|
56
|
+
return Qnil;
|
57
|
+
} else {
|
58
|
+
/* Otherwise return an enumerator from this method to the caller. */
|
59
|
+
return rb_funcall(self, rb_intern("enum_for"), 1, ID2SYM(rb_intern("each")));
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE rbpod_collection_initialize(VALUE self) {
|
64
|
+
return self;
|
65
|
+
}
|
66
|
+
|
67
|
+
static void rbpod_collection_deallocate(void *handle) {
|
68
|
+
struct collection *collection = (struct collection *) handle;
|
69
|
+
|
70
|
+
if (collection->list != NULL)
|
71
|
+
g_list_free(collection->list);
|
72
|
+
|
73
|
+
xfree(handle);
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
|
77
|
+
inline VALUE rbpod_collection_wrap(GList *list, VALUE type, gboolean freeable) {
|
78
|
+
struct collection *collection = ALLOC(struct collection);
|
79
|
+
collection->list = list;
|
80
|
+
collection->klass = type;
|
81
|
+
return Data_Wrap_Struct(cRbPodCollection, NULL, freeable ? rbpod_collection_deallocate : NULL, (void *) collection);
|
82
|
+
}
|
83
|
+
|
84
|
+
static VALUE rbpod_collection_allocate(VALUE self) {
|
85
|
+
return rbpod_collection_wrap(g_list_alloc(), Qnil, TRUE);
|
86
|
+
}
|
87
|
+
|
88
|
+
void Init_rbpod_collection(void) {
|
89
|
+
cRbPodCollection = rb_define_class_under(mRbPod, "Collection", rb_cObject);
|
90
|
+
|
91
|
+
rb_define_alloc_func(cRbPodCollection, rbpod_collection_allocate);
|
92
|
+
|
93
|
+
rb_include_module(cRbPodCollection, rb_mEnumerable);
|
94
|
+
|
95
|
+
rb_define_method(cRbPodCollection, "initialize", rbpod_collection_initialize, 0);
|
96
|
+
|
97
|
+
rb_define_method(cRbPodCollection, "each", rbpod_collection_each, 0);
|
98
|
+
rb_define_method(cRbPodCollection, "count", rbpod_collection_count, 0);
|
99
|
+
|
100
|
+
rb_define_method(cRbPodCollection, "first", rbpod_collection_first, 0);
|
101
|
+
rb_define_method(cRbPodCollection, "last", rbpod_collection_last, 0);
|
102
|
+
|
103
|
+
rb_define_method(cRbPodCollection, "[]", rbpod_collection_get, 1);
|
104
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/* collection.h */
|
2
|
+
|
3
|
+
#ifndef RBPOD_COLLECTION_H
|
4
|
+
#define RBPOD_COLLECTION_H
|
5
|
+
|
6
|
+
extern VALUE cRbPodCollection;
|
7
|
+
|
8
|
+
void Init_rbpod_collection(void);
|
9
|
+
|
10
|
+
inline VALUE rbpod_collection_wrap(GList *list, VALUE type, gboolean freeable);
|
11
|
+
|
12
|
+
#endif /* RBPOD_COLLECTION_H */
|
@@ -0,0 +1,173 @@
|
|
1
|
+
/* database.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "track.h"
|
5
|
+
#include "device.h"
|
6
|
+
#include "playlist.h"
|
7
|
+
#include "database.h"
|
8
|
+
#include "collection.h"
|
9
|
+
|
10
|
+
/*
|
11
|
+
* Although libgpod has an itdb_new(), itdb_parse() also returns a pointer to a
|
12
|
+
* newly allocated Itdb_iTunesDB structure. Since overwriting the data pointer from
|
13
|
+
* Data_Get_Struct() at runtime is dangerous, we use a double-pointer to wrap the
|
14
|
+
* Itdb_iTunesDB handle, so as not to confuse the Ruby implementation internals.
|
15
|
+
*/
|
16
|
+
|
17
|
+
VALUE cRbPodDatabase;
|
18
|
+
|
19
|
+
static inline Itdb_iTunesDB *rbpod_database_unwrap(VALUE self) {
|
20
|
+
Itdb_iTunesDB **database = NULL;
|
21
|
+
Data_Get_Struct(self, Itdb_iTunesDB *, database);
|
22
|
+
return *database;
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE rbpod_database_write(VALUE self) {
|
26
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
27
|
+
gboolean success = itdb_write(database, NULL); /* TODO: Improve error handling. */
|
28
|
+
return BooleanValue(success);
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE rbpod_database_is_synchronized(VALUE self) {
|
32
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
33
|
+
guint32 nontransferred = itdb_tracks_number_nontransferred(database);
|
34
|
+
return BooleanValue(nontransferred == 0);
|
35
|
+
}
|
36
|
+
|
37
|
+
static VALUE rbpod_database_playlists_get(VALUE self) {
|
38
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
39
|
+
return rbpod_collection_wrap(database->playlists, cRbPodPlaylist, FALSE);
|
40
|
+
}
|
41
|
+
|
42
|
+
static VALUE rbpod_database_tracks_get(VALUE self) {
|
43
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
44
|
+
return rbpod_collection_wrap(database->tracks, cRbPodTrack, FALSE);
|
45
|
+
}
|
46
|
+
|
47
|
+
static VALUE rbpod_database_device_get(VALUE self) {
|
48
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
49
|
+
return rbpod_device_wrap(database->device, FALSE);
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE rbpod_database_filename_get(VALUE self) {
|
53
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
54
|
+
return rb_str_new2(database->filename);
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE rbpod_database_version_get(VALUE self) {
|
58
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
59
|
+
return INT2NUM(database->version);
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE rbpod_database_id_get(VALUE self) {
|
63
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
64
|
+
return INT2NUM(database->id);
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE rbpod_database_mountpoint_get(VALUE self) {
|
68
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
69
|
+
return rb_str_new2(itdb_get_mountpoint(database));
|
70
|
+
}
|
71
|
+
|
72
|
+
static VALUE rbpod_database_mountpoint_set(VALUE self, VALUE path) {
|
73
|
+
Itdb_iTunesDB *database = rbpod_database_unwrap(self);
|
74
|
+
itdb_set_mountpoint(database, StringValueCStr(path));
|
75
|
+
return rbpod_database_mountpoint_get(self);
|
76
|
+
}
|
77
|
+
|
78
|
+
static void rbpod_database_deallocate(void *handle) {
|
79
|
+
Itdb_iTunesDB **database = (Itdb_iTunesDB **) handle;
|
80
|
+
itdb_free(*database);
|
81
|
+
xfree(handle);
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
|
85
|
+
static VALUE rbpod_database_create(VALUE self, VALUE device_name, VALUE mount_point, VALUE model_number) {
|
86
|
+
Itdb_iTunesDB **database = ALLOC(Itdb_iTunesDB *);
|
87
|
+
gchar *_mount_point, *_model_number, *_device_name;
|
88
|
+
|
89
|
+
_device_name = StringValueCStr(device_name);
|
90
|
+
_mount_point = StringValueCStr(mount_point);
|
91
|
+
|
92
|
+
/* GPod can function with a NULL model number, however, artwork will not function. */
|
93
|
+
_model_number = !NIL_P(model_number) ? StringValueCStr(model_number) : NULL;
|
94
|
+
|
95
|
+
/* Initialize the iPod at this mount point, with this device name and model number. */
|
96
|
+
/* TODO: Improve error handling. */
|
97
|
+
if (itdb_init_ipod(_mount_point, _model_number, _device_name, NULL) == FALSE) {
|
98
|
+
free(database);
|
99
|
+
rb_raise(rb_eRuntimeError, "Unable to format this iPod.");
|
100
|
+
return Qfalse;
|
101
|
+
}
|
102
|
+
|
103
|
+
/* Parse the newly created database. */
|
104
|
+
/* TODO: Improve error handling. */
|
105
|
+
*database = itdb_parse(_mount_point, NULL);
|
106
|
+
|
107
|
+
if (*database == NULL) {
|
108
|
+
free(database);
|
109
|
+
rb_raise(rb_eRuntimeError, "Not an iPod mount point.");
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
|
113
|
+
/* Return an instance of this class using the newly created database. */
|
114
|
+
return Data_Wrap_Struct(self, NULL, rbpod_database_deallocate, (void *) database);
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE rbpod_database_initialize(VALUE self, VALUE mount_point) {
|
118
|
+
Itdb_iTunesDB **database;
|
119
|
+
|
120
|
+
/* Extract the wrapper from the class itself. */
|
121
|
+
Data_Get_Struct(self, Itdb_iTunesDB *, database);
|
122
|
+
|
123
|
+
/* Try to parse the database from the given mount point. */
|
124
|
+
/* TODO: Improve error handling. */
|
125
|
+
*database = itdb_parse(StringValueCStr(mount_point), NULL);
|
126
|
+
|
127
|
+
/* The given mount point was not an iPod mount point. */
|
128
|
+
if (*database == NULL) {
|
129
|
+
rb_raise(rb_eRuntimeError, "Not an iPod mount point.");
|
130
|
+
return Qnil;
|
131
|
+
}
|
132
|
+
|
133
|
+
return self;
|
134
|
+
}
|
135
|
+
|
136
|
+
inline VALUE rbpod_database_wrap(Itdb_iTunesDB **database, gboolean freeable) {
|
137
|
+
return Data_Wrap_Struct(cRbPodDatabase, NULL, freeable ? rbpod_database_deallocate : NULL, (void *) database);
|
138
|
+
}
|
139
|
+
|
140
|
+
static VALUE rbpod_database_allocate(VALUE self) {
|
141
|
+
Itdb_iTunesDB **database = ALLOC(Itdb_iTunesDB *);
|
142
|
+
|
143
|
+
/* Initialize a new, empty database. */
|
144
|
+
*database = itdb_new();
|
145
|
+
|
146
|
+
return rbpod_database_wrap(database, TRUE);
|
147
|
+
}
|
148
|
+
|
149
|
+
void Init_rbpod_database(void) {
|
150
|
+
cRbPodDatabase = rb_define_class_under(mRbPod, "Database", rb_cObject);
|
151
|
+
|
152
|
+
rb_define_alloc_func(cRbPodDatabase, rbpod_database_allocate);
|
153
|
+
|
154
|
+
rb_define_method(cRbPodDatabase, "initialize", rbpod_database_initialize, 1);
|
155
|
+
|
156
|
+
rb_define_singleton_method(cRbPodDatabase, "create!", rbpod_database_create, 3);
|
157
|
+
|
158
|
+
rb_define_method(cRbPodDatabase, "mountpoint", rbpod_database_mountpoint_get, 0);
|
159
|
+
rb_define_method(cRbPodDatabase, "mountpoint=", rbpod_database_mountpoint_set, 1);
|
160
|
+
|
161
|
+
rb_define_method(cRbPodDatabase, "id", rbpod_database_id_get, 0);
|
162
|
+
rb_define_method(cRbPodDatabase, "version", rbpod_database_version_get, 0);
|
163
|
+
rb_define_method(cRbPodDatabase, "filename", rbpod_database_filename_get, 0);
|
164
|
+
|
165
|
+
rb_define_method(cRbPodDatabase, "device", rbpod_database_device_get, 0);
|
166
|
+
rb_define_method(cRbPodDatabase, "tracks", rbpod_database_tracks_get, 0);
|
167
|
+
rb_define_method(cRbPodDatabase, "playlists", rbpod_database_playlists_get, 0);
|
168
|
+
|
169
|
+
rb_define_method(cRbPodDatabase, "synchronized?", rbpod_database_is_synchronized, 0);
|
170
|
+
|
171
|
+
rb_define_method(cRbPodDatabase, "write!", rbpod_database_write, 0);
|
172
|
+
}
|
173
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/* database.h */
|
2
|
+
|
3
|
+
#ifndef RBPOD_DATABASE_H
|
4
|
+
#define RBPOD_DATABASE_H
|
5
|
+
|
6
|
+
extern VALUE cRbPodDatabase;
|
7
|
+
|
8
|
+
void Init_rbpod_database(void);
|
9
|
+
|
10
|
+
inline VALUE rbpod_database_wrap(Itdb_iTunesDB **database, gboolean freeable);
|
11
|
+
|
12
|
+
#endif /* RBPOD_DATABASE_H */
|
data/ext/rbpod/device.c
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
/* device.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "device.h"
|
5
|
+
|
6
|
+
VALUE cRbPodDevice;
|
7
|
+
|
8
|
+
static inline Itdb_Device *rbpod_device_unwrap(VALUE self) {
|
9
|
+
Itdb_Device *device = NULL;
|
10
|
+
Data_Get_Struct(self, Itdb_Device, device);
|
11
|
+
return device;
|
12
|
+
}
|
13
|
+
|
14
|
+
static VALUE rbpod_device_has_chapter_image_support(VALUE self) {
|
15
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
16
|
+
return BooleanValue(itdb_device_supports_chapter_image(device));
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE rbpod_device_has_podcast_support(VALUE self) {
|
20
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
21
|
+
return BooleanValue(itdb_device_supports_podcast(device));
|
22
|
+
}
|
23
|
+
|
24
|
+
static VALUE rbpod_device_has_artwork_support(VALUE self) {
|
25
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
26
|
+
return BooleanValue(itdb_device_supports_artwork(device));
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE rbpod_device_has_video_support(VALUE self) {
|
30
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
31
|
+
return BooleanValue(itdb_device_supports_video(device));
|
32
|
+
}
|
33
|
+
|
34
|
+
static VALUE rbpod_device_has_photo_support(VALUE self) {
|
35
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
36
|
+
return BooleanValue(itdb_device_supports_photo(device));
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE rbpod_device_model_name_get(VALUE self) {
|
40
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
41
|
+
Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
|
42
|
+
return rb_str_new2(itdb_info_get_ipod_model_name_string(info->ipod_model));
|
43
|
+
}
|
44
|
+
|
45
|
+
static VALUE rbpod_device_model_number_get(VALUE self) {
|
46
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
47
|
+
Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
|
48
|
+
return rb_str_new2(info->model_number);
|
49
|
+
}
|
50
|
+
|
51
|
+
static VALUE rbpod_device_generation_get(VALUE self) {
|
52
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
53
|
+
const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
|
54
|
+
return rb_str_new2(itdb_info_get_ipod_generation_string(info->ipod_generation));
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE rbpod_device_capacity_get(VALUE self) {
|
58
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
59
|
+
const Itdb_IpodInfo *info = itdb_device_get_ipod_info(device);
|
60
|
+
return DBL2NUM(info->capacity);
|
61
|
+
}
|
62
|
+
|
63
|
+
static VALUE rbpod_device_sysinfo_get(VALUE self, VALUE key) {
|
64
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
65
|
+
gchar *value = NULL;
|
66
|
+
VALUE result;
|
67
|
+
|
68
|
+
value = itdb_device_get_sysinfo(device, StringValueCStr(key));
|
69
|
+
result = (value == NULL) ? Qnil : rb_str_new2(value);
|
70
|
+
|
71
|
+
g_free(value);
|
72
|
+
return result;
|
73
|
+
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE rbpod_device_sysinfo_set(VALUE self, VALUE key, VALUE value) {
|
77
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
78
|
+
gchar *_value, *_key;
|
79
|
+
|
80
|
+
_key = StringValueCStr(key);
|
81
|
+
_value = !NIL_P(value) ? StringValueCStr(value) : NULL;
|
82
|
+
|
83
|
+
itdb_device_set_sysinfo(device, _key, _value);
|
84
|
+
|
85
|
+
return rbpod_device_sysinfo_get(self, _key);
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE rbpod_device_sysinfo_write(VALUE self) {
|
89
|
+
Itdb_Device *device = rbpod_device_unwrap(self);
|
90
|
+
/* TODO: Improve error handling. */
|
91
|
+
return BooleanValue(itdb_device_write_sysinfo(device, NULL));
|
92
|
+
}
|
93
|
+
|
94
|
+
static VALUE rbpod_device_initialize(VALUE self) {
|
95
|
+
/* Private. */
|
96
|
+
return self;
|
97
|
+
}
|
98
|
+
|
99
|
+
static void rbpod_device_deallocate(void *handle) {
|
100
|
+
itdb_device_free((Itdb_Device *) handle);
|
101
|
+
}
|
102
|
+
|
103
|
+
inline VALUE rbpod_device_wrap(Itdb_Device *device, gboolean freeable) {
|
104
|
+
return Data_Wrap_Struct(cRbPodDevice, NULL, freeable ? rbpod_device_deallocate : NULL, (void *) device);
|
105
|
+
}
|
106
|
+
|
107
|
+
static VALUE rbpod_device_allocate(VALUE self) {
|
108
|
+
return rbpod_device_wrap(itdb_device_new(), TRUE);
|
109
|
+
}
|
110
|
+
|
111
|
+
void Init_rbpod_device(void) {
|
112
|
+
cRbPodDevice = rb_define_class_under(mRbPod, "Device", rb_cObject);
|
113
|
+
|
114
|
+
rb_define_alloc_func(cRbPodDevice, rbpod_device_allocate);
|
115
|
+
|
116
|
+
/* We don't want to explicitly create these, so mark the constructor as private. */
|
117
|
+
rb_define_private_method(cRbPodDevice, "initialize", rbpod_device_initialize, 0);
|
118
|
+
|
119
|
+
rb_define_method(cRbPodDevice, "[]", rbpod_device_sysinfo_get, 1);
|
120
|
+
rb_define_method(cRbPodDevice, "[]=", rbpod_device_sysinfo_set, 2);
|
121
|
+
rb_define_method(cRbPodDevice, "save!", rbpod_device_sysinfo_write, 0);
|
122
|
+
|
123
|
+
rb_define_method(cRbPodDevice, "capacity", rbpod_device_capacity_get, 0);
|
124
|
+
rb_define_method(cRbPodDevice, "generation", rbpod_device_generation_get, 0);
|
125
|
+
rb_define_method(cRbPodDevice, "model_name", rbpod_device_model_name_get, 0);
|
126
|
+
rb_define_method(cRbPodDevice, "model_number", rbpod_device_model_number_get, 0);
|
127
|
+
|
128
|
+
rb_define_method(cRbPodDevice, "supports_photos?", rbpod_device_has_photo_support, 0);
|
129
|
+
rb_define_method(cRbPodDevice, "supports_videos?", rbpod_device_has_video_support, 0);
|
130
|
+
rb_define_method(cRbPodDevice, "supports_artwork?", rbpod_device_has_artwork_support, 0);
|
131
|
+
rb_define_method(cRbPodDevice, "supports_podcasts?", rbpod_device_has_podcast_support, 0);
|
132
|
+
rb_define_method(cRbPodDevice, "supports_chapter_images?", rbpod_device_has_chapter_image_support, 0);
|
133
|
+
|
134
|
+
return;
|
135
|
+
}
|
136
|
+
|
data/ext/rbpod/device.h
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
/* playlist.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "track.h"
|
5
|
+
#include "playlist.h"
|
6
|
+
|
7
|
+
VALUE cRbPodPlaylist;
|
8
|
+
|
9
|
+
static inline Itdb_Playlist *rbpod_playlist_unwrap(VALUE self) {
|
10
|
+
Itdb_Playlist *playlist = NULL;
|
11
|
+
Data_Get_Struct(self, Itdb_Playlist, playlist);
|
12
|
+
return playlist;
|
13
|
+
}
|
14
|
+
|
15
|
+
static VALUE rbpod_playlist_is_podcast(VALUE self) {
|
16
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
17
|
+
return BooleanValue(itdb_playlist_is_podcasts(playlist));
|
18
|
+
}
|
19
|
+
|
20
|
+
static VALUE rbpod_playlist_is_master(VALUE self) {
|
21
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
22
|
+
return BooleanValue(itdb_playlist_is_mpl(playlist));
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE rbpod_playlist_is_smart(VALUE self) {
|
26
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
27
|
+
return BooleanValue(playlist->is_spl);
|
28
|
+
}
|
29
|
+
|
30
|
+
static VALUE rbpod_playlist_tracks_get(VALUE self) {
|
31
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
32
|
+
return rbpod_collection_wrap(playlist->members, cRbPodTrack, FALSE);
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE rbpod_playlist_length_get(VALUE self) {
|
36
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
37
|
+
return INT2NUM(playlist->num);
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE rbpod_playlist_name_get(VALUE self) {
|
41
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
42
|
+
return rb_str_new2(playlist->name);
|
43
|
+
}
|
44
|
+
|
45
|
+
static VALUE rbpod_playlist_id_get(VALUE self) {
|
46
|
+
Itdb_Playlist *playlist = rbpod_playlist_unwrap(self);
|
47
|
+
return INT2FIX(playlist->id);
|
48
|
+
}
|
49
|
+
|
50
|
+
static VALUE rbpod_playlist_initialize(VALUE self) {
|
51
|
+
return self;
|
52
|
+
}
|
53
|
+
|
54
|
+
static void rbpod_playlist_deallocate(void *handle) {
|
55
|
+
itdb_playlist_free((Itdb_Playlist *) handle);
|
56
|
+
}
|
57
|
+
|
58
|
+
inline VALUE rbpod_playlist_wrap(Itdb_Playlist *playlist, gboolean freeable) {
|
59
|
+
return Data_Wrap_Struct(cRbPodPlaylist, NULL, freeable ? rbpod_playlist_deallocate : NULL, (void *) playlist);
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE rbpod_playlist_allocate(VALUE self) {
|
63
|
+
Itdb_Playlist *playlist = itdb_playlist_new("Untitled Playlist", FALSE);
|
64
|
+
return rbpod_playlist_wrap(playlist, TRUE);
|
65
|
+
}
|
66
|
+
|
67
|
+
void Init_rbpod_playlist(void) {
|
68
|
+
cRbPodPlaylist = rb_define_class_under(mRbPod, "Playlist", rb_cObject);
|
69
|
+
|
70
|
+
rb_define_alloc_func(cRbPodPlaylist, rbpod_playlist_allocate);
|
71
|
+
|
72
|
+
rb_define_method(cRbPodPlaylist, "initialize", rbpod_playlist_initialize, 0);
|
73
|
+
|
74
|
+
rb_define_method(cRbPodPlaylist, "id", rbpod_playlist_id_get, 0);
|
75
|
+
rb_define_method(cRbPodPlaylist, "name", rbpod_playlist_name_get, 0);
|
76
|
+
rb_define_method(cRbPodPlaylist, "length", rbpod_playlist_length_get, 0);
|
77
|
+
rb_define_method(cRbPodPlaylist, "tracks", rbpod_playlist_tracks_get, 0);
|
78
|
+
|
79
|
+
rb_define_method(cRbPodPlaylist, "smart_playlist?", rbpod_playlist_is_smart, 0);
|
80
|
+
rb_define_method(cRbPodPlaylist, "master_playlist?", rbpod_playlist_is_master, 0);
|
81
|
+
rb_define_method(cRbPodPlaylist, "podcast_playlist?", rbpod_playlist_is_podcast, 0);
|
82
|
+
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/* playlist.h */
|
2
|
+
|
3
|
+
#ifndef RBPOD_PLAYLIST_H
|
4
|
+
#define RBPOD_PLAYLIST_H
|
5
|
+
|
6
|
+
extern VALUE cRbPodPlaylist;
|
7
|
+
|
8
|
+
void Init_rbpod_playlist(void);
|
9
|
+
|
10
|
+
inline VALUE rbpod_playlist_wrap(Itdb_Playlist *playlist, gboolean freeable);
|
11
|
+
|
12
|
+
#endif /* RBPOD_PLAYLIST_H */
|
data/ext/rbpod/rbpod.c
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
/* rbpod.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "track.h"
|
5
|
+
#include "device.h"
|
6
|
+
#include "playlist.h"
|
7
|
+
#include "database.h"
|
8
|
+
#include "collection.h"
|
9
|
+
|
10
|
+
VALUE mRbPod;
|
11
|
+
|
12
|
+
void Init_rbpod(void) {
|
13
|
+
/* Set up the top-level RbPod module. */
|
14
|
+
mRbPod = rb_define_module("RbPod");
|
15
|
+
|
16
|
+
/* Set up the RbPod::Database class. */
|
17
|
+
Init_rbpod_database();
|
18
|
+
|
19
|
+
/* Set up the RbPod::Device class. */
|
20
|
+
Init_rbpod_device();
|
21
|
+
|
22
|
+
/* Set up the RbPod::Collection class. */
|
23
|
+
Init_rbpod_collection();
|
24
|
+
|
25
|
+
/* Set up the RbPod::Playlist class. */
|
26
|
+
Init_rbpod_playlist();
|
27
|
+
|
28
|
+
/* Set up the RbPod::Track class. */
|
29
|
+
Init_rbpod_track();
|
30
|
+
|
31
|
+
return;
|
32
|
+
}
|
33
|
+
|
34
|
+
|
data/ext/rbpod/rbpod.h
ADDED
data/ext/rbpod/track.c
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
/* track.c */
|
2
|
+
|
3
|
+
#include "rbpod.h"
|
4
|
+
#include "track.h"
|
5
|
+
|
6
|
+
VALUE cRbPodTrack;
|
7
|
+
|
8
|
+
static inline Itdb_Track *rbpod_track_unwrap(VALUE self) {
|
9
|
+
Itdb_Track *track = NULL;
|
10
|
+
Data_Get_Struct(self, Itdb_Track, track);
|
11
|
+
return track;
|
12
|
+
}
|
13
|
+
|
14
|
+
static VALUE rbpod_track_is_transferred(VALUE self) {
|
15
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
16
|
+
return BooleanValue(track->transferred);
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE rbpod_track_ipod_path_get(VALUE self) {
|
20
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
21
|
+
return rb_str_new2(track->ipod_path);
|
22
|
+
}
|
23
|
+
|
24
|
+
static VALUE rbpod_track_file_type_get(VALUE self) {
|
25
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
26
|
+
return rb_str_new2(track->filetype);
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE rbpod_track_artist_get(VALUE self) {
|
30
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
31
|
+
return rb_str_new2(track->artist);
|
32
|
+
}
|
33
|
+
|
34
|
+
static VALUE rbpod_track_album_get(VALUE self) {
|
35
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
36
|
+
return rb_str_new2(track->album);
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE rbpod_track_title_get(VALUE self) {
|
40
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
41
|
+
return rb_str_new2(track->title);
|
42
|
+
}
|
43
|
+
|
44
|
+
static VALUE rbpod_track_id_get(VALUE self) {
|
45
|
+
Itdb_Track *track = rbpod_track_unwrap(self);
|
46
|
+
return rb_str_new2(track->filetype);
|
47
|
+
}
|
48
|
+
|
49
|
+
static VALUE rbpod_track_initialize(VALUE self) {
|
50
|
+
return self;
|
51
|
+
}
|
52
|
+
|
53
|
+
static void rbpod_track_deallocate(void *handle) {
|
54
|
+
itdb_track_free((Itdb_Track *) handle);
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
inline VALUE rbpod_track_wrap(Itdb_Track *track, gboolean freeable) {
|
59
|
+
return Data_Wrap_Struct(cRbPodTrack, NULL, freeable ? rbpod_track_deallocate : NULL, (void *) track);
|
60
|
+
}
|
61
|
+
|
62
|
+
static VALUE rbpod_track_allocate(VALUE self) {
|
63
|
+
return rbpod_track_wrap(itdb_track_new(), TRUE);
|
64
|
+
}
|
65
|
+
|
66
|
+
void Init_rbpod_track(void) {
|
67
|
+
cRbPodTrack = rb_define_class_under(mRbPod, "Track", rb_cObject);
|
68
|
+
|
69
|
+
rb_define_alloc_func(cRbPodTrack, rbpod_track_allocate);
|
70
|
+
|
71
|
+
rb_define_method(cRbPodTrack, "initialize", rbpod_track_initialize, 0);
|
72
|
+
|
73
|
+
rb_define_method(cRbPodTrack, "id", rbpod_track_id_get, 0);
|
74
|
+
rb_define_method(cRbPodTrack, "title", rbpod_track_title_get, 0);
|
75
|
+
rb_define_method(cRbPodTrack, "album", rbpod_track_album_get, 0);
|
76
|
+
rb_define_method(cRbPodTrack, "artist", rbpod_track_artist_get, 0);
|
77
|
+
rb_define_method(cRbPodTrack, "file_type", rbpod_track_file_type_get, 0);
|
78
|
+
rb_define_method(cRbPodTrack, "ipod_path", rbpod_track_ipod_path_get, 0);
|
79
|
+
|
80
|
+
rb_define_method(cRbPodTrack, "transferred?", rbpod_track_is_transferred, 0);
|
81
|
+
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
|
data/ext/rbpod/track.h
ADDED
data/lib/rbpod.rb
ADDED
data/rbpod.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rbpod/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rbpod"
|
8
|
+
spec.version = RbPod::VERSION
|
9
|
+
|
10
|
+
spec.authors = ["Joshua M. Keyes"]
|
11
|
+
spec.email = ["joshua.michael.keyes@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = %q{Ruby bindings to the libgpod library.}
|
14
|
+
spec.description = %q{Lightweight native bindings to the libgpod library.}
|
15
|
+
spec.homepage = "https://github.com/jmkeyes/rbpod"
|
16
|
+
spec.requirements << 'libgpod-1.0'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
spec.files = `git ls-files`.split($/)
|
20
|
+
spec.extensions = ["ext/rbpod/extconf.rb"]
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
|
28
|
+
spec.add_dependency 'trollop', '~> 2.0'
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbpod
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joshua M. Keyes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: trollop
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
description: Lightweight native bindings to the libgpod library.
|
63
|
+
email:
|
64
|
+
- joshua.michael.keyes@gmail.com
|
65
|
+
executables:
|
66
|
+
- rbpod
|
67
|
+
extensions:
|
68
|
+
- ext/rbpod/extconf.rb
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- bin/rbpod
|
77
|
+
- ext/rbpod/collection.c
|
78
|
+
- ext/rbpod/collection.h
|
79
|
+
- ext/rbpod/database.c
|
80
|
+
- ext/rbpod/database.h
|
81
|
+
- ext/rbpod/device.c
|
82
|
+
- ext/rbpod/device.h
|
83
|
+
- ext/rbpod/extconf.rb
|
84
|
+
- ext/rbpod/playlist.c
|
85
|
+
- ext/rbpod/playlist.h
|
86
|
+
- ext/rbpod/rbpod.c
|
87
|
+
- ext/rbpod/rbpod.h
|
88
|
+
- ext/rbpod/track.c
|
89
|
+
- ext/rbpod/track.h
|
90
|
+
- lib/rbpod.rb
|
91
|
+
- lib/rbpod/version.rb
|
92
|
+
- rbpod.gemspec
|
93
|
+
homepage: https://github.com/jmkeyes/rbpod
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements:
|
113
|
+
- libgpod-1.0
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.8.23
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Ruby bindings to the libgpod library.
|
119
|
+
test_files: []
|