User:AnomieBOT/source/tasks/FlagIconRemover.pm
Appearance
Approved 2011-09-12 Wikipedia:Bots/Requests for approval/AnomieBOT 52 |
package tasks::FlagIconRemover;
=pod
=begin metadata
Bot: AnomieBOT
Task: FlagIconRemover
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 52
Status: Approved 2011-09-12
Created: 2011-08-26
Remove flag icons from certain infoboxes and layout templates per community consensus.
=end metadata
=cut
use utf8;
use strict;
use AnomieBOT::Task qw/onlylist/;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
use Data::Dumper;
my $version=3;
my $screwup="Errors? [[User:AnomieBOT/shutoff/FlagIconRemover]]";
my %templates=(
'Template:Infobox company' => qr/.*/s,
'Template:Infobox dam' => qr/.*/s,
'Template:Infobox power station' => qr/.*/s,
'Template:Infobox World Heritage Site' => qr/.*/s,
'Template:Infobox language' => qr/(?!nation$|minority$).*/s,
);
my @flagcats=(
'Category:Flag templates',
'Category:Flag template system',
'Category:Flag template shorthands',
'Category:Canada flag template shorthands',
);
sub new {
my $class=shift;
my $self=$class->SUPER::new;
$self->{'iter'}=undef;
bless $self, $class;
return $self;
}
=pod
=for info
Approved 2011-09-12<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 52]]
=cut
sub approved {
return 3;
}
sub run {
my ($self, $api)=@_;
my $res;
$api->task('FlagIconRemover', 0, 10, qw(d::Templates d::Redirects d::Talk));
if(($api->store->{'version'}//0) != $version){
foreach my $k (keys %{$api->store}) {
delete $api->store->{$k} if $k=~/^revid /;
}
$api->store->{'version'}=$version;
}
# Spend a max of 5 minutes on this task before restarting
my $endtime=time()+300;
# Get the list of flag templates
my $flags=$api->cache->get('FlagIconRemover:flags');
if(!defined($flags)){
my %f=();
my $iter=$api->iterator(
list => 'categorymembers',
cmtitle => [ @flagcats ],
cmprop => 'title',
cmnamespace => 10,
cmlimit => 'max',
);
while(my $t=$iter->next){
return 0 if $api->halting;
if(!$t->{'_ok_'}){
$api->warn("Failed to retrieve members of ".$iter->iterval.": ".$t->{'error'}."\n");
return 300;
}
$f{$t->{'title'}}=1;
}
$flags=\%f;
$api->cache->set('FlagIconRemover:flags', $flags, 86400);
}
my %flags=%{$flags};
# Query list of pages transcluding our target templates
if(!defined($self->{'iter'})){
$self->{'iter'}=$api->iterator(
generator => 'embeddedin',
geititle => [ keys %templates ],
geinamespace => 0,
geilimit => '100',
prop => 'templates',
tllimit => 'max',
onlylist('tltemplates', 500, keys %flags),
);
}
my $iter=$self->{'iter'};
while(my $p=$iter->next){
return 0 if $api->halting;
if(!$p->{'_ok_'}){
$api->warn("Failed to retrieve embeddedin list for ".$iter->iterval.": ".$p->{'error'}."\n");
return 300;
}
my $any=0;
for my $t (@{$p->{'templates'}}) {
$any=1 if exists($flags{$t->{'title'}});
}
next unless $any;
my $title=$p->{'title'};
my $tok=$api->edittoken($title);
if($tok->{'code'} eq 'shutoff'){
$api->warn("Task disabled: ".$tok->{'content'}."\n");
return 300;
}
if($tok->{'code'} eq 'pageprotected' || $tok->{'code'} eq 'botexcluded'){
$api->warn("Cannot edit $title: ".$tok->{'error'});
next;
}
if($tok->{'code'} ne 'success'){
$api->warn("Failed to get edit token for $title: ".$tok->{'error'});
return 60;
}
next if $tok->{'lastrevid'} eq ($api->store->{"revid $title"} // 0);
$api->log("Need to check $title");
my $res=$api->query(
titles => $title,
generator => 'templates',
gtllimit => 'max',
redirects => 1,
);
if($res->{'code'} ne 'success'){
$api->warn("Failed to get templates and redirects for $title: ".$res->{'error'});
return 60;
}
my %map=();
for my $r (@{$res->{'query'}{'redirects'} // []}) {
$r->{'from'}=~s/^Template://;
$r->{'to'}=~s/^Template://;
$map{$r->{'from'}}=$r->{'to'};
}
my $fail=0;
my %log=();
my $intxt=$tok->{'revisions'}[0]{'slots'}{'main'}{'*'};
my $outtxt=$api->process_templates($intxt, sub {
return undef if $fail;
my $tname=shift;
my $params=shift;
shift; # $wikitext
shift; # $data
my $oname = shift;
my $name=$map{$tname} // $tname;
return undef unless exists($templates{"Template:$name"});
my $ret="{{$oname";
my $paramre = $templates{"Template:$name"};
for my $p ($api->process_paramlist(@$params)) {
if ($p->{'name'} =~ /^$paramre$/){
my $o=$p->{'value'};
my $v=$api->process_templates($o, sub {
return undef if $fail;
my $name=shift;
my $params=shift;
my $wikitext=shift;
return undef if grep /^\s*consensus[\s_]*to[\s_]*keep\s*=/i, @$params;
$name=$map{$name} // $name;
return undef unless exists($flags{"Template:$name"});
my $res=$api->query(
action => 'expandtemplates',
title => $title,
text => $wikitext,
prop => 'wikitext',
);
if($res->{'code'} ne 'success'){
$api->warn("Failed to expand $wikitext: ".$res->{'error'}."\n");
$fail=1;
return undef;
}
my $intxt=$res->{'expandtemplates'}{'wikitext'};
my $outtxt=$intxt;
$outtxt=~s!<span (?:[^>]* )?class="flagicon"(?: [^>]*)?>.*?</span>!!g;
if($outtxt eq $intxt){
$api->warn("Found nothing to replace in $wikitext in $title!\n") if $outtxt eq $intxt;
return undef;
}
$outtxt=~s/\[\[\s*([^]|])([^]|]*?)\s*\|\s*((?i:\1)\2)\s*\]\]/[[$3]]/g;
return $outtxt;
});
return undef if $fail;
if($o ne $v){
$log{"{{$tname}}"}=1;
$p->{'text'}=~s/\Q$o\E(\s*)$/$v$1/;
}
}
$ret.="|".$p->{'text'};
}
$ret.="}}";
return $ret;
});
next if $fail;
if(%log){
my @log=keys %log;
$log[-1]='and '.$log[-1] if @log>1;
my $summary="Removing flag icons from ".join(@log>2?', ':' ', @log)." per consensus, see [[User:AnomieBOT/docs/FlagIconRemover]] for details. $screwup";
$api->log("$summary in $title");
my $r=$api->edit($tok, $outtxt, $summary, 0, 1);
if($r->{'code'} ne 'success'){
$api->warn("Write failed on $title: ".$r->{'error'}."\n");
} else {
$api->store->{"revid $title"}=$r->{'edit'}{'newrevid'};
}
} else {
$api->log("Nothing to do in $title");
$api->store->{"revid $title"}=$tok->{'lastrevid'};
}
# If we've been at it long enough, let another task have a go.
return 0 if time()>=$endtime;
}
$self->{'iter'}=undef;
return 14400;
}
1;