snarl-snp 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/GUIDE.rdoc.ja +126 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +144 -0
- data/README.rdoc.ja +166 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/exsample/ping.rb +8 -0
- data/exsample/winamp_nowplaying.rb +227 -0
- data/exsample/yahoo_weather.rb +35 -0
- data/lib/snarl/autotest.rb +112 -0
- data/lib/snarl/snp.rb +11 -0
- data/lib/snarl/snp/action.rb +138 -0
- data/lib/snarl/snp/config.rb +32 -0
- data/lib/snarl/snp/error.rb +76 -0
- data/lib/snarl/snp/request.rb +83 -0
- data/lib/snarl/snp/response.rb +36 -0
- data/lib/snarl/snp/snp.rb +142 -0
- data/snarl-snp.gemspec +78 -0
- data/spec/exsample/data/weather_yahoo_co_jp.html +608 -0
- data/spec/exsample/yahoo_weather_spec.rb +22 -0
- data/spec/snp/action_spec.rb +198 -0
- data/spec/snp/config_spec.rb +53 -0
- data/spec/snp/request_spec.rb +72 -0
- data/spec/snp/response_sprc.rb +96 -0
- data/spec/snp/snp_spec.rb +265 -0
- data/spec/spec_helper.rb +20 -0
- metadata +119 -0
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "snarl-snp"
|
8
|
+
gem.summary = %Q{Snarl Network Protocol Client. You can notify to Snarl over LAN.}
|
9
|
+
gem.description = %Q{Snarl Network Protocol Client. Snarl is the notification program for Windows. You can send notification messages to Snarl with SNP over LAN.}
|
10
|
+
gem.email = "ezookojo@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/kitamomonga/snarl-snp"
|
12
|
+
gem.authors = ["kitamomonga"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_development_dependency "webmock"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "snarl-snp #{version}"
|
44
|
+
rdoc.rdoc_files.include('README.rdoc*')
|
45
|
+
rdoc.rdoc_files.include('GUIDE.rdoc*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
data/exsample/ping.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
#!ruby -Ks
|
2
|
+
|
3
|
+
# require 'rubygems'
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(File.expand_path(__FILE__)), '/../lib/'))
|
5
|
+
require 'snarl/snp'
|
6
|
+
|
7
|
+
# You may use Winamp plugin "File Runner" (gen_runner.dll)
|
8
|
+
# http://www.geocities.jp/nanasiya3/ext.html#WA-GEN-RUNNER
|
9
|
+
#
|
10
|
+
# "File Runner" Command: "fullpath_rubyw_with_quote"
|
11
|
+
# "File Runner" Parameter: "fullpath_winamp_nowplaying.rb_with_quote" quoted_params
|
12
|
+
# quoted_params => "%artist%||%album%||%title%||%tracknumber%||%year%||%genre%||%comment%||%filename%||%index%||icon=>:album"
|
13
|
+
# or
|
14
|
+
# quoted_params => "%artist%||%album%||%title%||%tracknumber%||%year%||%genre%||%comment%||%filename%||%index%||icon=>c:\icon.jpg"
|
15
|
+
# icon=>:album means icon=>"#{File.dirname(%filename%)}\#{%album%}.[jpg|gif|png|bmp]"
|
16
|
+
# icon=>:loose means icon=>"Dir.glob(#{File.dirname(%filename%)}\**.[jpg|gif|png|bmp])[0]"
|
17
|
+
|
18
|
+
# just run me, and you will get parameters infomation.
|
19
|
+
# See WinampNowPlaying#warn_paramerter_infomation_and_exit.
|
20
|
+
class WinampNowPlaying
|
21
|
+
|
22
|
+
class MusicData
|
23
|
+
WINAMPDATA_ORDER = %w(artist album title tracknumber year genre comment filename index iconinfo)
|
24
|
+
def initialize(data)
|
25
|
+
@data = data
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](k) ; @data[k] ; end
|
29
|
+
def []=(k, v) ; @data[k] = v ; end
|
30
|
+
|
31
|
+
WINAMPDATA_ORDER.each do |mes|
|
32
|
+
eval("def #{mes} ; self['#{mes}'] ; end; def #{mes}=(v) ; self['#{mes}']=v ; end")
|
33
|
+
end
|
34
|
+
def icon_value
|
35
|
+
iconinfo.to_s.scan(/icon=>(.+?)\Z/).flatten[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
def query
|
39
|
+
WINAMPDATA_ORDER[0..-2].map do |e|
|
40
|
+
s = self.__send__(e)
|
41
|
+
if (s.nil? || s.empty?) then '' else s end
|
42
|
+
end.join('||')
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"#{query}||icon=>#{icon_value}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.parse(argv)
|
50
|
+
self.new(Hash[*WINAMPDATA_ORDER.zip(argv.join(" ").split(/\|\|/)).flatten])
|
51
|
+
end
|
52
|
+
def icon_mode
|
53
|
+
case
|
54
|
+
when /icon=>:album\Z/ =~ iconinfo then
|
55
|
+
:album
|
56
|
+
when /icon=>:loose\Z/ =~ iconinfo then
|
57
|
+
:loose
|
58
|
+
when /icon=>\Z|icon=>nil\Z|icon=>:default\Z/ =~ iconinfo then
|
59
|
+
:default
|
60
|
+
when iconinfo.nil? then
|
61
|
+
:default
|
62
|
+
else
|
63
|
+
:user
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
## Winamp data "icon=>xxxx"
|
69
|
+
# icon=>:album
|
70
|
+
# use "#{@album}.{gif,png,jpg,bmp}" ,if none, go :default
|
71
|
+
# icon=>:loose
|
72
|
+
# use "#{@album}.{gif,png,jpg,bmp}", if none, Dir.glob(*.{gif,png,jpg,bmp})[0] , or, go :default
|
73
|
+
# icon=>:default
|
74
|
+
# use Snarl Setting (maybe Snarl facemark)
|
75
|
+
# icon=>full_file_path_for_image
|
76
|
+
# use filepath for reading icon(i.e, C:\icon.jpg). separators are '\' or "/"
|
77
|
+
# icon=>image_url
|
78
|
+
# access url and use it
|
79
|
+
class Icon
|
80
|
+
|
81
|
+
ICON_EXTNAME = %w(gif png jpg bmp jpeg)
|
82
|
+
|
83
|
+
def initialize(d, strict = false)
|
84
|
+
@d = d
|
85
|
+
@albumdir = File.dirname(@d['filename']) #or Winamp %folder%
|
86
|
+
@strict = strict
|
87
|
+
end
|
88
|
+
|
89
|
+
def expecting_jacketimages
|
90
|
+
ICON_EXTNAME.map{|ext| File.join(@albumdir, "#{@d['album']}.#{ext}")}
|
91
|
+
end
|
92
|
+
|
93
|
+
def album_name_image
|
94
|
+
expecting_jacketimages.find{|path| FileTest.file?(path)}
|
95
|
+
end
|
96
|
+
|
97
|
+
def albumdir_entries
|
98
|
+
albumdir_glob = @albumdir.gsub(/\\/){'/'} + '/*'
|
99
|
+
Dir.glob(albumdir_glob)
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_image?(f)
|
103
|
+
/#{ICON_EXTNAME.join('|')}/ =~ f
|
104
|
+
end
|
105
|
+
|
106
|
+
def altanative_image
|
107
|
+
albumdir_entries.find{|file| is_image?(file)}
|
108
|
+
end
|
109
|
+
|
110
|
+
def user_image
|
111
|
+
@d.icon_value
|
112
|
+
end
|
113
|
+
|
114
|
+
def icon
|
115
|
+
# xxxx_image actually returns nil.
|
116
|
+
case @d.icon_mode
|
117
|
+
when :album then album_name_image || nil
|
118
|
+
when :loose then album_name_image || altanative_image || nil
|
119
|
+
when :default then nil
|
120
|
+
when :user then user_image || nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def initialize(host, port, &block)
|
126
|
+
warn_paramerter_infomation_and_exit if argv.empty?
|
127
|
+
|
128
|
+
@host = host || '127.0.0.1'
|
129
|
+
@port = port || 9887
|
130
|
+
# The following applications are registered with Snarl:
|
131
|
+
@app = "Winamp"
|
132
|
+
# Notification classes:
|
133
|
+
@class = "Now Playing"
|
134
|
+
# Message "First Line"
|
135
|
+
@title = "Winamp Now Playing:"
|
136
|
+
@text = nil
|
137
|
+
@icon = nil
|
138
|
+
|
139
|
+
@log_output = File.join(ENV['HOME'], 'snarl_winamp.log.txt')
|
140
|
+
@logger = defined?(Logger) ? Logger.new(@log_output) : nil
|
141
|
+
@data = MusicData.parse(argv)
|
142
|
+
|
143
|
+
yield(self) if block_given?
|
144
|
+
end
|
145
|
+
|
146
|
+
attr_writer :host, :app, :class, :title, :logger, :log_output, :text, :icon
|
147
|
+
attr_reader :data
|
148
|
+
|
149
|
+
def argv
|
150
|
+
ARGV
|
151
|
+
end
|
152
|
+
|
153
|
+
def icon
|
154
|
+
case
|
155
|
+
when %w(default system none).include?(@icon.to_s) then nil
|
156
|
+
when @icon.nil? then Icon.new(@data).icon
|
157
|
+
when %w(album).include?(@icon.to_s) then Icon.new(@data).icon
|
158
|
+
when @icon then @icon
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def text
|
163
|
+
# do not join with "\r\n"
|
164
|
+
case
|
165
|
+
when @text.kind_of?(Proc) then
|
166
|
+
res = @text.call(self)
|
167
|
+
when @text.kind_of?(String) then
|
168
|
+
res = @text
|
169
|
+
else
|
170
|
+
res = [@data.title, "#{@data.artist}/#{@data.album}"].join("\n")
|
171
|
+
end
|
172
|
+
res
|
173
|
+
end
|
174
|
+
|
175
|
+
def show_message
|
176
|
+
Snarl::SNP.open(@host, @port) do |c|
|
177
|
+
c.logger = @logger if @logger
|
178
|
+
c.register(@app)
|
179
|
+
c.add_class(@class)
|
180
|
+
c.notification(@title, text, icon, 8, @class)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def warn_paramerter_infomation_and_exit
|
185
|
+
require 'rbconfig'
|
186
|
+
warn 'You may use Winamp plugin "File Runner" (gen_runner.dll)'
|
187
|
+
warn 'http://www.geocities.jp/nanasiya3/ext.html#WA-GEN-RUNNER'
|
188
|
+
warn ''
|
189
|
+
|
190
|
+
# display path of rubyw.exe
|
191
|
+
if Config::CONFIG.has_key?('rubyw_install_name')
|
192
|
+
rubyw = File.join(Config::CONFIG['bindir'], Config::CONFIG['rubyw_install_name'])
|
193
|
+
warn %Q{"#{rubyw}"}
|
194
|
+
else
|
195
|
+
warn "*** rubyw is missing? ***"
|
196
|
+
end
|
197
|
+
# display where_am_i and Winamp param
|
198
|
+
me = File.expand_path(__FILE__)
|
199
|
+
params = WinampNowPlaying::MusicData::WINAMPDATA_ORDER[0..-2].map{|e| "%#{e}%"}.join('||')
|
200
|
+
param = "#{params}||icon=>:album"
|
201
|
+
warn %Q{"#{me}" "#{param}"}
|
202
|
+
exit(1)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
if $0 == __FILE__ then
|
207
|
+
WinampNowPlaying.new(ENV['SNARL_HOST'], ENV['SNARL_PORT']) do |amp|
|
208
|
+
## The following applications are registered with Snarl: / nil default
|
209
|
+
amp.app = "Winamp"
|
210
|
+
## Notification classes: /nil default
|
211
|
+
amp.class = "Now Playing"
|
212
|
+
## Message "First Line" / nil default
|
213
|
+
amp.title = "Winamp Now Playing:"
|
214
|
+
## Message Body / Proc is called, String is as-is, default is nil
|
215
|
+
amp.text = lambda{|x| "#{x.data.title}\n#{x.data.artist}\n#{x.data.album}"}
|
216
|
+
## Message Icon / path is path, :default is Snarl Setting, nil is album
|
217
|
+
## when nil, if playing dir has "#{@album}.{gif,png,jpg,bmp}", use it as Message icon.
|
218
|
+
# amp.icon = 'C:\icon.jpg'
|
219
|
+
|
220
|
+
## logger for SNP log output
|
221
|
+
# require 'logger'
|
222
|
+
# output_file = File.join(ENV['HOME'], 'winamp_nowplaying_log_for_rubyw.txt')
|
223
|
+
# amp.logger = Logger.new(output_file)
|
224
|
+
|
225
|
+
amp.show_message
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!ruby -Ku
|
2
|
+
require 'rubygems'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'nokogiri'
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(File.expand_path(__FILE__)), '/../lib/'))
|
6
|
+
require 'snarl/snp'
|
7
|
+
|
8
|
+
@uri = 'http://weather.yahoo.co.jp/weather/jp/1b/1400.html'
|
9
|
+
@host = ENV['SNARL_HOST'] || ARGV[0] || (if ARGV[0] == '-H' then ARGV[1] else nil end)
|
10
|
+
|
11
|
+
def encode_win(s)
|
12
|
+
if s.respond_to?(:encode) then
|
13
|
+
s.dup.encode(::Encoding::SHIFT_JIS)
|
14
|
+
else
|
15
|
+
require 'kconv'
|
16
|
+
s.tosjis
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
uri = URI.parse(@uri)
|
21
|
+
html = open(uri, 'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.50727; .NET CLR 1.1.4322)').read
|
22
|
+
doc = Nokogiri::HTML.parse(html, nil, 'EUC-JP')
|
23
|
+
|
24
|
+
place = doc.at('div#cat-pass p').inner_text.split(/>/).last.gsub(/\s+/){''}
|
25
|
+
table = doc.at('table.yjw_table tr')
|
26
|
+
weather = table.at('img')
|
27
|
+
|
28
|
+
title = encode_win("Yahoo! Weather\n#{place}")
|
29
|
+
text = encode_win(table.at('table').inner_text.gsub(/\s+/){''})
|
30
|
+
icon = weather['src']
|
31
|
+
|
32
|
+
Snarl::SNP.open(@host) do |snp|
|
33
|
+
snp.register('Ruby-Snarl')
|
34
|
+
snp.notification(title, text, icon, 20)
|
35
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'snp'
|
4
|
+
|
5
|
+
# Usage:
|
6
|
+
# On $HOME/.autotest.
|
7
|
+
# require 'snarl/autotest'
|
8
|
+
# Autotest::Snarl.host = '192.168.0.1'
|
9
|
+
module Autotest::Snarl
|
10
|
+
|
11
|
+
@snarl_host = '127.0.0.1'
|
12
|
+
@snarl_port = 9887
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :snarl_host, :snarl_port
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.host
|
19
|
+
ENV['SNARL_HOST'] || Autotest::Snarl.snarl_host
|
20
|
+
end
|
21
|
+
def self.host=(host)
|
22
|
+
Autotest::Snarl.snarl_host = host
|
23
|
+
end
|
24
|
+
def self.port
|
25
|
+
ENV['SNARL_PORT'] || Autotest::Snarl.snarl_port
|
26
|
+
end
|
27
|
+
def self.port=(port)
|
28
|
+
Autotest::Snarl.snarl_port = port.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
# Windows Snarl shortcut's "working folder" (left click property)
|
32
|
+
# %HOME%\Application Data\full phat\snarl\styles
|
33
|
+
def self.hostdir
|
34
|
+
"./"
|
35
|
+
end
|
36
|
+
def self.icon_ok
|
37
|
+
# %HOME%\Application Data\full phat\snarl\styles\ok.png works fine
|
38
|
+
"ok.png"
|
39
|
+
end
|
40
|
+
def self.icon_fail
|
41
|
+
"fail.png"
|
42
|
+
end
|
43
|
+
def self.icon_pending
|
44
|
+
"pending.png"
|
45
|
+
end
|
46
|
+
def self.app
|
47
|
+
"Autotest::Snarl"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.iconset
|
51
|
+
{
|
52
|
+
:green => File.join(hostdir, icon_ok),
|
53
|
+
:red => File.join(hostdir, icon_fail),
|
54
|
+
:yellow => File.join(hostdir, icon_pending), # TODO:
|
55
|
+
:info => nil
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.classes
|
60
|
+
{
|
61
|
+
'green' => 'test ok',
|
62
|
+
'red' => 'test fail',
|
63
|
+
'yellow' => 'test pending',
|
64
|
+
'info' => 'system message'
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.snarl(title, text, status = :info, timeout = nil)
|
69
|
+
Snarl::SNP.open(host, port){|c|
|
70
|
+
c.iconset(iconset)
|
71
|
+
c.register(app)
|
72
|
+
c.add_classes(classes)
|
73
|
+
c.notification(
|
74
|
+
:title => title,
|
75
|
+
:text => text,
|
76
|
+
:class => status.to_s,
|
77
|
+
:timeout => (timeout||10),
|
78
|
+
:icon => status)
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
Autotest.add_hook :run do |at|
|
83
|
+
snarl("Run", "Run", :info)
|
84
|
+
end
|
85
|
+
|
86
|
+
Autotest.add_hook :red do |at|
|
87
|
+
failed_tests = at.files_to_test.inject(0){ |s,a| k,v = a; s + v.size}
|
88
|
+
snarl("Tests Failed", "#{failed_tests} tests failed", :red)
|
89
|
+
end
|
90
|
+
|
91
|
+
Autotest.add_hook :green do |at|
|
92
|
+
# TODO: "All tests passed (and pending 3)"
|
93
|
+
snarl("Tests Passed", "All tests passed", :green)
|
94
|
+
end
|
95
|
+
|
96
|
+
Autotest.add_hook :run do |at|
|
97
|
+
snarl("autotest", "autotest was started", :info, 5) if $DEBUG
|
98
|
+
end
|
99
|
+
|
100
|
+
Autotest.add_hook :interrupt do |at|
|
101
|
+
snarl("autotest", "autotest was reset", :info, 5) if $DEBUG
|
102
|
+
end
|
103
|
+
|
104
|
+
Autotest.add_hook :quit do |at|
|
105
|
+
snarl("autotest", "autotest is exiting", :info, 5) if $DEBUG
|
106
|
+
end
|
107
|
+
|
108
|
+
Autotest.add_hook :all do |at|_hook
|
109
|
+
snarl("autotest", "Tests have fully passed", :green)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/lib/snarl/snp.rb
ADDED