|
@@ -53,6 +53,12 @@ func zncWireTimeToTime(str string) (result time.Time) {
|
53
|
53
|
return time.Unix(seconds, int64(fraction*1000000000)).UTC()
|
54
|
54
|
}
|
55
|
55
|
|
|
56
|
+func timeToZncWireTime(t time.Time) (result string) {
|
|
57
|
+ secs := t.Unix()
|
|
58
|
+ nano := t.UnixNano() - (secs * 1000000000)
|
|
59
|
+ return fmt.Sprintf("%d.%d", secs, nano)
|
|
60
|
+}
|
|
61
|
+
|
56
|
62
|
type zncPlaybackTimes struct {
|
57
|
63
|
start time.Time
|
58
|
64
|
end time.Time
|
|
@@ -77,13 +83,25 @@ func (z *zncPlaybackTimes) ValidFor(target string) bool {
|
77
|
83
|
}
|
78
|
84
|
|
79
|
85
|
// https://wiki.znc.in/Playback
|
|
86
|
+func zncPlaybackHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
|
87
|
+ if len(params) == 0 {
|
|
88
|
+ return
|
|
89
|
+ }
|
|
90
|
+ switch strings.ToLower(params[0]) {
|
|
91
|
+ case "play":
|
|
92
|
+ zncPlaybackPlayHandler(client, command, params, rb)
|
|
93
|
+ case "list":
|
|
94
|
+ zncPlaybackListHandler(client, command, params, rb)
|
|
95
|
+ default:
|
|
96
|
+ return
|
|
97
|
+ }
|
|
98
|
+}
|
|
99
|
+
|
80
|
100
|
// PRIVMSG *playback :play <target> [lower_bound] [upper_bound]
|
81
|
101
|
// e.g., PRIVMSG *playback :play * 1558374442
|
82
|
|
-func zncPlaybackHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
|
102
|
+func zncPlaybackPlayHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
83
|
103
|
if len(params) < 2 || len(params) > 4 {
|
84
|
104
|
return
|
85
|
|
- } else if strings.ToLower(params[0]) != "play" {
|
86
|
|
- return
|
87
|
105
|
}
|
88
|
106
|
targetString := params[1]
|
89
|
107
|
|
|
@@ -123,6 +141,9 @@ func zncPlaybackHandler(client *Client, command string, params []string, rb *Res
|
123
|
141
|
|
124
|
142
|
if params[1] == "*" {
|
125
|
143
|
zncPlayPrivmsgs(client, rb, "*", start, end)
|
|
144
|
+ } else if params[1] == "*self" {
|
|
145
|
+ zncPlayPrivmsgs(client, rb, "*", start, end)
|
|
146
|
+ targets = make(StringSet) // XXX non-nil but empty channel set means "no channels"
|
126
|
147
|
} else {
|
127
|
148
|
targets = make(StringSet)
|
128
|
149
|
for _, targetName := range strings.Split(targetString, ",") {
|
|
@@ -169,3 +190,22 @@ func zncPlayPrivmsgs(client *Client, rb *ResponseBuffer, target string, after, b
|
169
|
190
|
client.replayPrivmsgHistory(rb, items, "", true)
|
170
|
191
|
}
|
171
|
192
|
}
|
|
193
|
+
|
|
194
|
+// PRIVMSG *playback :list
|
|
195
|
+func zncPlaybackListHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
|
196
|
+ nick := client.Nick()
|
|
197
|
+ for _, channel := range client.Channels() {
|
|
198
|
+ _, sequence, err := client.server.GetHistorySequence(channel, client, "")
|
|
199
|
+ if err != nil {
|
|
200
|
+ client.server.logger.Error("internal", "couldn't get history sequence for ZNC list", err.Error())
|
|
201
|
+ continue
|
|
202
|
+ }
|
|
203
|
+ items, _, err := sequence.Between(history.Selector{}, history.Selector{}, 1) // i.e., LATEST * 1
|
|
204
|
+ if err != nil {
|
|
205
|
+ client.server.logger.Error("internal", "couldn't query history for ZNC list", err.Error())
|
|
206
|
+ } else if len(items) != 0 {
|
|
207
|
+ stamp := timeToZncWireTime(items[0].Message.Time)
|
|
208
|
+ rb.Add(nil, "*playback!znc@znc.in", "PRIVMSG", nick, fmt.Sprintf("%s 0 %s", channel.Name(), stamp))
|
|
209
|
+ }
|
|
210
|
+ }
|
|
211
|
+}
|