hallon 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -4,12 +4,31 @@ Hallon’s Changelog
4
4
  [HEAD][]
5
5
  ------------------
6
6
 
7
+ [v0.15.0][]
8
+ ------------------
9
+ Updated to libspotify v11.1.60 [3c810b0], and improved the examples provided within Hallon codebase significantly.
10
+
11
+ __Removed__
12
+
13
+ - Hallon::Search.radio (was removed in libspotify upgrade)
14
+
7
15
  __Added__
8
16
 
17
+ - You can now construct Search objects from a Link! [7f87e74c]
18
+ - Playlist#upload [479c3d20, 2a90097]
19
+
9
20
  __Changed__
10
21
 
22
+ - Observable#on now returns the previous handler [7ed42c4b]
23
+ - Default load time is now 30 seconds instead of 5 [d04440ba]
24
+
11
25
  __Fixed__
12
26
 
27
+ - Hallon::URI now matches entire URIs [397cf711]
28
+ - Image IDs with NUL-bytes now no longer raise errors [30a376eb]
29
+ - Link#to_str/to_uri now returns a String in UTF-8 encoding [f1661736]
30
+ - Session#login now raises an error when given empty credentials [dbc390ea]
31
+
13
32
  [v0.14.0][]
14
33
  ------------------
15
34
  This release brings a lot more meat added to the README, in addition to the following:
@@ -301,4 +320,5 @@ easier to handle.
301
320
  [v0.12.0]: https://github.com/Burgestrand/Hallon/compare/v0.11.0...v0.12.0
302
321
  [v0.13.0]: https://github.com/Burgestrand/Hallon/compare/v0.12.0...v0.13.0
303
322
  [v0.14.0]: https://github.com/Burgestrand/Hallon/compare/v0.13.0...v0.14.0
304
- [HEAD]: https://github.com/Burgestrand/Hallon/compare/v0.14.0...HEAD
323
+ [v0.15.0]: https://github.com/Burgestrand/Hallon/compare/v0.14.0...v0.15.0
324
+ [HEAD]: https://github.com/Burgestrand/Hallon/compare/v0.15.0...HEAD
data/README.markdown CHANGED
@@ -5,13 +5,55 @@ Hallon (Swedish for “[Raspberry][]”) is _the_ ruby gem for interacting with
5
5
 
