-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathScribe.fs
187 lines (155 loc) · 5.38 KB
/
Scribe.fs
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
module FScribe.Scribe
open System
open FSharpPlus
open FSharpPlus.Data
open Microsoft.FSharp.Collections
open Mirai.Net.Sessions
open Mirai.Net.Data.Messages.Concretes
open Mirai.Net.Data.Messages.Receivers
open FScribe.Msg
open FScribe.Util
type IScribeRecord =
abstract member MsgId: string
abstract member Markdown: string
type PlainScribeRecord =
{ MsgId: string
Markdown: string }
interface IScribeRecord with
member x.MsgId = x.MsgId
member x.Markdown = x.Markdown
type ScribeRecord(msg: GroupMessageReceiver) =
let senderName = msg.Sender.Name
let content = msg.MessageChain
let maybeSource =
content
|> Seq.tryHead
|> Option.bind tryParse<SourceMessage>
let timestamp =
maybeSource
|> Option.map (fun s ->
DateTimeOffset
.FromUnixTimeSeconds(
int64 s.Time
)
.DateTime)
|> Option.defaultValue DateTime.Now
let msgId =
maybeSource
|> Option.map (fun s -> s.MessageId)
|> Option.defaultWith timestamp.ToString
let lazyMarkdown =
let cst =
TimeZoneInfo.FindSystemTimeZoneById("China Standard Time")
let timeChina =
TimeZoneInfo.ConvertTimeFromUtc(timestamp, cst)
lazy
($"{senderName} ({timeChina}): "
+ (content
|> Seq.map (function
| :? PlainMessage as plain -> plain.Text
| :? AtMessage as atm -> $"@{atm.Target}" // TODO: actual name instead of id
| :? AppMessage as app -> $"{app.Content}"
| :? FaceMessage as face -> $"[{face.Name}]"
| :? FileMessage as file -> $"[文件] {file.Name}"
| :? ForwardMessage as forward -> $"[{Seq.length forward.NodeList}条聊天记录]"
| :? ImageMessage as img -> $"![{img.ImageId}]({img.Url})"
| :? MarketFaceMessage as face -> face.Name
| :? MusicShareMessage as music -> $"[{music.Title} - {music.Summary}]({music.MusicUrl})"
| :? QuoteMessage as quote -> $"|回复{quote.SenderId}| "
| :? SourceMessage -> ""
| x -> x.ToString())
|> String.concat ""))
member x.Markdown =
(x :> IScribeRecord).Markdown
interface IScribeRecord with
member _.MsgId = msgId
member _.Markdown = lazyMarkdown.Value
type MessageCollectContext =
{ TimeLimit: DateTime
TargetMsgId: string }
type GroupContext =
{ Records: IScribeRecord list
Collecting: MessageCollectContext option }
static member Default: GroupContext =
{ Records = List.empty
Collecting = None }
let handle (bot: MiraiBot) (someMap: Map<uint, GroupContext>) (msg: GroupMessageReceiver) =
// logInfo "Handling message."
let groupId = uint msg.GroupId
let ctx =
someMap
|> Map.tryFind groupId
|> Option.defaultValue GroupContext.Default
let isAtBot =
msg.MessageChain
|> Seq.exists (function
| :? AtMessage as atm -> atm.Target = bot.QQ
| _ -> false)
let maybeQuote =
msg.MessageChain
|> Seq.choose tryParse<QuoteMessage>
|> Seq.tryHead
// match ctx.Collecting with
// | Some { TimeLimit = time; TargetMsgId = id } when time >= DateTime.Now ->
// // TODO: check for caller
// msg.Sender.Group
// |> MrGroup.send "五秒内回了"
// |> Async.Start
//
// someMap
// |> Map.add groupId { ctx with Collecting = None }
// | Some _ ->
// // TODO: check for caller
// msg.Sender.Group
// |> MrGroup.send "没能五秒内回"
// |> Async.Start
//
// someMap
// |> Map.add groupId { ctx with Collecting = None }
// | _ when isAtBot ->
// // TODO: me is at?
// logInfo "At bot."
//
// msg.Sender.Group
// |> MrGroup.send "试试五秒内回复我"
// |> Async.Start
//
// someMap
// |> Map.add
// groupId
// { ctx with
// Collecting =
// Some
// { TimeLimit = DateTime.Now + TimeSpan.FromSeconds(5)
// TargetMsgId = "" } }
// | _ ->
// // Just record it
// let r = ScribeRecord(msg)
// logDebug "Message: %s" r.Markdown
//
// someMap
// |> Map.add groupId { ctx with Records = r :: ctx.Records }
match isAtBot, maybeQuote with
| true, None
| false, _ ->
let r = ScribeRecord(msg)
logVerbose "Message: %s" r.Markdown
someMap
|> Map.add groupId { ctx with Records = r :: ctx.Records }
| true, Some q -> // at bot in quote
let skipped =
ctx.Records
|> List.skipWhile (fun r -> r.MsgId <> q.MessageId)
let selectedRecords =
if skipped.IsEmpty then
ctx.Records
else
skipped
logInfo "Selected %d records." (selectedRecords |> Seq.length)
let combined =
selectedRecords |> List.map (fun r -> r.Markdown)
logDebug "----Quote-Start----"
logDebug "%s" (string combined)
logDebug "----Quote-End----"
External.commentCollected combined |> Async.Start
someMap