muzak 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 554e40f18c30b64f0e2c9be0ee3ee6227b7449a3
4
- data.tar.gz: feaadbe0d3ceb603cb7d8013d9ca2faad3e703a0
3
+ metadata.gz: 5d627d0c95c41896f1c8acb0b47403f240924571
4
+ data.tar.gz: 11f8e33ea6d45befe35fdffcc20b1cba87a05b7a
5
5
  SHA512:
6
- metadata.gz: 3fcce8ffa18023a30c59f79e8ea5795972378af99b4d69df3969de23922773c37634bffd0bebe05d3da6eedfef7cb734fdb224fe927a8c9642139e590663d8d2
7
- data.tar.gz: 2d940d322ec8116e4873da8d24d9318c61a2397fec5639ff8e2526a52d0a4dd0f1e1dcfefc5c4dd2467b0b7abdf4620e3df969678595cec232b417764176ea46
6
+ metadata.gz: e6581bb5f6a785076619b44596f09ab3835a47be33e23e0e0bd1b1b032caee4ceefde24144abbc23c0e09d4158abc86ee7e33fbb04a09e1c3d91b336aded6ded
7
+ data.tar.gz: 6c46c4694d1cfbb67e2e9cbfdbd2eb02899747cef65d10a195efd8daccb27dcc0b39a737108923e11d8470b73bb7f4b59761755936a6095d095b93a263151ec2
data/CONFIGURATION.md CHANGED
@@ -76,6 +76,16 @@ These are the configuration keys observed by muzak's "core," particularly
76
76
 
77
77
  In no particular order:
78
78
 
79
+ ### `event`
80
+
81
+ *Optional.*
82
+
83
+ *Default:* `true`
84
+
85
+ If `event: false` is set in the configuration file, then muzak will not
86
+ attempt to propagate events to plugins. This might be useful for debugging
87
+ or when using multiple players at once via {Muzak::Player::MultiPlayer}.
88
+
79
89
  ### `debug`
80
90
 
81
91
  *Optional.*
@@ -131,6 +141,34 @@ set, then `mpv` will be instructed to disable all video output entirely.
131
141
  This option is primarily useful in conjunction with plugins that provide
132
142
  album art display, or for making Muzak entirely non-graphical.
133
143
 
144
+ ### `multiplayer-players`
145
+
146
+ *Mandatory if using `multiplayer`.*
147
+
148
+ *No default.*
149
+
150
+ If the `player` key is set to `multiplayer`, then this should be set to the
151
+ array of players to use together. For example,
152
+ `multiplayer-players: [mpv, mpd]`.
153
+
154
+ ### `mpd-host`
155
+
156
+ *Optional.*
157
+
158
+ *Default:* `localhost`
159
+
160
+ If `mpd-host` is set *and* the `mpd` player is used, then `mpd` will use this
161
+ value as the MPD host to connect to.
162
+
163
+ ### `mpd-port`
164
+
165
+ *Optional.*
166
+
167
+ *Default:* `6600`
168
+
169
+ If `mpd-port` is set *and* the `mpd` player is used, then `mpd` will use this
170
+ value as the MPD port to connect to.
171
+
134
172
  ### `jukebox-size`
135
173
 
136
174
  *Mandatory.*
data/lib/muzak.rb CHANGED
@@ -12,5 +12,5 @@ require_relative "muzak/instance"
12
12
  # The primary namespace for muzak.
13
13
  module Muzak
14
14
  # Muzak's current version
15
- VERSION = "0.4.0".freeze
15
+ VERSION = "0.4.1".freeze
16
16
  end
data/lib/muzak/config.rb CHANGED
@@ -57,6 +57,7 @@ module Muzak
57
57
  # The default configuration keys and values.
