Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
217 lines (179 sloc) 7.26 KB
# Copyright (C) 2012-2013 Stefan Wold <ratler@stderr.eu>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# Source available on GitHUB: https://github.com/Ratler/join2fast
#
#
# Automatically queue and join channels on UnderNET that get throttled due to "Target change too fast".
use 5.010;
use POSIX qw/strftime/;
use strict;
use warnings;
my $SCRIPT_NAME = "join2fast";
my $VERSION = "0.8.1";
my %timers;
my %next_join;
my %channel_list;
my %default_options = ('timer_delay' => ['4', 'default delay in seconds added to the timer before trying to join the next channel in the list'],
'date_format' => ['%H:%M:%S', 'date and time format for time of the next join. Used by join2fast bar item.'],
'hide_event_msg' => ['on', 'hide target change too fast message']);
my %options = ();
# Register script
weechat::register($SCRIPT_NAME, "Ratler <ratler\@stderr.eu>", $VERSION, "GPL3",
"Automatically join channels on UnderNET that get throttled due to \"Target change too fast\"", "clear_all_on_script_unload", "");
my $weechat_version = weechat::info_get("version_number", "") || 0;
if ($weechat_version < 0x00030200) {
weechat::print("", weechat::prefix("error") . "$SCRIPT_NAME: requires weechat >= v0.3.2");
weechat::command("", "/wait 1ms /perl unload $SCRIPT_NAME");
}
# Initialize config
init_config();
# Hook command /j2f
weechat::hook_command("j2f",
"list/clear join2fast queue",
"[list] | [clear [server]]",
" list: list current queues\n".
" clear [server]: clear all queues or the queue for a specific server",
"list || clear %(irc_servers)",
"j2f_command_cb", "");
# Hook server disconnect to clear active queue
weechat::hook_signal("irc_server_disconnected", "clear_queue_on_disconnect", "");
# Callback for "Target change too fast" events
weechat::hook_modifier("irc_in_439", "event_439_cb", "");
# Setup bar item
weechat::bar_item_new($SCRIPT_NAME, "bar_cb", "");
sub event_439_cb {
my ($data, $modifier, $server, $string) = @_;
# $string - the message (:server 439 nick #channel :Target change too fast. Please wait 17 seconds.)
my $channel = (split " ", $string)[3];
my $delay = (split " ", $string)[10];
# Return if target is not a channel
# TODO: Add option to allow queueing private messages
return $string unless $channel =~ /^(#|&)/;
# Check if channel has been already added or add it
if (!exists($channel_list{$server}) or ((ref $channel_list{$server} eq 'ARRAY') and !($channel ~~ @{$channel_list{$server}}))) {
push @{$channel_list{$server}}, $channel;
}
# Reset timer to the last delay received
weechat::unhook($timers{$server}) if exists($timers{$server});
$next_join{$server} = {timestamp => time() + $delay + 2};
$timers{$server} = weechat::hook_timer(($delay + 2) * 1000, 0, 1, "join_channel_cb", $server);
# Update bar
weechat::bar_item_update($SCRIPT_NAME);
return lc($options{hide_event_msg}) eq 'off' ? $string : "";
}
sub clear_queue_on_disconnect {
my $server = $_[2];
if (exists($channel_list{$server})) {
delete $channel_list{$server};
delete $next_join{$server};
weechat::bar_item_update($SCRIPT_NAME);
}
return weechat::WEECHAT_RC_OK;
}
sub clear_all_on_script_unload {
foreach my $server (keys %timers) {
weechat::unhook($timers{$server});
}
undef %channel_list;
undef %next_join;
return weechat::WEECHAT_RC_OK;
}
sub join_channel_cb {
my $server = shift;
if ((ref $channel_list{$server} eq 'ARRAY') and scalar @{$channel_list{$server}} > 0) {
my $channel = pop @{$channel_list{$server}};
if ($weechat_version >= 0x00040000) {
weechat::command("", "/join -noswitch -server $server $channel");
} else {
# Save current buffer
my $buffer_ptr = weechat::current_buffer();
my $buffer_name = weechat::buffer_get_string($buffer_ptr, "name");
weechat::command("", "/join -server $server $channel");
# Switch back to the old buffer (a bit flakey) - disabled when irc.look.buffer_switch_join is set to off
my $option = weechat::config_get("irc.look.buffer_switch_join");
if (weechat::config_boolean($option)) {
weechat::command("", "/wait 1s /buffer $buffer_name");
}
}
# Setup a new timer
if ((ref $channel_list{$server} eq 'ARRAY') and scalar @{$channel_list{$server}} > 0) {
$timers{$server} = weechat::hook_timer($options{timer_delay} * 1000, 0, 1, "join_channel_cb", $server);
$next_join{$server} = {timestamp => time() + $options{timer_delay}};
} else {
delete $channel_list{$server};
delete $next_join{$server};
}
}
# Update bar
weechat::bar_item_update($SCRIPT_NAME);
return weechat::WEECHAT_RC_OK;
}
sub bar_cb {
my $queue_size = 0;
foreach my $server (keys %channel_list) {
$queue_size += scalar @{$channel_list{$server}};
}
return $queue_size > 0 ? "Q: $queue_size N: " . get_next_join_time() : "";
}
sub get_next_join_time {
my $key = (sort {$next_join{$a}->{timestamp} <=> $next_join{$b}->{timestamp}} keys (%next_join))[0];
return strftime($options{date_format}, localtime($next_join{$key}{timestamp}));
}
sub j2f_command_cb {
my ($data, $buffer, $args) = @_;
my ($option, $arg) = split " ", $args;
if ($option eq 'list') {
if (scalar (keys %channel_list) > 0) {
foreach my $server (keys %channel_list) {
weechat::print("", "$SCRIPT_NAME: Throttled channels on '$server': " . join(', ', @{$channel_list{$server}}));
}
} else {
weechat::print("", "$SCRIPT_NAME: no channels currently queued.");
}
} elsif ($option eq 'clear') {
if (defined($arg)) {
if (exists($timers{$arg})) {
weechat::unhook($timers{$arg});
delete $timers{$arg};
}
delete $channel_list{$arg};
delete $next_join{$arg};
} else {
foreach my $server (keys %channel_list) {
if (exists($timers{$server})) {
weechat::unhook($timers{$server});
delete $timers{$server};
}
delete $channel_list{$server};
delete $next_join{$server};
}
}
weechat::bar_item_update($SCRIPT_NAME);
}
return weechat::WEECHAT_RC_OK;
}
sub init_config {
foreach my $option (keys %default_options) {
if (!weechat::config_is_set_plugin($option)) {
weechat::config_set_plugin($option, $default_options{$option}[0]);
$options{$option} = $default_options{$option}[0];
} else {
$options{$option} = weechat::config_get_plugin($option);
}
weechat::config_set_desc_plugin($option, $default_options{$option}[1] . " (default: " . $default_options{$option}[0] . ")") if ($weechat_version >= 0x00030500);
}
}