dag-amazing 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +202 -0
- data/README.rdoc +72 -0
- data/bin/amazing +19 -0
- data/lib/amazing.rb +24 -0
- data/lib/amazing/awesome.rb +46 -0
- data/lib/amazing/cli.rb +66 -0
- data/lib/amazing/cli/commands.rb +240 -0
- data/lib/amazing/cli/helpers.rb +159 -0
- data/lib/amazing/cli/initializers.rb +60 -0
- data/lib/amazing/config.rb +66 -0
- data/lib/amazing/config/dsl.rb +32 -0
- data/lib/amazing/config/dsl/awesome.rb +26 -0
- data/lib/amazing/config/dsl/awesome/widget.rb +27 -0
- data/lib/amazing/config/yaml.rb +11 -0
- data/lib/amazing/helpers/pango_markup.rb +26 -0
- data/lib/amazing/numeric.rb +50 -0
- data/lib/amazing/options.rb +93 -0
- data/lib/amazing/proc_file.rb +59 -0
- data/lib/amazing/string.rb +19 -0
- data/lib/amazing/widget.rb +140 -0
- data/lib/amazing/widgets.rb +37 -0
- data/lib/amazing/widgets/ac_adapter.rb +31 -0
- data/lib/amazing/widgets/alsa.rb +35 -0
- data/lib/amazing/widgets/battery.rb +51 -0
- data/lib/amazing/widgets/clock.rb +31 -0
- data/lib/amazing/widgets/cpu_info.rb +35 -0
- data/lib/amazing/widgets/cpu_usage.rb +50 -0
- data/lib/amazing/widgets/file.rb +44 -0
- data/lib/amazing/widgets/file_system.rb +42 -0
- data/lib/amazing/widgets/gmail.rb +61 -0
- data/lib/amazing/widgets/maildir.rb +34 -0
- data/lib/amazing/widgets/memory.rb +47 -0
- data/lib/amazing/widgets/moc.rb +80 -0
- data/lib/amazing/widgets/mpd.rb +146 -0
- data/lib/amazing/widgets/net_traffic.rb +50 -0
- data/lib/amazing/widgets/noop.rb +24 -0
- data/lib/amazing/widgets/pacman.rb +34 -0
- data/lib/amazing/widgets/raggle.rb +42 -0
- data/lib/amazing/widgets/sup.rb +38 -0
- data/lib/amazing/x11.rb +15 -0
- data/lib/amazing/x11/display_name.rb +50 -0
- metadata +101 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class Clock < Widget
|
20
|
+
description "Displays date and time"
|
21
|
+
option :format, "Time format as described in DATE(1)", "%R"
|
22
|
+
option :offset, "UTC offset in hours", Time.now.utc_offset / 3600
|
23
|
+
field :time, "Formatted time"
|
24
|
+
default { @time }
|
25
|
+
|
26
|
+
init do
|
27
|
+
@time = (Time.now.utc + @offset.to_f * 3600).strftime(@format)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
require 'amazing/proc_file'
|
17
|
+
|
18
|
+
module Amazing
|
19
|
+
module Widgets
|
20
|
+
|
21
|
+
# TODO: There might be more yummy stuff in /proc/cpuinfo
|
22
|
+
class CpuInfo < Widget
|
23
|
+
description "CPU Information"
|
24
|
+
option :cpu, "CPU number for default format (0 based)", 0
|
25
|
+
field :speed, "CPU Speed in MHz", []
|
26
|
+
default { @speed[@cpu].to_i }
|
27
|
+
|
28
|
+
init do
|
29
|
+
ProcFile.parse_file("cpuinfo").each_with_index do |info, cpu|
|
30
|
+
@speed[cpu] = info["cpu MHz"].to_f
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class CpuUsage < Widget
|
20
|
+
description "CPU usage"
|
21
|
+
option :cpu, "CPU number, 0 is all", 0
|
22
|
+
field :usage, "Percent of CPU in use", []
|
23
|
+
default { @usage[@cpu].to_i }
|
24
|
+
|
25
|
+
init do
|
26
|
+
first = gather_data()
|
27
|
+
sleep 1
|
28
|
+
second = gather_data()
|
29
|
+
first.each_index do |cpunum|
|
30
|
+
idle = second[cpunum][3].to_i - first[cpunum][3].to_i
|
31
|
+
sum = second[cpunum][0..5].inject {|a,b| a.to_i + b.to_i } -
|
32
|
+
first[cpunum][0..5].inject {|a,b| a.to_i + b.to_i }
|
33
|
+
@usage[cpunum] = 100 - (idle * 100) / sum.to_f
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def gather_data
|
40
|
+
cpus = []
|
41
|
+
::File.readlines("/proc/stat").select {|l| l =~ /^cpu/ }.each do |l|
|
42
|
+
l = l.split
|
43
|
+
cpunum = l[0] == "cpu" ? 0 : l[0].scan(/\d+/)[0].to_i + 1
|
44
|
+
cpus[cpunum] = l[1..-1]
|
45
|
+
end
|
46
|
+
cpus
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class File < Widget
|
20
|
+
description "Information for a file"
|
21
|
+
option :file, "The file to work with", ""
|
22
|
+
option :time_format, "Time format for timestamps as described in DATE(1)", "%c"
|
23
|
+
field :lines, "All the lines in the file", []
|
24
|
+
field :first, "The first line in the file", ""
|
25
|
+
field :last, "The last line in the file", ""
|
26
|
+
field :count, "Number of lines in the file", 0
|
27
|
+
field :atime, "Access time", Time.now.strftime("%c")
|
28
|
+
field :ctime, "Change time", Time.now.strftime("%c")
|
29
|
+
field :mtime, "Modification time", Time.now.strftime("%c")
|
30
|
+
default { @last }
|
31
|
+
|
32
|
+
init do
|
33
|
+
@file = ::File.expand_path(@file, "~")
|
34
|
+
@lines = ::File.readlines(@file).map {|line| line.chomp }
|
35
|
+
@first = @lines.first || ""
|
36
|
+
@last = @lines.last || ""
|
37
|
+
@count = @lines.size
|
38
|
+
@atime = ::File.atime(@file).strftime(@time_format)
|
39
|
+
@ctime = ::File.ctime(@file).strftime(@time_format)
|
40
|
+
@mtime = ::File.mtime(@file).strftime(@time_format)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class FileSystem < Widget
|
20
|
+
description "Various filesystem information"
|
21
|
+
option :mountpoint, "Mountpoint for default format", "/"
|
22
|
+
field :size, "Total size of volume in MB", {}
|
23
|
+
field :used, "Size of used data in MB", {}
|
24
|
+
field :free, "Size of free data in MB", {}
|
25
|
+
field :percentage, "Percentage of used space", {}
|
26
|
+
field :device, "Device name of mount point", {}
|
27
|
+
default { @percentage[@mountpoint] }
|
28
|
+
|
29
|
+
init do
|
30
|
+
IO.popen("df") do |io|
|
31
|
+
io.readlines[1..-1].map {|l| l.split }.each do |fs|
|
32
|
+
@device[fs[5]] = fs[0].to_s
|
33
|
+
@size[fs[5]] = fs[1].to_f / 1024
|
34
|
+
@used[fs[5]] = fs[2].to_f / 1024
|
35
|
+
@free[fs[5]] = fs[3].to_f / 1024
|
36
|
+
@percentage[fs[5]] = fs[4].to_i
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class Gmail < Widget
|
20
|
+
description "GMail checker"
|
21
|
+
dependency "net/https", "Ruby standard library"
|
22
|
+
dependency "rexml/document", "Ruby standard library"
|
23
|
+
dependency "time", "Ruby standard library"
|
24
|
+
option :username, "Username"
|
25
|
+
option :password, "Password"
|
26
|
+
option :certificates, "Path to SSL certificates", "/etc/ssl/certs"
|
27
|
+
option :verify, "Verify certificates", false
|
28
|
+
field :messages, "List of new messages"
|
29
|
+
field :count, "Number of new messages"
|
30
|
+
default { @count }
|
31
|
+
|
32
|
+
init do
|
33
|
+
http = Net::HTTP.new("mail.google.com", 443)
|
34
|
+
http.use_ssl = true
|
35
|
+
if @verify
|
36
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
37
|
+
http.ca_path = @certificates
|
38
|
+
else
|
39
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
40
|
+
end
|
41
|
+
request = Net::HTTP::Get.new("/mail/feed/atom")
|
42
|
+
request.basic_auth(@username, @password)
|
43
|
+
doc = REXML::Document.new(http.request(request).body)
|
44
|
+
begin
|
45
|
+
@messages = doc.elements.to_a("//entry").map do |e|
|
46
|
+
{:subject => e.elements["title"].text,
|
47
|
+
:summary => e.elements["summary"].text,
|
48
|
+
:from => e.elements.to_a("author").map do |a|
|
49
|
+
{:name => a.elements["name"].text,
|
50
|
+
:email => a.elements["email"].text}
|
51
|
+
end[0],
|
52
|
+
:date => Time.xmlschema(e.elements["issued"].text),
|
53
|
+
:link => e.elements["link"].attributes["href"]}
|
54
|
+
end
|
55
|
+
rescue
|
56
|
+
end
|
57
|
+
@count = doc.root.elements["fullcount"].text.to_i
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
|
17
|
+
module Amazing
|
18
|
+
module Widgets
|
19
|
+
class Maildir < Widget
|
20
|
+
description "Mail count in maildirs"
|
21
|
+
option :directories, "Globs of maildirs" # TODO: does a default make sense?
|
22
|
+
field :count, "Ammount of mail in searched directories", 0
|
23
|
+
default { @count }
|
24
|
+
|
25
|
+
init do
|
26
|
+
raise WidgetError, "No directories configured" unless @directories
|
27
|
+
@directories.to_a.each do |glob|
|
28
|
+
glob = ::File.expand_path(glob, "~")
|
29
|
+
@count += Dir["#{glob}/*"].size
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
require 'amazing/proc_file'
|
17
|
+
|
18
|
+
module Amazing
|
19
|
+
module Widgets
|
20
|
+
class Memory < Widget
|
21
|
+
description "Various memory related data"
|
22
|
+
field :total, "Total kilobytes of memory"
|
23
|
+
field :free, "Free kilobytes of memory"
|
24
|
+
field :buffers, "Buffered kilobytes of memory"
|
25
|
+
field :cached, "Cached kilobytes of memory"
|
26
|
+
field :usage, "Percentage of used memory"
|
27
|
+
field :swap_total, "Total kilobytes of swap"
|
28
|
+
field :swap_free, "Free kilobytes of swap"
|
29
|
+
field :swap_cached, "Cached kilobytes of swap"
|
30
|
+
field :swap_usage, "Percentage of used swap"
|
31
|
+
default { @usage.to_i }
|
32
|
+
|
33
|
+
init do
|
34
|
+
meminfo = ProcFile.parse_file("meminfo")[0]
|
35
|
+
@total = meminfo["MemTotal"].to_i
|
36
|
+
@free = meminfo["MemFree"].to_i
|
37
|
+
@buffers = meminfo["Buffers"].to_i
|
38
|
+
@cached = meminfo["Cached"].to_i
|
39
|
+
@usage = ((@total - @free - @cached - @buffers) * 100) / @total.to_f
|
40
|
+
@swap_total = meminfo["SwapTotal"].to_i
|
41
|
+
@swap_free = meminfo["SwapFree"].to_i
|
42
|
+
@swap_cached = meminfo["SwapCached"].to_i
|
43
|
+
@swap_usage = ((@swap_total - @swap_free - @swap_cached) * 100) / @swap_total.to_f
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
require 'amazing/proc_file'
|
17
|
+
|
18
|
+
module Amazing
|
19
|
+
module Widgets
|
20
|
+
class Moc < Widget
|
21
|
+
description "Music On Console status"
|
22
|
+
option :mocp, "Path to mocp program", "mocp"
|
23
|
+
field :state, "Play state, :playing, :paused or :stopped"
|
24
|
+
field :file, "Playing file"
|
25
|
+
field :title, "Title as seen by MOC"
|
26
|
+
field :artist, "Artist name"
|
27
|
+
field :song_title, "Song title"
|
28
|
+
field :album, "Album of song"
|
29
|
+
field :total_time, "Total length of song"
|
30
|
+
field :time_left, "Time left of playing song"
|
31
|
+
field :total_sec, "Total length of song in seconds"
|
32
|
+
field :current_time, "Current position in playing song"
|
33
|
+
field :current_sec, "Current position in playing song in seconds"
|
34
|
+
field :bitrate, "Song bitrate"
|
35
|
+
field :rate, "Song sample rate"
|
36
|
+
|
37
|
+
default do
|
38
|
+
case @state
|
39
|
+
when :playing
|
40
|
+
"#@artist - #@song_title"
|
41
|
+
when :paused
|
42
|
+
"#@artist - #@song_title [paused]"
|
43
|
+
when :stopped
|
44
|
+
"[moc not playing]"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
init do
|
49
|
+
moc = ProcFile.new(IO.popen("#@mocp --info"))[0]
|
50
|
+
@state = {:play => :playing, :pause => :paused, :stop => :stopped}[moc["State"].downcase.to_sym]
|
51
|
+
@file = moc["File"]
|
52
|
+
@title = moc["Title"]
|
53
|
+
@artist = moc["Artist"]
|
54
|
+
@song_title = moc["SongTitle"]
|
55
|
+
@album = moc["Album"]
|
56
|
+
@total_time = moc["TotalTime"]
|
57
|
+
@time_left = moc["TimeLeft"]
|
58
|
+
@total_sec = moc["TotalSec"].to_i
|
59
|
+
@current_time = moc["CurrentTime"]
|
60
|
+
@current_sec = moc["CurrentSec"].to_i
|
61
|
+
@bitrate = moc["Bitrate"]
|
62
|
+
@rate = moc["Rate"]
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def playing?
|
68
|
+
@state == :playing
|
69
|
+
end
|
70
|
+
|
71
|
+
def paused?
|
72
|
+
@state == :paused
|
73
|
+
end
|
74
|
+
|
75
|
+
def stopped?
|
76
|
+
@state == :stopped
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# Copyright 2008 Dag Odenhall <dag.odenhall@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'amazing/widget'
|
16
|
+
require 'amazing/proc_file'
|
17
|
+
|
18
|
+
module Amazing
|
19
|
+
module Widgets
|
20
|
+
class Mpd < Widget
|
21
|
+
description "MPD Information"
|
22
|
+
dependency "socket", "Ruby standard library"
|
23
|
+
option :hostname, "MPD server hostname", "localhost"
|
24
|
+
option :port, "MPD server port number", 6600
|
25
|
+
option :password, "Authentication password"
|
26
|
+
field :state, "Play state, :playing, :paused or :stopped"
|
27
|
+
field :artist, "Song artist"
|
28
|
+
field :title, "Song title"
|
29
|
+
field :length, "Song length"
|
30
|
+
field :position, "Song position"
|
31
|
+
field :date, "Song date from ID3 tag"
|
32
|
+
field :id, "Song ID in playlist"
|
33
|
+
field :genre, "Song genre"
|
34
|
+
field :album, "Song album"
|
35
|
+
field :file, "Filename of current song"
|
36
|
+
field :shortfile, "Filename without directory path and extension"
|
37
|
+
field :percentage, "Finished percentage of current song", 0.0
|
38
|
+
field :random, "True if playlist is on random"
|
39
|
+
field :repeat, "True if playlist is on repeat"
|
40
|
+
field :volume, "Volume of MPD mixer", 0
|
41
|
+
|
42
|
+
default do
|
43
|
+
track = "#{@artist && "#@artist - "}#@title"
|
44
|
+
track = @shortfile if track.empty?
|
45
|
+
case @state
|
46
|
+
when :playing
|
47
|
+
track
|
48
|
+
when :paused
|
49
|
+
"#{track} [paused]"
|
50
|
+
when :stopped
|
51
|
+
"[mpd not playing]"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
init do
|
56
|
+
mpd = get_socket
|
57
|
+
status = send_command(:status)
|
58
|
+
@state = {:play => :playing, :pause => :paused, :stop => :stopped}[status["state"].to_sym]
|
59
|
+
@random = {0 => false, 1 => true}[status["random"].to_i]
|
60
|
+
@repeat = {0 => false, 1 => true}[status["repeat"].to_i]
|
61
|
+
@volume = status["volume"].to_i
|
62
|
+
if song = send_command(:currentsong)
|
63
|
+
@artist = song["Artist"]
|
64
|
+
@title = song["Title"]
|
65
|
+
len = song["Time"].to_i
|
66
|
+
minutes = (len / 60) % 60
|
67
|
+
seconds = len % 60
|
68
|
+
@length = "%d:%02d" % [minutes, seconds]
|
69
|
+
pos = status["time"].to_i
|
70
|
+
minutes = (pos / 60) % 60
|
71
|
+
seconds = pos % 60
|
72
|
+
@position = "%d:%02d" % [minutes, seconds]
|
73
|
+
@date = song["Date"]
|
74
|
+
@id = song["Id"].to_i
|
75
|
+
@genre = song["Genre"]
|
76
|
+
@album = song["Album"]
|
77
|
+
@file = song["file"]
|
78
|
+
@shortfile = ::File.basename(@file)
|
79
|
+
@shortfile = @shortfile[0..-::File.extname(@shortfile).length-1]
|
80
|
+
@percentage = pos == 0 ? 0.0 : pos / len.to_f * 100
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def playing?
|
87
|
+
@state == :playing
|
88
|
+
end
|
89
|
+
|
90
|
+
def paused?
|
91
|
+
@state == :paused
|
92
|
+
end
|
93
|
+
|
94
|
+
def stopped?
|
95
|
+
@state == :stopped
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_socket
|
99
|
+
@@connections ||= {}
|
100
|
+
mpd = nil
|
101
|
+
unless @@connections["#@identifier"]
|
102
|
+
@@connections["#@identifier"] = TCPSocket.new(@hostname, @port)
|
103
|
+
mpd = @@connections["#@identifier"]
|
104
|
+
mpd.gets
|
105
|
+
authenticate
|
106
|
+
else
|
107
|
+
mpd = @@connections["#@identifier"]
|
108
|
+
mpd.puts("ping")
|
109
|
+
unless mpd.gets
|
110
|
+
@@connections["#@identifier"] = TCPSocket.new(@hostname, @port)
|
111
|
+
mpd = @@connections["#@identifier"]
|
112
|
+
mpd.gets
|
113
|
+
authenticate
|
114
|
+
end
|
115
|
+
end
|
116
|
+
mpd
|
117
|
+
end
|
118
|
+
|
119
|
+
def authenticate
|
120
|
+
mpd = @@connections["#@identifier"]
|
121
|
+
if @password
|
122
|
+
mpd.puts("password #@password")
|
123
|
+
if mpd.gets.split[0] == "ACK"
|
124
|
+
raise WidgetError, "incorrect password"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def send_command(command)
|
130
|
+
mpd = @@connections["#@identifier"]
|
131
|
+
mpd.puts(command.to_s)
|
132
|
+
lines = []
|
133
|
+
loop do
|
134
|
+
line = mpd.gets
|
135
|
+
if line.split[0] == "ACK"
|
136
|
+
raise WidgetError, line.scan(/\{#{command}\} (.+)/).to_s
|
137
|
+
elsif line.split[0] == "OK"
|
138
|
+
return ProcFile.new(lines.join)[0]
|
139
|
+
else
|
140
|
+
lines << line
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|