Добавил больше плагинов
This commit is contained in:
parent
8339fb95c9
commit
08896e9598
1
Gemfile
1
Gemfile
|
@ -2,3 +2,4 @@ source 'https://rubygems.org'
|
|||
gem 'cinch'
|
||||
gem 'cinch-dicebag'
|
||||
gem 'translit'
|
||||
gem 'nokogiri'
|
||||
|
|
27
bot.rb
27
bot.rb
|
@ -1,19 +1,40 @@
|
|||
require 'cinch'
|
||||
require 'cinch-dicebag'
|
||||
require 'translit'
|
||||
require_relative 'plugins/history'
|
||||
require_relative 'plugins/link_info'
|
||||
require_relative 'plugins/help'
|
||||
require_relative 'plugins/seen'
|
||||
|
||||
bot = Cinch::Bot.new do
|
||||
configure do |c|
|
||||
c.server = "irc.forestnet.org"
|
||||
c.port = 6667
|
||||
c.channels = ["#urq"]
|
||||
c.channels = ["#urq", "#instead", "#qsp", "#ifrus"]
|
||||
c.nick = 'Дроид'
|
||||
c.plugins.plugins = [Cinch::Plugins::Dicebag]
|
||||
c.plugins.plugins = [
|
||||
Cinch::Plugins::Dicebag,
|
||||
Cinch::History,
|
||||
Cinch::Help,
|
||||
Cinch::LinkInfo,
|
||||
Cinch::Seen
|
||||
]
|
||||
c.plugins.options[Cinch::History] = {
|
||||
:mode => :max_messages,
|
||||
:max_messages => 20,
|
||||
# :max_age => 5,
|
||||
:time_format => "%H:%M",
|
||||
:file => "/home/znc/seenlog.dat"
|
||||
}
|
||||
c.plugins.options[Cinch::LinkInfo] = {
|
||||
:blacklist => [/\.xz$/i, /\.zip$/i, /\.rar$/i],
|
||||
:no_description => true,
|
||||
}
|
||||
end
|
||||
|
||||
on :message do |m|
|
||||
if m.user.nick == 'MAlischka' or m.user.nick == 'MA' then
|
||||
Channel('#urq').send(Translit.convert(m.message, :russian))
|
||||
m.reply( Translit.convert(m.message, :russian) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
206
plugins/help.rb
Normal file
206
plugins/help.rb
Normal file
|
@ -0,0 +1,206 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# = Cinch help plugin
|
||||
# This plugin parses the +help+ option of all plugins registered with
|
||||
# the bot when connecting to the server and provides a nice interface
|
||||
# for querying these help strings via the 'help' command.
|
||||
#
|
||||
# == Commands
|
||||
# [cinch help]
|
||||
# Print the intro message and list all plugins.
|
||||
# [cinch help <plugin>]
|
||||
# List all commands with explanations for a plugin.
|
||||
# [cinch help search <query>]
|
||||
# List all commands with explanations that contain <query>.
|
||||
#
|
||||
# == Dependencies
|
||||
# None.
|
||||
#
|
||||
# == Configuration
|
||||
# Add the following to your bot’s configure.do stanza:
|
||||
#
|
||||
# config.plugins.options[Cinch::Help] = {
|
||||
# :intro => "%s at your service."
|
||||
# }
|
||||
#
|
||||
# [intro]
|
||||
# First message posted when the user issues 'help' to the bot
|
||||
# without any parameters. %s is replaced with Cinch’s current
|
||||
# nickname.
|
||||
#
|
||||
# == Writing help messages
|
||||
# In order to add help strings, update your plugins to set +help+
|
||||
# properly like this:
|
||||
#
|
||||
# class YourPlugin
|
||||
# include Cinch::Plugin
|
||||
#
|
||||
# set :help, <<-HELP
|
||||
# command <para1> <para2>
|
||||
# This command does this and that. The description may
|
||||
# as well be multiline.
|
||||
# command2 <para1> [optpara]
|
||||
# Another sample command.
|
||||
# HELP
|
||||
# end
|
||||
#
|
||||
# Cinch recognises a command in the help string as one if it starts at
|
||||
# the beginning of the line, all subsequent indented lines are considered
|
||||
# part of the command explanation, up until the next line that is not
|
||||
# indented or the end of the string. Multiline explanations are therefore
|
||||
# handled fine, but you should still try to keep the descriptions as short
|
||||
# as possible, because many IRC servers will block too much text as flooding,
|
||||
# resulting in the help messages being cut. Instead, provide a web link or
|
||||
# something similar for full-blown descriptions.
|
||||
#
|
||||
# The command itself may be in any form you want (as long as it’s a single
|
||||
# line), but I recommend the following conventions so users know how to
|
||||
# talk to the bot:
|
||||
#
|
||||
# [cinch ...]
|
||||
# A command Cinch understands when posted publicely into the channel,
|
||||
# prefixed with its name (or whatever prefix you want, replace "cinch"
|
||||
# accordingly).
|
||||
# [/msg cinch ...]
|
||||
# A command Cinch understands when send directly to him via PM and
|
||||
# without a prefix.
|
||||
# [[/msg] cinch ...]
|
||||
# A command Cinch understands when posted publicely with his nick as
|
||||
# a prefix, or privately to him without any prefix.
|
||||
# [...]
|
||||
# That is, a bare command without a prefix. Cinch watches the conversion
|
||||
# on the channel, and whenever he encounters this string/pattern he will
|
||||
# take action, without any prefix at all.
|
||||
#
|
||||
# The word "cinch" in the command string will automatically be replaced with
|
||||
# the actual nickname of your bot.
|
||||
#
|
||||
# == Author
|
||||
# Marvin Gülker (Quintus)
|
||||
#
|
||||
# == License
|
||||
# A help plugin for Cinch.
|
||||
# Copyright © 2012 Marvin Gülker
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Help plugin for Cinch.
|
||||
class Cinch::Help
|
||||
include Cinch::Plugin
|
||||
|
||||
listen_to :connect, :method => :on_connect
|
||||
match /help(.*)/i, :prefix => lambda{|msg| Regexp.compile("^#{Regexp.escape(msg.bot.nick)}:?\s*")}, :react_on => :channel
|
||||
match /help(.*)/i, :use_prefix => false, :react_on => :private
|
||||
|
||||
set :help, <<-EOF
|
||||
[/msg] cinch help
|
||||
Post a short introduction and list available plugins.
|
||||
[/msg] cinch help <plugin>
|
||||
List all commands available in a plugin.
|
||||
[/msg] cinch help search <query>
|
||||
Search all plugin’s commands and list all commands containing
|
||||
<query>.
|
||||
EOF
|
||||
|
||||
def execute(msg, query)
|
||||
query = query.strip.downcase
|
||||
response = ""
|
||||
|
||||
# Act depending on the subcommand.
|
||||
if query.empty?
|
||||
response << @intro_message.strip << "\n"
|
||||
response << "Available plugins:\n"
|
||||
response << bot.config.plugins.plugins.map{|plugin| format_plugin_name(plugin)}.join(", ")
|
||||
response << "\n'help <plugin>' for help on a specific plugin."
|
||||
|
||||
# Help for a specific plugin
|
||||
elsif plugin = @help.keys.find{|plugin| format_plugin_name(plugin) == query}
|
||||
@help[plugin].keys.sort.each do |command|
|
||||
response << format_command(command, @help[plugin][command], plugin)
|
||||
end
|
||||
|
||||
# help search <...>
|
||||
elsif query =~ /^search (.*)$/i
|
||||
query2 = $1.strip
|
||||
@help.each_pair do |plugin, hsh|
|
||||
hsh.each_pair do |command, explanation|
|
||||
response << format_command(command, explanation, plugin) if command.include?(query2)
|
||||
end
|
||||
end
|
||||
|
||||
# For plugins without help
|
||||
response << "Sorry, no help available for the #{format_plugin_name(plugin)} plugin." if response.empty?
|
||||
|
||||
# Something we don't know what do do with
|
||||
else
|
||||
response << "Sorry, I cannot find '#{query}'."
|
||||
end
|
||||
|
||||
response << "Sorry, nothing found." if response.empty?
|
||||
msg.reply(response)
|
||||
end
|
||||
|
||||
# Called on startup. This method iterates the list of registered plugins
|
||||
# and parses all their help messages, collecting them in the @help hash,
|
||||
# which has a structure like this:
|
||||
#
|
||||
# {Plugin => {"command" => "explanation"}}
|
||||
#
|
||||
# where +Plugin+ is the plugin’s class object. It also parses configuration
|
||||
# options.
|
||||
def on_connect(msg)
|
||||
@help = {}
|
||||
|
||||
if config[:intro]
|
||||
@intro_message = config[:intro] % bot.nick
|
||||
else
|
||||
@intro_message = "#{bot.nick} at your service."
|
||||
end
|
||||
|
||||
bot.config.plugins.plugins.each do |plugin|
|
||||
@help[plugin] = Hash.new{|h, k| h[k] = ""}
|
||||
next unless plugin.help # Some plugins don't provide help
|
||||
current_command = "<unparsable content>" # For not properly formatted help strings
|
||||
|
||||
plugin.help.lines.each do |line|
|
||||
if line =~ /^\s+/
|
||||
@help[plugin][current_command] << line.strip
|
||||
else
|
||||
current_command = line.strip.gsub(/cinch/i, bot.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Format the help for a single command in a nice, unicode mannor.
|
||||
def format_command(command, explanation, plugin)
|
||||
result = ""
|
||||
|
||||
result << "┌─ " << command << " ─── Plugin: " << format_plugin_name(plugin) << " ─" << "\n"
|
||||
result << explanation.lines.map(&:strip).join(" ").chars.each_slice(80).map(&:join).join("\n")
|
||||
result << "\n" << "└ ─ ─ ─ ─ ─ ─ ─ ─\n"
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# Downcase the plugin name and clip it to the last component
|
||||
# of the namespace, so it can be displayed in a user-friendly
|
||||
# way.
|
||||
def format_plugin_name(plugin)
|
||||
plugin.to_s.split("::").last.downcase
|
||||
end
|
||||
|
||||
end
|
184
plugins/history.rb
Normal file
184
plugins/history.rb
Normal file
|
@ -0,0 +1,184 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# = Cinch history plugin
|
||||
# This plugin adds a non-persistant, short-time memory to Cinch that allows
|
||||
# users to replay part of the session Cinch currently observers. This plugin
|
||||
# can act in two different modes: The default mode is :max_messags, in which
|
||||
# Cinch will only remember a fixed number of messages for replay; however, in
|
||||
# a busy channel this may not provide enough information for finding one’s way
|
||||
# into a discussion without having to raise the limit of remembered messages
|
||||
# to some extraordinarily high value which this plugin is not meant for (if
|
||||
# you want real, persistant logging, use the Logging plugin). Instead, you
|
||||
# can switch to :max_age mode, in which Cinch will remember all messages
|
||||
# whose age does not exceed a certain number of minutes.
|
||||
#
|
||||
# == Usage
|
||||
# As a user, issue the following command privately to Cinch:
|
||||
#
|
||||
# /msg cinch history
|
||||
#
|
||||
# Cinch will respond to you with a private message containing the history
|
||||
# in the configured format.
|
||||
#
|
||||
# == Configuration
|
||||
# Add the following to your bot’s configure.do stanza:
|
||||
#
|
||||
# config.plugins.options[Cinch::History] = {
|
||||
# :mode => :max_messages,
|
||||
# :max_messages => 10,
|
||||
# # :max_age => 5,
|
||||
# :time_format => "%H:%M"
|
||||
# }
|
||||
#
|
||||
# [mode (:max_messages)]
|
||||
# Either :max_messages or :max_age, see explanations above.
|
||||
# [max_messages (10)]
|
||||
# If you chose :max_messages mode, this is the number of messages
|
||||
# Cinch will remember.
|
||||
# [max_age (5)]
|
||||
# If you chose :max_age mode, this is the maximum age in minutes
|
||||
# that a message may have before Cinch drops it from his memory.
|
||||
# The smallest useful value is 1, floating point values are not
|
||||
# allowed.
|
||||
# [time_format ("%H:%M")]
|
||||
# When replaying history, Cinch prints the time stamp for each
|
||||
# message next to it, in the format specified via this configuration
|
||||
# option. See date(1) for possible directives.
|
||||
#
|
||||
# == Author
|
||||
# Marvin Gülker (Quintus)
|
||||
#
|
||||
# == License
|
||||
# A history plugin for Cinch.
|
||||
# Copyright © 2012 Marvin Gülker
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Cinch::History
|
||||
include Cinch::Plugin
|
||||
|
||||
Entry = Struct.new(:time, :prefix, :message)
|
||||
|
||||
listen_to :connect, :method => :on_connect
|
||||
listen_to :channel, :method => :on_channel
|
||||
listen_to :topic, :method => :on_topic
|
||||
listen_to :away, :method => :on_away
|
||||
listen_to :unaway, :method => :on_unaway
|
||||
listen_to :action, :method => :on_action
|
||||
listen_to :leaving, :method => :on_leaving
|
||||
listen_to :join, :method => :on_join
|
||||
timer 60, :method => :check_message_age
|
||||
match /history/, :method => :replay, :react_on => :private, :use_prefix => false
|
||||
|
||||
set :help, <<-HELP
|
||||
/msg cinch history
|
||||
Sends the most recent messages of the channel to you via PM.
|
||||
HELP
|
||||
|
||||
def on_connect(*)
|
||||
@mode = config[:mode] || :max_messages
|
||||
@max_messages = config[:max_messages] || 10
|
||||
@max_age = (config[:max_age] || 5 ) * 60
|
||||
@timeformat = config[:time_format] || "%H:%M"
|
||||
@history_mutex = Mutex.new
|
||||
@history = []
|
||||
end
|
||||
|
||||
def on_channel(msg)
|
||||
return if msg.message.start_with?("\u0001")
|
||||
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, msg.user.nick, msg.message)
|
||||
|
||||
if @mode == :max_messages
|
||||
# In :max_messages mode, let messages over the limit just
|
||||
# fall out of the history.
|
||||
@history.shift if @history.length > @max_messages
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def on_topic(msg)
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "##", "#{msg.user.nick} changed the topic to “#{msg.channel.topic}”")
|
||||
end
|
||||
end
|
||||
|
||||
def on_away(msg)
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "##", "#{msg.user.nick} is away (“#{msg.message}”)")
|
||||
end
|
||||
end
|
||||
|
||||
def on_unaway(msg)
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "##" "#{msg.user.nick} is back")
|
||||
end
|
||||
end
|
||||
|
||||
def on_action(msg)
|
||||
return unless msg.message =~ /^\u0001ACTION(.*?)\u0001/
|
||||
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "**", "#{msg.user.nick} #{$1.strip}")
|
||||
end
|
||||
end
|
||||
|
||||
def on_leaving(msg, user)
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "<=", "#{user.nick} left the channel")
|
||||
end
|
||||
end
|
||||
|
||||
def on_join(msg)
|
||||
@history_mutex.synchronize do
|
||||
@history << Entry.new(msg.time, "=>", "#{msg.user.nick} entered the channel")
|
||||
end
|
||||
end
|
||||
|
||||
# In :max_age mode, remove messages from the history older than
|
||||
# the threshold.
|
||||
def check_message_age
|
||||
return unless @mode == :max_age
|
||||
|
||||
@history_mutex.synchronize do
|
||||
@history.delete_if{|entry| Time.now - entry.time > @max_age}
|
||||
end
|
||||
end
|
||||
|
||||
def replay(msg)
|
||||
# Informative preamble
|
||||
if @mode == :max_age
|
||||
msg.reply("Here are the messages of the last #@max_age seconds:")
|
||||
else
|
||||
msg.reply("Here are the last #{@history.count} messages:")
|
||||
end
|
||||
|
||||
# Actual historic(al) response
|
||||
@history_mutex.synchronize do
|
||||
r = @history.reduce("") do |answer, entry|
|
||||
answer + format_entry(entry)
|
||||
end
|
||||
|
||||
msg.reply(r.chomp)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_entry(entry)
|
||||
sprintf("[%s] %15s | %s\n", entry.time.strftime(@timeformat), entry.prefix, entry.message)
|
||||
end
|
||||
|
||||
end
|
93
plugins/link_info.rb
Normal file
93
plugins/link_info.rb
Normal file
|
@ -0,0 +1,93 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# = Cinch Link Info plugin
|
||||
# Inspects any links that are posted into a channel Cinch
|
||||
# is currently in and prints out the value of the title
|
||||
# and description meta tags, if any.
|
||||
#
|
||||
# == Dependencies
|
||||
# * Gem: nokogiri
|
||||
#
|
||||
# == Configuration
|
||||
# Add the following to your bot’s configure.do stanza:
|
||||
#
|
||||
# config.plugins.options[Cinch::LinkInfo] = {
|
||||
# :blacklist => [/\.xz$/],
|
||||
# :no_description => false,
|
||||
# }
|
||||
#
|
||||
# [blacklist]
|
||||
# If a URL matches any of the regular expressions defined
|
||||
# in this array, it will not be inspected. This plugin
|
||||
# alraedy ignores URLs ending in common image file
|
||||
# extensions, so you don’t have to specify .png, .jpeg,
|
||||
# etc.
|
||||
# [no_description]
|
||||
# Set this to true if you want Cinch to not print the
|
||||
# content of the Meta description tag.
|
||||
#
|
||||
# == Author
|
||||
# Marvin Gülker (Quintus)
|
||||
#
|
||||
# == License
|
||||
# A link info plugin for Cinch.
|
||||
# Copyright © 2012 Marvin Gülker
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require "open-uri"
|
||||
require "nokogiri"
|
||||
|
||||
# Plugin for inspecting links pasted into channels.
|
||||
class Cinch::LinkInfo
|
||||
include Cinch::Plugin
|
||||
|
||||
# Default list of URL regexps to ignore.
|
||||
DEFAULT_BLACKLIST = [/\.png$/i, /\.jpe?g$/i, /\.bmp$/i, /\.gif$/i, /\.pdf$/i].freeze
|
||||
|
||||
set :help, <<-HELP
|
||||
http[s]://...
|
||||
I’ll fire a GET request at any link I encounter, parse the HTML
|
||||
meta tags, and paste the result back into the channel.
|
||||
HELP
|
||||
|
||||
match %r{(https?://.*?)(?:\s|$|,|\.\s|\.$)}, :use_prefix => false
|
||||
|
||||
def execute(msg, url)
|
||||
blacklist = DEFAULT_BLACKLIST.dup
|
||||
blacklist.concat(config[:blacklist]) if config[:blacklist]
|
||||
|
||||
return if blacklist.any?{|entry| url =~ entry}
|
||||
debug "URL matched: #{url}"
|
||||
html = Nokogiri::HTML(open(url))
|
||||
|
||||
if node = html.at_xpath("html/head/title")
|
||||
msg.reply("Title: #{node.text}")
|
||||
end
|
||||
|
||||
if !config[:no_description]
|
||||
node = html.at_xpath('html/head/meta[@name="description"]') || html.at_xpath('html/head/meta[@name="Description"]')
|
||||
if node
|
||||
if node[:content].chars.count > 255
|
||||
msg.reply("Description: #{node[:content].lines.first(3).join("").gsub("\n", " ")[0..255] + "..."}")
|
||||
else
|
||||
msg.reply("Description: #{node[:content]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
error "#{e.class.name}: #{e.message}"
|
||||
end
|
||||
|
||||
end
|
94
plugins/seen.rb
Normal file
94
plugins/seen.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# = Cinch Seen plugin
|
||||
#
|
||||
# == Configuration
|
||||
# Add the following to your bot’s configure.do stanza:
|
||||
#
|
||||
# config.plugins.options[Cinch::History] = {
|
||||
# :file => "/var/cache/seenlog.dat"
|
||||
# }
|
||||
#
|
||||
# [file]
|
||||
# Where to store the message log. This is a required
|
||||
# argument.
|
||||
#
|
||||
# == Author
|
||||
# Marvin Gülker (Quintus)
|
||||
#
|
||||
# == License
|
||||
# An seen info plugin for Cinch.
|
||||
# Copyright © 2014 Marvin Gülker
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Cinch::Seen
|
||||
include Cinch::Plugin
|
||||
|
||||
SeenInfo = Struct.new(:time, :nick, :message)
|
||||
|
||||
match /seen (.*)/
|
||||
listen_to :connect, :method => :on_connect
|
||||
listen_to :channel, :method => :on_channel
|
||||
|
||||
def on_connect(*)
|
||||
@filepath = config[:file] || raise("Missing required argument: :file")
|
||||
@file = File.open(@filepath, "a+")
|
||||
@file.seek(0, File::SEEK_END) # Work around Ruby bug https://bugs.ruby-lang.org/issues/10039
|
||||
@filemutex = Mutex.new
|
||||
|
||||
at_exit{@file.close}
|
||||
end
|
||||
|
||||
def on_channel(msg)
|
||||
return if msg.message.start_with?("\u0001") # ACTION
|
||||
|
||||
@filemutex.synchronize do
|
||||
@file.puts("#{msg.time.to_i}\0#{msg.user.nick}\0#{msg.message.strip}")
|
||||
end
|
||||
end
|
||||
|
||||
def execute(msg, nick)
|
||||
if nick == bot.nick
|
||||
msg.reply "Self-reference err err tilt BOOOOM"
|
||||
return
|
||||
end
|
||||
|
||||
if info = find_last_message(nick)
|
||||
msg.reply("I have last seen #{nick} on #{info.time} saying: #{info.message}")
|
||||
else
|
||||
msg.reply("I have not yet seen #{nick} saying something.")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_last_message(nick)
|
||||
@filemutex.synchronize do
|
||||
@file.rewind
|
||||
@file.lines.reverse_each do |line|
|
||||
parts = line.split("\0")
|
||||
|
||||
if parts[1] == nick
|
||||
return SeenInfo.new(Time.at(parts[0].to_i), parts[1], parts[2])
|
||||
end
|
||||
end
|
||||
|
||||
@file.seek(0, File::SEEK_END)
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue