mumbletune 0.1.3 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,23 +0,0 @@
1
- module Mumbletune
2
-
3
- # The Spotify Metadata API seems to throw 502 (Bad Gateway) errors *a lot*.
4
- # There's some complaint about this online, and I can reproduce it with
5
- # plenty of REST clients, so I am sure it's Spotify's problem. But they
6
- # don't seem too interested in fixing what appears to be a long-standing
7
- # issue. Ho hum.
8
- def self.handle_sp_error
9
- begin
10
- yield
11
- rescue MetaSpotify::ServerError => err
12
- puts "Caught ServerError: #{err}"
13
- failed ||= 0
14
- failed += 1
15
- if failed < 4
16
- sleep 1
17
- retry
18
- else
19
- raise
20
- end
21
- end
22
- end
23
- end
@@ -1,171 +0,0 @@
1
- require 'ruby-mpd'
2
-
3
- module Mumbletune
4
-
5
- class Player
6
-
7
- attr_accessor :history
8
-
9
- def initialize(host=Mumbletune.config['mpd']['host'], port=Mumbletune.config['mpd']['port'])
10
- @mpd = MPD.new(host, port)
11
- self.connect
12
- self.clear_all
13
-
14
- @history = Array.new
15
- @prev_id = 0
16
-
17
- self.defaults
18
- self.establish_callbacks
19
- end
20
-
21
- def connect
22
- @disconnecting = false
23
- @mpd.connect true # 'true' enables callbacks
24
- end
25
-
26
- def disconnect
27
- @disconnecting = true
28
- @mpd.disconnect
29
- puts ">> Disconnected from MPD"
30
- end
31
-
32
- # Setup
33
-
34
- def defaults
35
- @mpd.volume = Mumbletune.config["mpd"]["default_volume"] || 100
36
- @mpd.consume = true
37
- end
38
-
39
- def establish_callbacks
40
- @mpd.on :connection do |status|
41
- if status == false && !@disconnecting
42
- self.connect
43
- else
44
- puts ">> MPD happens to be connected."
45
- end
46
- end
47
-
48
- # Fires when currently playing song changes.
49
- @mpd.on :songid do |id|
50
-
51
- # Clear old tracks from the store.
52
- Track.store.delete_if { |t| t.mpd_id == @prev_id }
53
-
54
- @prev_id = id
55
- end
56
- end
57
-
58
- # Status methods
59
-
60
- def playing?
61
- state = @mpd.status[:state]
62
- if state =~ /^(play|pause)$/i
63
- true
64
- else
65
- false
66
- end
67
- end
68
-
69
- def paused?
70
- state = @mpd.status[:state]
71
- if state == :pause
72
- true
73
- else
74
- false
75
- end
76
- end
77
-
78
-
79
- # MPD Settings
80
-
81
- def volume?
82
- @mpd.volume
83
- end
84
-
85
- def volume(percent)
86
- @mpd.volume = percent
87
- end
88
-
89
-
90
-
91
- # Queue
92
-
93
- def add_collection(col, now=false)
94
- col.tracks.each do |t|
95
- id = @mpd.addid t.url,
96
- (now) ? col.tracks.index(t)+1 : nil
97
- t.mpd_id = id
98
- end
99
-
100
- @history.push col
101
-
102
- @mpd.next if now
103
- end
104
-
105
- def queue
106
- # Combine the future queue with the current track.
107
- # MPD puts the current track in its queue only if
108
- # other tracks are queued to play. Account for this.
109
- queue = @mpd.queue
110
- queue.unshift @mpd.current_song if @mpd.current_song
111
-
112
- # Delete index 0 if first queue position and current song are duplicates.
113
- queue.delete_at(0) if queue[1] && queue[0] == queue[1]
114
-
115
- # Associate known Tracks with Queue items.
116
- mapped_queue = queue.map do |mpd_song|
117
- t = Track.retreive_from_mpd_id(mpd_song.id)
118
- if t
119
- t.queue_pos = mpd_song.pos
120
- t
121
- end
122
- end
123
- mapped_queue
124
- end
125
-
126
- def current_song
127
- Track.retreive_from_mpd_id(@mpd.current_song.id) if @mpd.playing?
128
- end
129
-
130
- def undo
131
- last_collection = @history.pop
132
-
133
- last_collection.tracks.each do |t|
134
- to_delete = @mpd.queue.select { |mpd_song| mpd_song.id == t.mpd_id }.first
135
- @mpd.delete(to_delete.pos) if to_delete
136
- end
137
- last_collection
138
- end
139
-
140
- def clear_all
141
- @mpd.clear
142
- end
143
-
144
- def clear_queue
145
- current = @mpd.current_song
146
- @mpd.queue.each do |t|
147
- @mpd.delete :id => t.id unless t.id == current.id
148
- end
149
- end
150
-
151
- # Playback commands
152
-
153
- def play
154
- @mpd.play
155
- end
156
-
157
- def pause
158
- @mpd.pause = (@mpd.playing?) ? true : false
159
- end
160
-
161
- def next
162
- @mpd.next
163
- end
164
-
165
- def stop
166
- @mpd.stop
167
- end
168
-
169
- end
170
-
171
- end
@@ -1,42 +0,0 @@
1
- require 'sinatra/base'
2
-
3
- module Mumbletune
4
-
5
- module SPURIServer
6
-
7
- class Server < Sinatra::Base
8
- set :run, true
9
- set :server, :thin
10
- set :logging, false
11
- set :app_file, __FILE__
12
- set :bind, 'localhost'
13
- set :port, 8081
14
-
15
- get '/play/:uri' do
16
- cred = Mumbletune.config['spotify']
17
- sp = Mumbletune::Spotify.new(cred['username'], cred['password'])
18
-
19
- track = sp.objectFromURI(params[:uri])
20
- halt 404, "Could not find a track with that URI." if track == nil
21
-
22
- url = track.getFileURL().to_s
23
- halt 404, "Could not find a track URL for that URI." if track == nil
24
-
25
- sp.logout
26
- redirect url, 303
27
- end
28
- end
29
-
30
- def self.url_for(uri)
31
- bind = Server::bind
32
- port = Server::port
33
- "http://#{bind}:#{port}/play/#{uri}"
34
- end
35
-
36
- def self.sp_uri_for(url)
37
- regexp = /(.+)(<sp_uri>spotify:\w+:\w+)/i
38
- matched = regexp.match(url)
39
- matched[:sp_uri]
40
- end
41
- end
42
- end
@@ -1,90 +0,0 @@
1
- require 'uri'
2
-
3
- module Mumbletune
4
-
5
- class SpotifyTrack < Track
6
- def initialize(params)
7
- super
8
-
9
- @uri = params[:uri]
10
- @url = SPURIServer.url_for(@uri)
11
- end
12
-
13
- def self.track_from_uri(track)
14
- track = MetaSpotify::Track.lookup(track) unless track.class == MetaSpotify::Track
15
-
16
- # force track to be playable within region
17
- unless track.album.available_territories.include? Mumbletune.config["spotify"]["region"]
18
- raise "#{track.name}: Not available in this region."
19
- end
20
-
21
- song = SpotifyTrack.new({
22
- :name => track.name,
23
- :artist => track.artists.first.name,
24
- :album => track.album.name,
25
- :uri => track.uri
26
- })
27
-
28
- # Technically, a collection of one.
29
- Collection.new(
30
- :TRACK,
31
- song,
32
- "<b>#{song.name}</b> by <b>#{song.artist}</b>"
33
- )
34
- end
35
-
36
- def self.tracks_from_album(album_ref)
37
- album_uri = album_ref.uri if album_ref.class == MetaSpotify::Album
38
- album = MetaSpotify::Album.lookup(album_uri, {:extras => "track"})
39
-
40
- # force album to be playable in region
41
- unless album.available_territories.include? Mumbletune.config["spotify"]["region"]
42
- raise "#{album.name}: Not available in this region."
43
- end
44
-
45
- tracks = []
46
- album.tracks.each do |track|
47
- tracks.push SpotifyTrack.new({
48
- :name => track.name,
49
- :artist => track.artists.first.name,
50
- :album => album.name,
51
- :uri => track.uri
52
- })
53
- end
54
-
55
- Collection.new(
56
- :ALBUM,
57
- tracks,
58
- "the album <b>#{album.name}</b> by <b>#{album.artists.first.name}</b>"
59
- )
60
- end
61
-
62
- def self.tracks_from_artist(artist)
63
- artist = MetaSpotify::Artist.lookup(artist) unless artist.class == MetaSpotify::Artist
64
-
65
- # spotify metadata api still error-prone
66
- search_result = Mumbletune.handle_sp_error { MetaSpotify::Track.search("artist:\"#{artist.name}\"") }
67
-
68
- # filter out tracks outside region
69
- search_result[:tracks].select! do |track|
70
- track.album.available_territories.include? Mumbletune.config["spotify"]["region"]
71
- end
72
-
73
- tracks = []
74
- search_result[:tracks][0...10].each do |track|
75
- tracks.push SpotifyTrack.new({
76
- :name => track.name,
77
- :artist => track.artists.first.name,
78
- :album => track.album.name,
79
- :uri => track.uri
80
- })
81
- end
82
-
83
- Collection.new(
84
- :ARTIST_TOP,
85
- tracks,
86
- "#{tracks.length} tracks by <b>#{artist.name}</b>"
87
- )
88
- end
89
- end
90
- end
@@ -1,32 +0,0 @@
1
- module Mumbletune
2
- class Track
3
- attr_accessor :name, :artist, :album, :url, :mpd_id, :queue_pos
4
-
5
- class << self
6
- attr_accessor :store
7
- end
8
- self.store = []
9
-
10
- def initialize(params)
11
- @name = params[:name]
12
- @artist = params[:artist]
13
- @album = params[:album]
14
- @url = params[:url]
15
-
16
- Track.store.push self
17
- end
18
-
19
- def playing?
20
- if self == Mumbletune.player.current_song
21
- true
22
- else
23
- false
24
- end
25
- end
26
-
27
- def self.retreive_from_mpd_id(id)
28
- Track.store.select { |t| t.mpd_id == id }.first
29
- end
30
-
31
- end
32
- end