ruby-mpd 0.3.1 → 0.3.2

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.
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require "bundler/gem_tasks"
1
2
  require 'rake/testtask'
2
3
 
3
4
  Rake::TestTask.new(:test) do |test|
@@ -6,7 +7,6 @@ end
6
7
 
7
8
  desc "Open an irb session preloaded with this API"
8
9
  task :console do
9
- $:.unshift(File.expand_path('../lib', __FILE__))
10
10
  require 'ruby-mpd'
11
11
  require 'irb'
12
12
  ARGV.clear
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ruby/mpd"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/lib/ruby-mpd.rb CHANGED
@@ -54,20 +54,13 @@ class MPD
54
54
  @hostname = hostname
55
55
  @port = port
56
56
  @options = {callbacks: false}.merge(opts)
57
+ @password = opts.delete(:password) || nil
57
58
  reset_vars
58
59
 
59
60
  @mutex = Mutex.new
60
61
  @callbacks = {}
61
62
  end
62
63
 
63
- # Initialize instance variables on new object, or on disconnect.
64
- def reset_vars
65
- @socket = nil
66
- @version = nil
67
- @tags = nil
68
- end
69
- private :reset_vars
70
-
71
64
  # This will register a block callback that will trigger whenever
72
65
  # that specific event happens.
73
66
  #
@@ -93,44 +86,9 @@ class MPD
93
86
  # @return [void]
94
87
  def emit(event, *args)
95
88
  return unless @callbacks[event]
96
- @callbacks[event].each { |handle| handle.call *args }
89
+ @callbacks[event].each { |handle| handle.call(*args) }
97
90
  end
98
91
 
99
- # Constructs a callback loop thread and/or resumes it.
100
- # @return [Thread]
101
- def callback_thread
102
- @cb_thread ||= Thread.new(self) do |mpd|
103
- old_status = {}
104
- while true
105
- status = mpd.status rescue {}
106
-
107
- status[:connection] = mpd.connected?
108
-
109
- status[:time] ||= [nil, nil] # elapsed, total
110
- status[:audio] ||= [nil, nil, nil] # samp, bits, chans
111
- status[:song] = mpd.current_song
112
-
113
- status.each do |key, val|
114
- next if val == old_status[key] # skip unchanged keys
115
- emit key, *val # splat arrays
116
- end
117
-
118
- old_status = status
119
- sleep 0.1
120
-
121
- unless status[:connection] || Thread.current[:stop]
122
- sleep 2
123
- mpd.connect rescue nil
124
- end
125
-
126
- Thread.stop if Thread.current[:stop]
127
- end
128
- end
129
- @cb_thread[:stop] = false
130
- @cb_thread.run if @cb_thread.stop?
131
- end
132
- private :callback_thread
133
-
134
92
  # Connect to the daemon.
135
93
  #
136
94
  # When called without any arguments, this will just connect to the server
@@ -139,16 +97,16 @@ class MPD
139
97
  # @return [true] Successfully connected.
140
98
  # @raise [MPDError] If connect is called on an already connected instance.
141
99
  def connect(callbacks = nil)
142
- raise ConnectionError, 'Already connected!' if self.connected?
143
-
144
- @socket = File.exists?(@hostname) ? UNIXSocket.new(@hostname) : TCPSocket.new(@hostname, @port)
100
+ raise ConnectionError, 'Already connected!' if connected?
145
101
 
146
102
  # by protocol, we need to get a 'OK MPD <version>' reply
147
103
  # should we fail to do so, the connection was unsuccessful
148
- unless response = @socket.gets
104
+ unless response = socket.gets
149
105
  reset_vars
150
106
  raise ConnectionError, 'Unable to connect (possibly too many connections open)'
151
107
  end
108
+
109
+ authenticate
152
110
  @version = response.chomp.gsub('OK MPD ', '') # Read the version
153
111
 
154
112
  if callbacks
@@ -208,6 +166,10 @@ class MPD
208
166
  send_command :password, pass
