greenstripes 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }