ruby-mpd-client 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +10 -0
- data/README.md +13 -5
- data/lib/mpd/commands.rb +61 -0
- data/lib/mpd/commands/abstract.rb +61 -0
- data/lib/mpd/commands/all_files.rb +17 -0
- data/lib/mpd/commands/change_volume.rb +14 -0
- data/lib/mpd/commands/current_playlist_add.rb +19 -0
- data/lib/mpd/commands/current_playlist_info.rb +18 -0
- data/lib/mpd/commands/current_playlist_remove.rb +20 -0
- data/lib/mpd/commands/current_song.rb +14 -0
- data/lib/mpd/commands/ping.rb +23 -0
- data/lib/mpd/commands/play.rb +23 -0
- data/lib/mpd/commands/set_volume.rb +14 -0
- data/lib/mpd/commands/status.rb +14 -0
- data/lib/mpd/connection.rb +41 -0
- data/lib/mpd/server_response.rb +50 -0
- data/lib/mpd/version.rb +1 -1
- data/lib/ruby-mpd-client.rb +1 -1
- data/ruby-mpd-client.gemspec +1 -0
- metadata +32 -10
- data/lib/mpd/client.rb +0 -51
- data/lib/mpd/client/commands.rb +0 -10
- data/lib/mpd/client/commands/current_playlist.rb +0 -17
- data/lib/mpd/client/commands/playback_control.rb +0 -36
- data/lib/mpd/client/commands/playback_options.rb +0 -36
- data/lib/mpd/client/connection.rb +0 -39
- data/lib/mpd/client/server_response.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8ca78849c735d15541f0f0e04e83ac1af66d71c3c3202739a0718f7cfc7860e4
|
4
|
+
data.tar.gz: db532da5093220f87880cd0d47137866b089be98ba8d03a7aa89334869b6da9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d23063c2519c020bcf16009a1f6f1874b2d4f53ad41879fc023b5b460e9a531f13a5a665574399cef5836bd9fadbfd4213d2a64f8cef966fa2b8c2dd79194e4
|
7
|
+
data.tar.gz: 0423b775979eb61f9eff55fcfd05d29e6375a17df5e1caf2bb6b9828d7b2d3c32e84e10c792ade9ab004f0462a91292d225e0851f9164a417c6f55c1b698504d
|
data/.travis.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.3.0
|
4
|
+
script: rake spec
|
5
|
+
deploy:
|
6
|
+
provider: rubygems
|
7
|
+
api_key:
|
8
|
+
secure: CCtmgUnWoiG4tKRalp9kfEcaeDUfipES0mcWPV4K0D/K651nxZ0kHe+VV+3rpvV1KDs4i5W+TosVvpH5lDL7+oALLFTsYgo3iam+kzMLfoskkZUuizUDxYjXrWI0T+SM0gL3Ax1J9oJ0cd7j1sUGi5TZ/IHXrKknm1yqFIx83mgKCFxYKJUAwQuwpo924ukqyQ0IsJtYX7AJ31hQwFBZSscJbriaxsz3dN+ptmvYVt9/+oIowHrvZCFnlgejel/eZ9iKCMR8buxx1RF3Q3y7LZkpMb20UBfjMwUkz/XBXGFCFVUaCLEcdFnAuoRePJ8a+q3Qkd0wZp+5g2offguVycTWsPTGgSjSAXcPUK0fOnE6bsBZ9XnkAiwkPtxO3MeG7iBcGBX2XY/Tzl+8EW2FgGeIICBh5sg+UqmrGAuqzmtgrJJwOaBeyLEbAKemAdPRfN7M0Hq1DgbOHchttmiCAY1Ja/RBiYwbEkZsPn9VI2tH3CUvdqc0B4jPV05OKU1sv06hHKJTWoCjsmvd52Tr0Kbr5ofBvLMj+uHnyCx78SwfReVCPEb2PzK5GUBG6+Ufu8UOTFdlS8gDmSO09R/qd/kSILvxCLntNVQAn/aUlnZ0aBJURxhoTQkKRSBGcGrOUXhMKnj3jnwZw1othJ5xxiSXy6fM/8JrsxyPH7TalT8=
|
9
|
+
on:
|
10
|
+
branch: master
|
data/README.md
CHANGED
@@ -18,13 +18,21 @@ It does not do much
|
|
18
18
|
```ruby
|
19
19
|
require 'ruby-mpd-client'
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
#
|
21
|
+
MPD::Commands::SetVolume.new(host: 'localhost') # :host can be ommited
|
22
|
+
.execute(75)
|
23
|
+
MPD::Commands::Next.new.execute
|
24
|
+
|
25
|
+
#
|
26
|
+
# to use one connection
|
27
|
+
#
|
28
|
+
conn = MPD::Connection.new(host: 'localhost', port: 6600)
|
29
|
+
conn.connect
|
30
|
+
MPD::Commands::Next.new(connection: conn).execute
|
31
|
+
MPD::Commands::Pause.new(connection: conn).execute
|
26
32
|
```
|
27
33
|
|
34
|
+
For available commands see [lib/mpd/commands](lib/mpd/commands).
|
35
|
+
|
28
36
|
## Contributing
|
29
37
|
|
30
38
|
Bug reports and pull requests are welcome on GitHub at https://github.com/Nondv/ruby-mpd-client.
|
data/lib/mpd/commands.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
Dir[File.join(__dir__, 'commands', '*.rb')].each { |f| require f }
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
#
|
5
|
+
# Contains classes representing MPD commands
|
6
|
+
#
|
7
|
+
module Commands
|
8
|
+
#
|
9
|
+
# To decrease code amount
|
10
|
+
#
|
11
|
+
def self.define_trivial_command(class_name, command)
|
12
|
+
klass = Class.new(::MPD::Commands::Abstract) do
|
13
|
+
define_method :execute do
|
14
|
+
super(command)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
const_set(class_name, klass)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# To define commands like 'save "whatever this is"'
|
23
|
+
#
|
24
|
+
def self.define_text_argument_command(class_name, command)
|
25
|
+
klass = Class.new(::MPD::Commands::Abstract) do
|
26
|
+
define_method :execute do |arg|
|
27
|
+
super("#{command} \"#{arg}\"")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
const_set(class_name, klass)
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# To define commands like "random <1/0>"
|
36
|
+
#
|
37
|
+
def self.define_option_command(class_name, command)
|
38
|
+
klass = Class.new(::MPD::Commands::Abstract) do
|
39
|
+
define_method :execute do |state|
|
40
|
+
super(command + state ? ' 1' : ' 0')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
const_set(class_name, klass)
|
45
|
+
end
|
46
|
+
|
47
|
+
define_trivial_command(:Pause, 'pause 1')
|
48
|
+
define_trivial_command(:Stop, 'stop')
|
49
|
+
define_trivial_command(:Previous, 'previous')
|
50
|
+
define_trivial_command(:Next, 'next')
|
51
|
+
define_trivial_command(:CurrentPlaylistClear, 'clear')
|
52
|
+
|
53
|
+
define_text_argument_command :PlaylistDelete, :rm
|
54
|
+
define_text_argument_command :PlaylistSave, :save
|
55
|
+
define_text_argument_command :PlaylistLoad, :load
|
56
|
+
|
57
|
+
%w[Consume Crossfade Random Repeat Single].each do |class_name|
|
58
|
+
define_option_command(class_name, class_name.downcase)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'mpd/connection'
|
2
|
+
require 'mpd/server_response'
|
3
|
+
require 'mpd/playlist'
|
4
|
+
|
5
|
+
module MPD
|
6
|
+
module Commands
|
7
|
+
#
|
8
|
+
# Base class for MPD commands.
|
9
|
+
#
|
10
|
+
class Abstract
|
11
|
+
attr_reader :connection
|
12
|
+
|
13
|
+
#
|
14
|
+
# You can provide you own connection. It should have same
|
15
|
+
#
|
16
|
+
def initialize(connection: nil, host: 'localhost', port: 6600)
|
17
|
+
@connection = connection || Connection.new(host: host, port: port).tap(&:connect).tap(&:gets)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# This method should be overriden.
|
22
|
+
# Example:
|
23
|
+
#
|
24
|
+
# def execute
|
25
|
+
# super('ping')
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
def execute(command)
|
29
|
+
exec_command(command)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def exec_command(command)
|
35
|
+
connection.puts(command)
|
36
|
+
response = ServerResponse.from_connection(connection)
|
37
|
+
raise(MpdError, response.status) if response.error?
|
38
|
+
response
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec_command_list(commands)
|
42
|
+
connection.puts('command_list_begin')
|
43
|
+
commands.each { |c| connection.puts(c) }
|
44
|
+
connection.puts('command_list_end')
|
45
|
+
|
46
|
+
response = ServerResponse.from_connection(connection)
|
47
|
+
raise(MpdError, response.status) if response.error?
|
48
|
+
response
|
49
|
+
end
|
50
|
+
|
51
|
+
def resolve_range(arg)
|
52
|
+
if arg.is_a?(Range)
|
53
|
+
last = arg.exclude_end? ? arg.end : arg.end + 1
|
54
|
+
"#{arg.begin}:#{last}"
|
55
|
+
else
|
56
|
+
arg
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Uses "listall" command to get
|
7
|
+
# all files (directories are filtered out) from db.
|
8
|
+
#
|
9
|
+
class AllFiles < Abstract
|
10
|
+
def execute
|
11
|
+
super('listall').key_value_pairs
|
12
|
+
.select { |e| e[0] == 'file' }
|
13
|
+
.map(&:last)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Adds song(s) to current playlist
|
7
|
+
# `songs` is an array of URIs.
|
8
|
+
#
|
9
|
+
class CurrentPlaylistAdd < Abstract
|
10
|
+
#
|
11
|
+
# `songs` is position (as int) or range
|
12
|
+
#
|
13
|
+
def execute(songs)
|
14
|
+
return exec_command("add \"#{songs}\"") unless songs.is_a?(Array)
|
15
|
+
exec_command_list(songs.map { |s| "add \"#{s}\"" })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Info about songs in current playlist
|
7
|
+
#
|
8
|
+
class CurrentPlaylistInfo < Abstract
|
9
|
+
# `songs` can be range
|
10
|
+
# or integer (to show info about one song)
|
11
|
+
# or completely ommited (to show info about all songs)
|
12
|
+
def execute(songs = nil)
|
13
|
+
response = super("playlistinfo #{resolve_range(songs)}")
|
14
|
+
Playlist.from_response(response)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Removes songs from current playlist
|
7
|
+
# by id or position/range
|
8
|
+
#
|
9
|
+
class CurrentPlaylistRemove < Abstract
|
10
|
+
#
|
11
|
+
# `position` is int or range
|
12
|
+
# `id` is int song id
|
13
|
+
#
|
14
|
+
def execute(position: nil, id: nil)
|
15
|
+
raise(ArgumentError) if position && id || !position && !id
|
16
|
+
exec_command(id ? "deleteid #{id}" : "delete #{resolve_range(position)}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Tries to execute "ping" command.
|
7
|
+
# Returns `true` if succedeed,
|
8
|
+
# raises error if `MpdError` occurred,
|
9
|
+
# `false` otherwise
|
10
|
+
#
|
11
|
+
class Ping < Abstract
|
12
|
+
# rubocop:disable Lint/RescueWithoutErrorClass
|
13
|
+
def execute
|
14
|
+
super('ping')
|
15
|
+
true
|
16
|
+
rescue => e
|
17
|
+
raise e if e.is_a?(MpdError)
|
18
|
+
false
|
19
|
+
end
|
20
|
+
# rubocop:enable Lint/RescueWithoutErrorClass
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'mpd/commands/abstract'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Play specific song (by id or cur. playlist position).
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class Play < Abstract
|
10
|
+
def execute(position: nil, id: nil)
|
11
|
+
raise(ArgumentError, 'too many arguments') if position && id
|
12
|
+
|
13
|
+
if position
|
14
|
+
super("play #{position}")
|
15
|
+
elsif id
|
16
|
+
super("playid #{id}")
|
17
|
+
else
|
18
|
+
super('play')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module MPD
|
4
|
+
#
|
5
|
+
# Simple wrapper over Socket
|
6
|
+
#
|
7
|
+
class Connection
|
8
|
+
def initialize(host:, port:)
|
9
|
+
@host = host
|
10
|
+
@port = port
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect
|
14
|
+
disconnect if socket
|
15
|
+
@socket = TCPSocket.open(host, port)
|
16
|
+
end
|
17
|
+
|
18
|
+
def disconnect
|
19
|
+
socket && socket.close
|
20
|
+
@socket = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def puts(text)
|
24
|
+
raise ConnectionError unless socket
|
25
|
+
socket.puts(text)
|
26
|
+
rescue Errno::ECONNRESET
|
27
|
+
raise ConnectionError
|
28
|
+
end
|
29
|
+
|
30
|
+
def gets
|
31
|
+
raise ConnectionError unless socket
|
32
|
+
socket.gets || raise(ConnectionError)
|
33
|
+
rescue Errno::ECONNRESET
|
34
|
+
raise ConnectionError
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :socket, :host, :port
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module MPD
|
2
|
+
#
|
3
|
+
# Just a frozen string with some useful methods
|
4
|
+
#
|
5
|
+
class ServerResponse < String
|
6
|
+
def self.from_connection(conn)
|
7
|
+
line = ''
|
8
|
+
buffer = ''
|
9
|
+
while line != "OK\n" && !line.start_with?('ACK')
|
10
|
+
line = conn.gets
|
11
|
+
raise(ConnectionError) if line.nil?
|
12
|
+
buffer << line
|
13
|
+
end
|
14
|
+
|
15
|
+
new(buffer.force_encoding('UTF-8'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(response_text)
|
19
|
+
super
|
20
|
+
freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h
|
24
|
+
key_value_pairs.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
def key_value_pairs
|
28
|
+
content.split("\n").map do |line|
|
29
|
+
index = line.index(':')
|
30
|
+
raise "can't create key-value pair" unless index
|
31
|
+
key = line[0...index]
|
32
|
+
value = line[(index + 1)..-1].strip
|
33
|
+
[key, value]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# text without status
|
38
|
+
def content
|
39
|
+
lines[0..-2].join
|
40
|
+
end
|
41
|
+
|
42
|
+
def status
|
43
|
+
lines.last.chomp
|
44
|
+
end
|
45
|
+
|
46
|
+
def error?
|
47
|
+
status.start_with?('ACK')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/mpd/version.rb
CHANGED
data/lib/ruby-mpd-client.rb
CHANGED
data/ruby-mpd-client.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mpd-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitriy Non
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-its
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description:
|
42
56
|
email:
|
43
57
|
- non.dmitriy@gmail.com
|
@@ -46,21 +60,29 @@ extensions: []
|
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
48
62
|
- ".gitignore"
|
63
|
+
- ".travis.yml"
|
49
64
|
- Gemfile
|
50
65
|
- LICENSE.txt
|
51
66
|
- README.md
|
52
67
|
- Rakefile
|
53
68
|
- bin/console
|
54
69
|
- bin/setup
|
55
|
-
- lib/mpd/
|
56
|
-
- lib/mpd/
|
57
|
-
- lib/mpd/
|
58
|
-
- lib/mpd/
|
59
|
-
- lib/mpd/
|
60
|
-
- lib/mpd/
|
61
|
-
- lib/mpd/
|
70
|
+
- lib/mpd/commands.rb
|
71
|
+
- lib/mpd/commands/abstract.rb
|
72
|
+
- lib/mpd/commands/all_files.rb
|
73
|
+
- lib/mpd/commands/change_volume.rb
|
74
|
+
- lib/mpd/commands/current_playlist_add.rb
|
75
|
+
- lib/mpd/commands/current_playlist_info.rb
|
76
|
+
- lib/mpd/commands/current_playlist_remove.rb
|
77
|
+
- lib/mpd/commands/current_song.rb
|
78
|
+
- lib/mpd/commands/ping.rb
|
79
|
+
- lib/mpd/commands/play.rb
|
80
|
+
- lib/mpd/commands/set_volume.rb
|
81
|
+
- lib/mpd/commands/status.rb
|
82
|
+
- lib/mpd/connection.rb
|
62
83
|
- lib/mpd/errors.rb
|
63
84
|
- lib/mpd/playlist.rb
|
85
|
+
- lib/mpd/server_response.rb
|
64
86
|
- lib/mpd/song.rb
|
65
87
|
- lib/mpd/version.rb
|
66
88
|
- lib/ruby-mpd-client.rb
|
@@ -85,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
107
|
version: '0'
|
86
108
|
requirements: []
|
87
109
|
rubyforge_project:
|
88
|
-
rubygems_version: 2.
|
110
|
+
rubygems_version: 2.7.3
|
89
111
|
signing_key:
|
90
112
|
specification_version: 4
|
91
113
|
summary: yet another MPD client on Ruby
|
data/lib/mpd/client.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'mpd/client/connection'
|
2
|
-
require 'mpd/client/server_response'
|
3
|
-
require 'mpd/client/commands'
|
4
|
-
|
5
|
-
module MPD
|
6
|
-
class Client
|
7
|
-
def self.connect(host: 'localhost', port: 6600)
|
8
|
-
new(host: host, port: port).tap(&:connect)
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize(host: 'localhost', port: 6600)
|
12
|
-
@connection = Connection.new(host: host, port: port)
|
13
|
-
end
|
14
|
-
|
15
|
-
def current_song
|
16
|
-
execute('currentsong').to_h
|
17
|
-
end
|
18
|
-
|
19
|
-
def status
|
20
|
-
response = execute('status')
|
21
|
-
response.to_h
|
22
|
-
end
|
23
|
-
|
24
|
-
def execute(command)
|
25
|
-
connection.puts(command)
|
26
|
-
response = ServerResponse.from_connection(connection)
|
27
|
-
raise(MpdError, response.status) if response.error?
|
28
|
-
response
|
29
|
-
end
|
30
|
-
|
31
|
-
def connected?
|
32
|
-
execute('ping')
|
33
|
-
rescue => e
|
34
|
-
raise e if e.is_a?(MpdError)
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
|
-
def connect
|
39
|
-
connection.connect
|
40
|
-
raise(ConnectionError) unless connection.gets =~ /^OK/
|
41
|
-
end
|
42
|
-
|
43
|
-
def disconnect
|
44
|
-
connection.disconnect
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
attr_reader :connection
|
50
|
-
end
|
51
|
-
end
|
data/lib/mpd/client/commands.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'mpd/playlist'
|
2
|
-
|
3
|
-
module MPD
|
4
|
-
class Client
|
5
|
-
module Commands
|
6
|
-
# https://www.musicpd.org/doc/protocol/queue.html
|
7
|
-
module CurrentPlaylist
|
8
|
-
# songs - integer or range
|
9
|
-
def playlist_info(songs = nil)
|
10
|
-
argument = songs.is_a?(Range) ? "#{songs.begin}:#{songs.end}" : songs
|
11
|
-
response = execute "playlistinfo #{argument}"
|
12
|
-
Playlist.from_response(response)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module MPD
|
2
|
-
class Client
|
3
|
-
module Commands
|
4
|
-
# https://www.musicpd.org/doc/protocol/playback_commands.html
|
5
|
-
module PlaybackControl
|
6
|
-
def play(position: nil, id: nil)
|
7
|
-
raise(ArgumentError, 'too many arguments') if position && id
|
8
|
-
|
9
|
-
if position
|
10
|
-
execute "play #{position}"
|
11
|
-
elsif id
|
12
|
-
execute "playid #{id}"
|
13
|
-
else
|
14
|
-
execute 'pause 0'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def pause
|
19
|
-
execute 'pause 1'
|
20
|
-
end
|
21
|
-
|
22
|
-
def stop
|
23
|
-
execute 'stop'
|
24
|
-
end
|
25
|
-
|
26
|
-
def previous
|
27
|
-
execute 'previous'
|
28
|
-
end
|
29
|
-
|
30
|
-
def next
|
31
|
-
execute 'next'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module MPD
|
2
|
-
class Client
|
3
|
-
module Commands
|
4
|
-
# https://www.musicpd.org/doc/protocol/playback_option_commands.html
|
5
|
-
module PlaybackOptions
|
6
|
-
def consume(state)
|
7
|
-
execute "consume #{state ? 1 : 0}"
|
8
|
-
end
|
9
|
-
|
10
|
-
def crossfade(state)
|
11
|
-
execute "crossfade #{state ? 1 : 0}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def random(state)
|
15
|
-
execute "random #{state ? 1 : 0}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def repeat(state)
|
19
|
-
execute "repeat #{state ? 1 : 0}"
|
20
|
-
end
|
21
|
-
|
22
|
-
def single(state)
|
23
|
-
execute "single #{state ? 1 : 0}"
|
24
|
-
end
|
25
|
-
|
26
|
-
def volume(val)
|
27
|
-
execute "setvol #{val}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def change_volume_by(val)
|
31
|
-
execute("volume #{val}")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
module MPD
|
4
|
-
class Client
|
5
|
-
#
|
6
|
-
# It's `Client`'s internal class. Don't use it outside `Client`
|
7
|
-
#
|
8
|
-
class Connection
|
9
|
-
def initialize(host:, port:)
|
10
|
-
@host = host
|
11
|
-
@port = port
|
12
|
-
end
|
13
|
-
|
14
|
-
def connect
|
15
|
-
disconnect if socket
|
16
|
-
@socket = TCPSocket.open(host, port)
|
17
|
-
end
|
18
|
-
|
19
|
-
def disconnect
|
20
|
-
socket && socket.close
|
21
|
-
@socket = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
def puts(text)
|
25
|
-
raise ConnectionError unless socket
|
26
|
-
socket.puts(text)
|
27
|
-
end
|
28
|
-
|
29
|
-
def gets
|
30
|
-
raise ConnectionError unless socket
|
31
|
-
socket.gets
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_reader :socket, :host, :port
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module MPD
|
2
|
-
class Client
|
3
|
-
#
|
4
|
-
# Just a frozen string with some useful methods
|
5
|
-
#
|
6
|
-
class ServerResponse < String
|
7
|
-
def self.from_connection(conn)
|
8
|
-
line = ''
|
9
|
-
buffer = ''
|
10
|
-
while line != "OK\n" && !line.start_with?('ACK')
|
11
|
-
line = conn.gets
|
12
|
-
raise(ConnectionError) if line.nil?
|
13
|
-
buffer << line
|
14
|
-
end
|
15
|
-
|
16
|
-
new(buffer.force_encoding('UTF-8'))
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(response_text)
|
20
|
-
super
|
21
|
-
freeze
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_h
|
25
|
-
key_value_pairs.to_h
|
26
|
-
end
|
27
|
-
|
28
|
-
def key_value_pairs
|
29
|
-
content.split("\n").map do |line|
|
30
|
-
index = line.index(':')
|
31
|
-
raise "can't create key-value pair" unless index
|
32
|
-
key = line[0...index]
|
33
|
-
value = line[(index + 1)..-1].strip
|
34
|
-
[key, value]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# text without status
|
39
|
-
def content
|
40
|
-
lines[0..-2].join
|
41
|
-
end
|
42
|
-
|
43
|
-
def status
|
44
|
-
lines.last.chomp
|
45
|
-
end
|
46
|
-
|
47
|
-
def error?
|
48
|
-
status.start_with?('ACK')
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|