snarl-snp 0.1.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/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