greenstripes 0.1.3

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.
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ dir_config('libspotify')
3
+ have_library('spotify', 'sp_session_init')
4
+ create_makefile("greenstripes")
@@ -0,0 +1,1494 @@
1
+ #include <ruby.h>
2
+ #include <spotify/api.h>
3
+
4
+ // modules and classes
5
+
6
+ static VALUE module_greenstripes;
7
+
8
+ static VALUE module_error;
9
+ static VALUE module_connection_state;
10
+ static VALUE module_link_type;
11
+
12
+ static VALUE class_session;
13
+ static VALUE class_user;
14
+ static VALUE class_playlist_container;
15
+ static VALUE class_playlist;
16
+ static VALUE class_search;
17
+ static VALUE class_artist_browse;
18
+ static VALUE class_album_browse;
19
+ static VALUE class_artist;
20
+ static VALUE class_album;
21
+ static VALUE class_track;
22
+ static VALUE class_link;
23
+
24
+ // callbacks
25
+
26
+ static void logged_in_callback(sp_session *session, sp_error error)
27
+ {
28
+ //fprintf(stderr, "logged_in_callback: %s\n", sp_error_message(error));
29
+ }
30
+
31
+ static void logged_out_callback(sp_session *session)
32
+ {
33
+ //fprintf(stderr, "logged_out_callback\n");
34
+ }
35
+
36
+ static void metadata_updated_callback(sp_session *session)
37
+ {
38
+ //fprintf(stderr, "metadata_updated_callback\n");
39
+ }
40
+
41
+ static void connection_error_callback(sp_session *session, sp_error error)
42
+ {
43
+ //fprintf(stderr, "connection_error_callback: %s\n", sp_error_message(error));
44
+ }
45
+
46
+ static void message_to_user_callback(sp_session *session, const char *message)
47
+ {
48
+ //fprintf(stderr, "message_to_user_callback: %s\n", message);
49
+ }
50
+
51
+ static void notify_main_thread_callback(sp_session *session)
52
+ {
53
+ //fprintf(stderr, "notify_main_thread_callback\n");
54
+ }
55
+
56
+ static void log_message_callback(sp_session *session, const char *data)
57
+ {
58
+ //fprintf(stderr, "log_message_callback: %s\n", data);
59
+ }
60
+
61
+ static void search_complete_callback(sp_search *result, void *userdata)
62
+ {
63
+ //fprintf(stderr, "search_complete_callback\n");
64
+ }
65
+
66
+ static void artist_browse_complete_callback(sp_artistbrowse *result, void *userdata)
67
+ {
68
+ //fprintf(stderr, "artist_browse_complete_callback\n");
69
+ }
70
+
71
+ static void album_browse_complete_callback(sp_albumbrowse *result, void *userdata)
72
+ {
73
+ //fprintf(stderr, "album_browse_complete_callback\n");
74
+ }
75
+
76
+ /*
77
+ * call-seq: Session.new(application_key, user_agent, cache_location, settings_location) -> session or nil
78
+ *
79
+ * Returns a new session.
80
+ */
81
+ static VALUE session_new(VALUE klass, VALUE application_key, VALUE user_agent, VALUE cache_location, VALUE settings_location)
82
+ {
83
+ // TODO: session callbacks should not be hardcoded
84
+ sp_session_callbacks callbacks =
85
+ {
86
+ logged_in_callback,
87
+ logged_out_callback,
88
+ metadata_updated_callback,
89
+ connection_error_callback,
90
+ message_to_user_callback,
91
+ notify_main_thread_callback,
92
+ NULL, // music_delivery
93
+ NULL, // play_token_lost
94
+ log_message_callback
95
+ };
96
+
97
+ sp_session_config config =
98
+ {
99
+ SPOTIFY_API_VERSION,
100
+ StringValuePtr(cache_location),
101
+ StringValuePtr(settings_location),
102
+ RSTRING_PTR(application_key),
103
+ RSTRING_LEN(application_key),
104
+ StringValuePtr(user_agent),
105
+ &callbacks,
106
+ NULL
107
+ };
108
+
109
+ sp_session *session = NULL;
110
+ sp_error error = sp_session_init(&config, &session);
111
+
112
+ // TODO: handle error in a better way?
113
+ if(error != SP_ERROR_OK)
114
+ {
115
+ fprintf(stderr, "error: %s\n", sp_error_message(error));
116
+ return Qnil;
117
+ }
118
+
119
+ VALUE session_value = Data_Wrap_Struct(class_session, NULL, NULL, session);
120
+ VALUE argv[4] = {application_key, user_agent, cache_location, settings_location};
121
+ rb_obj_call_init(session_value, 4, argv);
122
+ return session_value;
123
+ }
124
+
125
+ /*
126
+ * call-seq: session.login(username, password) -> error
127
+ *
128
+ * Attempts to log in with the given username and password. Returns one of the
129
+ * constants defined in Error.
130
+ */
131
+ static VALUE session_login(VALUE self, VALUE username, VALUE password)
132
+ {
133
+ sp_session *session;
134
+ Data_Get_Struct(self, sp_session, session);
135
+ sp_error error = sp_session_login(session, StringValuePtr(username), StringValuePtr(password));
136
+ // TODO: throw an exception instead?
137
+ return INT2FIX(error);
138
+ }
139
+
140
+ /*
141
+ * call-seq: session.logout -> error
142
+ *
143
+ * Attempts to log out. Returns one of the constants defined in Error.
144
+ */
145
+ static VALUE session_logout(VALUE self)
146
+ {
147
+ sp_session *session;
148
+ Data_Get_Struct(self, sp_session, session);
149
+ sp_error error = sp_session_logout(session);
150
+ // TODO: throw an exception instead?
151
+ return INT2FIX(error);
152
+ }
153
+
154
+ /*
155
+ * call-seq: session.connection_state -> state
156
+ *
157
+ * Returns one of the constants defined in ConnectionState.
158
+ */
159
+ static VALUE session_connection_state(VALUE self)
160
+ {
161
+ sp_session *session;
162
+ Data_Get_Struct(self, sp_session, session);
163
+ int state = sp_session_connectionstate(session);
164
+ return INT2FIX(state);
165
+ }
166
+
167
+ /*
168
+ * call-seq: session.process_events -> fixnum
169
+ *
170
+ * Makes the session process any pending events. Returns the number of
171
+ * milliseconds until you should call this method again.
172
+ */
173
+ static VALUE session_process_events(VALUE self)
174
+ {
175
+ sp_session *session;
176
+ Data_Get_Struct(self, sp_session, session);
177
+ int next_timeout;
178
+ sp_session_process_events(session, &next_timeout);
179
+ return INT2FIX(next_timeout);
180
+ }
181
+
182
+ /*
183
+ * call-seq: session.user -> user or nil
184
+ *
185
+ * Returns the user for the session.
186
+ */
187
+ static VALUE session_user(VALUE self)
188
+ {
189
+ sp_session *s;
190
+ Data_Get_Struct(self, sp_session, s);
191
+ sp_user *user = NULL;
192
+ user = sp_session_user(s);
193
+ return user ? Data_Wrap_Struct(class_user, NULL, NULL, user) : Qnil;
194
+ }
195
+
196
+ /*
197
+ * call-seq: session.playlist_container -> playlist_container or nil
198
+ *
199
+ * Returns the playlist container for the session.
200
+ */
201
+ static VALUE session_playlist_container(VALUE self)
202
+ {
203
+ sp_session *s;
204
+ Data_Get_Struct(self, sp_session, s);
205
+ sp_playlistcontainer *pc = NULL;
206
+ pc = sp_session_playlistcontainer(s);
207
+ return pc ? Data_Wrap_Struct(class_playlist_container, NULL, NULL, pc) : Qnil;
208
+ }
209
+
210
+ /*
211
+ * call-seq: user.loaded? -> true or false
212
+ *
213
+ * Returns true if the user is loaded, false otherwise.
214
+ */
215
+ static VALUE user_loaded(VALUE self)
216
+ {
217
+ sp_user *user;
218
+ Data_Get_Struct(self, sp_user, user);
219
+ return sp_user_is_loaded(user) ? Qtrue : Qfalse;
220
+ }
221
+
222
+ /*
223
+ * call-seq: user.canonical_name -> string or nil
224
+ *
225
+ * Returns the user's canonical name.
226
+ */
227
+ static VALUE user_canonical_name(VALUE self)
228
+ {
229
+ sp_user *user;
230
+ Data_Get_Struct(self, sp_user, user);
231
+ const char *name = sp_user_canonical_name(user);
232
+ return name ? rb_str_new2(name) : Qnil;
233
+ }
234
+
235
+ /*
236
+ * call-seq: user.display_name -> string or nil
237
+ *
238
+ * Returns the user's display name, or the canonical name if the display name is
239
+ * not known.
240
+ */
241
+ static VALUE user_display_name(VALUE self)
242
+ {
243
+ sp_user *user;
244
+ Data_Get_Struct(self, sp_user, user);
245
+ const char *name = sp_user_display_name(user);
246
+ return name ? rb_str_new2(name) : Qnil;
247
+ }
248
+
249
+ /*
250
+ * call-seq: playlist_container.num_playlists -> fixnum or nil
251
+ *
252
+ */
253
+ static VALUE playlist_container_num_playlists(VALUE self)
254
+ {
255
+ sp_playlistcontainer *playlistcontainer;
256
+ Data_Get_Struct(self, sp_playlistcontainer, playlistcontainer);
257
+ int n = sp_playlistcontainer_num_playlists(playlistcontainer);
258
+ return (n >= 0) ? INT2FIX(n) : Qnil;
259
+ }
260
+
261
+ /*
262
+ * call-seq: playlist_container.playlist(index) -> playlist or nil
263
+ *
264
+ */
265
+ static VALUE playlist_container_playlist(VALUE self, VALUE index)
266
+ {
267
+ sp_playlistcontainer *playlistcontainer;
268
+ Data_Get_Struct(self, sp_playlistcontainer, playlistcontainer);
269
+ int i = FIX2INT(index);
270
+ sp_playlist *playlist = NULL;
271
+ playlist = sp_playlistcontainer_playlist(playlistcontainer, i);
272
+ return playlist ? Data_Wrap_Struct(class_playlist, NULL, NULL, playlist) : Qnil;
273
+ }
274
+
275
+ /*
276
+ * call-seq: playlist_container.add_new_playlist(name) -> error
277
+ *
278
+ */
279
+ static VALUE playlist_container_add_new_playlist(VALUE self, VALUE name)
280
+ {
281
+ sp_playlistcontainer *pc;
282
+ Data_Get_Struct(self, sp_playlistcontainer, pc);
283
+ sp_playlist *p = sp_playlistcontainer_add_new_playlist(pc, StringValuePtr(name));
284
+ return p ? Data_Wrap_Struct(class_playlist, NULL, NULL, p) : Qnil;
285
+ }
286
+
287
+ /*
288
+ * call-seq: playlist_container.add_playlist(link) -> error
289
+ *
290
+ */
291
+ static VALUE playlist_container_add_playlist(VALUE self, VALUE link)
292
+ {
293
+ sp_playlistcontainer *pc;
294
+ Data_Get_Struct(self, sp_playlistcontainer, pc);
295
+ sp_link *l;
296
+ Data_Get_Struct(link, sp_link, l);
297
+ sp_playlist *p = sp_playlistcontainer_add_playlist(pc, l);
298
+ return p ? Data_Wrap_Struct(class_playlist, NULL, NULL, p) : Qnil;
299
+ }
300
+
301
+ /*
302
+ * call-seq: playlist_container.remove_playlist(index) -> error
303
+ *
304
+ */
305
+ static VALUE playlist_container_remove_playlist(VALUE self, VALUE index)
306
+ {
307
+ sp_playlistcontainer *pc;
308
+ Data_Get_Struct(self, sp_playlistcontainer, pc);
309
+ sp_error e = sp_playlistcontainer_remove_playlist(pc, FIX2INT(index));
310
+ return INT2FIX(e);
311
+ }
312
+
313
+ /*
314
+ * call-seq: playlist_container.move_playlist(index, new_position) -> error
315
+ *
316
+ */
317
+ static VALUE playlist_container_move_playlist(VALUE self, VALUE indices, VALUE new_position)
318
+ {
319
+ sp_playlistcontainer *pc;
320
+ Data_Get_Struct(self, sp_playlistcontainer, pc);
321
+ sp_error e = sp_playlistcontainer_move_playlist(pc, FIX2INT(index), FIX2INT(new_position));
322
+ return INT2FIX(e);
323
+ }
324
+
325
+ /*
326
+ * call-seq: playlist.loaded? -> true or false
327
+ *
328
+ * Returns true if the playlist is loaded, false otherwise.
329
+ */
330
+ static VALUE playlist_loaded(VALUE self)
331
+ {
332
+ sp_playlist *playlist;
333
+ Data_Get_Struct(self, sp_playlist, playlist);
334
+ return sp_playlist_is_loaded(playlist) ? Qtrue : Qfalse;
335
+ }
336
+
337
+ /*
338
+ * call-seq: playlist.name -> string or nil
339
+ *
340
+ * Returns the playlist's name.
341
+ */
342
+ static VALUE playlist_name(VALUE self)
343
+ {
344
+ sp_playlist *playlist;
345
+ Data_Get_Struct(self, sp_playlist, playlist);
346
+ const char *name = sp_playlist_name(playlist);
347
+ return name ? rb_str_new2(name) : Qnil;
348
+ }
349
+
350
+ /*
351
+ * call-seq: playlist.name = new_name -> string or nil
352
+ *
353
+ * Sets the playlist's name to the value of new_name.
354
+ */
355
+ static VALUE playlist_name_set(VALUE self, VALUE new_name)
356
+ {
357
+ sp_playlist *playlist;
358
+ Data_Get_Struct(self, sp_playlist, playlist);
359
+
360
+ sp_error error = sp_playlist_rename(playlist, StringValuePtr(new_name));
361
+
362
+ // TODO: throw exception instead?
363
+ if(error != SP_ERROR_OK)
364
+ return Qnil;
365
+
366
+ return new_name;
367
+ }
368
+
369
+ /*
370
+ * call-seq: playlist.owner -> user or nil
371
+ *
372
+ * Returns the playlist's owner.
373
+ */
374
+ static VALUE playlist_owner(VALUE self)
375
+ {
376
+ sp_playlist *playlist;
377
+ Data_Get_Struct(self, sp_playlist, playlist);
378
+ sp_user *user = NULL;
379
+ user = sp_playlist_owner(playlist);
380
+ return user ? Data_Wrap_Struct(class_user, NULL, NULL, user) : Qnil;
381
+ }
382
+
383
+ /*
384
+ * call-seq: playlist.collaborative? -> true or false
385
+ *
386
+ * Returns true if the playlist is collaborative, false otherwise.
387
+ */
388
+ static VALUE playlist_collaborative(VALUE self)
389
+ {
390
+ sp_playlist *playlist;
391
+ Data_Get_Struct(self, sp_playlist, playlist);
392
+ return sp_playlist_is_collaborative(playlist) ? Qtrue : Qfalse;
393
+ }
394
+
395
+ /*
396
+ * call-seq: playlist.collaborative = true or false -> true or false
397
+ *
398
+ * Sets the collaborative status of the playlist.
399
+ */
400
+ static VALUE playlist_collaborative_set(VALUE self, VALUE collaborative)
401
+ {
402
+ sp_playlist *playlist;
403
+ Data_Get_Struct(self, sp_playlist, playlist);
404
+ sp_playlist_set_collaborative(playlist, collaborative != Qnil && collaborative != Qfalse);
405
+ return collaborative;
406
+ }
407
+
408
+ /*
409
+ * call-seq: playlist.num_tracks -> fixnum or nil
410
+ *
411
+ */
412
+ static VALUE playlist_num_tracks(VALUE self)
413
+ {
414
+ sp_playlist *playlist;
415
+ Data_Get_Struct(self, sp_playlist, playlist);
416
+ int n = sp_playlist_num_tracks(playlist);
417
+ return (n >= 0) ? INT2FIX(n) : Qnil;
418
+ }
419
+
420
+ /*
421
+ * call-seq: playlist.track(index) -> track or nil
422
+ *
423
+ */
424
+ static VALUE playlist_track(VALUE self, VALUE index)
425
+ {
426
+ sp_playlist *playlist;
427
+ Data_Get_Struct(self, sp_playlist, playlist);
428
+ int i = FIX2INT(index);
429
+ sp_track *track = NULL;
430
+ track = sp_playlist_track(playlist, i);
431
+ return track ? Data_Wrap_Struct(class_track, NULL, NULL, track) : Qnil;
432
+ }
433
+
434
+ /*
435
+ * call-seq: playlist.pending_changes? -> true or false
436
+ *
437
+ * Returns true if the playlist has local changes that have not yet been
438
+ * acknowledged by the server, false otherwise.
439
+ */
440
+ static VALUE playlist_pending_changes(VALUE self)
441
+ {
442
+ sp_playlist *playlist;
443
+ Data_Get_Struct(self, sp_playlist, playlist);
444
+ return sp_playlist_has_pending_changes(playlist) ? Qtrue : Qfalse;
445
+ }
446
+
447
+ /*
448
+ * call-seq: playlist.add_tracks(tracks, position) -> error
449
+ *
450
+ * Add tracks at position in the playlist.
451
+ */
452
+ static VALUE playlist_add_tracks(VALUE self, VALUE tracks, VALUE position)
453
+ {
454
+ sp_playlist *p;
455
+ Data_Get_Struct(self, sp_playlist, p);
456
+ int n = rb_ary_length(tracks);
457
+ const sp_track **ts = malloc(n*sizeof(sp_track *));
458
+ int i;
459
+ for(i = 0; i < n; ++i)
460
+ {
461
+ sp_track *t;
462
+ Data_Get_Struct(rb_ary_entry(tracks, i), sp_track, t);
463
+ ts[i] = t;
464
+ }
465
+ sp_error e = sp_playlist_add_tracks(p, ts, n, FIX2INT(position));
466
+ free(ts);
467
+ return INT2FIX(e);
468
+ }
469
+
470
+ /*
471
+ * call-seq: playlist.remove_tracks(indices) -> error
472
+ *
473
+ * Remove the tracks at indices from the playlist.
474
+ */
475
+ static VALUE playlist_remove_tracks(VALUE self, VALUE indices)
476
+ {
477
+ sp_playlist *p;
478
+ Data_Get_Struct(self, sp_playlist, p);
479
+ int n = rb_ary_length(indices);
480
+ int *is = malloc(n*sizeof(int));
481
+ int i;
482
+ for(i = 0; i < n; ++i)
483
+ is[i] = FIX2INT(rb_ary_entry(indices, i));
484
+ sp_error e = sp_playlist_remove_tracks(p, is, n);
485
+ free(is);
486
+ return INT2FIX(e);
487
+ }
488
+
489
+ /*
490
+ * call-seq: playlist.reorder_tracks(indices, new_position) -> error
491
+ *
492
+ * Move the tracks at indices to new_position in the playlist.
493
+ */
494
+ static VALUE playlist_reorder_tracks(VALUE self, VALUE indices, VALUE new_position)
495
+ {
496
+ sp_playlist *p;
497
+ Data_Get_Struct(self, sp_playlist, p);
498
+ int n = rb_ary_length(indices);
499
+ int *is = malloc(n*sizeof(int));
500
+ int i;
501
+ for(i = 0; i < n; ++i)
502
+ is[i] = FIX2INT(rb_ary_entry(indices, i));
503
+ sp_error e = sp_playlist_reorder_tracks(p, is, n, FIX2INT(new_position));
504
+ free(is);
505
+ return INT2FIX(e);
506
+ }
507
+
508
+ static void search_free(void *search)
509
+ {
510
+ sp_search_release(search);
511
+ }
512
+
513
+ /*
514
+ * call-seq: Search.new(session, query, offset, count) -> search or nil
515
+ *
516
+ * Returns a new search object.
517
+ */
518
+ static VALUE search_new(VALUE klass, VALUE session, VALUE query, VALUE offset, VALUE count)
519
+ {
520
+ // TODO: search callback should not be hardcoded
521
+
522
+ sp_session *sess;
523
+ Data_Get_Struct(session, sp_session, sess);
524
+
525
+ sp_search *search = NULL;
526
+ search = sp_search_create(sess,
527
+ StringValuePtr(query),
528
+ FIX2INT(offset),
529
+ FIX2INT(count),
530
+ 0,
531
+ 100,
532
+ 0,
533
+ 100,
534
+ search_complete_callback,
535
+ NULL);
536
+
537
+ if(!search)
538
+ return Qnil;
539
+
540
+ VALUE search_value = Data_Wrap_Struct(class_search, NULL, search_free, search);
541
+ VALUE argv[4] = {session, query, offset, count};
542
+ rb_obj_call_init(search_value, 4, argv);
543
+ return search_value;
544
+ }
545
+
546
+ /*
547
+ * call-seq: search.loaded? -> true or false
548
+ *
549
+ * Returns true if the search object is loaded, false otherwise.
550
+ */
551
+ static VALUE search_loaded(VALUE self)
552
+ {
553
+ sp_search *search;
554
+ Data_Get_Struct(self, sp_search, search);
555
+ return sp_search_is_loaded(search) ? Qtrue : Qfalse;
556
+ }
557
+
558
+ /*
559
+ * call-seq: search.error -> error
560
+ *
561
+ * Returns one of the constants defined in Error.
562
+ */
563
+ static VALUE search_error(VALUE self)
564
+ {
565
+ sp_search *search;
566
+ Data_Get_Struct(self, sp_search, search);
567
+ sp_error error = sp_search_error(search);
568
+ return INT2FIX(error);
569
+ }
570
+
571
+ /*
572
+ * call-seq: search.num_artists -> fixnum or nil
573
+ *
574
+ */
575
+ static VALUE search_num_artists(VALUE self)
576
+ {
577
+ sp_search *search;
578
+ Data_Get_Struct(self, sp_search, search);
579
+ int n = sp_search_num_artists(search);
580
+ return (n >= 0) ? INT2FIX(n) : Qnil;
581
+ }
582
+
583
+ /*
584
+ * call-seq: search.artist(index) -> artist or nil
585
+ *
586
+ */
587
+ static VALUE search_artist(VALUE self, VALUE index)
588
+ {
589
+ sp_search *search;
590
+ Data_Get_Struct(self, sp_search, search);
591
+ int i = FIX2INT(index);
592
+ sp_artist *artist = NULL;
593
+ artist = sp_search_artist(search, i);
594
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
595
+ }
596
+
597
+ /*
598
+ * call-seq: search.num_albums -> fixnum or nil
599
+ *
600
+ */
601
+ static VALUE search_num_albums(VALUE self)
602
+ {
603
+ sp_search *search;
604
+ Data_Get_Struct(self, sp_search, search);
605
+ int n = sp_search_num_albums(search);
606
+ return (n >= 0) ? INT2FIX(n) : Qnil;
607
+ }
608
+
609
+ /*
610
+ * call-seq: search.album(index) -> album or nil
611
+ *
612
+ */
613
+ static VALUE search_album(VALUE self, VALUE index)
614
+ {
615
+ sp_search *search;
616
+ Data_Get_Struct(self, sp_search, search);
617
+ int i = FIX2INT(index);
618
+ sp_album *album = NULL;
619
+ album = sp_search_album(search, i);
620
+ return album ? Data_Wrap_Struct(class_album, NULL, NULL, album) : Qnil;
621
+ }
622
+
623
+ /*
624
+ * call-seq: search.num_tracks -> fixnum or nil
625
+ *
626
+ */
627
+ static VALUE search_num_tracks(VALUE self)
628
+ {
629
+ sp_search *search;
630
+ Data_Get_Struct(self, sp_search, search);
631
+ int n = sp_search_num_tracks(search);
632
+ return (n >= 0) ? INT2FIX(n) : Qnil;
633
+ }
634
+
635
+ /*
636
+ * call-seq: search.track(index) -> track or nil
637
+ *
638
+ */
639
+ static VALUE search_track(VALUE self, VALUE index)
640
+ {
641
+ sp_search *search;
642
+ Data_Get_Struct(self, sp_search, search);
643
+ int i = FIX2INT(index);
644
+ sp_track *track = NULL;
645
+ track = sp_search_track(search, i);
646
+ return track ? Data_Wrap_Struct(class_track, NULL, NULL, track) : Qnil;
647
+ }
648
+
649
+ /*
650
+ * call-seq: search.total_tracks -> fixnum or nil
651
+ *
652
+ * Returns the total number of track hits for the search query.
653
+ */
654
+ static VALUE search_total_tracks(VALUE self)
655
+ {
656
+ sp_search *search;
657
+ Data_Get_Struct(self, sp_search, search);
658
+ int n = sp_search_total_tracks(search);
659
+ return (n >= 0) ? INT2FIX(n) : Qnil;
660
+ }
661
+
662
+ /*
663
+ * call-seq: search.query -> string or nil
664
+ *
665
+ * Returns the query for the search object.
666
+ */
667
+ static VALUE search_query(VALUE self)
668
+ {
669
+ sp_search *search;
670
+ Data_Get_Struct(self, sp_search, search);
671
+ const char *q = sp_search_query(search);
672
+ return q ? rb_str_new2(q) : Qnil;
673
+ }
674
+
675
+ /*
676
+ * call-seq: search.did_you_mean -> string or nil
677
+ *
678
+ * Returns the "did you mean" suggestion for the search object, or nil if no
679
+ * suggestion is available.
680
+ */
681
+ static VALUE search_did_you_mean(VALUE self)
682
+ {
683
+ sp_search *search;
684
+ Data_Get_Struct(self, sp_search, search);
685
+ const char *d = sp_search_did_you_mean(search);
686
+ return d ? rb_str_new2(d) : Qnil;
687
+ }
688
+
689
+ static void artist_browse_free(void *ab)
690
+ {
691
+ sp_artistbrowse_release(ab);
692
+ }
693
+
694
+ /*
695
+ * call-seq: ArtistBrowse.new(session, artist) -> artist_browse or nil
696
+ *
697
+ * Returns a new artist browse object.
698
+ */
699
+ static VALUE artist_browse_new(VALUE klass, VALUE session, VALUE artist)
700
+ {
701
+ // TODO: artist browse callback should not be hardcoded
702
+
703
+ sp_session *s;
704
+ Data_Get_Struct(session, sp_session, s);
705
+
706
+ sp_artist *a;
707
+ Data_Get_Struct(artist, sp_artist, a);
708
+
709
+ sp_artistbrowse *artistbrowse = NULL;
710
+ artistbrowse = sp_artistbrowse_create(s, a, artist_browse_complete_callback, NULL);
711
+
712
+ if(!artistbrowse)
713
+ return Qnil;
714
+
715
+ VALUE ab_value = Data_Wrap_Struct(class_artist_browse, NULL, artist_browse_free, artistbrowse);
716
+ VALUE argv[2] = {session, artist};
717
+ rb_obj_call_init(ab_value, 2, argv);
718
+ return ab_value;
719
+ }
720
+
721
+ /*
722
+ * call-seq: artist_browse.loaded? -> true or false
723
+ *
724
+ * Returns true if the artist browse object is loaded, false otherwise.
725
+ */
726
+ static VALUE artist_browse_loaded(VALUE self)
727
+ {
728
+ sp_artistbrowse *artistbrowse;
729
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
730
+ return sp_artistbrowse_is_loaded(artistbrowse) ? Qtrue : Qfalse;
731
+ }
732
+
733
+ /*
734
+ * call-seq: artist_browse.error -> error
735
+ *
736
+ * Returns one of the constants defined in Error.
737
+ */
738
+ static VALUE artist_browse_error(VALUE self)
739
+ {
740
+ sp_artistbrowse *artistbrowse;
741
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
742
+ sp_error error = sp_artistbrowse_error(artistbrowse);
743
+ return INT2FIX(error);
744
+ }
745
+
746
+ /*
747
+ * call-seq: artist_browse.artist -> artist or nil
748
+ *
749
+ * Returns the artist for the artist browse object.
750
+ */
751
+ static VALUE artist_browse_artist(VALUE self)
752
+ {
753
+ sp_artistbrowse *artistbrowse;
754
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
755
+ sp_artist *artist = sp_artistbrowse_artist(artistbrowse);
756
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
757
+ }
758
+
759
+ /*
760
+ * call-seq: artist_browse.num_tracks -> fixnum or nil
761
+ *
762
+ */
763
+ static VALUE artist_browse_num_tracks(VALUE self)
764
+ {
765
+ sp_artistbrowse *artistbrowse;
766
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
767
+ int n = sp_artistbrowse_num_tracks(artistbrowse);
768
+ return (n >= 0) ? INT2FIX(n) : Qnil;
769
+ }
770
+
771
+ /*
772
+ * call-seq: artist_browse.track(index) -> track or nil
773
+ *
774
+ */
775
+ static VALUE artist_browse_track(VALUE self, VALUE index)
776
+ {
777
+ sp_artistbrowse *artistbrowse;
778
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
779
+ int i = FIX2INT(index);
780
+ sp_track *track = NULL;
781
+ track = sp_artistbrowse_track(artistbrowse, i);
782
+ return track ? Data_Wrap_Struct(class_track, NULL, NULL, track) : Qnil;
783
+ }
784
+
785
+ /*
786
+ * call-seq: artist_browse.num_similar_artists -> fixnum or nil
787
+ *
788
+ */
789
+ static VALUE artist_browse_num_similar_artists(VALUE self)
790
+ {
791
+ sp_artistbrowse *artistbrowse;
792
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
793
+ int n = sp_artistbrowse_num_similar_artists(artistbrowse);
794
+ return (n >= 0) ? INT2FIX(n) : Qnil;
795
+ }
796
+
797
+ /*
798
+ * call-seq: artist_browse.similar_artist(index) -> artist or nil
799
+ *
800
+ */
801
+ static VALUE artist_browse_similar_artist(VALUE self, VALUE index)
802
+ {
803
+ sp_artistbrowse *artistbrowse;
804
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
805
+ int i = FIX2INT(index);
806
+ sp_artist *artist = NULL;
807
+ artist = sp_artistbrowse_similar_artist(artistbrowse, i);
808
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
809
+ }
810
+
811
+ /*
812
+ * call-seq: artist_browse.biography -> string or nil
813
+ *
814
+ * Returns the biography for the artist browse object, or nil if no biography is
815
+ * available.
816
+ */
817
+ static VALUE artist_browse_biography(VALUE self)
818
+ {
819
+ sp_artistbrowse *artistbrowse;
820
+ Data_Get_Struct(self, sp_artistbrowse, artistbrowse);
821
+ const char *bio = sp_artistbrowse_biography(artistbrowse);
822
+ return bio ? rb_str_new2(bio) : Qnil;
823
+ }
824
+
825
+ static void album_browse_free(void *ab)
826
+ {
827
+ sp_albumbrowse_release(ab);
828
+ }
829
+
830
+ /*
831
+ * call-seq: AlbumBrowse.new(session, album) -> album_browse or nil
832
+ *
833
+ * Returns a new album browse object.
834
+ */
835
+ static VALUE album_browse_new(VALUE klass, VALUE session, VALUE album)
836
+ {
837
+ // TODO: album browse callback should not be hardcoded
838
+
839
+ sp_session *s;
840
+ Data_Get_Struct(session, sp_session, s);
841
+
842
+ sp_album *a;
843
+ Data_Get_Struct(album, sp_album, a);
844
+
845
+ sp_albumbrowse *albumbrowse = NULL;
846
+ albumbrowse = sp_albumbrowse_create(s, a, album_browse_complete_callback, NULL);
847
+
848
+ if(!albumbrowse)
849
+ return Qnil;
850
+
851
+ VALUE ab_value = Data_Wrap_Struct(class_album_browse, NULL, album_browse_free, albumbrowse);
852
+ VALUE argv[2] = {session, album};
853
+ rb_obj_call_init(ab_value, 2, argv);
854
+ return ab_value;
855
+ }
856
+
857
+ /*
858
+ * call-seq: album_browse.loaded? -> true or false
859
+ *
860
+ * Returns true if the album browse object is loaded, false otherwise.
861
+ */
862
+ static VALUE album_browse_loaded(VALUE self)
863
+ {
864
+ sp_albumbrowse *albumbrowse;
865
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
866
+ return sp_albumbrowse_is_loaded(albumbrowse) ? Qtrue : Qfalse;
867
+ }
868
+
869
+ /*
870
+ * call-seq: album_browse.error -> error
871
+ *
872
+ * Returns one of the constants defined in Error.
873
+ */
874
+ static VALUE album_browse_error(VALUE self)
875
+ {
876
+ sp_albumbrowse *albumbrowse;
877
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
878
+ sp_error error = sp_albumbrowse_error(albumbrowse);
879
+ return INT2FIX(error);
880
+ }
881
+
882
+ /*
883
+ * call-seq: album_browse.artist -> artist or nil
884
+ *
885
+ * Returns the artist for the album browse object.
886
+ */
887
+ static VALUE album_browse_artist(VALUE self)
888
+ {
889
+ sp_albumbrowse *albumbrowse;
890
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
891
+ sp_artist *artist = sp_albumbrowse_artist(albumbrowse);
892
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
893
+ }
894
+
895
+ /*
896
+ * call-seq: album_browse.album -> album or nil
897
+ *
898
+ * Returns the album for the album browse object.
899
+ */
900
+ static VALUE album_browse_album(VALUE self)
901
+ {
902
+ sp_albumbrowse *albumbrowse;
903
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
904
+ sp_album *album = sp_albumbrowse_album(albumbrowse);
905
+ return album ? Data_Wrap_Struct(class_album, NULL, NULL, album) : Qnil;
906
+ }
907
+
908
+ /*
909
+ * call-seq: album_browse.num_tracks -> fixnum or nil
910
+ *
911
+ */
912
+ static VALUE album_browse_num_tracks(VALUE self)
913
+ {
914
+ sp_albumbrowse *albumbrowse;
915
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
916
+ int n = sp_albumbrowse_num_tracks(albumbrowse);
917
+ return (n >= 0) ? INT2FIX(n) : Qnil;
918
+ }
919
+
920
+ /*
921
+ * call-seq: album_browse_track(index) -> track or nil
922
+ *
923
+ */
924
+ static VALUE album_browse_track(VALUE self, VALUE index)
925
+ {
926
+ sp_albumbrowse *albumbrowse;
927
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
928
+ int i = FIX2INT(index);
929
+ sp_track *track = NULL;
930
+ track = sp_albumbrowse_track(albumbrowse, i);
931
+ return track ? Data_Wrap_Struct(class_track, NULL, NULL, track) : Qnil;
932
+ }
933
+
934
+ /*
935
+ * call-seq: album_browse.num_copyrights -> fixnum or nil
936
+ *
937
+ */
938
+ static VALUE album_browse_num_copyrights(VALUE self)
939
+ {
940
+ sp_albumbrowse *albumbrowse;
941
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
942
+ int n = sp_albumbrowse_num_copyrights(albumbrowse);
943
+ return (n >= 0) ? INT2FIX(n) : Qnil;
944
+ }
945
+
946
+ /*
947
+ * call-seq: album_browse.copyright(index) -> string or nil
948
+ *
949
+ */
950
+ static VALUE album_browse_copyright(VALUE self, VALUE index)
951
+ {
952
+ sp_albumbrowse *albumbrowse;
953
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
954
+ int i = FIX2INT(index);
955
+ const char *c = sp_albumbrowse_copyright(albumbrowse, i);
956
+ return c ? rb_str_new2(c) : Qnil;
957
+ }
958
+
959
+ /*
960
+ * call-seq: album_browse.review -> string or nil
961
+ *
962
+ * Returns the review for the album browse object, or nil if no review is
963
+ * available.
964
+ */
965
+ static VALUE album_browse_review(VALUE self)
966
+ {
967
+ sp_albumbrowse *albumbrowse;
968
+ Data_Get_Struct(self, sp_albumbrowse, albumbrowse);
969
+ const char *r = sp_albumbrowse_review(albumbrowse);
970
+ return r ? rb_str_new2(r) : Qnil;
971
+ }
972
+
973
+ /*
974
+ * call-seq: artist.loaded? -> true or false
975
+ *
976
+ * Returns true if the artist is loaded, false otherwise.
977
+ */
978
+ static VALUE artist_loaded(VALUE self)
979
+ {
980
+ sp_artist *artist;
981
+ Data_Get_Struct(self, sp_artist, artist);
982
+ return sp_artist_is_loaded(artist) ? Qtrue : Qfalse;
983
+ }
984
+
985
+ /*
986
+ * call-seq: artist.name -> string or nil
987
+ *
988
+ * Returns the artist's name.
989
+ */
990
+ static VALUE artist_name(VALUE self)
991
+ {
992
+ sp_artist *artist;
993
+ Data_Get_Struct(self, sp_artist, artist);
994
+ const char *name = sp_artist_name(artist);
995
+ return name ? rb_str_new2(name) : Qnil;
996
+ }
997
+
998
+ /*
999
+ * call-seq: album.loaded? -> true or false
1000
+ *
1001
+ * Returns true if the album is loaded, false otherwise.
1002
+ */
1003
+ static VALUE album_loaded(VALUE self)
1004
+ {
1005
+ sp_album *album;
1006
+ Data_Get_Struct(self, sp_album, album);
1007
+ return sp_album_is_loaded(album) ? Qtrue : Qfalse;
1008
+ }
1009
+
1010
+ /*
1011
+ * call-seq: album.artist -> artist or nil
1012
+ *
1013
+ * Returns the album's artist.
1014
+ */
1015
+ static VALUE album_artist(VALUE self)
1016
+ {
1017
+ sp_album *album;
1018
+ Data_Get_Struct(self, sp_album, album);
1019
+ sp_artist *artist = sp_album_artist(album);
1020
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
1021
+ }
1022
+
1023
+ /*
1024
+ * call-seq: album.name -> string or nil
1025
+ *
1026
+ * Returns the album's name.
1027
+ */
1028
+ static VALUE album_name(VALUE self)
1029
+ {
1030
+ sp_album *album;
1031
+ Data_Get_Struct(self, sp_album, album);
1032
+ const char *name = sp_album_name(album);
1033
+ return name ? rb_str_new2(name) : Qnil;
1034
+ }
1035
+
1036
+ /*
1037
+ * call-seq: album.year -> fixnum or nil
1038
+ *
1039
+ * Returns the year the album was released.
1040
+ */
1041
+ static VALUE album_year(VALUE self)
1042
+ {
1043
+ sp_album *album;
1044
+ Data_Get_Struct(self, sp_album, album);
1045
+ int year = sp_album_year(album);
1046
+ return year ? INF2FIX(year) : Qnil;
1047
+ }
1048
+
1049
+ /*
1050
+ * call-seq: track.loaded? -> true or false
1051
+ *
1052
+ * Returns true if the track is loaded, false otherwise.
1053
+ */
1054
+ static VALUE track_loaded(VALUE self)
1055
+ {
1056
+ sp_track *track;
1057
+ Data_Get_Struct(self, sp_track, track);
1058
+ return sp_track_is_loaded(track) ? Qtrue : Qfalse;
1059
+ }
1060
+
1061
+ /*
1062
+ * call-seq: track.error -> error
1063
+ *
1064
+ * Returns one of the constants defined in Error.
1065
+ */
1066
+ static VALUE track_error(VALUE self)
1067
+ {
1068
+ sp_track *track;
1069
+ Data_Get_Struct(self, sp_track, track);
1070
+ sp_error error = sp_track_error(track);
1071
+ return INT2FIX(error);
1072
+ }
1073
+
1074
+ /*
1075
+ * call-seq: track.num_artists -> fixnum or nil
1076
+ *
1077
+ */
1078
+ static VALUE track_num_artists(VALUE self)
1079
+ {
1080
+ sp_track *track;
1081
+ Data_Get_Struct(self, sp_track, track);
1082
+ int n = sp_track_num_artists(track);
1083
+ return n ? INT2FIX(n) : Qnil;
1084
+ }
1085
+
1086
+ /*
1087
+ * call-seq: track.artist(index) -> artist or nil
1088
+ *
1089
+ */
1090
+ static VALUE track_artist(VALUE self, VALUE index)
1091
+ {
1092
+ sp_track *track;
1093
+ Data_Get_Struct(self, sp_track, track);
1094
+ int i = FIX2INT(index);
1095
+ sp_artist *artist = sp_track_artist(track, i);
1096
+ return artist ? Data_Wrap_Struct(class_artist, NULL, NULL, artist) : Qnil;
1097
+ }
1098
+
1099
+ /*
1100
+ * call-seq: track.album -> album or nil
1101
+ *
1102
+ * Returns the track's album.
1103
+ */
1104
+ static VALUE track_album(VALUE self)
1105
+ {
1106
+ sp_track *track;
1107
+ Data_Get_Struct(self, sp_track, track);
1108
+ sp_album *album = sp_track_album(track);
1109
+ return album ? Data_Wrap_Struct(class_album, NULL, NULL, album) : Qnil;
1110
+ }
1111
+
1112
+ /*
1113
+ * call-seq: track.name -> string or nil
1114
+ *
1115
+ * Returns the track's name.
1116
+ */
1117
+ static VALUE track_name(VALUE self)
1118
+ {
1119
+ sp_track *track;
1120
+ Data_Get_Struct(self, sp_track, track);
1121
+ const char *name = sp_track_name(track);
1122
+ return name ? rb_str_new2(name) : Qnil;
1123
+ }
1124
+
1125
+ /*
1126
+ * call-seq: track.duration -> fixnum
1127
+ *
1128
+ * Returns the track's duration in milliseconds.
1129
+ */
1130
+ static VALUE track_duration(VALUE self)
1131
+ {
1132
+ sp_track *track;
1133
+ Data_Get_Struct(self, sp_track, track);
1134
+ int d = sp_track_duration(track);
1135
+ return INT2FIX(d);
1136
+ }
1137
+
1138
+ /*
1139
+ * call-seq: track.popularity -> fixnum
1140
+ *
1141
+ * Returns the track's popularity as a number in the range [0, 100].
1142
+ */
1143
+ static VALUE track_popularity(VALUE self)
1144
+ {
1145
+ sp_track *track;
1146
+ Data_Get_Struct(self, sp_track, track);
1147
+ int p = sp_track_popularity(track);
1148
+ return INT2FIX(p);
1149
+ }
1150
+
1151
+ /*
1152
+ * call-seq: track.disc -> fixnum or nil
1153
+ *
1154
+ * Returns the index of the disc the track is on, counting from 1.
1155
+ */
1156
+ static VALUE track_disc(VALUE self)
1157
+ {
1158
+ sp_track *track;
1159
+ Data_Get_Struct(self, sp_track, track);
1160
+ int d = sp_track_disc(track);
1161
+ return d ? INT2FIX(d) : Qnil;
1162
+ }
1163
+
1164
+ /*
1165
+ * call-seq: track.index -> fixnum or nil
1166
+ *
1167
+ * Returns the index of the track on its disc, counting from 1.
1168
+ */
1169
+ static VALUE track_index(VALUE self)
1170
+ {
1171
+ sp_track *track;
1172
+ Data_Get_Struct(self, sp_track, track);
1173
+ int i = sp_track_index(track);
1174
+ return i ? INT2FIX(i) : Qnil;
1175
+ }
1176
+
1177
+ static void link_free(void *link)
1178
+ {
1179
+ sp_link_release(link);
1180
+ }
1181
+
1182
+ /*
1183
+ * call-seq:
1184
+ * Link.new(artist) -> link
1185
+ * Link.new(album) -> link
1186
+ * Link.new(track) -> link
1187
+ * Link.new(playlist) -> link
1188
+ * Link.new(search) -> link
1189
+ * Link.new(string) -> link or nil
1190
+ *
1191
+ * Returns a new link pointing to the given resource.
1192
+ */
1193
+ static VALUE link_new(VALUE klass, VALUE object)
1194
+ {
1195
+ sp_link *link = NULL;
1196
+
1197
+ if(rb_obj_is_kind_of(object, class_artist))
1198
+ {
1199
+ sp_artist *a;
1200
+ Data_Get_Struct(object, sp_artist, a);
1201
+ link = sp_link_create_from_artist(a);
1202
+ }
1203
+ else if(rb_obj_is_kind_of(object, class_album))
1204
+ {
1205
+ sp_album *a;
1206
+ Data_Get_Struct(object, sp_album, a);
1207
+ link = sp_link_create_from_album(a);
1208
+ }
1209
+ else if(rb_obj_is_kind_of(object, class_track))
1210
+ {
1211
+ sp_track *t;
1212
+ Data_Get_Struct(object, sp_track, t);
1213
+ link = sp_link_create_from_track(t, 0); // TODO: offset
1214
+ }
1215
+ else if(rb_obj_is_kind_of(object, class_playlist))
1216
+ {
1217
+ sp_playlist *p;
1218
+ Data_Get_Struct(object, sp_playlist, p);
1219
+ link = sp_link_create_from_playlist(p);
1220
+ }
1221
+ else if(rb_obj_is_kind_of(object, class_search))
1222
+ {
1223
+ sp_search *s;
1224
+ Data_Get_Struct(object, sp_search, s);
1225
+ link = sp_link_create_from_search(s);
1226
+ }
1227
+ else
1228
+ {
1229
+ link = sp_link_create_from_string(StringValuePtr(object));
1230
+ }
1231
+
1232
+ if(!link)
1233
+ return Qnil;
1234
+
1235
+ VALUE link_value = Data_Wrap_Struct(class_link, NULL, link_free, link);
1236
+ VALUE argv[1] = {object};
1237
+ rb_obj_call_init(link_value, 1, argv);
1238
+ return link_value;
1239
+ }
1240
+
1241
+ /*
1242
+ * call-seq: link.link_type -> type
1243
+ *
1244
+ * Returns the link type. Named link_type instead of just type to avoid
1245
+ * overriding a method in Object.
1246
+ */
1247
+ static VALUE link_link_type(VALUE self)
1248
+ {
1249
+ sp_link *link;
1250
+ Data_Get_Struct(self, sp_link, link);
1251
+ int type = sp_link_type(link);
1252
+ return INT2FIX(type);
1253
+ }
1254
+
1255
+ /*
1256
+ * call-seq: link.to_s -> string or nil
1257
+ *
1258
+ * Returns a string representation of the link.
1259
+ */
1260
+ static VALUE link_to_s(VALUE self)
1261
+ {
1262
+ sp_link *link;
1263
+ Data_Get_Struct(self, sp_link, link);
1264
+ char buffer[100];
1265
+ int n = sp_link_as_string(link, buffer, 100);
1266
+ return (n < 100) ? rb_str_new2(buffer) : Qnil;
1267
+ }
1268
+
1269
+ /*
1270
+ * call-seq: link.to_artist -> artist or nil
1271
+ *
1272
+ */
1273
+ static VALUE link_to_artist(VALUE self)
1274
+ {
1275
+ sp_link *l;
1276
+ Data_Get_Struct(self, sp_link, l);
1277
+ sp_artist *a = sp_link_as_artist(l);
1278
+ return a ? Data_Wrap_Struct(class_artist, NULL, NULL, a) : Qnil;
1279
+ }
1280
+
1281
+ /*
1282
+ * call-seq: link.to_album -> album or nil
1283
+ *
1284
+ */
1285
+ static VALUE link_to_album(VALUE self)
1286
+ {
1287
+ sp_link *l;
1288
+ Data_Get_Struct(self, sp_link, l);
1289
+ sp_album *a = sp_link_as_album(l);
1290
+ return a ? Data_Wrap_Struct(class_album, NULL, NULL, a) : Qnil;
1291
+ }
1292
+
1293
+ /*
1294
+ * call-seq: link.to_track -> track or nil
1295
+ *
1296
+ */
1297
+ static VALUE link_to_track(VALUE self)
1298
+ {
1299
+ sp_link *l;
1300
+ Data_Get_Struct(self, sp_link, l);
1301
+ sp_track *t = sp_link_as_track(l);
1302
+ return t ? Data_Wrap_Struct(class_track, NULL, NULL, t) : Qnil;
1303
+ }
1304
+
1305
+ // init
1306
+
1307
+ void Init_greenstripes()
1308
+ {
1309
+ /*
1310
+ * GreenStripes
1311
+ */
1312
+ module_greenstripes = rb_define_module("GreenStripes");
1313
+
1314
+ /*
1315
+ * The Error module defines constants for error codes returned by various
1316
+ * methods.
1317
+ */
1318
+ module_error = rb_define_module_under(module_greenstripes, "Error");
1319
+ rb_define_const(module_error, "OK", INT2FIX(SP_ERROR_OK));
1320
+ rb_define_const(module_error, "BAD_API_VERSION", INT2FIX(SP_ERROR_BAD_API_VERSION));
1321
+ rb_define_const(module_error, "API_INITIALIZATION_FAILED", INT2FIX(SP_ERROR_API_INITIALIZATION_FAILED));
1322
+ rb_define_const(module_error, "TRACK_NOT_PLAYABLE", INT2FIX(SP_ERROR_TRACK_NOT_PLAYABLE));
1323
+ rb_define_const(module_error, "RESOURCE_NOT_LOADED", INT2FIX(SP_ERROR_RESOURCE_NOT_LOADED));
1324
+ rb_define_const(module_error, "BAD_APPLICATION_KEY", INT2FIX(SP_ERROR_BAD_APPLICATION_KEY));
1325
+ rb_define_const(module_error, "BAD_USERNAME_OR_PASSWORD", INT2FIX(SP_ERROR_BAD_USERNAME_OR_PASSWORD));
1326
+ rb_define_const(module_error, "USER_BANNED", INT2FIX(SP_ERROR_USER_BANNED));
1327
+ rb_define_const(module_error, "UNABLE_TO_CONTACT_SERVER", INT2FIX(SP_ERROR_UNABLE_TO_CONTACT_SERVER));
1328
+ rb_define_const(module_error, "CLIENT_TOO_OLD", INT2FIX(SP_ERROR_CLIENT_TOO_OLD));
1329
+ rb_define_const(module_error, "OTHER_PERMANENT", INT2FIX(SP_ERROR_CLIENT_TOO_OLD));
1330
+ rb_define_const(module_error, "BAD_USER_AGENT", INT2FIX(SP_ERROR_BAD_USER_AGENT));
1331
+ rb_define_const(module_error, "MISSING_CALLBACK", INT2FIX(SP_ERROR_MISSING_CALLBACK));
1332
+ rb_define_const(module_error, "INVALID_INDATA", INT2FIX(SP_ERROR_INVALID_INDATA));
1333
+ rb_define_const(module_error, "INDEX_OUT_OF_RANGE", INT2FIX(SP_ERROR_INDEX_OUT_OF_RANGE));
1334
+ rb_define_const(module_error, "USER_NEEDS_PREMIUM", INT2FIX(SP_ERROR_USER_NEEDS_PREMIUM));
1335
+ rb_define_const(module_error, "OTHER_TRANSIENT", INT2FIX(SP_ERROR_OTHER_TRANSIENT));
1336
+ rb_define_const(module_error, "IS_LOADING", INT2FIX(SP_ERROR_IS_LOADING));
1337
+
1338
+ /*
1339
+ * The ConnectionState module defines constants describing the current state
1340
+ * of a connection.
1341
+ */
1342
+ module_connection_state = rb_define_module_under(module_greenstripes, "ConnectionState");
1343
+ rb_define_const(module_connection_state, "LOGGED_OUT", INT2FIX(SP_CONNECTION_STATE_LOGGED_OUT));
1344
+ rb_define_const(module_connection_state, "LOGGED_IN", INT2FIX(SP_CONNECTION_STATE_LOGGED_IN));
1345
+ rb_define_const(module_connection_state, "DISCONNECTED", INT2FIX(SP_CONNECTION_STATE_DISCONNECTED));
1346
+ rb_define_const(module_connection_state, "UNDEFINED", INT2FIX(SP_CONNECTION_STATE_UNDEFINED));
1347
+
1348
+ /*
1349
+ * The LinkType module defines constants for link types.
1350
+ */
1351
+ module_link_type = rb_define_module_under(module_greenstripes, "LinkType");
1352
+ rb_define_const(module_link_type, "INVALID", INT2FIX(SP_LINKTYPE_INVALID));
1353
+ rb_define_const(module_link_type, "TRACK", INT2FIX(SP_LINKTYPE_TRACK));
1354
+ rb_define_const(module_link_type, "ALBUM", INT2FIX(SP_LINKTYPE_ALBUM));
1355
+ rb_define_const(module_link_type, "ARTIST", INT2FIX(SP_LINKTYPE_ARTIST));
1356
+ rb_define_const(module_link_type, "SEARCH", INT2FIX(SP_LINKTYPE_SEARCH));
1357
+ rb_define_const(module_link_type, "PLAYLIST", INT2FIX(SP_LINKTYPE_PLAYLIST));
1358
+
1359
+ /*
1360
+ * Session
1361
+ */
1362
+ class_session = rb_define_class_under(module_greenstripes, "Session", rb_cObject);
1363
+ rb_define_singleton_method(class_session, "new", session_new, 4);
1364
+ rb_define_method(class_session, "login", session_login, 2);
1365
+ rb_define_method(class_session, "logout", session_logout, 0);
1366
+ rb_define_method(class_session, "connection_state", session_connection_state, 0);
1367
+ rb_define_method(class_session, "process_events", session_process_events, 0);
1368
+ rb_define_method(class_session, "user", session_user, 0);
1369
+ rb_define_method(class_session, "playlist_container", session_playlist_container, 0);
1370
+
1371
+ /*
1372
+ * User
1373
+ */
1374
+ class_user = rb_define_class_under(module_greenstripes, "User", rb_cObject);
1375
+ rb_define_method(class_user, "loaded?", user_loaded, 0);
1376
+ rb_define_method(class_user, "canonical_name", user_canonical_name, 0);
1377
+ rb_define_method(class_user, "display_name", user_display_name, 0);
1378
+
1379
+ /*
1380
+ * PlaylistContainer
1381
+ */
1382
+ class_playlist_container = rb_define_class_under(module_greenstripes, "PlaylistContainer", rb_cObject);
1383
+ rb_define_method(class_playlist_container, "num_playlists", playlist_container_num_playlists, 0);
1384
+ rb_define_method(class_playlist_container, "playlist", playlist_container_playlist, 1);
1385
+ rb_define_method(class_playlist_container, "add_new_playlist", playlist_container_add_new_playlist, 1);
1386
+ rb_define_method(class_playlist_container, "add_playlist", playlist_container_add_playlist, 1);
1387
+ rb_define_method(class_playlist_container, "remove_playlist", playlist_container_remove_playlist, 1);
1388
+ rb_define_method(class_playlist_container, "move_playlist", playlist_container_move_playlist, 2);
1389
+
1390
+ /*
1391
+ * Playlist
1392
+ */
1393
+ class_playlist = rb_define_class_under(module_greenstripes, "Playlist", rb_cObject);
1394
+ rb_define_method(class_playlist, "loaded?", playlist_loaded, 0);
1395
+ rb_define_method(class_playlist, "name", playlist_name, 0);
1396
+ rb_define_method(class_playlist, "name=", playlist_name_set, 1);
1397
+ rb_define_method(class_playlist, "owner", playlist_owner, 0);
1398
+ rb_define_method(class_playlist, "collaborative?", playlist_collaborative, 0);
1399
+ rb_define_method(class_playlist, "collaborative=", playlist_collaborative_set, 1);
1400
+ rb_define_method(class_playlist, "num_tracks", playlist_num_tracks, 0);
1401
+ rb_define_method(class_playlist, "track", playlist_track, 1);
1402
+ rb_define_method(class_playlist, "pending_changes?", playlist_pending_changes, 0);
1403
+ rb_define_method(class_playlist, "add_tracks", playlist_add_tracks, 2);
1404
+ rb_define_method(class_playlist, "remove_tracks", playlist_remove_tracks, 1);
1405
+ rb_define_method(class_playlist, "reorder_tracks", playlist_reorder_tracks, 2);
1406
+
1407
+ /*
1408
+ * Search
1409
+ */
1410
+ class_search = rb_define_class_under(module_greenstripes, "Search", rb_cObject);
1411
+ rb_define_singleton_method(class_search, "new", search_new, 4);
1412
+ rb_define_method(class_search, "loaded?", search_loaded, 0);
1413
+ rb_define_method(class_search, "error", search_error, 0);
1414
+ rb_define_method(class_search, "num_artists", search_num_artists, 0);
1415
+ rb_define_method(class_search, "artist", search_artist, 1);
1416
+ rb_define_method(class_search, "num_albums", search_num_albums, 0);
1417
+ rb_define_method(class_search, "album", search_album, 1);
1418
+ rb_define_method(class_search, "num_tracks", search_num_tracks, 0);
1419
+ rb_define_method(class_search, "track", search_track, 1);
1420
+ rb_define_method(class_search, "total_tracks", search_total_tracks, 0);
1421
+ rb_define_method(class_search, "query", search_query, 0);
1422
+ rb_define_method(class_search, "did_you_mean", search_did_you_mean, 0);
1423
+
1424
+ /*
1425
+ * ArtistBrowse
1426
+ */
1427
+ class_artist_browse = rb_define_class_under(module_greenstripes, "ArtistBrowse", rb_cObject);
1428
+ rb_define_singleton_method(class_artist_browse, "new", artist_browse_new, 2);
1429
+ rb_define_method(class_artist_browse, "loaded?", artist_browse_loaded, 0);
1430
+ rb_define_method(class_artist_browse, "error", artist_browse_error, 0);
1431
+ rb_define_method(class_artist_browse, "artist", artist_browse_artist, 0);
1432
+ rb_define_method(class_artist_browse, "num_tracks", artist_browse_num_tracks, 0);
1433
+ rb_define_method(class_artist_browse, "track", artist_browse_track, 1);
1434
+ rb_define_method(class_artist_browse, "num_similar_artists", artist_browse_num_similar_artists, 0);
1435
+ rb_define_method(class_artist_browse, "similar_artist", artist_browse_similar_artist, 1);
1436
+ rb_define_method(class_artist_browse, "biography", artist_browse_biography, 0);
1437
+
1438
+ /*
1439
+ * AlbumBrowse
1440
+ */
1441
+ class_album_browse = rb_define_class_under(module_greenstripes, "AlbumBrowse", rb_cObject);
1442
+ rb_define_singleton_method(class_album_browse, "new", album_browse_new, 2);
1443
+ rb_define_method(class_album_browse, "loaded?", album_browse_loaded, 0);
1444
+ rb_define_method(class_album_browse, "error", album_browse_error, 0);
1445
+ rb_define_method(class_album_browse, "artist", album_browse_artist, 0);
1446
+ rb_define_method(class_album_browse, "album", album_browse_album, 0);
1447
+ rb_define_method(class_album_browse, "num_tracks", album_browse_num_tracks, 0);
1448
+ rb_define_method(class_album_browse, "track", album_browse_track, 1);
1449
+ rb_define_method(class_album_browse, "num_copyrights", album_browse_num_copyrights, 0);
1450
+ rb_define_method(class_album_browse, "copyright", album_browse_copyright, 1);
1451
+ rb_define_method(class_album_browse, "review", album_browse_review, 0);
1452
+
1453
+ /*
1454
+ * Artist
1455
+ */
1456
+ class_artist = rb_define_class_under(module_greenstripes, "Artist", rb_cObject);
1457
+ rb_define_method(class_artist, "loaded?", artist_loaded, 0);
1458
+ rb_define_method(class_artist, "name", artist_name, 0);
1459
+
1460
+ /*
1461
+ * Album
1462
+ */
1463
+ class_album = rb_define_class_under(module_greenstripes, "Album", rb_cObject);
1464
+ rb_define_method(class_album, "loaded?", album_loaded, 0);
1465
+ rb_define_method(class_album, "artist", album_artist, 0);
1466
+ rb_define_method(class_album, "name", album_name, 0);
1467
+ rb_define_method(class_album, "year", album_year, 0);
1468
+
1469
+ /*
1470
+ * Track
1471
+ */
1472
+ class_track = rb_define_class_under(module_greenstripes, "Track", rb_cObject);
1473
+ rb_define_method(class_track, "loaded?", track_loaded, 0);
1474
+ rb_define_method(class_track, "error", track_error, 0);
1475
+ rb_define_method(class_track, "num_artists", track_num_artists, 0);
1476
+ rb_define_method(class_track, "artist", track_artist, 1);
1477
+ rb_define_method(class_track, "album", track_album, 0);
1478
+ rb_define_method(class_track, "name", track_name, 0);
1479
+ rb_define_method(class_track, "duration", track_duration, 0);
1480
+ rb_define_method(class_track, "popularity", track_popularity, 0);
1481
+ rb_define_method(class_track, "disc", track_disc, 0);
1482
+ rb_define_method(class_track, "index", track_index, 0);
1483
+
1484
+ /*
1485
+ * Link
1486
+ */
1487
+ class_link = rb_define_class_under(module_greenstripes, "Link", rb_cObject);
1488
+ rb_define_singleton_method(class_link, "new", link_new, 1);
1489
+ rb_define_method(class_link, "link_type", link_link_type, 0);
1490
+ rb_define_method(class_link, "to_s", link_to_s, 0);
1491
+ rb_define_method(class_link, "to_artist", link_to_artist, 0);
1492
+ rb_define_method(class_link, "to_album", link_to_album, 0);
1493
+ rb_define_method(class_link, "to_track", link_to_track, 0);
1494
+ }