doc: List the inner classes in the search bar.
[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.client(host, port)
38
39 sys.nanosleep(0,5000)
40
41 var rep = p.read(1024)
42 assert not rep.is_empty
43 if not rep.has_prefix("OK") then
44 print "MPD responded {rep}"
45 abort
46 end
47
48 socket = p
49
50 var password = password
51 if password != null then
52 write_and_check("password {password}\n")
53 end
54 end
55
56 # Write a command to the MPD server
57 protected fun write_and_check(msg: String)
58 do
59 if socket == null then connect
60
61 socket.write(msg)
62 sys.nanosleep(0,5000)
63 var rep = socket.read(1024)
64 if not rep.has_prefix("OK") then
65 print "Error: MPD responded {rep}"
66 socket.close
67 socket = null
68 end
69 end
70
71 # Get MPD server status
72 fun status: nullable ServerStatus
73 do
74 if socket == null then connect
75
76 var volume: nullable Int = null
77 var state: nullable String = null
78 var elapsed: nullable Int = null
79 var time_at: nullable Int = null
80 var time_total: nullable Int = null
81
82 # get current status
83 socket.write("status\n")
84 var rep = socket.read(1024)
85 for l in rep.split_with("\n") do
86 var words = l.split_with(" ")
87 if words.length > 1 then
88 var key = words[0].to_lower
89 var first_space = l.chars.index_of(' ')
90 var rest = l.substring_from(first_space+1)
91 if key == "volume:" then
92 volume = rest.to_i
93 if volume == -1 then volume = null
94 else if key == "state:" then
95 state = rest
96 else if key == "elapsed:" then
97 elapsed = rest.to_i
98 else if key == "time:" then
99 var times = rest.split(":")
100 time_at = times[0].to_i
101 time_total = times[1].to_i
102 end
103 end
104 end
105
106 if state != null then
107 var status = new ServerStatus(volume, state, elapsed, time_at, time_total)
108 return status
109 else
110 return null
111 end
112 end
113
114 # Set the volume relatively
115 fun relative_volume=(diff: Int)
116 do
117 if socket == null then connect
118
119 var status = status
120 if status != null then
121 var vol = status.volume
122 if vol != null then
123 var new_vol = vol + diff
124 new_vol = new_vol.max(0).min(100)
125 volume = new_vol
126 return
127 end
128 end
129
130 error = "Cannot get volume"
131 end
132
133 fun volume=(vol: Int) do write_and_check("setvol {vol}\n")
134
135 # Pause music playing on the MPD server
136 fun pause do write_and_check("pause\n")
137
138 # Stop music playing on the MPD server
139 fun stop do write_and_check("stop\n")
140
141 # Play music playing on the MPD server
142 fun play do write_and_check("play\n")
143
144 # Get information on the currently playing song on the MPD server
145 fun current_song: nullable SongInfo
146 do
147 if socket == null then connect
148
149 var album: nullable String = null
150 var artist: nullable String = null
151 var title: nullable String = null
152 var time: nullable Int = null
153
154 socket.write("currentsong\n")
155 var rep = socket.read(1024)
156 for l in rep.split_with("\n") do
157 var words = l.split_with(" ")
158 if words.length > 1 then
159 var key = words[0].to_lower
160 var first_space = l.chars.index_of(' ')
161 var rest = l.substring_from(first_space+1)
162 if key == "album:" then
163 album = rest
164 else if key == "artist:" then
165 artist = rest
166 else if key == "title:" then
167 title = rest
168 else if key == "time:" then
169 time = rest.to_i
170 end
171 end
172 end
173
174 if album != null and artist != null and
175 title != null and time != null then
176 return new SongInfo(album, artist, title, time)
177 else
178 return null
179 end
180 end
181
182 fun load_playlist(name: String)
183 do
184 write_and_check "load \"{name}\""
185 end
186 end
187
188 # MPD song info
189 class SongInfo
190 var album: String
191 var artist: String
192 var title: String
193 var time: Int
194 end
195
196 # MPD server status
197 class ServerStatus
198 var volume: nullable Int
199
200 var state: String
201 fun playing: Bool do return state == "play"
202 fun stopped: Bool do return state == "stop"
203
204 var elapsed: nullable Int
205 var time_at: nullable Int
206 var time_total: nullable Int
207 fun time_ratio: nullable Float do
208 if time_at == null or time_total == null then return null
209 return time_at.to_f / time_total.to_f
210 end
211
212 redef fun to_s do
213 var vol = "unknown"
214 if volume != null then vol = volume.to_s
215
216 var time_at = time_at
217 var time_total = time_total
218 var elapsed = elapsed
219 if time_at != null and time_total != null and elapsed != null then
220 return "volume: {vol}\nstate: {state}\nelapsed: {elapsed}\ntime_[at|total]: {time_at}:{time_total}\ntime_ratio: {time_ratio.as(not null)}"
221 else
222 return "volume: {vol}\nstate: {state}"
223 end
224 end
225 end