209
167
  end
210
168
 
169
+ def authenticate
170
+ send_command(:password, @password) if @password
171
+ end
172
+
211
173
  # Ping the server.
212
174
  # @macro returnraise
213
175
  def ping
@@ -224,7 +186,7 @@ class MPD
224
186
  # @return (see #handle_server_response)
225
187
  # @raise [MPDError] if the command failed.
226
188
  def send_command(command, *args)
227
- raise ConnectionError, "Not connected to the server!" if !@socket
189
+ raise ConnectionError, "Not connected to the server!" unless @socket
228
190
 
229
191
  @mutex.synchronize do
230
192
  begin
@@ -238,7 +200,49 @@ class MPD
238
200
  end
239
201
  end
240
202
 
241
- private
203
+ private
204
+
205
+ # Initialize instance variables on new object, or on disconnect.
206
+ def reset_vars
207
+ @socket = nil
208
+ @version = nil
209
+ @tags = nil
210
+ end
211
+
212
+ # Constructs a callback loop thread and/or resumes it.
213
+ # @return [Thread]
214
+ def callback_thread
215
+ @cb_thread ||= Thread.new(self) do |mpd|
216
+ old_status = {}
217
+ while true
218
+ status = mpd.status rescue {}
219
+
220
+ status[:connection] = mpd.connected?
221
+
222
+ status[:time] ||= [nil, nil] # elapsed, total
223
+ status[:audio] ||= [nil, nil, nil] # samp, bits, chans
224
+ status[:song] = mpd.current_song rescue nil
225
+ status[:updating_db] ||= nil
226
+
227
+ status.each do |key, val|
228
+ next if val == old_status[key] # skip unchanged keys
229
+ emit key, *val # splat arrays
230
+ end
231
+
232
+ old_status = status
233
+ sleep 0.1
234
+
235
+ unless status[:connection] || Thread.current[:stop]
236
+ sleep 2
237
+ mpd.connect rescue nil
238
+ end
239
+
240
+ Thread.stop if Thread.current[:stop]
241
+ end
242
+ end
243
+ @cb_thread[:stop] = false
244
+ @cb_thread.run if @cb_thread.stop?
245
+ end
242
246
 
243
247
  # Handles the server's response (called inside {#send_command}).
244
248
  # Repeatedly reads the server's response from the socket.
@@ -265,6 +269,10 @@ class MPD
265
269
  raise SERVER_ERRORS[err[:code].to_i], "[#{err[:command]}] #{err[:message]}"
266
270
  end
267
271
 
