mumbletune 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,8 +2,6 @@ require 'uri'
2
2
  require 'text'
3
3
  require 'mustache'
4
4
 
5
- Thread.abort_on_exception=true # development only
6
-
7
5
  module Mumbletune
8
6
 
9
7
  class Message
@@ -29,9 +27,6 @@ module Mumbletune
29
27
  else
30
28
  play_now = false
31
29
  end
32
-
33
- # reassurance that it's working
34
- message.respond "I'm searching. Hang tight."
35
30
 
36
31
  collection = Mumbletune.resolve(message.argument)
37
32
 
@@ -49,9 +44,6 @@ module Mumbletune
49
44
  else
50
45
  message.respond_all "#{message.sender.name} added #{collection.description} to the queue."
51
46
  end
52
-
53
- Mumbletune.player.play unless Mumbletune.player.playing?
54
-
55
47
 
56
48
  else # user wants to unpause
57
49
  if Mumbletune.player.paused?
@@ -77,9 +69,13 @@ module Mumbletune
77
69
 
78
70
 
79
71
  when /^next$/i
80
- Mumbletune.player.next
81
- current = Mumbletune.player.current_song
82
- message.respond_all "#{message.sender.name} skipped to #{current.artist} - #{current.name}" if current
72
+ if Mumbletune.player.any?
73
+ Mumbletune.player.next
74
+ current = Mumbletune.player.current_track
75
+ message.respond_all "#{message.sender.name} skipped to #{current.artist.name} - #{current.name}" if current
76
+ else
77
+ message.respond "We're at the end of the queue. Try adding something to play!"
78
+ end
83
79
 
84
80
  when /^clear$/i
85
81
  Mumbletune.player.clear_queue
@@ -96,22 +92,29 @@ module Mumbletune
96
92
 
97
93
  when /^(what|queue)$/i
98
94
  queue = Mumbletune.player.queue
95
+ current = Mumbletune.player.current_track
96
+ template_queue = Array.new
97
+ queue.each do |col|
98
+ template_col = {description: col.description, tracks: Array.new}
99
+ col.tracks.each { |t| template_col[:tracks] << {name: t.name, artist: t.artist.name, playing?: current == t, username: col.user} }
100
+ template_queue << template_col
101
+ end
99
102
 
100
103
  # Now, a template.
101
104
  rendered = Mustache.render Message.template[:queue],
102
- :queue => queue,
105
+ :queue => template_queue,
103
106
  :anything? => (queue.empty?) ? false : true
104
107
  message.respond rendered
105
108
 
106
109
  when /^volume\?$/i
107
- message.respond "The volume is #{Mumbletune.player.volume?}."
110
+ message.respond "The volume is #{Mumbletune.mumble.volume}."
108
111
 
109
112
  when /^volume/i
110
113
  if message.argument.length == 0
111
- message.respond "The volume is #{Mumbletune.player.volume?}."
114
+ message.respond "The volume is #{Mumbletune.mumble.volume}."
112
115
  else
113
- Mumbletune.player.volume(message.argument)
114
- message.respond "Now the volume is #{Mumbletune.player.volume?}."
116
+ Mumbletune.mumble.volume = message.argument
117
+ message.respond "Now the volume is #{Mumbletune.mumble.volume}."
115
118
  end
116
119
 
117
120
  when /^help$/i
@@ -126,8 +129,10 @@ module Mumbletune
126
129
 
127
130
  rescue => err # Catch any command that errored.
128
131
  message.respond "Woah, an error occurred: #{err.message}"
129
- puts "#{err.class}: #{err.message}"
130
- puts err.backtrace
132
+ unless Mumbletune.verbose
133
+ puts "#{err.class}: #{err.message}"
134
+ puts err.backtrace
135
+ end
131
136
  end
132
137
  end
133
138
 
@@ -157,7 +162,7 @@ module Mumbletune
157
162
  end
158
163
 
159
164
  # load templates
160
- Dir.glob(File.dirname(__FILE__) + "/templates/*.mustache").each do |f_path|
165
+ Dir.glob(File.dirname(__FILE__) + "/template/*.mustache").each do |f_path|
161
166
  f = File.open(f_path)