6
6
  Code samples can be found under the `examples/` directory. An explanation on how to run them can be found on the [Hallon wiki on GitHub](https://github.com/Burgestrand/Hallon/wiki).
7
7
 
8
- Installation
9
- ------------
8
+ Prerequisites
9
+ -------------
10
+
11
+ Before you start using Hallon you’ll need to complete the following steps.
12
+
13
+ 1. Get yourself a Spotify premium account, which is required for libspotify to work. You username and password
14
+ (either classic Spotify, or facebook credentials) will be used to connect to Spotify later.
15
+ 2. [Download your application key from developer.spotify.com](https://developer.spotify.com/en/libspotify/application-key/),
16
+ and place it in a known location. You’ll have the option of downloading it either in **binary** or c-code. You want the
17
+ **binary** one. If you do not have an application key already, you will be asked to create one.
18
+ 3. Install libspotify. Hallon always aims to support to most recent version, which is currently **v10.1.16**. Older
19
+ versions are not supported. For help installing libspotify, please see the wiki on [How to install libspotify][].
20
+ 4. Once the above are done, you are ready to try out Hallon.
21
+
22
+ ### Using Hallon
23
+
24
+ First, begin by installing the latest version of Hallon.
10
25
 
11
26
  ```bash
12
27
  gem install hallon
13
28
  ```
14
29
 
30
+ Great! Now you’re ready to start experimenting. Everything in Hallon, from searching to looking up tracks, requires you to
31
+ have an active Spotify session. You create it by initializing it with your application key.
32
+
33
+ ```ruby
34
+ require 'hallon'
35
+
36
+ session = Hallon::Session.initialize IO.read('./spotify_appkey.key')
37
+ ```
38
+
39
+ Now that you have your session you may also want to login (even though you can still do a few things without logging in).
40
+
41
+ ```ruby
42
+ session.login!('username', 'password')
43
+ ```
44
+
45
+ You may now experiment with just about anything. For an API reference, please see [Hallon’s page at rdoc.info](http://rdoc.info/github/Burgestrand/Hallon/master/frames).
46
+ As a starter tip, many objects can be constructed by giving it a Spotify URI, like this.
47
+
48
+ ```ruby
49
+ track = Hallon::Track.new("spotify:track:1ZPsdTkzhDeHjA5c2Rnt2I").load
50
+ artist = track.artist.load
51
+
52
+ puts "#{track.name} by #{artist.name}"
53
+ ```
54
+
55
+ ### If you want to play audio…
56
+
15
57
  If you want to play audio you’ll need to install an audio driver. As of current writing there is only one driver in existence. You can install it with:
16
58
 
17
59
  ```bash
@@ -20,6 +62,14 @@ gem install hallon-openal
20
62
 
21
63
  For more information about audio support in Hallon, see the section "Audio support" below.
22
64
 
65
+ ### Contact details
66
+
67
+ - __Got questions?__ Ask on the mailing list: <https://groups.google.com/d/forum/ruby-hallon>
68
+ - __Found a bug?__ Report an issue: <https://github.com/Burgestrand/Hallon/issues/new>
69
+ - __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
70
+
71
+ If you for some reason cannot use the mailing list or GitHub issue tracker you may contact me directly. My email is found on [my GitHub profile](https://github.com/Burgestrand), and I’m also available as [@burgestrand on twitter](https://twitter.com/Burgestrand).
72
+
23
73
  Hallon and Spotify objects
24
74
  --------------------------
25
75
  All objects from libspotify have a counterpart in Hallon, and just like in libspotify the objects are populated with information as it becomes available. All objects that behave in this way respond to `#loaded?`, which’ll return true if the object has been populated with data.
@@ -82,8 +132,17 @@ Audio support
82
132
  Hallon supports streaming audio from Spotify via [Hallon::Player][]. When you create the player you give it your current session and an audio driver, which the player will then use for audio playback.
83
133
 
84
134
  ```ruby
135
+ require 'hallon'
136
+ require 'hallon-openal'
137
+
138
+ session = Hallon::Session.initialize(IO.read('./spotify_appkey.key'))
139
+ session.login!('username', 'password')
140
+
141
+ track = Hallon::Track.new("spotify:track:1ZPsdTkzhDeHjA5c2Rnt2I")
142
+ track.load
143
+
85
144
  player = Hallon::Player.new(session, Hallon::OpenAL)
86
- player.play(loaded_track)
145
+ player.play!(track)
87
146
  ```
88
147
 
89
148
  Available drivers are:
@@ -97,9 +156,6 @@ For information on how to write your own audio driver, see [Hallon::ExampleAudio
97
156
  Finally, here are some important notes
98
157
  --------------------------------------
99
158
 
100
- ### [Please tell me your feedback and requests!](https://github.com/Burgestrand/Hallon/issues/new)
101
- Really, I ❤ feedback! Suggestions on how to improve the API, tell me what is delicious about Hallon, tell me what is yucky about Hallon… anything! All feedback is useful in one way or another. You have any issues with Hallon? Just ask, and I’ll answer if I can.
102
-
103
159
  ### Contributing to Hallon
104
160
  [Fork](http://help.github.com/forking/) Hallon, write tests for everything you do (so I don’t break your stuff during my own development) and send a pull request. If you modify existing files, please adhere to the coding standard surrounding your code.
105
161
 
@@ -112,10 +168,6 @@ You can only keep one session with Spotify alive at a time within the same proce
112
168
  ### When forking, you need to be extra careful
113
169
  If you fork, you need to instantiate the session within the process you plan to use Hallon in. You want to use Hallon in the parent? Create the session in the parent. You want to use it in the child? Create the session in the child! This is a limitation of libspotify itself.
114
170
 
115
- You have more questions?
116
- ------------------------
117
- I can be reached at my [email (found on GitHub profile)](http://github.com/Burgestrand) or [@burgestrand on twitter](http://twitter.com/Burgestrand). I’d be extremely happy to discuss Hallon with you if you have any feedback or thoughts.
118
-
119
171
  Credits
120
172
  -------
121
173
  - Per Reimers, cracking synchronization bugs with me deep in the night (4 AM), thanks. :)
@@ -135,6 +187,8 @@ Hallon is licensed under a 2-clause (Simplified) BSD license. More information c
135
187
  [What is Hallon?]: http://burgestrand.se/articles/hallon-delicious-ruby-bindings-to-libspotify.html
136
188
  [Build Status]: https://secure.travis-ci.org/Burgestrand/Hallon.png
137
189
 
190
+ [How to install libspotify]: https://github.com/Burgestrand/Hallon/wiki/How-to-install-libspotify
191
+
138
192
  [API page for Hallon::Observable]: http://rubydoc.info/github/Burgestrand/Hallon/master/Hallon/Observable
139
193
 
140
194
  [Hallon::Enumerator]: http://rubydoc.info/github/Burgestrand/Hallon/Hallon/Enumerator
data/dev/login.rb CHANGED
@@ -1,16 +1,5 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require File.expand_path('../../spec/support/config', __FILE__)
3
-
4
- require 'bundler/setup'
5
- require 'hallon'
6
1
  require 'pry'
7
-
8
- session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
9
- on(:log_message) do |message|
10
- puts "[LOG] #{message}"
11
- end
12
- end
13
-
14
- session.login! ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
2
+ require_relative '../examples/example_support'
3
+ session = Hallon::Session.instance
15
4
 
16
5
  binding.pry
@@ -1,52 +1,54 @@
1
1
  # coding: utf-8
2
2
 
3
- $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
3
+ # Require support code, used by all the examples.
4
+ require_relative 'example_support'
5
+ session = Hallon::Session.instance
4
6
 
5
- require 'hallon'
6
- require './spec/support/config'
7
+ puts
8
+ puts "Hi there! I am adding_tracks_to_playlist.rb. You and me, we will manipulate some playlists today.
9
+ We shall add a few tracks to a playlist of your choice."
7
10
 
8
- ##
9
- # Configuration
10
- #
11
- # uri to the playlist you wish to add tracks to
12
- playlist_uri = "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi"
13
-
14
- # array of track uris you wish to add to the playlist
15
- track_uris = %w[spotify:track:6GHrP1i3vQo1e8VkEHRnvz spotify:track:2t7u74OJXHf0qQxXHpnb2R spotify:track:24q7a0Bo5MFLJUslg1lsS5]
16
-
17
- # index to add the tracks to in the playlist
18
- position = 0
11
+ playlist_uri = loop do
12
+ uri = prompt_link("Give me a Spotify URI to a playlist to modify (e. g. spotify:playlist:…)")
13
+ break uri if uri
14
+ end
19
15
 
20
- session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
21
- on(:log_message) do |message|
22
- puts "[LOG] #{message}"
23
- end
16
+ puts
17
+ puts "Now I need the tracks we should add to it. Give them all to me. End it with a blank line."
18
+ track_uris = []
19
+ loop do
20
+ uri = prompt_link("Give me a Spotify URI to a track")
21
+ track_uris << uri
22
+ break unless uri
24
23
  end
24
+ track_uris.compact!
25
25
 
26
- session.login!(ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD'])
27
- puts "Successfully logged in!"
26
+ puts "Great. We’ll be adding these babies to #{playlist_uri}."
27
+ puts track_uris.join("\n")
28
+ puts
28
29
 
29
- # First, we load the playlist. This is necessary for libspotify
30
- # to know if we have write access to it or not. Not doing it might
31
- # end us up getting permission denied errors later.
32
- puts "Loading playlist #{playlist_uri}"
33
- playlist = Hallon::Playlist.new(playlist_uri)
34
- session.wait_for { playlist.loaded? }
30
+ # First, we load the playlist. This is necessary for libspotify to know if we
31
+ # have write access to it or not. Not doing it might end us up getting permission
32
+ # denied errors later.
33
+ puts
34
+ puts "Loading playlist #{playlist_uri}."
35
+ playlist = Hallon::Playlist.new(playlist_uri).load
36
+ puts "(it has #{playlist.size} tracks)"
35
37
 
36
38
  # Convert all track URIs to actual Tracks.
37
- puts "Loading #{track_uris.length} tracks"
38
39
  tracks = track_uris.map { |x| Hallon::Track.new(x) }
39
40
 
40
41
  # … insert the tracks at the desired position into the playlist.
42
+ position = 0
41
43
  playlist.insert(position, tracks)
42
44
 
43
45
  # finally, wait for the updates to the playlist to be acknowledged by the
44
46
  # Spotify back-end. Once they have, we’ll see the tracks in our desktop
45
47
  # client as well.
48
+ puts
46
49
  puts "Uploading playlist changes to Spotify back-end!"
47
50
 
48
- state_changed = false
49
- playlist.on(:playlist_state_changed) { state_changed = true }
50
- session.wait_for { state_changed && ! playlist.pending? }
51
+ # We allow a timeout of 30 seconds. These things sometimes take a long time.
52
+ playlist.upload
51
53
 
52
54
  puts "We’re done!"
@@ -0,0 +1,100 @@
1
+ # coding: utf-8
2
+
3
+ # Hello there, and welcome!
4
+ #
5
+ # My name is example_support.rb, and I shall be your loyal servant. What you see here
6
+ # is all my offerings I have for today. Of course, I shall gladly point out to you what
7
+ # each and every one of these offers bring you.
8
+ #
9
+ # If at any point you feel lost, do not hesitate to consult with my superiors. You may
10
+ # find them at https://github.com/Burgestrand/Hallon. Thank you!
11
+
12
+ # First, I need the power to ask you questions. You need not care much about this particular
13
+ # piece of me; only keep in mind that it should help keep the rest of me less cluttered.
14
+ def prompt(string, options = {})
15
+ print(string + ': ')
16
+ $stdout.flush
17
+ system("stty -echo") if options[:hide]
18
+ gets.chomp
19
+ ensure
20
+ if options[:hide]
21
+ system("stty echo")
22
+ puts
23
+ end
24
+ end
25
+
26
+ # Like before, this piece of me is not of much important. It is only to make sure you do
27
+ # not try to feed me propaganda. Move along.
28
+ def prompt_link(string)
29
+ loop do
30
+ uri = prompt(string)
31
+ if uri.empty?
32
+ break
33
+ elsif Hallon::Link.valid?(uri)
34
+ break uri
35
+ else
36
+ puts "Please enter a valid Spotify URI (or just enter to quit)."
37
+ end
38
+ end
39
+ end
40
+
41
+ # Making sure you receive the latest of the latest. Hallon does not wish to
42
+ # be replaced by older versions when showing you the shiny.
43
+ $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
44
+ require 'hallon'
45
+
46
+ # This is a quick sanity check, to make sure we have all the necessities in order.
47
+ appkey_path = File.expand_path('./spotify_appkey.key')
48
+ unless File.exists?(appkey_path)
49
+ abort <<-ERROR
50
+ Your Spotify application key could not be found at the path:
51
+ #{appkey_path}
52
+
53
+ Please adjust the path in examples/common.rb or put your application key in:
54
+ #{appkey_path}
55
+
56
+ You may download your application key from:
57
+ https://developer.spotify.com/en/libspotify/application-key/
58
+ ERROR
59
+ end
60
+
61
+ # And now, before I ask you for your jewels, I shall instill within you a sense of
62
+ # belonging and comfort. This is in order to make you less surprised about my rude
63
+ # questions.
64
+ puts "Hallon’s interactive examples run live against Spotify, and as such
65
+ they require actual login credentials before they may run."
66
+
67
+ # Spotify requires a rite of passage. It’s own variant of “open sesame”, so we will
68
+ # ask you to provide them with your information.
69
+ hallon_username = prompt("Please enter your spotify username")
70
+ hallon_password = prompt("Please enter your spotify password", hide: true)
71
+ hallon_appkey = IO.read(appkey_path)
72
+
73
+ # Make sure the credentials are there. We don’t want to go without them.
74
+ if hallon_username.empty? or hallon_password.empty?
75
+ abort <<-ERROR
76
+ Sorry, you must supply both username and password for Hallon to be able to log in.
77
+
78
+ You may also edit examples/common.rb by setting your username and password directly.
79
+ ERROR
80
+ end
81
+
82
+ # Finally, we log in, making sure we show you just about everything Spotify tells us
83
+ # for the entire coming session.
84
+ session = Hallon::Session.initialize(hallon_appkey) do
85
+ on(:log_message) do |message|
86
+ puts "[LOG] #{message}"
87
+ end
88
+
89
+ on(:connection_error) do |error|
90
+ Hallon::Error.maybe_raise(error)
91
+ end
92
+
93
+ on(:logged_out) do
94
+ abort "[FAIL] Logged out!"
95
+ end
96
+ end
97
+ session.login!(hallon_username, hallon_password)
98
+
99
+ puts "Successfully logged in!"
100
+ # that is all for me. Thank you, I will see you again!
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
4
-
5
- require 'hallon'
3
+ # Require support code, used by all the examples.
4
+ require_relative 'example_support'
5
+ session = Hallon::Session.instance
6
6
 
7
7
  begin
8
8
  require 'hallon/openal'
@@ -11,64 +11,28 @@ rescue LoadError => e
11
11
  abort "[ERROR] Could not load gem 'hallon-openal', please install with 'gem install hallon-openal'"
12
12
  end
13
13
 
14
- require_relative '../spec/support/config'
15
-
16
- # Utility
17
- def say(string)
18
- # system('say', string)
19
- end
20
-
21
- def tell(string)
22
- puts(string)
23
- say(string)
24
- end
25
-
26
- def prompt(string)
27
- print(string + ': ')
28
- $stdout.flush
29
- say(string)
30
- gets.chomp
31
- end
32
-
33
- # Hallon set-up.
34
-
35
- session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
36
- on(:connection_error) do |error|
37
- Hallon::Error.maybe_raise(error)
38
- end
39
-
40
- on(:logged_out) do
41
- abort "[FAIL] Logged out!"
42
- end
43
- end
44
-
45
14
  player = Hallon::Player.new(session, Hallon::OpenAL)
46
15
 
47
16
  # Program flow.
48
17
 
49
- session.login!(ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD'])
50
-
51
18
  search = loop do
52
19
  query = prompt("Enter a search term for a track you’d like to play")
53
20
  search = Hallon::Search.new(query)
54
21
 
55
- tell "Searching for “#{search.query}”…"
56
- session.wait_for do
57
- search.loaded? or Hallon::Error.maybe_raise(search.status, ignore: :is_loading)
58
- end
22
+ puts "Searching for “#{query}”…"
23
+ search.load
59
24
 
60
25
  if search.tracks.size.zero?
61
- tell "No results for “#{search.query}”."
26
+ puts "No results for “#{search.query}”."
62
27
  next
63
28
  else
64
29
  break search
65
30
  end
66
31
  end
67
32
 
68
- tracks = search.tracks[0...10]
69
- session.wait_for { tracks.all?(&:loaded?) }
33
+ tracks = search.tracks[0...10].map(&:load)
70
34
 
71
- tell "Results for “#{search.query}”: "
35
+ puts "Results for “#{search.query}”: "
72
36
  tracks.each_with_index do |track, index|
73
37
  puts " [#{index + 1}] #{track.name} — #{track.artist.name} (#{track.to_link.to_str})"
74
38
  end
@@ -80,10 +44,10 @@ track = loop do
80
44
  if track = tracks[index - 1]
81
45
  break track
82
46
  else
83
- tell "No such track."
47
+ puts "No such track."
84
48
  end
85
49
  end
86
50
 
87
- tell "Alright! Playing “#{track.name}” by “#{track.artist.name}”."
51
+ puts "Alright! Playing “#{track.name}” by “#{track.artist.name}”."
88
52
  player.play!(track)
89
- tell "Done! This was “#{track.name}” by “#{track.artist.name}”. Bye bye!"
53
+ puts "Done! This was “#{track.name}” by “#{track.artist.name}”. Bye bye!"