aboutsummaryrefslogtreecommitdiffstats
path: root/core/addon
diff options
context:
space:
mode:
Diffstat (limited to 'core/addon')
-rw-r--r--core/addon/activity/activity.rb245
-rw-r--r--core/addon/bugreport.rb7
-rw-r--r--core/addon/change_account.rb10
-rw-r--r--core/addon/extract.rb4
-rw-r--r--core/addon/image_file_cache/image_file_cache.rb2
-rw-r--r--core/addon/list/liststream.rb2
-rw-r--r--core/addon/profile.rb15
-rw-r--r--core/addon/search.rb3
-rw-r--r--core/addon/settings/builder.rb49
-rw-r--r--core/addon/settings/multiselect.rb67
-rw-r--r--core/addon/streaming.rb31
11 files changed, 412 insertions, 23 deletions
diff --git a/core/addon/activity/activity.rb b/core/addon/activity/activity.rb
new file mode 100644
index 00000000..32e54ab0
--- /dev/null
+++ b/core/addon/activity/activity.rb
@@ -0,0 +1,245 @@
+# -*- coding: utf-8 -*-
+# 通知管理プラグイン
+
+miquire :mui, 'tree_view_pretty_scroll'
+module Plugin::Activity
+ # アクティビティを更新する。
+ # ==== Args
+ # [kind] Symbol イベントの種類
+ # [title] タイトル
+ # [args] その他オプション。主に以下の値
+ # icon :: String|Gdk::Pixbuf アイコン
+ # date :: Time イベントの発生した時刻
+ # service :: Service 関係するServiceオブジェクト
+ # related :: 自分に関係するかどうかのフラグ
+ def activity(kind, title, args = {})
+ Plugin.call(:modify_activity,
+ { plugin: self,
+ kind: kind,
+ title: title,
+ date: Time.new,
+ description: title }.merge(args))
+ end
+end
+
+class Plugin
+ include Plugin::Activity
+
+ def self.activity(kind, title, args = {})
+ Plugin.call(:modify_activity,
+ { plugin: nil,
+ kind: kind,
+ title: title,
+ date: Time.new,
+ description: title }.merge(args))
+ end
+end
+
+Plugin.create(:activity) do
+ class ActivityView < Gtk::CRUD
+ include Gtk::TreeViewPrettyScroll
+
+ ICON = 0
+ KIND = 1
+ TITLE = 2
+ DATE = 3
+ PLUGIN = 4
+ ID = 5
+ SERVICE = 6
+ EVENT = 7
+
+ def initialize
+ super()
+ @creatable = @updatable = @deletable = false
+ end
+
+ def column_schemer
+ [{:kind => :pixbuf, :type => Gdk::Pixbuf, :label => 'icon'}, # ICON
+ {:kind => :text, :type => String, :label => '種類'}, # KIND
+ {:kind => :text, :type => String, :label => '説明'}, # TITLE
+ {:kind => :text, :type => String, :label => '時刻'}, # DATE
+ {:type => Plugin}, # PLUGIN
+ {:type => Integer}, # ID
+ {:type => Service}, # SERVICE
+ {:type => Hash} ].freeze # EVENT
+ end
+ end
+
+ BOOT_TIME = Time.new.freeze
+
+ # そのイベントをミュートするかどうかを返す(trueなら表示しない)
+ def mute?(params)
+ mute_kind = UserConfig[:activity_mute_kind]
+ if mute_kind.is_a? Array
+ return true if mute_kind.include? params[:kind].to_s end
+ mute_kind_related = UserConfig[:activity_mute_kind_related]
+ if mute_kind_related
+ return true if mute_kind_related.include?(params[:kind].to_s) and !params[:related] end
+ false end
+
+ activity_view = ActivityView.new
+ activity_vscrollbar = Gtk::VScrollbar.new(activity_view.vadjustment)
+ activity_hscrollbar = Gtk::HScrollbar.new(activity_view.hadjustment)
+ activity_shell = Gtk::Table.new(2, 2)
+ activity_description = Gtk::IntelligentTextview.new
+ activity_status = Gtk::Label.new
+ activity_container = Gtk::VBox.new
+
+ activity_container.
+ pack_start(activity_shell.
+ attach(activity_view, 0, 1, 0, 1, Gtk::FILL|Gtk::SHRINK|Gtk::EXPAND, Gtk::FILL|Gtk::SHRINK|Gtk::EXPAND).
+ attach(activity_vscrollbar, 1, 2, 0, 1, Gtk::FILL, Gtk::SHRINK|Gtk::FILL).
+ attach(activity_hscrollbar, 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::FILL)).
+ closeup(activity_description).
+ closeup(activity_status.right)
+
+ Delayer.new do
+ Plugin.call(:mui_tab_regist, activity_container, 'アクティビティ', MUI::Skin.get("underconstruction.png"))
+ end
+
+ activity_view.ssc("cursor-changed") { |this|
+ iter = this.selection.selected
+ if iter
+ activity_description.rewind(iter[ActivityView::EVENT][:description])
+ activity_status.set_text(iter[ActivityView::DATE])
+ end
+ false
+ }
+
+ # アクティビティ更新を受け取った時の処理
+ # plugin, kind, title, icon, date, service
+ on_modify_activity do |params|
+ if not mute?(params)
+ iter = activity_view.model.prepend
+ if params[:icon].is_a? String
+ iter[ActivityView::ICON] = Gdk::WebImageLoader.pixbuf(params[:icon], 24, 24){ |loaded_icon|
+ iter[ActivityView::ICON] = loaded_icon }
+ else
+ iter[ActivityView::ICON] = params[:icon] end
+ iter[ActivityView::KIND] = params[:kind].to_s
+ iter[ActivityView::TITLE] = params[:title].tr("\n", "")
+ iter[ActivityView::DATE] = params[:date].strftime('%Y/%m/%d %H:%M:%S')
+ iter[ActivityView::PLUGIN] = params[:plugin]
+ iter[ActivityView::ID] = 0
+ iter[ActivityView::SERVICE] = params[:service]
+ iter[ActivityView::EVENT] = params
+ if (UserConfig[:activity_show_timeline] || []).include?(params[:kind].to_s)
+ Plugin.call(:update, nil, [Message.new(message: params[:description], system: true, source: params[:plugin].to_s, created: params[:date])])
+ end
+ end
+ end
+
+ on_favorite do |service, user, message|
+ activity(:favorite, "#{message.user[:idname]}: #{message.to_s}",
+ description:("@#{user[:idname]} がふぁぼふぁぼしました\n"+
+ "@#{message.user[:idname]}: #{message.to_s}\n"+
+ "https://twitter.com/#!/#{message.user[:idname]}/statuses/#{message[:id]}"),
+ icon: user[:profile_image_url],
+ related: message.user.is_me? || user.is_me?,
+ service: service)
+ end
+
+ on_unfavorite do |service, user, message|
+ activity(:unfavorite, "#{message.user[:idname]}: #{message.to_s}",
+ description:("@#{user[:idname]} があんふぁぼしました\n"+
+ "@#{message.user[:idname]}: #{message.to_s}\n"+
+ "https://twitter.com/#!/#{message.user[:idname]}/statuses/#{message[:id]}"),
+ icon: user[:profile_image_url],
+ related: message.user.is_me? || user.is_me?,
+ service: service)
+ end
+
+ on_retweet do |retweets|
+ retweets.each { |retweet|
+ retweet.retweet_source_d.next{ |source|
+ activity(:retweet, retweet.to_s,
+ description:("@#{retweet.user[:idname]} がリツイートしました\n"+
+ "@#{source.user[:idname]}: #{source.to_s}\n"+
+ "https://twitter.com/#!/#{source.user[:idname]}/statuses/#{source[:id]}"),
+ icon: retweet.user[:profile_image_url],
+ date: retweet[:created],
+ related: (retweet.user.is_me? || source && source.user.is_me?),
+ service: Service.primary) }.terminate('リツイートソースが取得できませんでした') }
+ end
+
+ on_list_member_added do |service, user, list, source_user|
+ activity(:list_member_added, "@#{user[:idname]}が#{list[:full_name]}に追加されました",
+ description:("@#{user[:idname]} が #{list[:full_name]} に追加されました\n"+
+ "#{list[:description]} (by @#{list.user[:idname]})\n"+
+ "https://twitter.com/#!/#{list.user[:idname]}/#{list[:slug]}"),
+ icon: user[:profile_image_url],
+ related: user.is_me? || source_user.is_me?,
+ service: service)
+ end
+
+ on_list_member_removed do |service, user, list, source_user|
+ activity(:list_member_removed, "@#{user[:idname]}が#{list[:full_name]}から削除されました",
+ description:("@#{user[:idname]} が #{list[:full_name]} から削除されました\n"+
+ "#{list[:description]} (by @#{list.user[:idname]})\n"+
+ "https://twitter.com/#!/#{list.user[:idname]}/#{list[:slug]}"),
+ icon: user[:profile_image_url],
+ related: user.is_me? || source_user.is_me?,
+ service: service)
+ end
+
+ on_follow do |by, to|
+ activity(:follow, "@#{by[:idname]}が@#{to[:idname]}をフョローしました",
+ related: by.is_me? || to.is_me?,
+ icon: (to.is_me? ? by : to)[:profile_image_url])
+ end
+
+ on_direct_messages do |service, dms|
+ dms.each{ |dm|
+ date = Time.parse(dm[:created_at])
+ if date > BOOT_TIME
+ first_line = dm[:sender].is_me? ? "ダイレクトメッセージを送信しました" : "ダイレクトメッセージを受信しました"
+ activity(:dm, "D #{dm[:recipient][:idname]} #{dm[:text]}",
+ description: ("#{first_line}\n" +
+ "@#{dm[:sender][:idname]}: D #{dm[:recipient][:idname]} #{dm[:text]}"),
+ icon: dm[:sender][:profile_image_url],
+ service: service,
+ date: date) end }
+ end
+
+ onunload do
+ Addon.remove_tab 'アクティビティ'
+ end
+
+ settings "アクティビティ" do
+ settings "表示しないイベント" do
+ multiselect("以下の自分に関係ないイベント", :activity_mute_kind_related) do
+ option "retweet", "リツイート"
+ option "favorite", "ふぁぼ"
+ option "follow", "フォロー"
+ option "list_member_added", "リストに追加"
+ option "list_member_removed", "リストから削除"
+ option "dm", "ダイレクトメッセージ"
+ option "system", "システムメッセージ"
+ option "error", "エラー"
+ end
+
+ multiselect("以下の全てのイベント", :activity_mute_kind) do
+ option "retweet", "リツイート"
+ option "favorite", "ふぁぼ"
+ option "follow", "フォロー"
+ option "list_member_added", "リストに追加"
+ option "list_member_removed", "リストから削除"
+ option "dm", "ダイレクトメッセージ"
+ option "system", "システムメッセージ"
+ option "error", "エラー"
+ end
+ end
+
+ multiselect("タイムラインに表示", :activity_show_timeline) do
+ option "retweet", "リツイート"
+ option "favorite", "ふぁぼ"
+ option "follow", "フォロー"
+ option "list_member_added", "リストに追加"
+ option "list_member_removed", "リストから削除"
+ option "dm", "ダイレクトメッセージ"
+ option "system", "システムメッセージ"
+ option "error", "エラー"
+ end
+
+ end
+end
diff --git a/core/addon/bugreport.rb b/core/addon/bugreport.rb
index 35807f37..3f879aeb 100644
--- a/core/addon/bugreport.rb
+++ b/core/addon/bugreport.rb
@@ -91,11 +91,10 @@ Module.new do
http.post('/', eparam) }
File.delete(File.expand_path(File.join(Environment::TMPDIR, 'mikutter_error'))) rescue nil
File.delete(File.expand_path(File.join(Environment::TMPDIR, 'crashed_exception'))) rescue nil
- Plugin.call(:update, nil, [Message.new(:message => "エラー報告を送信しました。ありがとう♡",
- :system => true)])
+ Plugin.activity :system, "エラー報告を送信しました。ありがとう♡"
rescue TimeoutError, StandardError => e
- Plugin.call(:update, nil, [Message.new(:message => "#{e.to_s}ピャアアアアアアアアアアアアアアアアアアアアアアアwwwwwwwwwwwwwwwwwwwwww",
- :system => true)])
+ Plugin.activity :system, "ピャアアアアアアアアアアアアアアアアアアアアアアアwwwwwwwwwwwwwwwwwwwwww"
+ Plugin.activity :error, e.to_s, exception: e
end } end
def self.revision
diff --git a/core/addon/change_account.rb b/core/addon/change_account.rb
index 3a477669..414de440 100644
--- a/core/addon/change_account.rb
+++ b/core/addon/change_account.rb
@@ -34,7 +34,7 @@ Module.new do
main_windows = Plugin.filtering(:get_windows, Set.new).first
alert_thread = if(Thread.main != Thread.current) then Thread.current end
dialog = Gtk::Dialog.new(Environment::NAME + " ログイン")
- container, key, request_token = main(watch)
+ container, key, request_token = main(watch, dialog)
dialog.set_size_request(600, 400)
dialog.window_position = Gtk::Window::POS_CENTER
dialog.vbox.pack_start(container, true, true, 30)
@@ -89,7 +89,7 @@ Module.new do
Gtk::VBox.new(false, 0).closeup(attention).closeup(decide)
end
- def self.main(watch)
+ def self.main(watch, dialog)
goaisatsu = Gtk::VBox.new(false, 0)
box = Gtk::VBox.new(false, 8)
request_token = watch.request_oauth_token
@@ -97,16 +97,18 @@ Module.new do
# w.add(Gtk::Mumble.new(Message.new(:message => hello(url), :system => true))).show_all
# }
goaisatsu.add(Gtk::IntelligentTextview.new(hello(request_token.authorize_url)))
- user, key_input = gen_input('暗証番号', true)
+ user, key_input = gen_input('暗証番号', dialog, true)
box.closeup(goaisatsu).closeup(user)
return box, key_input, request_token
end
- def self.gen_input(label, visibility=true, default="")
+ def self.gen_input(label, dialog, visibility=true, default="")
container = Gtk::HBox.new(false, 0)
input = Gtk::Entry.new
input.text = default
input.visibility = visibility
+ input.signal_connect('activate') { |elm|
+ dialog.response(Gtk::Dialog::RESPONSE_OK) }
container.pack_start(Gtk::Label.new(label), false, true, 0)
container.pack_start(Gtk::Alignment.new(1.0, 0.5, 0, 0).add(input), true, true, 0)
return container, input
diff --git a/core/addon/extract.rb b/core/addon/extract.rb
index 161df116..72f23633 100644
--- a/core/addon/extract.rb
+++ b/core/addon/extract.rb
@@ -95,13 +95,13 @@ Module.new do
def hook_plugin(event)
Plugin.create(:extract).add_event(event){ |service, messages|
- tabclass.tabs.each{ |tab| tab.__send__("event_#{event}", messages) } }
+ tabclass.tabs.deach{ |tab| tab.__send__("event_#{event}", messages) } }
end
def boot_plugin
[:update,:mention,:posted].each{ |event| hook_plugin(event) }
Plugin.create(:extract).add_event(:appear){ |messages|
- tabclass.tabs.each{ |tab| tab.__send__("event_appear", messages) } }
+ tabclass.tabs.deach{ |tab| tab.__send__("event_appear", messages) } }
end
def tabclass
diff --git a/core/addon/image_file_cache/image_file_cache.rb b/core/addon/image_file_cache/image_file_cache.rb
index 4c307fa6..c2445794 100644
--- a/core/addon/image_file_cache/image_file_cache.rb
+++ b/core/addon/image_file_cache/image_file_cache.rb
@@ -9,7 +9,7 @@ Plugin.create :image_file_cache do
# appear_limit 回TLに出現したユーザはキャッシュに登録する
# (30分ツイートしなければカウンタはリセット)
onappear do |messages|
- messages.each { |message|
+ messages.deach { |message|
image_url = message.user[:profile_image_url]
if not j_include?(image_url)
appear_counter[image_url] ||= 0
diff --git a/core/addon/list/liststream.rb b/core/addon/list/liststream.rb
index 3949213c..01e71f81 100644
--- a/core/addon/list/liststream.rb
+++ b/core/addon/list/liststream.rb
@@ -33,7 +33,7 @@ Plugin::create(:liststream) do
member_anything - Plugin.filtering(:followings, Set.new).first end
def start
- service = Service.services.first
+ service = Service.primary
Thread.new{
loop{
sleep(3)
diff --git a/core/addon/profile.rb b/core/addon/profile.rb
index 96c3af4a..629c4662 100644
--- a/core/addon/profile.rb
+++ b/core/addon/profile.rb
@@ -30,11 +30,18 @@ Module.new do
if not locked[iter[1]]
locked[iter[1]] = true
flag = iter[0] # = !iter[0]
+ list = iter[2]
@service.__send__(flag ? :delete_list_member : :add_list_member,
- :list_id => iter[2]['id'],
+ :list_id => list['id'],
:user_id => user[:id]).next{ |result|
iter[0] = !flag if not(@list.destroyed?)
locked[iter[1]] = false
+ if flag
+ list.remove_member(user)
+ Plugin.call(:list_member_removed, @service, user, list, @service.user_obj)
+ else
+ list.add_member(user)
+ Plugin.call(:list_member_added, @service, user, list, @service.user_obj) end
}.terminate{ |e|
locked[iter[1]] = false
"@#{user[:idname]} をリスト #{iter[2]['name']} に追加できませんでした" } end }
@@ -102,7 +109,7 @@ Module.new do
@service.method(new ? :follow : :unfollow).call(user){ |event, msg|
case event
when :exit
- Plugin::call(new ? :followings_created : :followings_destroy, @service, [user])
+ Plugin.call(new ? :followings_created : :followings_destroy, @service, [user])
following = new
Delayer.new{
unless widget.destroyed?
@@ -191,8 +198,8 @@ Module.new do
makescreen(user, service) }
plugin.add_event(:boot){ |service|
set_contextmenu(plugin, service)
- Message::Entity.addlinkrule(:user_mentions, /(?:@|@|〄)[a-zA-Z0-9_]+/){ |segment|
- idname = segment[:url].match(/^(?:@|@|〄)?(.+)$/)[1]
+ Message::Entity.addlinkrule(:user_mentions, /(?:@|@|〄|☯|⑨|♨|(?:\W|^)D )[a-zA-Z0-9_]+/){ |segment|
+ idname = segment[:url].match(/^(?:@|@|〄|☯|⑨|♨|(?:\W|^)D )?(.+)$/)[1]
user = User.findbyidname(idname)
if user
makescreen(user, service)
diff --git a/core/addon/search.rb b/core/addon/search.rb
index 214f647a..1ba723b5 100644
--- a/core/addon/search.rb
+++ b/core/addon/search.rb
@@ -13,6 +13,9 @@ Module.new do
searchbtn = Gtk::Button.new('検索')
savebtn = Gtk::Button.new('保存')
+ querybox.signal_connect('activate'){ |elm|
+ searchbtn.clicked }
+
searchbtn.signal_connect('clicked'){ |elm|
elm.sensitive = querybox.sensitive = false
main.clear
diff --git a/core/addon/settings/builder.rb b/core/addon/settings/builder.rb
index 99d984c7..14d55cac 100644
--- a/core/addon/settings/builder.rb
+++ b/core/addon/settings/builder.rb
@@ -133,6 +133,40 @@ class Plugin::Setting < Gtk::VBox
container
end
+ # 複数テキストボックス
+ # 任意個の項目を入力させて、配列で受け取る。
+ # ==== Args
+ # [label] ラベル
+ # [config] 設定のキー
+ def multi(label, config)
+ settings(label) do
+ container, box = Gtk::HBox.new(false, 0), Gtk::VBox.new(false, 0)
+ input_ary = []
+ btn_add = Gtk::Button.new(Gtk::Stock::ADD)
+ array_converter = lambda {
+ c = Listener[config].get || []
+ (c.is_a?(Array) ? c : [c]).select(&ret_nth) }
+ add_button = lambda { |content|
+ input = Gtk::Entry.new
+ input.text = content.to_s
+ input.ssc(:changed) { |w|
+ Listener[config].set w.parent.children.map(&:text).select(&ret_nth) }
+ input.ssc('focus_out_event'){ |w|
+ w.parent.remove(w) if w.text.empty?
+ false }
+ box.closeup input
+ input }
+ input_ary = array_converter.call.each(&add_button)
+ btn_add.ssc(:clicked) { |w|
+ w.get_ancestor(Gtk::Window).set_focus(add_button.call("").show)
+ false }
+ container.pack_start(box, true, true, 0)
+ container.pack_start(Gtk::Alignment.new(1.0, 1.0, 0, 0).add(btn_add), false, true, 0)
+ closeup container
+ container
+ end
+ end
+
# 設定のグループ。関連の強い設定をカテゴライズできる。
# ==== Args
# [title] ラベル
@@ -213,6 +247,20 @@ class Plugin::Setting < Gtk::VBox
closeup container = builder.build(label, config)
container end
+ # 要素を複数個選択させる
+ # ==== Args
+ # [label] ラベル
+ # [config] 設定のキー
+ # [default]
+ # 連想配列で、 _値_ => _ラベル_ の形式で、デフォルト値を与える。
+ # _block_ と同時に与えれられたら、 _default_ の値が先に入って、 _block_ は後に入る。
+ # [&block] 内容
+ def multiselect(label, config, default = {})
+ builder = Plugin::Setting::MultiSelect.new(default)
+ builder.instance_eval(&Proc.new) if block_given?
+ closeup container = builder.build(label, config)
+ container end
+
private
def about_converter
Hash.new(ret_nth).merge!( :logo => lambda{ |value| Gtk::WebIcon.new(value).pixbuf rescue nil } ) end
@@ -236,4 +284,5 @@ class Plugin::Setting < Gtk::VBox
end
require File.expand_path File.join(File.dirname(__FILE__), 'select')
+require File.expand_path File.join(File.dirname(__FILE__), 'multiselect')
require File.expand_path File.join(File.dirname(__FILE__), 'listener')
diff --git a/core/addon/settings/multiselect.rb b/core/addon/settings/multiselect.rb
new file mode 100644
index 00000000..c17b3355
--- /dev/null
+++ b/core/addon/settings/multiselect.rb
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+require File.expand_path File.join(File.dirname(__FILE__), 'builder')
+require File.expand_path File.join(File.dirname(__FILE__), 'select')
+
+class Plugin::Setting::MultiSelect < Plugin::Setting::Select
+
+ # optionメソッドで追加された項目をウィジェットに組み立てる
+ # ==== Args
+ # [label] ラベル。文字列。
+ # [config] 設定のキー
+ # ==== Return
+ # ウィジェット
+ def build(label, config)
+ if has_widget?
+ group = Gtk::Frame.new.set_border_width(8)
+ group.set_label(label)
+ group.add(build_box(Plugin::Setting::Listener[config]))
+ group
+ else
+ group = Gtk::Frame.new.set_border_width(8).
+ set_label(label)
+ box = Plugin::Setting.new.set_border_width(4).
+ closeup(build_combobox(Plugin::Setting::Listener[config]))
+ group.add(box)
+ end end
+
+ private
+
+ def build_box(listener)
+ box = Gtk::VBox.new
+
+ options = @options
+ box.instance_eval{
+ options.each{ |value, face|
+ if face.is_a? String
+ closeup check = Gtk::CheckButton.new(face)
+ elsif face.is_a? Plugin::Setting
+ container = Gtk::HBox.new
+ check = Gtk::CheckButton.new
+ closeup container.closeup(check).add(face)
+ end
+ check.signal_connect('toggled'){ |widget|
+ if widget.active?
+ listener.set((listener.get || []) + [value])
+ else
+ listener.set((listener.get || []) - [value]) end
+ face.sensitive = widget.active? if face.is_a? Gtk::Widget }
+ check.active = (listener.get || []).include? value
+ face.sensitive = check.active? if face.is_a? Gtk::Widget } }
+ box end
+
+ # すべてテキストなら、コンボボックスで要素を描画する
+ def build_combobox(listener)
+ container = Gtk::VBox.new
+ sorted = @options.map{ |o| o.first }.sort_by(&:to_s).freeze
+ state = listener.get || []
+ sorted.each{ |node|
+ check = Gtk::CheckButton.new(@options.assoc(node).last)
+ check.active = state.include?(node)
+ check.signal_connect('toggled'){ |widget|
+ if widget.active?
+ listener.set((listener.get || []) + [node])
+ else
+ listener.set((listener.get || []) - [node]) end }
+ container.closeup check }
+ container end
+end
diff --git a/core/addon/streaming.rb b/core/addon/streaming.rb
index f1149a86..18cf2a96 100644
--- a/core/addon/streaming.rb
+++ b/core/addon/streaming.rb
@@ -59,7 +59,7 @@ Module.new do
yield(service, lock.synchronize{ data = events; events = Set.new; data.freeze }) }
rescue => e
error e
- abort end }
+ Plugin.activity :error, e.to_s, :exception => e end }
define_method("event_#{event_name}"){ |json|
type_strict json => tcor(Array, Hash)
service ||= @service
@@ -68,7 +68,7 @@ Module.new do
thread.wakeup
else
error "event_#{event_name}: event processing thread was dead."
- abort end } end
+ thread.join end } end
def start
unless @thread and @thread.alive?
@@ -96,16 +96,16 @@ Module.new do
event_direct_message(json['direct_message'])
when json['delete']
if Mopt.debug
- Plugin.call(:update, nil, [Message.new(:message => YAML.dump(json),
- :system => true)]) end
+ Plugin.activity :system, YAML.dump(json) end
+
when !json.has_key?('event')
# thread_storage(:update).push(json)
event_update(json)
when Mopt.debug
- Plugin.call(:update, nil, [Message.new(:message => YAML.dump(json),
- :system => true)])
+ Plugin.activity :system, YAML.dump(json)
end
rescue Exception => e
+ Plugin.activity :error, e.to_s, exception: e
notice e
end end
@@ -127,7 +127,8 @@ Module.new do
Plugin.call(event_name, service, data) } end
define_together_event(:direct_message) do |service, data|
- trigger_event(service, :direct_messages => data.map{ |datum| datum.symbolize }) end
+ trigger_event(service, :direct_messages => data.map{ |datum|
+ MikuTwitter::ApiCallSupport::Request::Parser.direct_message(datum.symbolize) }) end
define_event(:favorite) do |service, json|
by = MikuTwitter::ApiCallSupport::Request::Parser.user(json['source'].symbolize)
@@ -149,6 +150,22 @@ Module.new do
elsif(source.is_me?)
Plugin.call(:followings_created, service, [target]) end end
+ define_event(:list_member_added) do |service, json|
+ target_user = MikuTwitter::ApiCallSupport::Request::Parser.user(json['target'].symbolize) # リストに追加されたユーザ
+ list = MikuTwitter::ApiCallSupport::Request::Parser.list(json['target_object'].symbolize) # リスト
+ source_user = MikuTwitter::ApiCallSupport::Request::Parser.user(json['source'].symbolize) # 追加したユーザ
+ list.add_member(target_user)
+ Plugin.call(:list_member_added, service, target_user, list, source_user)
+ end
+
+ define_event(:list_member_removed) do |service, json|
+ target_user = MikuTwitter::ApiCallSupport::Request::Parser.user(json['target'].symbolize) # リストに追加されたユーザ
+ list = MikuTwitter::ApiCallSupport::Request::Parser.list(json['target_object'].symbolize) # リスト
+ source_user = MikuTwitter::ApiCallSupport::Request::Parser.user(json['source'].symbolize) # 追加したユーザ
+ list.remove_member(target_user)
+ Plugin.call(:list_member_removed, service, target_user, list, source_user)
+ end
+
def start_streaming(&proc)
begin
Plugin.call(:rewindstatus, 'UserStream: start')