lib/mpd: do not crash when connection fails
[nit.git] / lib / mpd.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Client for a MPD server
18 module mpd
19
20 import socket
21
22 # Connection to a MPD server
23 class MPDConnection
24 var socket: nullable Socket = null
25
26 var host: String
27 var port: Int
28 var password: nullable String
29
30 var error: nullable String = null
31
32 # Connect to the MPD server
33 fun connect
34 do
35 var p: nullable Socket = null
36
37 p = new Socket.stream_with_host(host, port)
38 p.connect
39
40 sys.nanosleep(0,5000)
41
42 var rep = p.read
43 assert not rep.is_empty
44 if not rep.has_prefix("OK") then
45 print "MPD responded {rep}"
46 abort
47 end
48
49 socket = p
50
51 var password = password
52 if password != null then
53 write_and_check("password {password}\n")
54 end
55 end
56
57 # Write a command to the MPD server
58 protected fun write_and_check(msg: String)
59 do
60 if socket == null then connect
61
62 socket.write(msg)
63 sys.nanosleep(0,5000)
64 var rep = socket.read
65 if not rep.has_prefix("OK") then
66 print "Error: MPD responded {rep}"
67 socket.close
68 socket = null
69 end
70 end
71
72 # Get MPD server status
73 fun status: nullable ServerStatus
74 do
75 if socket == null then connect
76
77 var volume: nullable Int = null
78 var state: nullable String = null
79
80 # get current status
81 socket.write("status\n")
82 var rep = socket.read
83 for l in rep.split_with("\n") do
84 var words = l.split_with(" ")
85 if words.length > 1 then
86 var key = words[0].to_lower
87 var first_space = l.index_of(' ')
88 var rest = l.substring_from(first_space+1)
89 if key == "volume:" then
90 volume = rest.to_i
91 if volume == -1 then volume = null
92 else if key == "volume:" then
93 state = rest
94 end
95 end
96 end
97
98 if state != null then
99 return new ServerStatus(volume, state)
100 else
101 return null
102 end
103 end
104
105 # Set the volume relatively
106 fun relative_volume=(diff: Int)
107 do
108 if socket == null then connect
109
110 var status = status
111 if status != null then
112 var vol = status.volume
113 if vol != null then
114 var new_vol = vol + diff
115 new_vol = new_vol.max(0).min(100)
116 volume = new_vol
117 return
118 end
119 end
120
121 error = "Cannot get volume"
122 end
123
124 fun volume=(vol: Int) do write_and_check("setvol {vol}\n")
125
126 # Pause music playing on the MPD server
127 fun pause do write_and_check("pause\n")
128
129 # Stop music playing on the MPD server
130 fun stop do write_and_check("stop\n")
131
132 # Play music playing on the MPD server
133 fun play do write_and_check("play\n")
134
135 # Get information on the currently playing song on the MPD server
136 fun current_song: nullable SongInfo
137 do
138 if socket == null then connect
139
140 var album: nullable String = null
141 var artist: nullable String = null
142 var title: nullable String = null
143
144 socket.write("currentsong\n")
145 var rep = socket.read
146 for l in rep.split_with("\n") do
147 var words = l.split_with(" ")
148 if words.length > 1 then
149 var key = words[0].to_lower
150 var first_space = l.index_of(' ')
151 var rest = l.substring_from(first_space+1)
152 if key == "album:" then
153 album = rest
154 else if key == "artist:" then
155 artist = rest
156 else if key == "title:" then
157 title = rest
158 end
159 end
160 end
161
162 if album != null and artist != null and title != null then
163 return new SongInfo(album, artist, title)
164 else
165 return null
166 end
167 end
168 end
169
170 # MPD song info
171 class SongInfo
172 var album: String
173 var artist: String
174 var title: String
175 end
176
177 # MPD server status
178 class ServerStatus
179 var volume: nullable Int
180 var state: String
181 end