162
167
  Message.template[File.basename(f_path, ".mustache").to_sym] = f.read
163
168
  end
@@ -4,16 +4,16 @@ module Mumbletune
4
4
  class MumbleClient
5
5
 
6
6
  def initialize
7
- opts = Mumbletune.config['mumble']
8
- @cli = Mumble::Client.new(opts['host'], opts['port'], opts['username'], opts['password'])
7
+ m_conf = Mumbletune.config["mumble"]
8
+ format = {rate: 44100, channels: 2} # Format used by spotify
9
+ @cli = Mumble::Client.new(m_conf['host'], m_conf['port'], m_conf['username'], m_conf['password'], format)
9
10
 
10
11
  @cli.on_server_sync do |message| # Once connected.
11
12
  @cli.session = message.session # housekeeping for mumble-ruby
12
- connect_to = @cli.channels.select { |key, hash| hash["name"] == opts['channel'] }.first[1][:name]
13
- @cli.join_channel(connect_to)
13
+ connect_to = @cli.channels.select { |key, hash| hash["name"] == m_conf["channel"] }.first[1][:name]
14
+ @cli.join_channel connect_to
14
15
 
15
16
  @ready = true
16
- puts ">> Connected to Mumble server at #{opts['host']}."
17
17
  end
18
18
 
19
19
  @cli.on_text_message do |data|
@@ -35,15 +35,34 @@ module Mumbletune
35
35
 
36
36
  def stream
37
37
  @ready_wait.join
38
- input = Mumbletune.config['mpd']['fifo_out']
39
38
  Thread.current.priority = 5
40
- puts ">> Streaming to Mumble from #{input}"
41
- @cli.stream_raw_audio(input)
39
+ queue = Mumbletune.player.audio_queue
40
+
41
+ @audio_stream = @cli.stream_from_queue(queue)
42
+
43
+ self.volume = Mumbletune.config["player"]["default_volume"]
42
44
  end
43
45
 
44
46
  def disconnect
47
+ @audio_stream.stop if @audio_stream
45
48
  @cli.disconnect
46
- puts ">> Disconnected from Mumble"
49
+ end
50
+
51
+ def message(users, text)
52
+ users = Array(users) # force into array
53
+ users.each { |u| @cli.text_user(u.session, text) }
54
+ end
55
+
56
+ def broadcast(text)
57
+ @cli.text_channel(@cli.me.channel_id, text)
58
+ end
59
+
60
+ def volume
61
+ (@audio_stream.volume * 100).to_i
62
+ end
63
+
64
+ def volume=(vol)
65
+ @audio_stream.volume = vol.to_i
47
66
  end
48
67
  end
49
68
 
@@ -1,8 +1,6 @@
1
1
  require 'uri'
2
- require 'meta-spotify'
3
2
  require 'text'
4
3
 
5
-
6
4
  module Mumbletune
7
5
  def self.resolve(argument)
8
6
  Resolvers.workers.each do |r|
@@ -56,11 +54,14 @@ module Mumbletune
56
54
  # behave according to URI type
57
55
  case type
58
56
  when "track" # Return this track
59
- SpotifyTrack::track_from_uri(sp_uri)
57
+ obj = Hallon::Track.new(sp_uri)
58
+ SpotifyResolver.track(obj)
60
59
  when "album" # Return all tracks of the album to queue
61
- SpotifyTrack::tracks_from_album(sp_uri)
60
+ obj = Hallon::Album.new(sp_uri)
61
+ SpotifyResolver.tracks_from_album(obj)
62
62
  when "artist" # Return 10 tracks for this artist
63
- SpotifyTrack::tracks_from_artist(sp_uri)
63
+ obj = Hallon::Artist.new(sp_uri)
64
+ SpotifyResolver.tracks_from_artist(obj)
64
65
  end
65
66
  end
66
67
  end
@@ -89,35 +90,21 @@ module Mumbletune
89
90
  region = Mumbletune.config["spotify"]["region"]
90
91
 
91
92
  # determine result based on a type in the first word
93
+ search = Hallon::Search.new(query, artists: 1, albums: 1, tracks: 1).load
92
94
  if first_word =~ /^artist$/i
