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.
@@ -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