emasaka-termtter 1.0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/History.txt +4 -0
  2. data/README.rdoc +100 -0
  3. data/Rakefile +55 -0
  4. data/bin/kill_termtter +22 -0
  5. data/bin/termtter +6 -0
  6. data/lib/plugins/addspace.rb +27 -0
  7. data/lib/plugins/april_fool.rb +15 -0
  8. data/lib/plugins/bomb.rb +39 -0
  9. data/lib/plugins/clear.rb +14 -0
  10. data/lib/plugins/command_plus.rb +47 -0
  11. data/lib/plugins/confirm.rb +12 -0
  12. data/lib/plugins/cool.rb +10 -0
  13. data/lib/plugins/countter.rb +23 -0
  14. data/lib/plugins/devel.rb +18 -0
  15. data/lib/plugins/direct_messages.rb +36 -0
  16. data/lib/plugins/en2ja.rb +11 -0
  17. data/lib/plugins/english.rb +25 -0
  18. data/lib/plugins/erb.rb +17 -0
  19. data/lib/plugins/exec_and_update.rb +14 -0
  20. data/lib/plugins/expand-tinyurl.rb +33 -0
  21. data/lib/plugins/fib.rb +28 -0
  22. data/lib/plugins/fib_filter.rb +14 -0
  23. data/lib/plugins/filter.rb +69 -0
  24. data/lib/plugins/graduatter.rb +8 -0
  25. data/lib/plugins/grass.rb +27 -0
  26. data/lib/plugins/group.rb +64 -0
  27. data/lib/plugins/growl.rb +52 -0
  28. data/lib/plugins/growl2.rb +143 -0
  29. data/lib/plugins/hatebu.rb +59 -0
  30. data/lib/plugins/history.rb +93 -0
  31. data/lib/plugins/ignore.rb +19 -0
  32. data/lib/plugins/keyword.rb +18 -0
  33. data/lib/plugins/l2.rb +25 -0
  34. data/lib/plugins/log.rb +73 -0
  35. data/lib/plugins/me.rb +10 -0
  36. data/lib/plugins/modify_arg_hook_sample.rb +7 -0
  37. data/lib/plugins/msagent.rb +38 -0
  38. data/lib/plugins/multi_reply.rb +27 -0
  39. data/lib/plugins/notify-send.rb +22 -0
  40. data/lib/plugins/notify-send2.rb +52 -0
  41. data/lib/plugins/open_url.rb +59 -0
  42. data/lib/plugins/otsune.rb +21 -0
  43. data/lib/plugins/outputz.rb +33 -0
  44. data/lib/plugins/pause.rb +3 -0
  45. data/lib/plugins/post_exec_hook_sample.rb +9 -0
  46. data/lib/plugins/pre_exec_hook_sample.rb +9 -0
  47. data/lib/plugins/primes.rb +30 -0
  48. data/lib/plugins/quicklook.rb +41 -0
  49. data/lib/plugins/random.rb +23 -0
  50. data/lib/plugins/reblog.rb +40 -0
  51. data/lib/plugins/reload.rb +3 -0
  52. data/lib/plugins/reply.rb +8 -0
  53. data/lib/plugins/retweet.rb +46 -0
  54. data/lib/plugins/reverse.rb +13 -0
  55. data/lib/plugins/say.rb +26 -0
  56. data/lib/plugins/scrape.rb +41 -0
  57. data/lib/plugins/screen-notify.rb +20 -0
  58. data/lib/plugins/screen.rb +24 -0
  59. data/lib/plugins/shell.rb +14 -0
  60. data/lib/plugins/shorturl_on_update.rb +36 -0
  61. data/lib/plugins/sl.rb +48 -0
  62. data/lib/plugins/spam.rb +16 -0
  63. data/lib/plugins/standard_plugins.rb +519 -0
  64. data/lib/plugins/stdout.rb +83 -0
  65. data/lib/plugins/storage.rb +55 -0
  66. data/lib/plugins/storage/DB.rb +37 -0
  67. data/lib/plugins/storage/status.rb +83 -0
  68. data/lib/plugins/storage/status_mook.rb +30 -0
  69. data/lib/plugins/switch_user.rb +22 -0
  70. data/lib/plugins/system_status.rb +33 -0
  71. data/lib/plugins/timer.rb +18 -0
  72. data/lib/plugins/translation.rb +38 -0
  73. data/lib/plugins/typable_id.rb +94 -0
  74. data/lib/plugins/update_editor.rb +53 -0
  75. data/lib/plugins/update_filter.rb +30 -0
  76. data/lib/plugins/uri-open.rb +66 -0
  77. data/lib/plugins/wassr_post.rb +22 -0
  78. data/lib/plugins/yhara.rb +148 -0
  79. data/lib/plugins/yhara_filter.rb +8 -0
  80. data/lib/plugins/yonda.rb +21 -0
  81. data/lib/termtter.rb +38 -0
  82. data/lib/termtter/api.rb +57 -0
  83. data/lib/termtter/client.rb +370 -0
  84. data/lib/termtter/command.rb +80 -0
  85. data/lib/termtter/config.rb +68 -0
  86. data/lib/termtter/config_setup.rb +38 -0
  87. data/lib/termtter/connection.rb +41 -0
  88. data/lib/termtter/hook.rb +31 -0
  89. data/lib/termtter/optparse.rb +14 -0
  90. data/lib/termtter/system_extensions.rb +161 -0
  91. data/lib/termtter/task.rb +17 -0
  92. data/lib/termtter/task_manager.rb +116 -0
  93. data/lib/termtter/version.rb +4 -0
  94. data/spec/plugins/cool_spec.rb +10 -0
  95. data/spec/plugins/english_spec.rb +19 -0
  96. data/spec/plugins/fib_spec.rb +15 -0
  97. data/spec/plugins/filter_spec.rb +18 -0
  98. data/spec/plugins/pause_spec.rb +8 -0
  99. data/spec/plugins/primes_spec.rb +15 -0
  100. data/spec/plugins/shell_spec.rb +10 -0
  101. data/spec/plugins/sl_spec.rb +8 -0
  102. data/spec/plugins/spam_spec.rb +4 -0
  103. data/spec/plugins/standard_plugins_spec.rb +23 -0
  104. data/spec/plugins/storage/DB_spec.rb +12 -0
  105. data/spec/plugins/storage/status_spec.rb +24 -0
  106. data/spec/spec_helper.rb +7 -0
  107. data/spec/termtter/client_spec.rb +255 -0
  108. data/spec/termtter/command_spec.rb +107 -0
  109. data/spec/termtter/config_spec.rb +111 -0
  110. data/spec/termtter/hook_spec.rb +78 -0
  111. data/spec/termtter/task_manager_spec.rb +78 -0
  112. data/spec/termtter/task_spec.rb +22 -0
  113. data/spec/termtter_spec.rb +29 -0
  114. data/test/friends_timeline.json +5 -0
  115. data/test/search.json +8 -0
  116. metadata +210 -0