272
+ def socket
273
+ @socket ||= File.exists?(@hostname) ? UNIXSocket.new(@hostname) : TCPSocket.new(@hostname, @port)
274
+ end
275
+
268
276
  SERVER_ERRORS = {
269
277
  1 => NotListError,
270
278
  2 => ServerArgumentError,
@@ -94,7 +94,7 @@ class MPD
94
94
  def build_hash(string)
95
95
  return {} if string.nil?
96
96
 
97
- string.split("\n").each_with_object({}) do |line, hash|
97
+ string.lines.each_with_object({}) do |line, hash|
98
98
  key, object = parse_line(line)
99
99
 
100
100
  # if val appears more than once, make an array of vals.
@@ -109,19 +109,19 @@ class MPD
109
109
  # Converts the response to MPD::Song objects.
110
110
  # @return [Array<MPD::Song>] An array of songs.
111
111
  def build_songs_list(array)
112
- return array.map { |hash| Song.new(hash) }
112
+ return array.map { |hash| Song.new(self, hash) }
113
113
  end
114
114
 
115
115
  # Remove lines which we don't want.
116
116
  def filter_lines(string, filter)
117
- string.split("\n").reject {|line| line =~ /(#{filter.join('|')}):/}.join("\n")
117
+ string.lines.reject {|line| line =~ /(#{filter.join('|')}):/}.join
118
118
  end
119
119
 
120
120
  # Make chunks from string.
121
121
  # @return [Array<String>]
122
122
  def make_chunks(string)
123
123
  first_key = string.match(/\A(.+?):\s?/)[1]
124
- chunks = string.split(/\n(?=#{first_key})/).map(&:strip)
124
+ string.split(/\n(?=#{first_key})/).map(&:strip)
125
125
  end
126
126
 
127
127
  # Parses the response, determining per-command on what parsing logic
@@ -26,9 +26,9 @@ class MPD
26
26
  def songs
27
27
  result = @mpd.send_command(:listplaylistinfo, @name)
28
28
  if result.to_s =~ URI::regexp
29
- Song.new({:file => result, :time => 0})
29
+ Song.new(@mpd, {:file => result, :time => 0})
30
30
  else
31
- result.map {|hash| Song.new(hash) }
31
+ result.map {|hash| Song.new(@mpd, hash) }
32
32
  end
33
33
  rescue TypeError
34
34
  puts "Files inside Playlist '#{@name}' do not exist!"
@@ -78,7 +78,7 @@ class MPD
78
78
  # Moves song with SONGID in the playlist to the position SONGPOS.
79
79
  # @macro returnraise
80
80
  def move(songid, songpos)
81
- @mpd.send_command :playlistmove, @name
81
+ @mpd.send_command :playlistmove, @name, songid, songpos
82
82
  end
83
83
 
84
84
  # Renames the playlist to +new_name+.
@@ -91,8 +91,13 @@ class MPD
91
91
  else
92
92
  command = options[:strict] ? :find : :search
93
93
  end
94
-
95
- build_songs_list send_command(command, params)
94
+
95
+ response = send_command(command, params)
96
+ if response == true
97
+ return true
98
+ else
99
+ build_songs_list response
100
+ end
96
101
  end
97
102
 
98
103
  # Tell the server to update the database. Optionally,
@@ -117,7 +122,7 @@ class MPD
117
122
  #
118
123
  # @return [Array<String>] Array of directory names
119
124
  def directories(path = nil)
120
- return files[:directory]
125
+ return files(path)[:directory]
121
126
  end
122
127
 
123
128
  # Lists all of the albums in the database.
@@ -18,7 +18,7 @@ class MPD
18
18
  def current_song
19
19
  hash = send_command :currentsong
20
20
  # if there is no current song (we get true, then return nil)
21
- hash.is_a?(TrueClass) ? nil : Song.new(hash)
21
+ hash.is_a?(TrueClass) ? nil : Song.new(self, hash)
22
22
  end
23
23
 
24
24
  # Waits until there is a noteworthy change in one or more of MPD's subsystems.
@@ -21,6 +21,13 @@ class MPD
21
21
  def disableoutput(num)
22
22
  send_command :disableoutput, num
23
23
  end
24
+
25
+ # Toggles specified output.
26
+ # @param [Integer] num Number of the output to enable.
27
+ # @macro returnraise
28
+ def toggleoutput(num)
29
+ send_command :toggleoutput, num
30
+ end
24
31
  end
25
32
  end
26
33
  end
@@ -78,7 +78,7 @@ class MPD
78
78
  # Returns the song with the +songid+ in the playlist,
79
79
  # @return [MPD::Song]
80
80
  def song_with_id(songid)
81
- Song.new send_command(:playlistid, songid)
81
+ Song.new(self, send_command(:playlistid, songid))
82
82
  end
83
83
 
84
84
  # Searches for songs in the queue matched by the what
data/lib/ruby-mpd/song.rb CHANGED
@@ -7,7 +7,8 @@ class MPD::Song
7
7
  # length in seconds
8
8
  attr_reader :file, :title, :time, :artist, :album, :albumartist
9
9
 
10
- def initialize(options)
10
+ def initialize(mpd, options)
11
+ @mpd = mpd
11
12
  @data = {} # allowed fields are @types + :file
12
13
  @time = options.delete(:time) { [nil] }.first # HAXX for array return
13
14
  @file = options.delete(:file)
@@ -28,6 +29,14 @@ class MPD::Song
28
29
  return '--:--' if @time.nil?
29
30
  "#{@time / 60}:#{"%02d" % (@time % 60)}"
30
31
  end
32
+
33
+ # Retrieve "comments" metadata from a file and cache it in the object.
34
+ #
35
+ # @return [Hash] Key value pairs from "comments" metadata on a file.
36
+ # @return [Boolean] True if comments are empty
37
+ def comments
38
+ @comments ||= @mpd.send_command :readcomments, @file
39
+ end
31
40
 
32
41
  # Pass any unknown calls over to the data hash.
33
42
  def method_missing(m, *a)
@@ -1,3 +1,3 @@
1
1
  class MPD
2
- VERSION = '0.3.1'
3
- end
2
+ VERSION = '0.3.2'
3
+ end
data/ruby-mpd.gemspec CHANGED
@@ -1,20 +1,26 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.unshift File.expand_path("../lib", __FILE__)
3
- require "ruby-mpd/version"
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruby-mpd/version'
4
5
 
5
- Gem::Specification.new do |s|
6
- s.platform = Gem::Platform::RUBY
7
- s.name = 'ruby-mpd'
8
- s.version = MPD::VERSION
9
- s.homepage = 'https://github.com/archSeer/ruby-mpd'
10
- s.license = 'GPL-2'
11
- s.authors = ["Blaž Hrastnik"]
12
- s.email = ['speed.the.bboy@gmail.com']
13
- s.summary = "Modern client library for MPD"
14
- s.description = "A powerful, modern and feature complete library for the Music Player Daemon."
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ruby-mpd"
8
+ spec.version = MPD::VERSION
9
+ spec.authors = ["Blaž Hrastnik"]
10
+ spec.email = ["speed.the.bboy@gmail.com"]
15
11
 
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
12
+ spec.summary = "Modern client library for MPD"
13
+ spec.description = "A powerful, modern and feature complete library for the Music Player Daemon"
14
+ spec.homepage = "https://github.com/archSeer/ruby-mpd"
15
+ spec.license = "GPL-2"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "minitest", "~> 5.5"
25
+ spec.add_development_dependency "rspec", "~> 3.1"
20
26
  end
metadata CHANGED
@@ -1,17 +1,73 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-mpd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blaž Hrastnik
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-01-27 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2015-05-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.1'
13
69
  description: A powerful, modern and feature complete library for the Music Player
14
- Daemon.
70
+ Daemon
15
71
  email:
16
72
  - speed.the.bboy@gmail.com
17
73
  executables: []
@@ -20,8 +76,12 @@ extra_rdoc_files: []
20
76
  files:
21
77
  - ".gitignore"
22
78
  - COPYING
23
- - README.rdoc
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
24
82
  - Rakefile
83
+ - bin/console
84
+ - bin/setup
25
85
  - lib/ruby-mpd.rb
26
86
  - lib/ruby-mpd/exceptions.rb
27
87
  - lib/ruby-mpd/parser.rb
@@ -39,7 +99,6 @@ files:
39
99
  - lib/ruby-mpd/song.rb
40
100
  - lib/ruby-mpd/version.rb
41
101
  - ruby-mpd.gemspec
42
- - test/test_parser.rb
43
102
  homepage: https://github.com/archSeer/ruby-mpd
44
103
  licenses:
45
104
  - GPL-2
@@ -60,9 +119,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
119
  version: '0'
61
120
  requirements: []
62
121
  rubyforge_project:
63
- rubygems_version: 2.2.0
122
+ rubygems_version: 2.2.2
64
123
  signing_key:
65
124
  specification_version: 4
66
125
  summary: Modern client library for MPD
67
- test_files:
68
- - test/test_parser.rb
126
+ test_files: []
127
+ has_rdoc: