mpd_client 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -3
- data/.travis.yml +6 -0
- data/CHANGELOG.md +26 -15
- data/Gemfile +2 -0
- data/LICENSE +2 -2
- data/MPD_COMMANDS.md +1 -1
- data/README.md +24 -2
- data/examples/albumart.rb +18 -0
- data/examples/client.rb +17 -0
- data/examples/range.rb +0 -1
- data/examples/rangeid.rb +0 -1
- data/examples/stickers.rb +1 -1
- data/lib/mpd_client/version.rb +1 -1
- data/lib/mpd_client.rb +200 -140
- data/mpd_client.gemspec +2 -2
- metadata +13 -28
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffc79b6fabba358c1dfb4009c4ae05d1dcf8e90aa2f197adc9ffe0eb539b5bba
|
4
|
+
data.tar.gz: 703ebecf1c53fb53e96ca24abcbe7ed7d17d4499973e860730ba621a8937f5ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 153b319bc45d272750a6df581be17694d3dd9ca57f3ce735fc8ba9598d7beff5097e0d4e773e4368e63db877d162a1e61f095dd8d0f04e2ec2f9b7c6c4a3ed89
|
7
|
+
data.tar.gz: 181f0c28e26f096fccef58f3848b25de4e7a06f6414bb38faea5fef7712904321bc10ee32e7d48cabc39c7230df937c6ba2b4a0dd9d437ebdc3bec0fd48c39eb
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,37 +1,48 @@
|
|
1
1
|
# MPD::Client CHANGELOG
|
2
2
|
|
3
|
+
## 0.3.0
|
4
|
+
|
5
|
+
- Require Ruby >= 3.2
|
6
|
+
|
7
|
+
## 0.2.0
|
8
|
+
|
9
|
+
- Tested with Ruby 3.1
|
10
|
+
- Add `albumart` command
|
11
|
+
- Add `readpicture` command
|
12
|
+
- Remove `playlist` command. Use `playlistinfo` instead
|
13
|
+
|
3
14
|
## 0.1.0
|
4
15
|
|
5
|
-
|
16
|
+
- Rename `MPDClient` to `MPD::Client`
|
6
17
|
|
7
18
|
## 0.0.6
|
8
19
|
|
9
|
-
|
20
|
+
- Fixed readcomments command
|
10
21
|
|
11
22
|
## 0.0.5
|
12
23
|
|
13
|
-
|
14
|
-
|
15
|
-
|
24
|
+
- Support for mount, umount, listmounts, listneighbors
|
25
|
+
- Support for listfiles
|
26
|
+
- Support for rangeid, addtagid, cleartagid
|
16
27
|
|
17
28
|
## 0.0.4
|
18
29
|
|
19
|
-
|
20
|
-
|
21
|
-
|
30
|
+
- Added support for readcomments, toggleoutput, volume
|
31
|
+
- Added a mutex protecting execution of MPD commands
|
32
|
+
- Automatic reconnect after the server dropped the connection
|
22
33
|
|
23
34
|
## 0.0.3
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
- Support for logging
|
37
|
+
- Better support for fetching stickers from MPD
|
38
|
+
- Fixed sticker commands
|
39
|
+
- Add support for ranges
|
29
40
|
|
30
41
|
## 0.0.2
|
31
42
|
|
32
|
-
|
33
|
-
|
43
|
+
- Support for connecting to unix domain sockets
|
44
|
+
- Fixed some bugs
|
34
45
|
|
35
46
|
## 0.0.1
|
36
47
|
|
37
|
-
|
48
|
+
- Porting code from mpd-python2
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2012 Anton Maminov
|
1
|
+
Copyright (c) 2012-2023 Anton Maminov
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/MPD_COMMANDS.md
CHANGED
@@ -102,7 +102,7 @@ If the optional `SUBSYSTEMS` argument is used, MPD will only send notifications
|
|
102
102
|
---
|
103
103
|
`mixrampdb {deciBels} => fetch_nothing`
|
104
104
|
|
105
|
-
> Sets the threshold at which songs will be overlapped. Like crossfading but doesn't fade the track volume, just overlaps. The songs need to have MixRamp tags added by an external tool. 0dB is the normalized maximum volume so use negative values, I prefer -17dB. In the absence of mixramp tags crossfading will be used. See [mixramp](https://
|
105
|
+
> Sets the threshold at which songs will be overlapped. Like crossfading but doesn't fade the track volume, just overlaps. The songs need to have MixRamp tags added by an external tool. 0dB is the normalized maximum volume so use negative values, I prefer -17dB. In the absence of mixramp tags crossfading will be used. See [mixramp](https://mpd.readthedocs.io/en/latest/user.html?highlight=mixramp#mixramp)
|
106
106
|
|
107
107
|
---
|
108
108
|
`mixrampdelay {SECONDS} => fetch_nothing`
|
data/README.md
CHANGED
@@ -31,6 +31,8 @@ gem install mpd_client
|
|
31
31
|
All functionality is contained in the `MPD::Client` class. Creating an instance of this class is as simple as:
|
32
32
|
|
33
33
|
```ruby
|
34
|
+
require 'mpd_client'
|
35
|
+
|
34
36
|
client = MPD::Client.new
|
35
37
|
```
|
36
38
|
|
@@ -64,6 +66,26 @@ client.status # insert the status command into the list
|
|
64
66
|
client.command_list_end # result will be a Array with the results
|
65
67
|
```
|
66
68
|
|
69
|
+
### Binary responses
|
70
|
+
|
71
|
+
Some commands can return binary data.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
require 'mpd_client'
|
75
|
+
|
76
|
+
client = MPD::Client.new
|
77
|
+
client.connect('localhost', 6600)
|
78
|
+
|
79
|
+
if (current_song = client.currentsong)
|
80
|
+
data, io = client.readpicture(current_song['file'])
|
81
|
+
io # StringIO
|
82
|
+
data # => {"size"=>"322860", "type"=>"image/jpeg", "binary"=>"3372"}
|
83
|
+
File.write('cover.jpg', io.string)
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
The above will locate album art for the current song and save image to `cover.jpg` file.
|
88
|
+
|
67
89
|
### Ranges
|
68
90
|
|
69
91
|
Some commands(e.g. `move`, `delete`, `load`, `shuffle`, `playlistinfo`) support integer ranges(`[START:END]`) as argument. This is done in `mpd_client` by using two element array:
|
@@ -103,7 +125,7 @@ client = MPD::Client.new
|
|
103
125
|
client.log = Logger.new($stderr)
|
104
126
|
```
|
105
127
|
|
106
|
-
For more information about logging configuration, see [Logger](https://ruby-doc.org/stdlib
|
128
|
+
For more information about logging configuration, see [Logger](https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html)
|
107
129
|
|
108
130
|
## Development
|
109
131
|
|
@@ -121,6 +143,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
121
143
|
|
122
144
|
## License and Author
|
123
145
|
|
124
|
-
Copyright (c)
|
146
|
+
Copyright (c) 2012-2023 by Anton Maminov
|
125
147
|
|
126
148
|
This library is distributed under the MIT license. Please see the LICENSE file.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup :default
|
5
|
+
|
6
|
+
require 'logger'
|
7
|
+
require 'mpd_client'
|
8
|
+
|
9
|
+
# MPD::Client.log = Logger.new($stderr)
|
10
|
+
|
11
|
+
client = MPD::Client.new
|
12
|
+
client.connect('localhost', 6600)
|
13
|
+
|
14
|
+
if (current_song = client.currentsong)
|
15
|
+
data, io = client.readpicture(current_song['file'])
|
16
|
+
puts data
|
17
|
+
File.write('cover.jpg', io.string)
|
18
|
+
end
|
data/examples/client.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup :default
|
5
|
+
|
6
|
+
require 'logger'
|
7
|
+
require 'mpd_client'
|
8
|
+
|
9
|
+
MPD::Client.log = Logger.new($stderr)
|
10
|
+
|
11
|
+
client = MPD::Client.new
|
12
|
+
client.connect('localhost', 6600)
|
13
|
+
|
14
|
+
puts client.stats
|
15
|
+
puts client.status
|
16
|
+
puts client.currentsong
|
17
|
+
puts client.playlistinfo
|
data/examples/range.rb
CHANGED
data/examples/rangeid.rb
CHANGED
data/examples/stickers.rb
CHANGED
data/lib/mpd_client/version.rb
CHANGED
data/lib/mpd_client.rb
CHANGED
@@ -1,131 +1,130 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'socket'
|
4
|
+
require 'stringio'
|
4
5
|
require 'mpd_client/version'
|
5
6
|
|
6
7
|
module MPD
|
7
8
|
HELLO_PREFIX = 'OK MPD '
|
8
9
|
ERROR_PREFIX = 'ACK '
|
9
|
-
SUCCESS =
|
10
|
-
NEXT =
|
10
|
+
SUCCESS = "OK\n"
|
11
|
+
NEXT = "list_OK\n"
|
11
12
|
|
12
|
-
# MPD changelog:
|
13
|
-
#
|
14
|
-
# http://git.musicpd.org/cgit/cirrus/mpd.git/plain/doc/protocol.xml
|
13
|
+
# MPD changelog: https://github.com/MusicPlayerDaemon/MPD/blob/master/NEWS
|
14
|
+
# Protocol: https://mpd.readthedocs.io/en/latest/protocol.html
|
15
15
|
COMMANDS = {
|
16
16
|
# Status Commands
|
17
|
-
'clearerror'
|
18
|
-
'currentsong'
|
19
|
-
'idle'
|
20
|
-
'noidle'
|
21
|
-
'status'
|
22
|
-
'stats'
|
17
|
+
'clearerror' => 'fetch_nothing',
|
18
|
+
'currentsong' => 'fetch_object',
|
19
|
+
'idle' => 'fetch_list',
|
20
|
+
'noidle' => '',
|
21
|
+
'status' => 'fetch_object',
|
22
|
+
'stats' => 'fetch_object',
|
23
23
|
# Playback Option Commands
|
24
|
-
'consume'
|
25
|
-
'crossfade'
|
26
|
-
'mixrampdb'
|
27
|
-
'mixrampdelay'
|
28
|
-
'random'
|
29
|
-
'repeat'
|
30
|
-
'setvol'
|
31
|
-
'single'
|
32
|
-
'replay_gain_mode'
|
24
|
+
'consume' => 'fetch_nothing',
|
25
|
+
'crossfade' => 'fetch_nothing',
|
26
|
+
'mixrampdb' => 'fetch_nothing',
|
27
|
+
'mixrampdelay' => 'fetch_nothing',
|
28
|
+
'random' => 'fetch_nothing',
|
29
|
+
'repeat' => 'fetch_nothing',
|
30
|
+
'setvol' => 'fetch_nothing',
|
31
|
+
'single' => 'fetch_nothing',
|
32
|
+
'replay_gain_mode' => 'fetch_nothing',
|
33
33
|
'replay_gain_status' => 'fetch_item',
|
34
|
-
'volume'
|
34
|
+
'volume' => 'fetch_nothing',
|
35
35
|
# Playback Control Commands
|
36
|
-
'next'
|
37
|
-
'pause'
|
38
|
-
'play'
|
39
|
-
'playid'
|
40
|
-
'previous'
|
41
|
-
'seek'
|
42
|
-
'seekid'
|
43
|
-
'seekcur'
|
44
|
-
'stop'
|
36
|
+
'next' => 'fetch_nothing',
|
37
|
+
'pause' => 'fetch_nothing',
|
38
|
+
'play' => 'fetch_nothing',
|
39
|
+
'playid' => 'fetch_nothing',
|
40
|
+
'previous' => 'fetch_nothing',
|
41
|
+
'seek' => 'fetch_nothing',
|
42
|
+
'seekid' => 'fetch_nothing',
|
43
|
+
'seekcur' => 'fetch_nothing',
|
44
|
+
'stop' => 'fetch_nothing',
|
45
45
|
# Playlist Commands
|
46
|
-
'add'
|
47
|
-
'addid'
|
48
|
-
'addtagid'
|
49
|
-
'cleartagid'
|
50
|
-
'clear'
|
51
|
-
'delete'
|
52
|
-
'deleteid'
|
53
|
-
'move'
|
54
|
-
'moveid'
|
55
|
-
'
|
56
|
-
'
|
57
|
-
'
|
58
|
-
'
|
59
|
-
'
|
60
|
-
'
|
61
|
-
'
|
62
|
-
'
|
63
|
-
'
|
64
|
-
'
|
65
|
-
'
|
66
|
-
'
|
67
|
-
'swapid' => 'fetch_nothing',
|
46
|
+
'add' => 'fetch_nothing',
|
47
|
+
'addid' => 'fetch_item',
|
48
|
+
'addtagid' => 'fetch_nothing',
|
49
|
+
'cleartagid' => 'fetch_nothing',
|
50
|
+
'clear' => 'fetch_nothing',
|
51
|
+
'delete' => 'fetch_nothing',
|
52
|
+
'deleteid' => 'fetch_nothing',
|
53
|
+
'move' => 'fetch_nothing',
|
54
|
+
'moveid' => 'fetch_nothing',
|
55
|
+
'playlistfind' => 'fetch_songs',
|
56
|
+
'playlistid' => 'fetch_songs',
|
57
|
+
'playlistinfo' => 'fetch_songs',
|
58
|
+
'playlistsearch' => 'fetch_songs',
|
59
|
+
'plchanges' => 'fetch_songs',
|
60
|
+
'plchangesposid' => 'fetch_changes',
|
61
|
+
'prio' => 'fetch_nothing',
|
62
|
+
'prioid' => 'fetch_nothing',
|
63
|
+
'rangeid' => 'fetch_nothing',
|
64
|
+
'shuffle' => 'fetch_nothing',
|
65
|
+
'swap' => 'fetch_nothing',
|
66
|
+
'swapid' => 'fetch_nothing',
|
68
67
|
# Stored Playlist Commands
|
69
|
-
'listplaylist'
|
70
|
-
'listplaylistinfo'
|
71
|
-
'listplaylists'
|
72
|
-
'load'
|
73
|
-
'playlistadd'
|
74
|
-
'playlistclear'
|
75
|
-
'playlistdelete'
|
76
|
-
'playlistmove'
|
77
|
-
'rename'
|
78
|
-
'rm'
|
79
|
-
'save'
|
68
|
+
'listplaylist' => 'fetch_list',
|
69
|
+
'listplaylistinfo' => 'fetch_songs',
|
70
|
+
'listplaylists' => 'fetch_playlists',
|
71
|
+
'load' => 'fetch_nothing',
|
72
|
+
'playlistadd' => 'fetch_nothing',
|
73
|
+
'playlistclear' => 'fetch_nothing',
|
74
|
+
'playlistdelete' => 'fetch_nothing',
|
75
|
+
'playlistmove' => 'fetch_nothing',
|
76
|
+
'rename' => 'fetch_nothing',
|
77
|
+
'rm' => 'fetch_nothing',
|
78
|
+
'save' => 'fetch_nothing',
|
80
79
|
# Database Commands
|
81
|
-
'count'
|
82
|
-
'find'
|
83
|
-
'findadd'
|
84
|
-
'list'
|
85
|
-
'listall'
|
86
|
-
'listallinfo'
|
87
|
-
'listfiles'
|
88
|
-
'lsinfo'
|
89
|
-
'search'
|
90
|
-
'searchadd'
|
91
|
-
'searchaddp1'
|
92
|
-
'update'
|
93
|
-
'rescan'
|
94
|
-
'readcomments'
|
80
|
+
'count' => 'fetch_object',
|
81
|
+
'find' => 'fetch_songs',
|
82
|
+
'findadd' => 'fetch_nothing',
|
83
|
+
'list' => 'fetch_list',
|
84
|
+
'listall' => 'fetch_database',
|
85
|
+
'listallinfo' => 'fetch_database',
|
86
|
+
'listfiles' => 'fetch_database',
|
87
|
+
'lsinfo' => 'fetch_database',
|
88
|
+
'search' => 'fetch_songs',
|
89
|
+
'searchadd' => 'fetch_nothing',
|
90
|
+
'searchaddp1' => 'fetch_nothing',
|
91
|
+
'update' => 'fetch_item',
|
92
|
+
'rescan' => 'fetch_item',
|
93
|
+
'readcomments' => 'fetch_object',
|
95
94
|
# Mounts and neighbors
|
96
|
-
'mount'
|
97
|
-
'unmount'
|
98
|
-
'listmounts'
|
99
|
-
'listneighbors'
|
95
|
+
'mount' => 'fetch_nothing',
|
96
|
+
'unmount' => 'fetch_nothing',
|
97
|
+
'listmounts' => 'fetch_mounts',
|
98
|
+
'listneighbors' => 'fetch_neighbors',
|
100
99
|
# Sticker Commands
|
101
|
-
'sticker get'
|
102
|
-
'sticker set'
|
103
|
-
'sticker delete'
|
104
|
-
'sticker list'
|
105
|
-
'sticker find'
|
100
|
+
'sticker get' => 'fetch_sticker',
|
101
|
+
'sticker set' => 'fetch_nothing',
|
102
|
+
'sticker delete' => 'fetch_nothing',
|
103
|
+
'sticker list' => 'fetch_stickers',
|
104
|
+
'sticker find' => 'fetch_songs',
|
106
105
|
# Connection Commands
|
107
|
-
'close'
|
108
|
-
'kill'
|
109
|
-
'password'
|
110
|
-
'ping'
|
106
|
+
'close' => '',
|
107
|
+
'kill' => '',
|
108
|
+
'password' => 'fetch_nothing',
|
109
|
+
'ping' => 'fetch_nothing',
|
111
110
|
# Audio Output Commands
|
112
|
-
'disableoutput'
|
113
|
-
'enableoutput'
|
114
|
-
'outputs'
|
115
|
-
'toggleoutput'
|
111
|
+
'disableoutput' => 'fetch_nothing',
|
112
|
+
'enableoutput' => 'fetch_nothing',
|
113
|
+
'outputs' => 'fetch_outputs',
|
114
|
+
'toggleoutput' => 'fetch_nothing',
|
116
115
|
# Reflection Commands
|
117
|
-
'config'
|
118
|
-
'commands'
|
119
|
-
'notcommands'
|
120
|
-
'tagtypes'
|
121
|
-
'urlhandlers'
|
122
|
-
'decoders'
|
116
|
+
'config' => 'fetch_item',
|
117
|
+
'commands' => 'fetch_list',
|
118
|
+
'notcommands' => 'fetch_list',
|
119
|
+
'tagtypes' => 'fetch_list',
|
120
|
+
'urlhandlers' => 'fetch_list',
|
121
|
+
'decoders' => 'fetch_plugins',
|
123
122
|
# Client To Client
|
124
|
-
'subscribe'
|
125
|
-
'unsubscribe'
|
126
|
-
'channels'
|
127
|
-
'readmessages'
|
128
|
-
'sendmessage'
|
123
|
+
'subscribe' => 'fetch_nothing',
|
124
|
+
'unsubscribe' => 'fetch_nothing',
|
125
|
+
'channels' => 'fetch_list',
|
126
|
+
'readmessages' => 'fetch_messages',
|
127
|
+
'sendmessage' => 'fetch_nothing'
|
129
128
|
}.freeze
|
130
129
|
|
131
130
|
# The `MPD::Client` is used for interactions with a MPD server.
|
@@ -160,6 +159,7 @@ module MPD
|
|
160
159
|
|
161
160
|
def add_command(name, retval)
|
162
161
|
escaped_name = name.tr(' ', '_')
|
162
|
+
|
163
163
|
define_method escaped_name.to_sym do |*args|
|
164
164
|
ensure_connected
|
165
165
|
|
@@ -169,6 +169,7 @@ module MPD
|
|
169
169
|
|
170
170
|
def remove_command(name)
|
171
171
|
raise "Can't remove not existent '#{name}' command" unless method_defined? name.to_sym
|
172
|
+
|
172
173
|
remove_method name.to_sym
|
173
174
|
end
|
174
175
|
end
|
@@ -188,11 +189,12 @@ module MPD
|
|
188
189
|
def reconnect
|
189
190
|
log&.info("MPD (re)connect #{@host}, #{@port}")
|
190
191
|
|
191
|
-
@socket =
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
192
|
+
@socket =
|
193
|
+
if @host.start_with?('/')
|
194
|
+
UNIXSocket.new(@host)
|
195
|
+
else
|
196
|
+
TCPSocket.new(@host, @port)
|
197
|
+
end
|
196
198
|
|
197
199
|
hello
|
198
200
|
@connected = true
|
@@ -216,15 +218,18 @@ module MPD
|
|
216
218
|
@connected
|
217
219
|
end
|
218
220
|
|
219
|
-
#
|
221
|
+
# https://www.musicpd.org/doc/protocol/command_lists.html
|
220
222
|
def command_list_ok_begin
|
221
223
|
raise 'Already in command list' unless @command_list.nil?
|
224
|
+
|
222
225
|
write_command('command_list_ok_begin')
|
226
|
+
|
223
227
|
@command_list = []
|
224
228
|
end
|
225
229
|
|
226
230
|
def command_list_end
|
227
231
|
raise 'Not in command list' if @command_list.nil?
|
232
|
+
|
228
233
|
write_command('command_list_end')
|
229
234
|
|
230
235
|
fetch_command_list
|
@@ -238,20 +243,28 @@ module MPD
|
|
238
243
|
# Sets the +logger+ used by this instance of MPD::Client
|
239
244
|
attr_writer :log
|
240
245
|
|
246
|
+
def albumart(uri)
|
247
|
+
fetch_binary(StringIO.new, 0, 'albumart', uri)
|
248
|
+
end
|
249
|
+
|
250
|
+
def readpicture(uri)
|
251
|
+
fetch_binary(StringIO.new, 0, 'readpicture', uri)
|
252
|
+
end
|
253
|
+
|
241
254
|
private
|
242
255
|
|
243
256
|
def ensure_connected
|
244
257
|
raise 'Please connect to MPD server' unless connected?
|
245
258
|
end
|
246
259
|
|
247
|
-
def execute(command,
|
260
|
+
def execute(command, *, retval)
|
248
261
|
@mutex.synchronize do
|
249
|
-
write_command(command, *
|
262
|
+
write_command(command, *)
|
250
263
|
|
251
|
-
if
|
252
|
-
@command_list << retval
|
253
|
-
else
|
264
|
+
if @command_list.nil?
|
254
265
|
eval retval
|
266
|
+
else
|
267
|
+
@command_list << retval
|
255
268
|
end
|
256
269
|
end
|
257
270
|
end
|
@@ -263,29 +276,33 @@ module MPD
|
|
263
276
|
reconnect
|
264
277
|
@socket.puts line
|
265
278
|
end
|
279
|
+
|
266
280
|
@socket.flush
|
267
281
|
end
|
268
282
|
|
269
283
|
def write_command(command, *args)
|
270
284
|
parts = [command]
|
285
|
+
|
271
286
|
args.each do |arg|
|
272
|
-
line =
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
287
|
+
line =
|
288
|
+
if arg.is_a?(Array)
|
289
|
+
arg.size == 1 ? "\"#{arg[0].to_i}:\"" : "\"#{arg[0].to_i}:#{arg[1].to_i}\""
|
290
|
+
else
|
291
|
+
"\"#{escape(arg)}\""
|
292
|
+
end
|
277
293
|
|
278
294
|
parts << line
|
279
295
|
end
|
280
|
-
|
296
|
+
|
281
297
|
log&.debug("Calling MPD: #{parts.join(' ')}")
|
282
298
|
write_line(parts.join(' '))
|
283
299
|
end
|
284
300
|
|
285
301
|
def read_line
|
286
|
-
line = @socket.gets
|
302
|
+
line = @socket.gets
|
303
|
+
|
287
304
|
raise 'Connection lost while reading line' unless line.end_with?("\n")
|
288
|
-
|
305
|
+
|
289
306
|
if line.start_with?(ERROR_PREFIX)
|
290
307
|
error = line[/#{ERROR_PREFIX}(.*)/, 1].strip
|
291
308
|
raise error
|
@@ -301,21 +318,22 @@ module MPD
|
|
301
318
|
line
|
302
319
|
end
|
303
320
|
|
304
|
-
def read_pair
|
321
|
+
def read_pair
|
305
322
|
line = read_line
|
323
|
+
|
306
324
|
return if line.nil?
|
307
|
-
pair = line.split(separator, 2)
|
308
|
-
raise "Could now parse pair: '#{line}'" if pair.size < 2
|
309
325
|
|
310
|
-
|
326
|
+
line.split(': ', 2)
|
311
327
|
end
|
312
328
|
|
313
|
-
def read_pairs
|
329
|
+
def read_pairs
|
314
330
|
result = []
|
315
|
-
|
331
|
+
|
332
|
+
pair = read_pair
|
333
|
+
|
316
334
|
while pair
|
317
335
|
result << pair
|
318
|
-
pair = read_pair
|
336
|
+
pair = read_pair
|
319
337
|
end
|
320
338
|
|
321
339
|
result
|
@@ -323,6 +341,7 @@ module MPD
|
|
323
341
|
|
324
342
|
def fetch_item
|
325
343
|
pairs = read_pairs
|
344
|
+
|
326
345
|
return nil if pairs.size != 1
|
327
346
|
|
328
347
|
pairs[0][1]
|
@@ -330,6 +349,7 @@ module MPD
|
|
330
349
|
|
331
350
|
def fetch_nothing
|
332
351
|
line = read_line
|
352
|
+
|
333
353
|
raise "Got unexpected value: #{line}" unless line.nil?
|
334
354
|
end
|
335
355
|
|
@@ -338,8 +358,11 @@ module MPD
|
|
338
358
|
seen = nil
|
339
359
|
|
340
360
|
read_pairs.each do |key, value|
|
361
|
+
value = value.chomp.force_encoding('utf-8')
|
362
|
+
|
341
363
|
if key != seen
|
342
364
|
raise "Expected key '#{seen}', got '#{key}'" unless seen.nil?
|
365
|
+
|
343
366
|
seen = key
|
344
367
|
end
|
345
368
|
|
@@ -352,14 +375,18 @@ module MPD
|
|
352
375
|
def fetch_objects(delimeters = [])
|
353
376
|
result = []
|
354
377
|
obj = {}
|
378
|
+
|
355
379
|
read_pairs.each do |key, value|
|
356
380
|
key = key.downcase
|
381
|
+
value = value.chomp.force_encoding('utf-8')
|
382
|
+
|
357
383
|
if delimeters.include?(key)
|
358
384
|
result << obj unless obj.empty?
|
359
385
|
obj = {}
|
360
386
|
elsif obj.include?(key)
|
361
387
|
obj[key] << value
|
362
388
|
end
|
389
|
+
|
363
390
|
obj[key] = value
|
364
391
|
end
|
365
392
|
|
@@ -374,6 +401,41 @@ module MPD
|
|
374
401
|
objs ? objs[0] : {}
|
375
402
|
end
|
376
403
|
|
404
|
+
def fetch_binary(io = StringIO.new, offset = 0, *)
|
405
|
+
data = {}
|
406
|
+
|
407
|
+
@mutex.synchronize do
|
408
|
+
write_command(*, offset)
|
409
|
+
|
410
|
+
binary = false
|
411
|
+
|
412
|
+
read_pairs.each do |item|
|
413
|
+
if binary
|
414
|
+
io << item.join(': ')
|
415
|
+
next
|
416
|
+
end
|
417
|
+
|
418
|
+
key = item[0]
|
419
|
+
value = item[1].chomp
|
420
|
+
|
421
|
+
binary = (key == 'binary')
|
422
|
+
|
423
|
+
data[key] = value
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
size = data['size'].to_i
|
428
|
+
binary = data['binary'].to_i
|
429
|
+
|
430
|
+
next_offset = offset + binary
|
431
|
+
|
432
|
+
return [data, io] if next_offset >= size
|
433
|
+
|
434
|
+
io.seek(-1, IO::SEEK_CUR)
|
435
|
+
|
436
|
+
fetch_binary(io, next_offset, *)
|
437
|
+
end
|
438
|
+
|
377
439
|
def fetch_changes
|
378
440
|
fetch_objects(['cpos'])
|
379
441
|
end
|
@@ -410,20 +472,13 @@ module MPD
|
|
410
472
|
fetch_objects(['playlist'])
|
411
473
|
end
|
412
474
|
|
413
|
-
def fetch_playlist
|
414
|
-
result = []
|
415
|
-
read_pairs(':').each do |_key, value|
|
416
|
-
result << value
|
417
|
-
end
|
418
|
-
|
419
|
-
result
|
420
|
-
end
|
421
|
-
|
422
475
|
def fetch_stickers
|
423
476
|
result = []
|
477
|
+
|
424
478
|
read_pairs.each do |_key, sticker|
|
425
479
|
value = sticker.split('=', 2)
|
426
480
|
raise "Could now parse sticker: #{sticker}" if value.size < 2
|
481
|
+
|
427
482
|
result << Hash[*value]
|
428
483
|
end
|
429
484
|
|
@@ -436,6 +491,7 @@ module MPD
|
|
436
491
|
|
437
492
|
def fetch_command_list
|
438
493
|
result = []
|
494
|
+
|
439
495
|
begin
|
440
496
|
@command_list.each do |retval|
|
441
497
|
result << (eval retval)
|
@@ -449,9 +505,13 @@ module MPD
|
|
449
505
|
|
450
506
|
def hello
|
451
507
|
line = @socket.gets
|
508
|
+
|
452
509
|
raise 'Connection lost while reading MPD hello' unless line.end_with?("\n")
|
510
|
+
|
453
511
|
line.chomp!
|
512
|
+
|
454
513
|
raise "Got invalid MPD hello: #{line}" unless line.start_with?(HELLO_PREFIX)
|
514
|
+
|
455
515
|
@mpd_version = line[/#{HELLO_PREFIX}(.*)/, 1]
|
456
516
|
end
|
457
517
|
|
data/mpd_client.gemspec
CHANGED
@@ -13,11 +13,11 @@ Gem::Specification.new do |gem|
|
|
13
13
|
|
14
14
|
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
15
15
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
16
|
-
gem.
|
16
|
+
gem.required_ruby_version = '>= 3.2'
|
17
17
|
gem.name = 'mpd_client'
|
18
18
|
gem.require_paths = ['lib']
|
19
19
|
gem.version = MPD::Client::VERSION
|
20
20
|
gem.license = 'MIT'
|
21
21
|
|
22
|
-
gem.
|
22
|
+
gem.metadata['rubygems_mfa_required'] = 'true'
|
23
23
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mpd_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Maminov
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
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.16'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.16'
|
11
|
+
date: 2023-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
27
13
|
description: Yet another Ruby MPD client library
|
28
14
|
email:
|
29
15
|
- anton.linux@gmail.com
|
@@ -36,7 +22,6 @@ files:
|
|
36
22
|
- ".gitignore"
|
37
23
|
- ".hound.yml"
|
38
24
|
- ".rubocop.yml"
|
39
|
-
- ".ruby-version"
|
40
25
|
- ".travis.yml"
|
41
26
|
- CHANGELOG.md
|
42
27
|
- Gemfile
|
@@ -46,6 +31,8 @@ files:
|
|
46
31
|
- bin/console
|
47
32
|
- bin/setup
|
48
33
|
- examples/Gemfile
|
34
|
+
- examples/albumart.rb
|
35
|
+
- examples/client.rb
|
49
36
|
- examples/idle.rb
|
50
37
|
- examples/range.rb
|
51
38
|
- examples/rangeid.rb
|
@@ -59,8 +46,9 @@ files:
|
|
59
46
|
homepage: https://github.com/mamantoha/mpd_client
|
60
47
|
licenses:
|
61
48
|
- MIT
|
62
|
-
metadata:
|
63
|
-
|
49
|
+
metadata:
|
50
|
+
rubygems_mfa_required: 'true'
|
51
|
+
post_install_message:
|
64
52
|
rdoc_options: []
|
65
53
|
require_paths:
|
66
54
|
- lib
|
@@ -68,18 +56,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
56
|
requirements:
|
69
57
|
- - ">="
|
70
58
|
- !ruby/object:Gem::Version
|
71
|
-
version: '
|
59
|
+
version: '3.2'
|
72
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
61
|
requirements:
|
74
62
|
- - ">="
|
75
63
|
- !ruby/object:Gem::Version
|
76
64
|
version: '0'
|
77
65
|
requirements: []
|
78
|
-
|
79
|
-
|
80
|
-
signing_key:
|
66
|
+
rubygems_version: 3.4.14
|
67
|
+
signing_key:
|
81
68
|
specification_version: 4
|
82
69
|
summary: Simple Music Player Daemon library written entirely in Ruby
|
83
|
-
test_files:
|
84
|
-
- spec/mpd_client/mpd_client_spec.rb
|
85
|
-
- spec/spec_helper.rb
|
70
|
+
test_files: []
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.5.1
|