93
- artist = Mumbletune.handle_sp_error { MetaSpotify::Artist.search(query) }
94
- result = artist[:artists].first
95
+ result = search.artists.first
95
96
 
96
97
  elsif first_word =~ /^album$/i
97
- album = Mumbletune.handle_sp_error { MetaSpotify::Album.search(query) }
98
- album[:albums].select! { |a| a.available_territories.include? region }
99
- result = album[:albums].first
98
+ result = search.albums.first
100
99
 
101
100
  elsif first_word =~ /^track$/i
102
- track = Mumbletune.handle_sp_error { MetaSpotify::Track.search(query) }
103
- track[:tracks].select! { |t| t.album.available_territories.include? region }
104
- result = track[:tracks].first
101
+ result = search.tracks.first
105
102
 
106
103
  else # determine intended result by similarity to the query
107
- artist = Mumbletune.handle_sp_error { MetaSpotify::Artist.search(query) }
108
- album = Mumbletune.handle_sp_error { MetaSpotify::Album.search(query) }
109
- track = Mumbletune.handle_sp_error { MetaSpotify::Track.search(query) }
110
-
111
- # searches now finished
112
-
113
- # remove anything out-of-region
114
- album[:albums].select! { |a| a.available_territories.include? region } if album[:albums].any?
115
- track[:tracks].select! { |t| t.album.available_territories.include? region } if track[:tracks].any?
116
-
117
104
  compare = []
118
- compare.push track[:tracks].first if track[:tracks].any?
119
- compare.push album[:albums].first if album[:albums].any?
120
- compare.push artist[:artists].first if artist[:artists].any?
105
+ compare.push search.tracks.first if search.tracks.any?
106
+ compare.push search.albums.first if search.albums.any?
107
+ compare.push search.artists.first if search.artists.any?
121
108
 
122
109
  white = Text::WhiteSimilarity.new
123
110
  compare.sort! do |a, b|
@@ -134,12 +121,12 @@ module Mumbletune
134
121
  result = compare.first
135
122
  end
136
123
 
137
- if result.class == MetaSpotify::Artist
138
- SpotifyTrack.tracks_from_artist(result)
139
- elsif result.class == MetaSpotify::Album
140
- SpotifyTrack.tracks_from_album(result)
141
- elsif result.class == MetaSpotify::Track
142
- SpotifyTrack.track_from_uri(result)
124
+ if result.class == Hallon::Artist
125
+ SpotifyResolver.tracks_from_artist(result)
126
+ elsif result.class == Hallon::Album
127
+ SpotifyResolver.tracks_from_album(result)
128
+ elsif result.class == Hallon::Track
129
+ SpotifyResolver.track(result)
143
130
  end
144
131
 
145
132
  end
@@ -0,0 +1,51 @@
1
+ require "hallon"
2
+
3
+ module Mumbletune
4
+ class SpotifyResolver
5
+ def self.track(track)
6
+ track.load
7
+
8
+ raise "#{track.name}: Not available in this region." unless track.available?
9
+
10
+ # Technically, a collection of one.
11
+ Collection.new(
12
+ :TRACK,
13
+ track,
14
+ "<b>#{track.name}</b> by <b>#{track.artist.name}</b>"
15
+ )
16
+ end
17
+
18
+ def self.tracks_from_album(album)
19
+ album.load
20
+
21
+ raise "#{album.name}: Not available in this region." unless album.available?
22
+
23
+ browse = album.browse
24
+ browse.load
25
+
26
+ Collection.new(
27
+ :ALBUM,
28
+ browse.tracks.to_a,
29
+ "the album <b>#{album.name}</b> by <b>#{album.artist.name}</b>"
30
+ )
31
+ end
32
+
33
+ def self.tracks_from_artist(artist)
34
+ artist.load
35
+
36
+ tracks_needed = Mumbletune.config["player"]["tracks_for_artist"] || 5
37
+
38
+ search = Hallon::Search.new("artist:\"#{artist.name}\"",
39
+ tracks: tracks_needed,
40
+ artists: 0,
41
+ albums: 0,
42
+ playlists: 0).load
43
+
44
+ Collection.new(
45
+ :ARTIST_TOP,
46
+ search.tracks.to_a,
47
+ "#{search.tracks.size} tracks by <b>#{artist.name}</b>"
48
+ )
49
+ end
50
+ end
51
+ end
@@ -63,6 +63,7 @@
63
63
  </tbody>
