-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathparser.rb
143 lines (132 loc) · 4.55 KB
/
parser.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
require 'cgi' # unescapeHTML
module Plugin::Worldon::Parser
def self.dehtmlize(html)
result = html
.gsub(%r!</p><p>!) { "\n\n" }
.gsub(%r!<span class="ellipsis">([^<]*)</span>!) {|s| $1 + "..." }
.gsub(%r!^<p>|</p>|<span class="invisible">[^<]*</span>|</?span[^>]*>!, '')
.gsub(/<br[^>]*>|<p>/) { "\n" }
.gsub(/'/) { "'" }
result
end
def self.dictate_score(html, mentions: [], emojis: [], media_attachments: [])
desc = dehtmlize(html)
score = []
# リンク処理
# TODO: user_detail_viewを作ったらacctをAccount Modelにする
pos = 0
anchor_re = %r|<a(?<attr1>[^>]*) href="(?<url>[^"]*)"(?<attr2>[^>]*)>(?<text>[^<]*)</a>|
urls = []
while m = anchor_re.match(desc, pos)
anchor_begin = m.begin(0)
anchor_end = m.end(0)
if pos < anchor_begin
score << Plugin::Score::TextNote.new(description: CGI.unescapeHTML(desc[pos...anchor_begin]))
end
url = Diva::URI.new(CGI.unescapeHTML(m["url"]))
if m["text"][0] == '#' || (score.last.to_s[-1] == '#')
score << Plugin::Worldon::Tag.new(name: CGI.unescapeHTML(m["text"]).sub(/\A#/, ''))
else
account = nil
if mentions.any? { |mention| mention.url == url }
mention = mentions.lazy.select { |mention| mention.url == url }.first
acct = Plugin::Worldon::Account.regularize_acct_by_domain(mention.url.host, mention.acct)
account = Plugin::Worldon::Account.findbyacct(acct)
end
if account
score << account
else
link_hash = {
description: CGI.unescapeHTML(m["text"]),
uri: url,
worldon_link_attr: Hash.new,
}
attrs = m["attr1"] + m["attr2"]
attr_pos = 0
attr_re = %r| (?<name>[^=]+)="(?<value>[^"]*)"|
while m2 = attr_re.match(attrs, attr_pos)
attr_name = m2["name"].to_sym
attr_value = m2["value"]
if [:class, :rel].include? attr_name
link_hash[:worldon_link_attr][attr_name] = attr_value.split(' ')
else
link_hash[:worldon_link_attr][attr_name] = attr_value
end
attr_pos = m2.end(0)
end
score << Plugin::Score::HyperLinkNote.new(link_hash)
end
end
urls << url
pos = anchor_end
end
if pos < desc.size
score << Plugin::Score::TextNote.new(description: CGI.unescapeHTML(desc[pos...desc.size]))
end
# 添付ファイル用のwork around
# TODO: mikutter本体側が添付ファイル用のNoteを用意したらそちらに移行する
if media_attachments.size > 0
media_attachments
.select {|attachment|
!urls.include?(attachment.url.to_s) && !urls.include?(attachment.text_url.to_s)
}
.each {|attachment|
score << Plugin::Score::TextNote.new(description: "\n")
description = attachment.text_url
if !description
description = attachment.url
end
score << Plugin::Score::HyperLinkNote.new(description: description, uri: attachment.url)
}
end
score = score.flat_map do |note|
if !note.is_a?(Plugin::Score::TextNote)
[note]
else
emoji_score = Enumerator.new{|y|
dictate_emoji(note.description, emojis, y)
}.first.to_a
if emoji_score.size > 0
emoji_score
else
[note]
end
end
end
description = score.inject('') do |acc, note|
desc = note.is_a?(Plugin::Score::HyperLinkNote) ? note.uri.to_s : note.description
acc + desc
end
[description, score]
end
# 与えられたテキスト断片に対し、emojisでEmojiを置換するscoreを返します。
def self.dictate_emoji(text, emojis, yielder)
score = emojis.inject(Array(text)){ |fragments, emoji|
shortcode = ":#{emoji.shortcode}:"
fragments.flat_map{|fragment|
if fragment.is_a?(String)
if fragment === shortcode
[emoji]
else
sub_fragments = fragment.split(shortcode).flat_map{|str|
[str, emoji]
}
sub_fragments.pop unless fragment.end_with?(shortcode)
sub_fragments
end
else
[fragment]
end
}
}.map{|chunk|
if chunk.is_a?(String)
Plugin::Score::TextNote.new(description: chunk)
else
chunk
end
}
if (score.size > 1 || score.size == 1 && !score[0].is_a?(Plugin::Score::TextNote))
yielder << score
end
end
end