58
58
  DEFAULT_CONFIG = {
59
59
  # core defaults
60
+ "events" => true,
60
61
  "debug" => false,
61
62
  "verbose" => true,
62
63
  "music" => File.expand_path("~/music"),
data/lib/muzak/index.rb CHANGED
@@ -38,6 +38,7 @@ module Muzak
38
38
  def reload!
39
39
  debug "reloading index from '#{file}'..."
40
40
  @hash = Marshal.load(File.read file)
41
+ @albums_hash = nil
41
42
  memoize_collections!
42
43
  end
43
44
 
@@ -53,7 +54,7 @@ module Muzak
53
54
 
54
55
  # @return [Array<String>] a list of all artists in the index
55
56
  def artists
56
- @artists ||= @hash["artists"].keys
57
+ @hash["artists"].keys
57
58
  end
58
59
 
59
60
  # @return [Hash{String => Album}] a hash of all album names with their
@@ -61,6 +61,8 @@ module Muzak
61
61
  # @return [void]
62
62
  # @note {Config::PLUGIN_EVENTS} contains all valid events.
63
63
  def event(type, *args)
64
+ # don't propagate events if disabled by the user
65
+ return unless Config.events
64
66
  return unless Config::PLUGIN_EVENTS.include?(type)
65
67
 
66
68
  plugins.each do |plugin|
@@ -0,0 +1,153 @@
1
+ require "ruby-mpd"
2
+
3
+ module Muzak
4
+ module Player
5
+ # Exposes a MPD connection to muzak for playback control.
6
+ class MPD < StubPlayer
7
+ def running?
8
+ !!@mpd&.connected?
9
+ end
10
+
11
+ # Activates the MPD connection.
12
+ # @return [void]
13
+ def activate!
14
+ return if running?
15
+
16
+ debug "activating #{self.class}"
17
+
18
+ host = Config.mpd_host || "localhost"
19
+ port = Config.mpd_port || 6600
20
+
21
+ @mpd = ::MPD.new host, port
22
+ @mpd.connect
23
+ @mpd.clear
24
+
25
+ instance.event :player_activated
26
+ end
27
+
28
+ # Deactivates the MPD connection.
29
+ # @return [void]
30
+ def deactivate!
31
+ @mpd.clear
32
+ sleep 0.1 # give mpd a little bit of time to process
33
+ @mpd.disconnect
34
+
35
+ debug "deactivating #{self.class}"
36
+
37
+ instance.event :player_deactivated
38
+ end
39
+
40
+ # Tell MPD to begin playback.
41
+ # @return [void]
42
+ # @note Does nothing is playback is already in progress.
43
+ def play
44
+ @mpd.play
45
+ end
46
+
47
+ # Tell MPD to pause playback.
48
+ # @return [void]
49
+ # @note Does nothing is playback is already paused.
50
+ def pause
51
+ @mpd.pause
52
+ end
53
+
54
+ # @return [Boolean] whether or not MPD is currently playing.
55
+ def playing?
56
+ return false unless running?
57
+
58
+ @mpd.playing?
59
+ end
60
+
61
+ # Tell MPD to play the next song in its queue.
62
+ # @return [void]
63
+ # @note Does nothing if the current song is the last.
64
+ def next_song
65
+ @mpd.next
66
+ end
67
+
68
+ # Tell MPD to play the previous song in its queue.
69
+ # @return [void]
70
+ # @note Restarts the song if the current song is the first.
71
+ def previous_song
72
+ @mpd.previous
73
+ end
74
+
75
+ # Tell MPD to add the given song to its queue.
76
+ # @param song [Song] the song to add
77
+ # @return [void]
78
+ # @note Activates MPD if not already activated.
79
+ def enqueue_song(song)
80
+ activate! unless running?
81
+
82
+ load_song song
83
+ end
84
+
85
+ # Tell MPD to add the given album to its queue.
86
+ # @param album [Album] the album to add
87
+ # @return [void]
88
+ # @note Activates MPD if not already activated.
89
+ def enqueue_album(album)
90
+ activate! unless running?
91
+
92
+ album.songs.each do |song|
93
+ load_song song
94
+ end
95
+ end
96
+
97
+ # Tell MPD to add the given playlist to its queue.
98
+ # @param playlist [Playlist] the playlist to add
99
+ # @return [void]
100
+ # @note Activates MPD if not already activated.
101
+ def enqueue_playlist(playlist)
102
+ activate! unless running?
103
+
104
+ playlist.songs.each do |song|
105
+ load_song song
106
+ end
107
+ end
108
+
109
+ # Get MPD's internal queue.
110
+ # @return [Array<Song>] all songs in MPD's queue
111
+ # @note This includes songs already played.
112
+ # @todo Implement this.
113
+ def list_queue
114
+ debug @mpd.playlist.to_s
115
+ danger "this player doesn't support list_queue"
116
+ []
117
+ end
118
+
119
+ # Shuffle MPD's internal queue.
120
+ # @return [void]
121
+ # @todo Implement this.
122
+ def shuffle
123
+ danger "this player doesn't support shuffling (?)"
124
+ end
125
+
126
+ # Clear MPD's internal queue.
127
+ # @return [void]
128
+ def clear_queue
129
+ return unless running?
130
+ @mpd.clear
131
+ end
132
+
133
+ # Get MPD's currently loaded song.
134
+ # @return [Song, nil] the currently loaded song
135
+ def now_playing
136
+ return unless playing?
137
+
138
+ path = "#{Config.music}/#{@mpd.current_song.file}"
139
+ Song.new(path)
140
+ end
141
+
142
+ # Load a song into MPD.
143
+ # @param song [Song] the song to load
144
+ # @return [void]
145
+ # @api private
146
+ def load_song(song)
147
+ path = song.path.sub("#{Config.music}/", "")
148
+ @mpd.add(path)
149
+ @mpd.play if Config.autoplay
150
+ end
151
+ end
152
+ end
153
+ end
@@ -166,8 +166,7 @@ module Muzak
166
166
  # @return [void]
167
167
  def clear_queue
168
168
  return unless running?
169
-
170
- @mpv.command "playlist-clear"
169
+ @mpv.command "stop"
171
170
  end
172
171
 
173
172
  # Get mpv's currently loaded song.
@@ -0,0 +1,141 @@
1
+ module Muzak
2
+ module Player
3
+ # Wraps multiple players into a single class.
4
+ # This can be useful for controlling a local and remote player
5
+ # simultaneously, e.g. one {MPD} and one {MPV} via the same Muzak instance.
6
+ class MultiPlayer < StubPlayer
7
+ # @return [Array<StubPlayer>] the players associated with this multiplayer
8
+ attr_reader :players
9
+
10
+ # @return [Boolean] whether or not all of the players are available
11
+ def self.available?
12
+ klasses = Config.multiplayer_players.map { |p| Player::PLAYER_MAP[p] }
13
+ klasses.all?(&:available?)
14
+ end
15
+
16
+ # @param instance [Instance] the instance associated with the player
17
+ def initialize(instance)
18
+ super(instance)
19
+
20
+ klasses = Config.multiplayer_players.map { |p| Player::PLAYER_MAP[p] }
21
+ @players = klasses.map { |pk| pk.new(instance) }
22
+ end
23
+
24
+ # @return [Boolean] whether or not any of the players are currently running.
25
+ def running?
26
+ @players.any?(&:running?)
27
+ end
28
+
29
+ # Activates each player under the multiplayer.
30
+ # @return [void]
31
+ def activate!
32
+ debug "activating #{self.class}"
33
+ @players.each(&:activate!)
34
+ end
35
+
36
+ # Deactivates each player under the multiplayer.
37
+ # @return [void]
38
+ def deactivate!
39
+ debug "deactivating #{self.class}"
40
+ @players.each(&:deactivate!)
41
+ end
42
+
43
+ # Tell all players to begin playback.
44
+ # @return [void]
45
+ # @note Does nothing is playback is already in progress.
46
+ def play
47
+ return unless running?
48
+ @players.each(&:play)
49
+ end
50
+
51
+ # Tell all players to pause playback.
52
+ # @return [void]
53
+ # @note Does nothing is playback is already paused.
54
+ def pause
55
+ return unless running?
56
+ @players.each(&:pause)
57
+ end
58
+
59
+ # @return [Boolean] Whether or not any of the players are currently playing.
60
+ def playing?
61
+ return false unless running?
62
+ @players.any?(&:playing?)
63
+ end
64
+
65
+ # Tell all players to play the next song in its queue.
66
+ # @return [void]
67
+ # @note Does nothing if the current song is the last.
68
+ def next_song
69
+ @players.each(&:next_song)
70
+ end
71
+
72
+ # Tell all players to play the previous song in its queue.
73
+ # @return [void]
74
+ # @note Does nothing if the current song is the first.
75
+ def previous_song
76
+ @players.each(&:previous_song)
77
+ end
78
+
79
+ # Tell all players to add the given song to its queue.
80
+ # @param song [Song] the song to add
81
+ # @return [void]
82
+ # @note Activates all players if not already activated.
83
+ def enqueue_song(song)
84
+ activate! unless running?
85
+ @players.each { |p| p.enqueue_song(song) }
86
+ end
87
+
88
+ # Tell all players to add the given album to its queue.
89
+ # @param album [Album] the album to add
90
+ # @return [void]
91
+ # @note Activates all players if not already activated.
92
+ def enqueue_album(album)
93
+ activate! unless running?
94
+ @players.each { |p| p.enqueue_album(album) }
95
+ end
96
+
97
+ # Tell all players to add the given playlist to its queue.
98
+ # @param playlist [Playlist] the playlist to add
99
+ # @return [void]
100
+ # @note Activates all players if not already activated.
101
+ def enqueue_playlist(playlist)
102
+ activate! unless running?
103
+ @players.each { |p| p.enqueue_playlist(playlist) }
104
+ end
105
+
106
+ # Get the internal queue of the first player.
107
+ # @return [Array<Song>] all songs in all players's queue
108
+ # @note This includes songs already played.
109
+ def list_queue
110
+ @players.first.list_queue
111
+ end
112
+
113
+ # Shuffle the internal queue.
114
+ # @return [void]
115
+ def shuffle_queue
116
+ return unless running?
117
+ # XXX: shuffling is currently done internally within each player,
118
+ # meaning that shuffling within multiplayer would leave each
119
+ # player in an inconsistent queue state.
120
+ # the solution to this is probably to list the queue, shuffle that
121
+ # list, clear the player's queue, and then load the single shuffled
122
+ # list back into each player.
123
+ danger "shuffling doesn't currently make any sense in multiplayer!"
124
+ end
125
+
126
+ # Clears the internal queue.
127
+ # @return [void]
128
+ def clear_queue
129
+ return unless running?
130
+ @players.each(&:clear_queue)
131
+ end
132
+
133
+ # Get the currently loaded song.
134
+ # @return [Song, nil] the currently loaded song
135
+ def now_playing
136
+ @players[1].now_playing
137
+ @players.first.now_playing
138
+ end
139
+ end
140
+ end
141
+ end
@@ -46,7 +46,6 @@ module Muzak
46
46
  @vlc.play
47
47
  end
48
48
 
49
-
50
49
  # Tell VLC to pause playback.
51
50
  # @return [void]
52
51
  # @note Does nothing is playback is already paused.
@@ -130,6 +129,7 @@ module Muzak
130
129
  # Clear VLC's internal queue.
131
130
  # @return [void]
132
131
  def clear_queue
132
+ return unless running?
133
133
  @vlc.clear
134
134
  end
135
135
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: muzak
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Woodruff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-01 00:00:00.000000000 Z
11
+ date: 2017-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: taglib-ruby
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.10.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: ruby-mpd
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.3.3
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.3.3
75
89
  description: A library for controlling playlists and media players.
76
90
  email: william@tuffbizz.com
77
91
  executables:
@@ -105,7 +119,9 @@ files:
105
119
  - lib/muzak/index.rb
106
120
  - lib/muzak/instance.rb
107
121
  - lib/muzak/player.rb
122
+ - lib/muzak/player/mpd.rb
108
123
  - lib/muzak/player/mpv.rb
124
+ - lib/muzak/player/multiplayer.rb
109
125
  - lib/muzak/player/stub_player.rb
110
126
  - lib/muzak/player/vlc.rb
111
127
  - lib/muzak/playlist.rb
@@ -133,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
149
  version: '0'
134
150
  requirements: []
135
151
  rubyforge_project:
136
- rubygems_version: 2.6.8
152
+ rubygems_version: 2.6.11
137
153
  signing_key:
138
154
  specification_version: 4
139
155
  summary: muzak - A metamusic player.