64
64
  </table>
65
65
  <p><br> For example:</p>
66
- <pre><code>play coldplay
67
- play nicki minaj starships</code></pre>
68
- <p>Mumbletune uses Spotify to find music.</p>
66
+ <p><code>play coldplay</code> plays the top 5 tracks by Coldplay.</p>
67
+ <p><code>play nicki minaj starships</code> will play the (excellent) song Starships.</p>
68
+ <p>Mumbletune uses Spotify to find and play music. You can <code>play</code> a Spotify URL directly instead of searching, like</p>
69
+ <p><code>play spotify:album:1HjSyGjmLNjRAKgT9t1cna</code></p>
@@ -18,17 +18,19 @@
18
18
  {{/anything?}}
19
19
 
20
20
  {{#queue}}
21
- <tr class="odd">
22
- <td align="left">
23
- {{#playing?}} &#9658; {{/playing?}}
24
- </td>
25
- <td align="left">
26
- {{name}}
27
- </td>
28
- <td align="left">
29
- {{artist}}
30
- </td>
31
- </tr>
21
+ {{#tracks}}
22
+ <tr>
23
+ <td align="left">
24
+ {{#playing?}} <span style="#a5a5a5">►</span> {{/playing?}}
25
+ </td>
26
+ <td align="left">
27
+ {{name}}
28
+ </td>
29
+ <td align="left">
30
+ {{artist}} <small style="color:#a5a5a5">{{username}}</small>
31
+ </td>
32
+ </tr>
33
+ {{/tracks}}
32
34
  {{/queue}}
33
35
 
34
36
  {{#anything?}}
@@ -1,3 +1,3 @@
1
1
  module Mumbletune
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
@@ -9,9 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Elliott Williams"]
10
10
  spec.email = ["e@elliottwillia.ms"]
11
11
  spec.description = "Mumbletune connects to a mumble server and allows users to"\
12
- " interact with and play a queue of music. Currently plays"\
13
- " from Spotify alone."
14
- spec.summary = "A mumble server bot that plays music"
12
+ " interact with and play a queue of music from Spotify."
13
+ spec.summary = "A Mumble VOIP bot that plays Spotify."
15
14
  spec.homepage = "http://github.com/elliottwilliams/mumbletune"
16
15
  spec.license = "MIT"
17
16
 
@@ -24,14 +23,10 @@ Gem::Specification.new do |spec|
24
23
  spec.add_development_dependency "rake"
25
24
 
26
25
  spec.add_runtime_dependency "mumble-ruby"
27
- spec.add_runtime_dependency "ruby-mpd"
28
- spec.add_runtime_dependency "sinatra"
29
- spec.add_runtime_dependency "meta-spotify"
30
- spec.add_runtime_dependency "rubypython"
26
+ spec.add_runtime_dependency "hallon"
27
+ spec.add_runtime_dependency "ffi", "~>1.3.0"
31
28
 
32
- spec.add_runtime_dependency "thin"
33
- spec.add_runtime_dependency "eventmachine"
29
+ spec.add_runtime_dependency "daemons"
34
30
  spec.add_runtime_dependency "text"
35
31
  spec.add_runtime_dependency "mustache"
36
- spec.add_development_dependency "debugger"
37
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumbletune
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-23 00:00:00.000000000 Z
12
+ date: 2013-06-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -60,7 +60,7 @@ dependencies:
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  - !ruby/object:Gem::Dependency
63
- name: ruby-mpd
63
+ name: hallon
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
@@ -76,71 +76,23 @@ dependencies:
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  - !ruby/object:Gem::Dependency
79
- name: sinatra
79
+ name: ffi
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  none: false
82
82
  requirements:
83
- - - ! '>='
84
- - !ruby/object:Gem::Version
85
- version: '0'
86
- type: :runtime
87
- prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ! '>='
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
- - !ruby/object:Gem::Dependency
95
- name: meta-spotify
96
- requirement: !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - ! '>='
100
- - !ruby/object:Gem::Version
101
- version: '0'
102
- type: :runtime
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ! '>='
108
- - !ruby/object:Gem::Version
109
- version: '0'
110
- - !ruby/object:Gem::Dependency
111
- name: rubypython
112
- requirement: !ruby/object:Gem::Requirement
113
- none: false
114
- requirements:
115
- - - ! '>='
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :runtime
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ! '>='
124
- - !ruby/object:Gem::Version
125
- version: '0'
126
- - !ruby/object:Gem::Dependency
127
- name: thin
128
- requirement: !ruby/object:Gem::Requirement
129
- none: false
130
- requirements:
131
- - - ! '>='
83
+ - - ~>
132
84
  - !ruby/object:Gem::Version
133
- version: '0'
85
+ version: 1.3.0
134
86
  type: :runtime
135
87
  prerelease: false
136
88
  version_requirements: !ruby/object:Gem::Requirement
137
89
  none: false
138
90
  requirements:
139
- - - ! '>='
91
+ - - ~>
140
92
  - !ruby/object:Gem::Version
141
- version: '0'
93
+ version: 1.3.0
142
94
  - !ruby/object:Gem::Dependency
143
- name: eventmachine
95
+ name: daemons
144
96
  requirement: !ruby/object:Gem::Requirement
145
97
  none: false
146
98
  requirements:
@@ -187,28 +139,13 @@ dependencies:
187
139
  - - ! '>='
188
140
  - !ruby/object:Gem::Version
189
141
  version: '0'
190
- - !ruby/object:Gem::Dependency
191
- name: debugger
192
- requirement: !ruby/object:Gem::Requirement
193
- none: false
194
- requirements:
195
- - - ! '>='
196
- - !ruby/object:Gem::Version
197
- version: '0'
198
- type: :development
199
- prerelease: false
200
- version_requirements: !ruby/object:Gem::Requirement
201
- none: false
202
- requirements:
203
- - - ! '>='
204
- - !ruby/object:Gem::Version
205
- version: '0'
206
142
  description: Mumbletune connects to a mumble server and allows users to interact with
207
- and play a queue of music. Currently plays from Spotify alone.
143
+ and play a queue of music from Spotify.
208
144
  email:
209
145
  - e@elliottwillia.ms
210
146
  executables:
211
147
  - mumbletune
148
+ - mumbletune-ctl
212
149
  extensions: []
213
150
  extra_rdoc_files: []
214
151
  files:
@@ -219,21 +156,20 @@ files:
219
156
  - README.md
220
157
  - Rakefile
221
158
  - bin/mumbletune
159
+ - bin/mumbletune-ctl
222
160
  - conf.example.yaml
223
161
  - docs/commands.md
224
162
  - lib/mumbletune.rb
225
163
  - lib/mumbletune/collection.rb
226
- - lib/mumbletune/handle_sp_error.rb
164
+ - lib/mumbletune/hallon_player.rb
227
165
  - lib/mumbletune/messages.rb
228
- - lib/mumbletune/mpd_client.rb
229
166
  - lib/mumbletune/mumble_client.rb
230
167
  - lib/mumbletune/resolver.rb
231
- - lib/mumbletune/sp_uri_server.rb
232
- - lib/mumbletune/spotify_track.rb
233
- - lib/mumbletune/templates/commands.mustache
234
- - lib/mumbletune/templates/queue.mustache
235
- - lib/mumbletune/track.rb
168
+ - lib/mumbletune/spotify_resolver.rb
169
+ - lib/mumbletune/template/commands.mustache
170
+ - lib/mumbletune/template/queue.mustache
236
171
  - lib/mumbletune/version.rb
172
+ - logs/.gitignore
237
173
  - mumbletune.gemspec
238
174
  homepage: http://github.com/elliottwilliams/mumbletune
239
175
  licenses:
@@ -259,5 +195,5 @@ rubyforge_project:
259
195
  rubygems_version: 1.8.25
260
196
  signing_key:
261
197
  specification_version: 3
262
- summary: A mumble server bot that plays music
198
+ summary: A Mumble VOIP bot that plays Spotify.
263
199
  test_files: []