1(import [mpd.ffi [*]] ctypes)2(require [hy.contrib.walk [let]])34(setv libmpdserver (ctypes.CDLL "libmpdserver.so"))5(setv parse libmpdserver.mpd_parse)6(setv parse.restype (ctypes.POINTER MPDCmd))7(setv freecmd libmpdserver.mpd_free_command)89(defclass Range [object]10 (defn __init__ [self start &optional end]11 (setv self.start start)12 (setv self.end end))1314 (defn single? [self]15 (= self.start self.end))1617 (defn infinite? [self]18 (not self.end))1920 (defn to-range [self &optional max]21 (if (.single? self)22 (range self.start (inc self.end))23 (if (and (self.infinite?) (is None max))24 (raise (ValueError "Range has infinite length and no maximum supplied"))25 (range self.start self.end)))))2627(defclass Command [object]28 (defn __init__ [self cmd]29 (setv self.name (.decode cmd.name))30 (let [args (self.argv-list cmd.argc cmd.argv)]31 (setv self.args (list (map self.convert-argument args)))))3233 (defn list? [self]34 (or (= self.name "command_list_begin")35 (= self.name "command_list_ok_begin")))3637 (defn argv-list [self argc argv]38 (lfor39 idx (range argc)40 (. (get argv idx) contents)))4142 (defn convert-argument [self arg]43 (let [t arg.type v arg.v]44 (cond45 [(= t MPDVal.INT) v.ival]46 [(= t MPDVal.UINT) v.uval]47 [(= t MPDVal.STR) (v.sval.decode)]48 [(= t MPDVal.FLOAT) v.fval]49 [(= t MPDVal.BOOL) v.bval]50 [(= t MPDVal.RANGE)51 (Range v.rval.start52 (if (= -1 v.rval.end) None v.rval.end))]53 [(= t MPDVal.CMD)54 (Command v.cmdval.contents)]55 [(= t MPDVal.EXPR)56 (raise (NotImplementedError "Expression not implemented yet"))]57 [True (raise (TypeError (+ "unknown type " (str t))))]))))5859(defn parse-command [string]60 (setv inptr (ctypes.c_char_p))61 (setv inptr.value (string.encode))62 (let [outptr (parse inptr)]63 (if (bool outptr)64 (let [cmd (Command outptr.contents)]65 (freecmd outptr)66 cmd)67 (raise (ValueError "not a valid MPD command")))))