@@ -0,0 +1,59 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'atomutil'
5
+
6
+ module Termtter::Client
7
+ register_command(
8
+ :name => :hatebu, :aliases => [],
9
+ :exec_proc => lambda {|arg|
10
+ if arg =~ /^(\d+)(.*)$/
11
+ id = $1.strip
12
+ comment = $2.strip
13
+ statuses = public_storage[:log].select { |s| s.id == id }
14
+ unless statuses.empty?
15
+ status = statuses.first
16
+ else
17
+ status = t.show(id).first
18
+ end
19
+ auth = auth = Atompub::Auth::Wsse.new({
20
+ :username => config.plugins.hatebu.username,
21
+ :password => config.plugins.hatebu.password,
22
+ })
23
+ link = Atom::Link.new({
24
+ :href => "http://twitter.com/#{status.user.screen_name}/status/#{status.id}",
25
+ :rel => 'related',
26
+ :type => 'text/html',
27
+ })
28
+ entry = Atom::Entry.new({
29
+ :link => link,
30
+ :title => 'dummy',
31
+ :summary => comment,
32
+ })
33
+ req = Net::HTTP::Post.new 'http://b.hatena.ne.jp/atom/post'
34
+ req['User-Agent'] = 'Mozilla/5.0'
35
+ req['Content-Type'] = 'application/atom+xml'
36
+ req['Slug'] = 'termtter'
37
+ req.body = entry.to_s
38
+ auth.authorize(req)
39
+ Net::HTTP.start('b.hatena.ne.jp', 80) do |http|
40
+ res = http.request(req)
41
+ end
42
+ end
43
+ },
44
+ :completion_proc => lambda {|cmd, args|
45
+ if args =~ /^(\d*)$/
46
+ find_status_id_candidates $1, "#{cmd} %s"
47
+ end
48
+ },
49
+ :help => ['hatebu ID', 'Hatena bookmark a status']
50
+ )
51
+ end
52
+
53
+ # hatebu.rb
54
+ # hatena bookmark it!
55
+ #
56
+ # config.plugins.hatebu.username = 'your-username-on-hatena'
57
+ # config.plugins.hatebu.password = 'your-password-on-hatena'
58
+ #
59
+ # hatebu 1114860346 [termtter][<82>±<82>ê<82>Í<82>·<82>²<82>¢]mattn++
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'zlib'
4
+
5
+ config.plugins.history.
6
+ set_default(:filename, Termtter::CONF_DIR + '/history')
7
+ config.plugins.history.
8
+ set_default(:keys, [:users, :status_ids])
9
+ config.plugins.history.
10
+ set_default(:max_of_history, 100)
11
+ config.plugins.history.
12
+ set_default(:enable_autosave, true)
13
+ config.plugins.history.
14
+ set_default(:autosave_interval, 3600)
15
+
16
+ module Termtter::Client
17
+ def self.load_history
18
+ filename = File.expand_path(config.plugins.history.filename)
19
+ keys = config.plugins.history.keys
20
+
21
+ if File.exist?(filename)
22
+ begin
23
+ history = Marshal.load Zlib::Inflate.inflate(File.read(filename))
24
+ end
25
+ if history
26
+ keys.each do |key|
27
+ public_storage[key] = history[key] if history[key]
28
+ end
29
+ Readline::HISTORY.push *history[:history] if history[:history]
30
+ puts "history loaded(#{File.size(filename)/1000}kb)"
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.save_history
36
+ filename = File.expand_path(config.plugins.history.filename)
37
+ keys = config.plugins.history.keys
38
+ history = { }
39
+ keys.each do |key|
40
+ history[key] = public_storage[key]
41
+ end
42
+ max_of_history = config.plugins.history.max_of_history
43
+ history[:history] = Readline::HISTORY.to_a.reverse.uniq.reverse
44
+ if history[:history].size > max_of_history
45
+ history[:history] = history[:history][-max_of_history..-1]
46
+ end
47
+
48
+ File.open(filename, 'w') do |f|
49
+ f.write Zlib::Deflate.deflate(Marshal.dump(history))
50
+ end
51
+ puts "history saved(#{File.size(filename)/1000}kb)"
52
+ end
53
+
54
+ register_hook(
55
+ :name => :history_initialize,
56
+ :points => [:initialize],
57
+ :exec_proc => lambda { load_history; logger.debug('load_history') }
58
+ )
59
+
60
+ register_hook(
61
+ :name => :history_exit,
62
+ :points => [:exit],
63
+ :exec_proc => lambda { save_history; logger.debug('save_history') }
64
+ )
65
+
66
+ if config.plugins.history.enable_autosave
67
+ Termtter::Client.add_task(:interval => config.plugins.history.autosave_interval,
68
+ :after => config.plugins.history.autosave_interval) do
69
+ save_history
70
+ end
71
+ end
72
+
73
+ register_command(
74
+ :name => :save,
75
+ :exec_proc => lambda{|arg|
76
+ save_history
77
+ },
78
+ :help => ['save', 'Save hisory']
79
+ )
80
+
81
+ register_command(
82
+ :name => :load,
83
+ :exec_proc => lambda{|arg|
84
+ load_history
85
+ },
86
+ :help => ['load', 'Load hisory']
87
+ )
88
+
89
+
90
+ end
91
+
92
+ # history.rb
93
+ # save log to file
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ config.filters.ignore.set_default(:words, [])
5
+
6
+ module Termtter::Client
7
+ add_filter do |statuses, _|
8
+ ignore_words = config.filters.ignore.words
9
+ statuses.delete_if do |s|
10
+ ignore_words.any? {|i| i =~ s.text }
11
+ end
12
+ end
13
+ end
14
+
15
+ # filter/ignore.rb
16
+ # ignore words
17
+ # setting
18
+ # config.filters.ignore.words = [ /ignore/, /words/ ]
19
+
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ config.set_default('plugins.keyword.keywords', [])
4
+
5
+ module Termtter
6
+ class Status
7
+ def has_keyword?
8
+ config.plugins.keyword.keywords.find { |k| k === self.text }
9
+ end
10
+ alias :has_keyword :has_keyword?
11
+ end
12
+ end
13
+
14
+ # keyword.rb
15
+ # provides a keyword watching method
16
+ # example config
17
+ # config.plugins.stdout.timeline_format = '<%= color(time, 90) %> <%= color(status, s.has_keyword ? 4 : status_color) %> <%= color(id, 90) %>'
18
+ # config.plugins.keyword.keywords = [ /motemen/ ]
data/lib/plugins/l2.rb ADDED
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ register_command(
5
+ :name => :list2,
6
+ :aliases => [:l2],
7
+ :exec_proc => lambda {|arg|
8
+ unless arg.empty?
9
+ targets = arg.split.uniq
10
+ statuses = targets ? targets.map { |target|
11
+ public_storage[:tweet][target]
12
+ }.flatten.uniq.compact.sort_by{ |s| s[:id]} : []
13
+ output(statuses, :search)
14
+ end
15
+ },
16
+ :completion_proc => lambda {|cmd, arg|
17
+ #todo
18
+ },
19
+ :help => ['list2,l2 A B (C..)', "List statuses of A's and B's (and C's..)"]
20
+ )
21
+ end
22
+
23
+ # l2.rb
24
+ # plugin 'l2'
25
+ # NOTE: l2.rb needs plugin/log
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ public_storage[:log] = []
5
+ public_storage[:tweet] = { }
6
+ config.plugins.log.set_default('max_size', 1/0.0)
7
+ config.plugins.log.set_default('print_max_size', 30)
8
+
9
+ register_hook(
10
+ :name => :log,
11
+ :points => [:pre_filter],
12
+ :exec_proc => lambda {|statuses, event|
13
+ # log(sequential storage)
14
+ public_storage[:log] += statuses
15
+ max_size = config.plugins.log.max_size
16
+ if public_storage[:log].size > max_size
17
+ public_storage[:log] = public_storage[:log][-max_size..-1]
18
+ end
19
+ public_storage[:log] = public_storage[:log].uniq.sort_by{|s| s.created_at} if statuses.first
20
+
21
+ # tweet(storage for each user)
22
+ statuses.each do |s|
23
+ public_storage[:tweet][s.user.screen_name] = [] unless public_storage[:tweet][s.user.screen_name]
24
+ public_storage[:tweet][s.user.screen_name] << s
25
+ end
26
+
27
+ statuses.map{ |s| s.user.screen_name}.uniq.each do |name|
28
+ public_storage[:tweet][name]
29
+ if public_storage[:tweet][name].size > max_size
30
+ public_storage[:tweet][name] = public_storage[:tweet][name][-max_size..-1]
31
+ end
32
+ end
33
+ }
34
+ )
35
+
36
+ register_command(
37
+ :name => :log,
38
+ :exec_proc => lambda{|arg|
39
+ if arg.empty?
40
+ # log
41
+ statuses = public_storage[:log]
42
+ print_max = config.plugins.log.print_max_size
43
+ print_max = 0 if statuses.size < print_max
44
+ output(statuses[-print_max..-1], :search)
45
+ else
46
+ # log (user) (max)
47
+ vars = arg.split(' ')
48
+ print_max = vars.last =~ /^\d+$/ ? vars.pop.to_i : config.plugins.log.print_max_size
49
+ id = vars
50
+ statuses = id.first ? public_storage[:log].select{ |s| id.include? s.user.screen_name} : public_storage[:log]
51
+ print_max = 0 if statuses.size < print_max
52
+ output(statuses[-print_max..-1], :search)
53
+ end
54
+ },
55
+ :completion_proc => lambda {|cmd, arg|
56
+ find_user_candidates arg, "#{cmd} %s"
57
+ },
58
+ :help => [ 'log (USER(S)) (MAX)', 'Show local log of the user(s)']
59
+ )
60
+
61
+ register_command(
62
+ :name => :search_log, :aliases => [:sl],
63
+ :exec_proc => lambda{|arg|
64
+ unless arg.strip.empty?
65
+ pat = Regexp.new arg
66
+ statuses = public_storage[:log].select { |s| s.text =~ pat }
67
+ output(statuses, :search)
68
+ end
69
+ },
70
+ :help => [ 'search_log WORD', 'Search log for WORD' ]
71
+ )
72
+
73
+ end
data/lib/plugins/me.rb ADDED
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Termtter::Client
3
+ register_command(
4
+ :name => :me, :aliases => [],
5
+ :exec_proc => lambda {|arg|
6
+ call_commands('list ' + config.user_name)
7
+ },
8
+ :help => ['me', 'show my timeline']
9
+ )
10
+ end
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Termtter::Client.register_hook(
4
+ :name => :modify_arg_hook_sample,
5
+ :points => [:modify_arg_for_update],
6
+ :exec_proc => lambda {|cmd, arg| arg + '\(^o^)/'}
7
+ )
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ raise 'msagent.rb runs only in windows' if RUBY_PLATFORM.downcase !~ /mswin(?!ce)|mingw|bccwin/
4
+ require 'win32ole'
5
+ require 'kconv'
6
+
7
+ agent = WIN32OLE.new('Agent.Control.2')
8
+ agent.connected = true
9
+ agent.characters.load("Merlin", ENV['WINDIR'] + "\\msagent\\chars\\Merlin.acs")
10
+ achar = agent.characters.character("Merlin")
11
+ achar.languageID = 0x411
12
+ achar.show
13
+
14
+ Termtter::Client.register_hook(
15
+ :name => :msagent,
16
+ :points => [:output],
17
+ :exec_proc => lambda {|statuses, event|
18
+ if !statuses.empty? && event == :update_friends_timeline
19
+ Thread.start do
20
+ statuses.each do |s|
21
+ req = achar.speak("#{s.user.screen_name}: #{s.text}".tosjis)
22
+ sleep 1
23
+ WIN32OLE_EVENT.message_loop
24
+ achar.stop(req)
25
+ end
26
+ end
27
+ end
28
+ }
29
+ )
30
+
31
+ Termtter::Client.register_hook(
32
+ :name => :msagent_exit,
33
+ :points => [:exit],
34
+ :exec_proc => lambda {
35
+ achar.hide
36
+ GC.start
37
+ }
38
+ )
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ register_command(
5
+ :name => :multi_reply, :aliases => [:mr],
6
+ :exec_proc => lambda {|arg|
7
+ text = ERB.new(arg).result(binding).gsub(/\n/, ' ')
8
+ unless text.empty?
9
+ /(@(.+))*\s+(.+)/ =~ text
10
+ if $1
11
+ msg = $3
12
+ text = $1.split(/\s+/).map {|u| "#{u} #{msg}" }
13
+ end
14
+ Array(text).each do |post|
15
+ Termtter::API.twitter.update(post)
16
+ puts "=> #{post}"
17
+ end
18
+ end
19
+ },
20
+ :completion_proc => lambda {|cmd, args|
21
+ if /(.*)@([^\s]*)$/ =~ args
22
+ find_user_candidates $2, "#{cmd} #{$1}@%s"
23
+ end
24
+ },
25
+ :help => ["multi_reply,mp TEXT", "Reply to multi user"]
26
+ )
27
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Termtter::Client.register_hook(
4
+ :name => :notify_send,
5
+ :points => [:output],
6
+ :exec_proc => lambda {|statuses, event|
7
+ if event == :update_friends_timeline
8
+ max = 10
9
+
10
+ text = statuses.take(max).map {|s|
11
+ status_text = CGI.escapeHTML(s.text)
12
+ status_text.gsub!(%r{https?://[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+},'<a href="\0">\0</a>')
13
+ "<b>#{s.user.screen_name}:</b> <span font=\"9.0\">#{status_text}</span>"
14
+ }.join("\n")
15
+
16
+ text << %Q|\n<a href="http://twitter.com/">more...</a>| if statuses.size > max
17
+
18
+ system 'notify-send', 'Termtter', text, '-t', '60000'
19
+ end
20
+ }
21
+ )
22
+
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'fileutils'
4
+
5
+ config.plugins.notify_send.set_default(:icon_cache_dir, "#{Termtter::CONF_DIR}/tmp/user_profile_images")
6
+
7
+ FileUtils.mkdir_p(config.plugins.notify_send.icon_cache_dir) unless File.exist?(config.plugins.notify_send.icon_cache_dir)
8
+ Dir.glob("#{config.plugins.notify_send.icon_cache_dir}/*") {|f| File.delete(f) unless File.size?(f) }
9
+ unless File.exist?("#{config.plugins.notify_send.icon_cache_dir}/default.png")
10
+ File.open("#{config.plugins.notify_send.icon_cache_dir}/default.png", "wb") do |f|
11
+ f << open("http://static.twitter.com/images/default_profile_normal.png").read
12
+ end
13
+ end
14
+
15
+ def get_icon_path(s)
16
+ /https?:\/\/.+\/(\d+)\/.*?$/ =~ s.user.profile_image_url
17
+ cache_file = "%s/%s-%s%s" % [ config.plugins.notify_send.icon_cache_dir,
18
+ s.user.screen_name,
19
+ $+,
20
+ File.extname(s.user.profile_image_url) ]
21
+ unless File.exist?(cache_file)
22
+ Thread.new(s,cache_file) do |s,cache_file|
23
+ Dir.glob("#{config.plugins.notify_send.icon_cache_dir}/#{s.user.screen_name}-*") {|f| File.delete(f) }
24
+ begin
25
+ s.user.profile_image_url.sub!(/^https/,'http')
26
+ File.open(cache_file, 'wb') do |f|
27
+ f << open(URI.escape(s.user.profile_image_url)).read
28
+ end
29
+ rescue OpenURI::HTTPError
30
+ cache_file = "#{config.plugins.notify_send.icon_cache_dir}/default.png"
31
+ end
32
+ end
33
+ end
34
+ return cache_file
35
+ end
36
+
37
+ Termtter::Client.register_hook(
38
+ :name => :notify_send2,
39
+ :points => [:output],
40
+ :exec_proc => lambda {|statuses, event|
41
+ return unless event == :update_friends_timeline
42
+ Thread.start do
43
+ statuses.each do |s|
44
+ text = CGI.escapeHTML(s.text)
45
+ text.gsub!(%r{https?://[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+},'<a href="\0">\0</a>')
46
+ system 'notify-send', s.user.screen_name, text, '-i', get_icon_path(s)
47
+ sleep 0.1
48
+ end
49
+ end
50
+ }
51
+ )
52
+