Dont let MPD@percentage go NaN
[amazing.git] / lib / amazing / widgets / mpd.rb
blobc1d768f76b89c5484ca95465122c3182b1218437
1 # Copyright (C) 2008 Dag Odenhall <dag.odenhall@gmail.com>
2 # Licensed under the Academic Free License version 3.0
4 require 'amazing/widget'
5 require 'amazing/proc_file'
7 module Amazing
8   module Widgets
9     class MPD < Widget
10       description "MPD Information"
11       dependency "socket", "Ruby standard library"
12       option :hostname, "MPD server hostname", "localhost"
13       option :port, "MPD server port number", 6600
14       option :password, "Authentication password"
15       field :state, "Play state, :playing, :paused or :stopped"
16       field :artist, "Song artist"
17       field :title, "Song title"
18       field :length, "Song length"
19       field :position, "Song position"
20       field :date, "Song date from ID3 tag"
21       field :id, "Song ID in playlist"
22       field :genre, "Song genre"
23       field :album, "Song album"
24       field :file, "Filename of current song"
25       field :shortfile, "Filename without directory path and extension"
26       field :percentage, "Finished percentage of current song", 0.0
27       field :random, "True if playlist is on random"
28       field :repeat, "True if playlist is on repeat"
29       field :volume, "Volume of MPD mixer", 0
31       default do
32         track = "#{@artist && "#@artist - "}#@title"
33         track = @shortfile if track.empty?
34         case @state
35         when :playing
36           track
37         when :paused
38           "#{track} [paused]"
39         when :stopped
40           "[mpd not playing]"
41         end
42       end
44       init do
45         mpd = get_socket
46         status = send_command(:status)
47         @state = {:play => :playing, :pause => :paused, :stop => :stopped}[status["state"].to_sym]
48         @random = {0 => false, 1 => true}[status["random"].to_i]
49         @repeat = {0 => false, 1 => true}[status["repeat"].to_i]
50         @volume = status["volume"].to_i
51         if song = send_command(:currentsong)
52           @artist = song["Artist"]
53           @title = song["Title"]
54           len = song["Time"].to_i
55           minutes = (len / 60) % 60
56           seconds = len % 60
57           @length = "%d:%02d" % [minutes, seconds]
58           pos = status["time"].to_i
59           minutes = (pos / 60) % 60
60           seconds = pos % 60
61           @position = "%d:%02d" % [minutes, seconds]
62           @date = song["Date"]
63           @id = song["Id"].to_i
64           @genre = song["Genre"]
65           @album = song["Album"]
66           @file = song["file"]
67           @shortfile = ::File.basename(@file)
68           @shortfile = @shortfile[0..-::File.extname(@shortfile).length-1]
69           @percentage = pos == 0 ? 0.0 : pos / len.to_f * 100
70         end
71       end
73       private
75       def get_socket
76         @@connections ||= {}
77         mpd = nil
78         unless @@connections["#@identifier"]
79           @@connections["#@identifier"] = TCPSocket.new(@hostname, @port)
80           mpd = @@connections["#@identifier"]
81           mpd.gets
82           authenticate
83         else
84           mpd = @@connections["#@identifier"]
85           mpd.puts("ping")
86           unless mpd.gets
87             @@connections["#@identifier"] = TCPSocket.new(@hostname, @port)
88             mpd = @@connections["#@identifier"]
89             mpd.gets
90             authenticate
91           end
92         end
93         mpd
94       end
96       def authenticate
97         mpd = @@connections["#@identifier"]
98         if @password
99           mpd.puts("password #@password")
100           if mpd.gets.split[0] == "ACK"
101             raise WidgetError, "incorrect password"
102           end
103         end
104       end
106       def send_command(command)
107         mpd = @@connections["#@identifier"]
108         mpd.puts(command.to_s)
109         lines = []
110         loop do
111           line = mpd.gets
112           if line.split[0] == "ACK"
113             raise WidgetError, line.scan(/\{#{command}\} (.+)/).to_s
114           elsif line.split[0] == "OK"
115             return ProcFile.new(lines.join)[0]
116           else
117             lines << line
118           end
119         end
120       end
121     end
122   end