提案 #1309 » load_more_timeline.patch
core/mui/cairo_timeline.rb | ||
---|---|---|
# ==== Args
|
||
# [iter] 削除するレコード(Gtk::TreeIter)
|
||
def tl_model_remove(iter)
|
||
Plugin.call(:gui_timeline_message_removed, @tl.imaginary, iter[Gtk::TimeLine::InnerTL::MESSAGE])
|
||
iter[InnerTL::MIRACLE_PAINTER].destroy
|
||
@tl.model.remove(iter) end end
|
||
core/plugin/extract_load_more/.mikutter.yml | ||
---|---|---|
---
|
||
name: extract_load more
|
||
slug: extract_load_more
|
||
description: 抽出タブの遡り機能を実装します。
|
||
depends:
|
||
mikutter: '3.8'
|
||
plugin:
|
||
- extract
|
||
- load_more_timeline
|
||
- gui
|
||
version: '1.0'
|
||
author: cobodo
|
||
core/plugin/extract_load_more/extract_load_more.rb | ||
---|---|---|
Plugin.create(:extract_load_more) do
|
||
# データソース単位のload moreイベント
|
||
# 第1引数: timeline slug
|
||
# 第2引数: datasource slug
|
||
# 第3引数: 抽出タブ内にある、そのdatasourceの最古のDiva::Model。
|
||
defevent :extract_load_more_datasource, prototype: [Symbol, Symbol, Diva::Model]
|
||
# 特定のデータソースにDiva::Model群を追加し、必要に応じてtimeline_maxの拡大も行なう。
|
||
# 第1引数: timeline slug
|
||
# 第2引数: datasource slug
|
||
# 第3引数: datasourceに追加するDiva::Modelの配列
|
||
defevent :extract_load_more_messages, prototype: [Symbol, Symbol, [Diva::Model]]
|
||
def tl_uris
|
||
@tl_uris ||= Hash.new # timeline_slug -> datasource_slug -> URI -> time
|
||
end
|
||
tl_uris
|
||
def extract_tabs
|
||
Plugin[:extract].extract_tabs
|
||
end
|
||
on_extract_receive_message do |source, messages|
|
||
tabs = extract_tabs.values.select{ |r| r.sources && r.using?(source) }
|
||
next if tabs.empty?
|
||
tabs.each do |record|
|
||
@tl_uris[record.slug] ||= Hash.new
|
||
@tl_uris[record.slug][source] ||= Hash.new
|
||
messages.each do |m|
|
||
if m && m.uri
|
||
unless m.retweet_source && tl_uris[record.slug][source].has_key?(m.retweet_source.uri.to_s)
|
||
@tl_uris[record.slug][source][m.uri.to_s] = m.retweet_source ? m.modified : m.created
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
# n=TLあたりのメッセージ保持数、m=タブあたりの平均データソース数として、O(nm)
|
||
on_gui_timeline_message_removed do |i_timeline, message|
|
||
next unless (message && message.uri)
|
||
@tl_uris[i_timeline.slug] ||= Hash.new
|
||
@tl_uris[i_timeline.slug].keys.each do |source|
|
||
@tl_uris[i_timeline.slug][source].delete(message.uri.to_s)
|
||
end
|
||
end
|
||
# O(n)
|
||
on_load_more_timeline do |tl_slug|
|
||
next unless @tl_uris[tl_slug]
|
||
@tl_uris[tl_slug].keys.each do |source|
|
||
pair = @tl_uris[tl_slug][source].to_a.min{|a, b| a[1] <=> b[1] }
|
||
oldest = timeline(tl_slug).find {|m| m && m.uri && m.uri == pair[0] }
|
||
Plugin.call(:extract_load_more_datasource, tl_slug, source, oldest) if oldest
|
||
end
|
||
end
|
||
on_extract_load_more_messages do |tl_slug, source, messages|
|
||
pp "on_extract_load_more_messages: #{tl_slug} #{source} #{messages}"
|
||
i_tl = timeline(tl_slug)
|
||
i_tl.timeline_max = [messages.size + i_tl.size, i_tl.timeline_max].max
|
||
@tl_uris[tl_slug] ||= Hash.new
|
||
@tl_uris[tl_slug][source] ||= Hash.new
|
||
messages.each do |m|
|
||
@tl_uris[tl_slug][source][m.uri] = m.retweet_source ? m.modified : m.created
|
||
end
|
||
i_tl << messages
|
||
end
|
||
end
|
||
core/plugin/gtk/gtk.rb | ||
---|---|---|
# _widget_ に対応するウィジェットオブジェクトまたは偽
|
||
def find_implement_widget_by_gtkwidget(widget)
|
||
@slug_dictionary.imaginally_by_gtk(widget) end
|
||
# timeline_maxを取得するフィルタ
|
||
filter_gui_timeline_get_timeline_max do |i_tl, _|
|
||
[i_tl, widgetof(i_tl).timeline_max]
|
||
end
|
||
# timeline_maxを設定するフィルタ
|
||
filter_gui_timeline_set_timeline_max do |i_tl, n|
|
||
widgetof(i_tl).timeline_max = n
|
||
[i_tl, n]
|
||
end
|
||
# タイムラインのメッセージを順に処理するフィルタ
|
||
filter_gui_timeline_each_messages do |i_tl, y|
|
||
widgetof(i_tl).each do |m|
|
||
y << m
|
||
end
|
||
[i_tl, y]
|
||
end
|
||
end
|
||
module Plugin::Gtk
|
core/plugin/gui/gui.rb | ||
---|---|---|
[(set || {}).merge(Plugin::GUI::Tab.cuscaded)]
|
||
end
|
||
# timeline_maxを取得するフィルタ
|
||
defevent :gui_timeline_get_timeline_max, prototype: [Plugin::GUI::Timeline, Integer]
|
||
# timeline_maxを設定するフィルタ
|
||
defevent :gui_timeline_set_timeline_max, prototype: [Plugin::GUI::Timeline, Integer]
|
||
# タイムラインのメッセージを順に処理するフィルタ
|
||
defevent :gui_timeline_each_messages, prototype: [Plugin::GUI::Timeline, :<<]
|
||
# タイムラインからメッセージが除去された際に発生させるイベント
|
||
defevent :gui_timeline_message_removed, prototype: [Plugin::GUI::Timeline, Diva::Model]
|
||
end
|
core/plugin/gui/timeline.rb | ||
---|---|---|
include Plugin::GUI::HierarchyParent
|
||
include Plugin::GUI::Widget
|
||
include Enumerable
|
||
role :timeline
|
||
set_parent_event :gui_timeline_join_tab
|
||
... | ... | |
Plugin.call(:gui_timeline_set_order, self, block)
|
||
end
|
||
# このタイムライン内の _message_ を繰り返し処理する
|
||
def each
|
||
enum = Enumerator.new do |y|
|
||
Plugin.filtering(:gui_timeline_each_messages, self, y)
|
||
end.lazy
|
||
return enum unless block_given?
|
||
enum.each do |m|
|
||
yield m
|
||
end
|
||
end
|
||
def size
|
||
to_a.size
|
||
end
|
||
# timeline_maxを取得する
|
||
def timeline_max
|
||
Plugin.filtering(:gui_timeline_get_timeline_max, self, nil)[1] || UserConfig[:timeline_max]
|
||
end
|
||
# timeline_maxを設定する
|
||
def timeline_max=(n)
|
||
Plugin.filtering(:gui_timeline_set_timeline_max, self, n)
|
||
end
|
||
end
|
core/plugin/load_more_timeline/.mikutter.yml | ||
---|---|---|
---
|
||
name: load more timeline
|
||
slug: load_more_timeline
|
||
description: mikutterのタイムラインを遡るためのイベントを定義し、コマンドを提供します。
|
||
depends:
|
||
mikutter: '3.8'
|
||
plugin:
|
||
- gui
|
||
version: '1.0'
|
||
author: cobodo
|
||
core/plugin/load_more_timeline/load_more_timeline.rb | ||
---|---|---|
Plugin.create(:load_more_timeline) do
|
||
defevent :load_more_timeline, prototype: [Symbol]
|
||
# 遡るコマンド
|
||
# プラグインは、on_load_more_timelineに渡されたタイムラインslugを見て遡ることができる。
|
||
command(:load_more_timeline,
|
||
name: _('タイムラインを遡る'),
|
||
condition: lambda{ |opt| true },
|
||
visible: true,
|
||
role: :timeline) do |opt|
|
||
i_tl = opt.widget
|
||
Plugin.call(:load_more_timeline, i_tl.slug)
|
||
end
|
||
end
|
||
core/plugin/twitter_load_more/.mikutter.yml | ||
---|---|---|
---
|
||
name: twitter_load more
|
||
slug: twitter_load_more
|
||
description: twitterのHome Timeline、リプライ、ユーザータイムライン、リストの遡り機能を実装します。
|
||
depends:
|
||
mikutter: '3.8'
|
||
plugin:
|
||
- twitter
|
||
- list
|
||
- load_more_timeline
|
||
- extract_load_more
|
||
- gui
|
||
- world
|
||
version: '1.0'
|
||
author: cobodo
|
||
core/plugin/twitter_load_more/twitter_load_more.rb | ||
---|---|---|
Plugin.create(:twitter_load_more) do
|
||
def load_more(tl_slug, source = nil, oldest = nil, &adder)
|
||
notice "twitter_load_more: tl_slug=#{tl_slug} source=#{source} oldest=#{oldest}"
|
||
world = Plugin.filtering(:worlds, []).first.find{|w| w.class.slug == :twitter }
|
||
if tl_slug == :home_timeline
|
||
oldest = timeline(tl_slug).min {|a, b| a.modified.to_i <=> b.modified.to_i }
|
||
params = {
|
||
count: 200,
|
||
max_id: oldest.id - 1,
|
||
tweet_mode: 'extended'.freeze
|
||
}
|
||
world.home_timeline(params).next(&adder).terminate("twitter_load_more: home_timeline の追加取得に失敗しました")
|
||
elsif tl_slug == :mentions
|
||
oldest = timeline(tl_slug).min {|a, b| a.modified.to_i <=> b.modified.to_i }
|
||
params = {
|
||
count: 200,
|
||
max_id: oldest.id - 1,
|
||
tweet_mode: 'extended'.freeze
|
||
}
|
||
world.mentions(params).next(&adder).terminate("twitter_load_more: reply の追加取得に失敗しました")
|
||
elsif timeline(tl_slug).parent.is_a?(Plugin::GUI::Fragment)
|
||
oldest = timeline(tl_slug).min {|a, b| a.modified.to_i <=> b.modified.to_i }
|
||
fragment_slug = timeline(tl_slug).parent.slug
|
||
%r!\Ausertimeline_(.+)_[0-9]+_[0-9A-Fa-f]{8}_[0-9A-Fa-f]{8}\z!.match(fragment_slug.to_s) do |m|
|
||
params = {
|
||
# profile-http://twitter.com/username -> username
|
||
screen_name: m[1].split('/').last,
|
||
max_id: oldest.id - 1,
|
||
count: 200,
|
||
include_rts: 1,
|
||
tweet_mode: 'extended'.freeze
|
||
}
|
||
world.user_timeline(params).next(&adder).terminate("twitter_load_more: usertimeline の追加取得に失敗しました")
|
||
end
|
||
elsif source
|
||
list = Plugin[:list].using_lists.find{|list| Plugin[:list].datasource_slug(list) == source }
|
||
return unless list
|
||
world = Plugin.filtering(:worlds, []).first.find{|w| w.class.slug == :twitter }
|
||
params = {
|
||
count: 200,
|
||
max_id: oldest.id - 1,
|
||
list_id: list[:id],
|
||
cache: :keep
|
||
}
|
||
world.list_statuses(params).next(&adder).terminate("twitter_load_more: home_timeline の追加取得に失敗しました")
|
||
end
|
||
end
|
||
on_load_more_timeline do |tl_slug|
|
||
notice "twitter_load_more: on_load_more_timeline: tl_slug=#{tl_slug}"
|
||
load_more(tl_slug) do |messages|
|
||
notice "on_load_more_timeline: add #{messages} to #{tl_slug}"
|
||
i_tl = timeline(tl_slug)
|
||
i_tl.timeline_max = [messages.size + i_tl.size, i_tl.timeline_max].max
|
||
i_tl << messages
|
||
end
|
||
end
|
||
on_extract_load_more_datasource do |tl_slug, source, oldest|
|
||
notice "twitter_load_more: on_extract_load_more_datasource: tl_slug=#{tl_slug} source=#{source} oldest=#{oldest}"
|
||
load_more(tl_slug, source, oldest) do |messages|
|
||
notice "on_extract_load_more_datasource: add #{messages} to #{tl_slug}, #{source}"
|
||
Plugin.call(:extract_load_more_messages, tl_slug, source, messages)
|
||
end
|
||
end
|
||
end
|
||