User:AnomieBOT/source/tasks/WikiProjectWorker.pm: Difference between revisions

Content deleted Content added
AnomieBOT (talk | contribs)
Updating published sources: General: * New task, WikiProjectWorker. d::Util: * Add cache to <code>resolve_redirects()</code>, and a clear-cache function. d::WikiProjectTagging: * Allow WPBmin/WPBma
 
AnomieBOT (talk | contribs)
Updating published sources: WikiProjectTagger, WikiProjectWorker: * Retire these tasks, WikiProject templates have changed a bunch since I last ran these.
 
(79 intermediate revisions by the same user not shown)
Line 1:
{{ombox|type=notice|text= ApprovalApproved requested2009-04-08<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 28]]}}
{{ombox|type=notice|text= Retired 2024-01-29. Haven't had call to run this in a while, and the related templates have changed so I'd probably have to update this code to run it again.}}
<source lang="perl">
<syntaxhighlight lang="perl">
package tasks::WikiProjectWorker;
 
Line 7 ⟶ 8:
=begin metadata
 
Bot: AnomieBOT
Task: WikiProjectWorker
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 28
Status: BRFAInactive 2024-01-29
Rate: Max 6 edits/minute
Created: 2009-03-27
OnDemand: true
Line 27 ⟶ 28:
 
use Data::Dumper;
use Digest::SHA qw/sha256_base64/;
use AnomieBOT::Task;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
 
### Request link, for edit summary.
my $req="[[User:AnomieBOT/req/WikiProjectJapanWikiProject 1Higher Education|request]]";
 
### Increment this number every time a new run is started, so we don't have to
### mess around with deleting previous runs' database entries.
my $seq=128;
 
### How to find the pages?
my %catmap = (
my @templates=('WP Shinto', 'Jmyth', 'Gaijin tarento', 'Project Owarai', 'WikiProject Japan');
"Category:Articles using infobox university" => "WikiProject Higher education",
);
my @cats=keys %catmap;
my @iterators=(
{
list generator => 'embeddedincategorymembers',
eititle gcmtitle => [ map "Template:$_", @templates cats],
eilimit gcmlimit => 'max'100,
},
);
 
### Filter function: manipulate the found data as necessary, returning the talk
### page to tag (or undef to skip).
sub filter {
$_[0]->{'title'}='Talk:'.$_[0]->{'title'} if $_[0]->{'ns'}==0;
$_[0]->{'title'}=~s/^([^:]*):/$1 talk:/ if($_[0]->{'ns'}!=0 && ($_[0]->{'ns'}&1)==0);
return $_[0]->{'title'};
}
 
### How to copy other projects' assessments
sub copy_class {
return ($_[0]->WPBmax($_[2]))[0];
#return '';
}
 
my $always_copy_importance = 0;
my $set_empty_importance = 0;
sub copy_importance {
#return ($_[0]->WPBmax($_[2]))[1];
return '';
}
 
# Banner configurations.
my $main_banner='WikiProject Higher education';
my %banner_cfgs=(
'WikiProject JapanHigher education' => {
meta => 01,
stubautoimportance => undef'',
canonicalize => 'WikiProject JapanHigher education',
},
);
 
# Extra parameters (e.g. workgroup).
my @extra_params=();
my $taggingwith = @extra_params ? '|' . join( '|', @extra_params ) : '';
 
# Regex fragment to match any aliases of params in @extra_params.
my %extra_param_aliases = ();
 
# Possible main banners, usually just $main_banner.
my @main_banners=(
$main_banner,
);
 
# Set this to merge these existing banners into $main_banner.
my @merge_banners=();
 
# Set this to tag WikiProject Biography workgroups in addition to the project's own banner.
my @bio_wg = (
);
 
Line 68 ⟶ 106:
my $self=$class->SUPER::new();
$self->{'config loaded'}=0;
$self->{'iter'}=undef;
$self->{'iterators'}=[@iterators];
bless $self, $class;
return $self;
Line 75 ⟶ 115:
 
=for info
ApprovalApproved requested2009-04-08<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 28]]
 
=for info
Retired 2024-01-29. Haven't had call to run this in a while, and the related templates have changed so I'd probably have to update this code to run it again.
 
=cut
 
sub approved {
return 0-1;
}
 
Line 87 ⟶ 130:
my $res;
 
$api->task('WikiProjectWorker', 0, 10, qw/d::Util d::WikiProjectTagging/);
my $errto = 'Errors? [[User:'.$api->user.'/shutoff/WikiProjectWorker]]';
 
# Load configs, if necessary
Line 95 ⟶ 139:
$cfg=$api->WPBMetaConfig($cfg->{'meta'}, %$cfg) if exists($cfg->{'meta'});
$cfg{$banner}=$cfg;
$banner_cfgs{$banner}{'stubauto'}=$cfg->{'stubauto'};
}
$api->WPBconfig(%cfg);
 
$self->{'config loaded'}=1;
}
if(($api->store->{'configured'} // 0) < $seq){
### Initialize configuration here
$api->store->{'conflicting assessments'}='';
$api->store->{'NA assessments'}='';
}
 
# Update log page
if($api->store->{'conflicting assessments'} ne '' || $api->store->{'NA assessments'} ne ''){
my $tok=$api->edittoken('Wikipedia:WikiProject Japan/Assessment/Tag cleanup');
if($tok->{'code'} ne 'success'){
$api->warn("Cannot update log: ".$tok->{'error'}."\n");
return 60;
}
my $txt=$tok->{'revisions'}[0]{'*'};
my $a=$api->store->{'conflicting assessments'};
my $b=$api->store->{'NA assessments'};
unless($txt=~s/(<!-- Insert conflicting assessments above here -->)/$a$1/ &&
$txt=~s/(<!-- Insert NA assessments above here -->)/$b$1/){
$api->warn("Log is missing conflicting assessments marker");
$api->whine("[[Wikipedia:WikiProject Japan/Assessment/Tag cleanup]] is broken", "Help! [[Wikipedia:WikiProject Japan/Assessment/Tag cleanup]] is missing the comments that tell me where to insert new log entries. I can't do anything to that page until someone fixes it.");
return 60;
}
$api->warn("Updating log\n");
my $r=$api->edit($tok, $txt, "Bot updating log", 0, 0);
if($r->{'code'} ne 'success'){
$api->warn("Write failed on log: ".$r->{'error'}."\n");
return 60;
}
$api->store->{'conflicting assessments'}='';
$api->store->{'NA assessments'}='';
}
 
# Preload cache
$api->redirects_to(map "Template:$_", @templates);
 
# Spend a max of 5 minutes on this task before restarting
my $endtime=time()+300;
 
while(1){
foreach my $itercfg (@iterators) {
my $iter=$apiself->iterator(%$itercfg){'iter'};
if(!defined($iter)){
my $i=shift @{$self->{'iterators'}};
last unless $i;
$iter=$api->iterator(%$i);
$self->{'iter'}=$iter;
}
while(my $page=$iter->next()){
if(!$page->{'_ok_'}){
Line 149 ⟶ 171:
my $title=filter($page);
if(!defined($title)){
$api->warnlog("Skipping ".$page->{'title'}.", filter returned undef\n");
$api->store->{$pageid}=$seq;
next;
Line 164 ⟶ 186:
}
if(($tok->{'ns'}&1)==0){
$api->warnlog("Cannot edit $title: namespace ".$tok->{'ns'}." is non-talk\n");
$api->store->{$pageid}=$seq;
next;
}
if(exists($tok->{'redirect'})){
$api->warnlog("$title is a redirect, skipping.\n");
$api->store->{$pageid}=$seq;
next;
}
 
$api->warnlog("Checking $title...\n");
 
my $intxt=exists($tok->{'revisions'}[0]{'*slots'})?$tok->{'revisionsmain'}[0]{'*'}: // '';
my ($outtxt,$nowiki)=$api->strip_nowiki($intxt);
 
my @params=@extra_params;
 
my $assess = undef;
my $class = copy_class($api, $title, $intxt);
if(ref($class) eq 'HASH'){
$api->warn("Processing $title failed: ".$class->{'error'}."\n");
next;
}
$class=~s/^\s+|\s+$//g;
$assess=$api->WPBassess($title);
if(ref($assess) eq 'HASH'){
if($assess->{'code'} eq 'pagemissing'){
# No subject page, doesn't matter
$assess=undef;
} else {
$api->warn("Processing $title failed: ".$assess->{'error'}."\n");
next;
}
}
 
my $copy_importance = $always_copy_importance; # Always copy?
if($class eq '' || lc($class) eq lc($assess)){
$class='';
} else {
$assess=undef;
push @params, "class=$class";
$copy_importance = 1;
}
 
if($copy_importance){
my $imp = copy_importance($api, $title, $intxt);
if(ref($imp) eq 'HASH'){
$api->warn("Processing $title failed: ".$imp->{'error'}."\n");
next;
}
push @params, "importance=$imp" if ( $set_empty_importance || ($imp//'') ne '' );
}
 
my $need_main_banner = ($api->WPBcheck($outtxt, @main_banners) == 0);
if(0){
# grr, already redirected so the above always returns true
$need_main_banner=1;
$api->WPBcheck($outtxt, sub {
my $banner=shift;
my $name=shift;
$need_main_banner=0 if(grep $name eq $_, @main_banners);
return undef;
}, @main_banners);
}
 
### PROCESSING ###
 
my @merge=();
# Is there a WikiProject Japan template already on the page?
my $need_WPJ@summary=($api->WPBcheck($outtxt, "WikiProject Japan") == 0);
my $no_summary = 0;
 
# First,Special: removeDifferent thedefault to-be-removedparent templatesbanner anddepending calculateon tasksource category.
#$main_banner force= parameters.$catmap{$iter->iterval};
my $fail=0;
my $class=undef;
my $imp=undef;
my %tf=();
(undef,$outtxt)=$api->WPBcheck($outtxt, sub {
my $banner=shift;
shift; # $name
my $oname=shift;
my @params=@{shift()};
 
my $wpj=if($banner eq 'WikiProject Japan'@merge_banners);{
(undef,$outtxt)=$api->WPBcheck($outtxt, sub {
my $banner=shift;
my $name=shift;
my $oname=shift;
my $params=shift;
my $wikitext=shift;
 
$tf{'shinto'}=1 return undef if(grep $bannername eq 'WP$_, Shinto'@main_banners);
 
$tf{'myth'}=1 if $banner eq 'Jmyth';
$tf{'gaijin'}=1 if $banner eq 'Gaijinpush tarento'@merge, $oname;
 
$tf{'owarai'}=1 if $banner eq 'Project Owarai';
foreach (@params) { return '' unless $need_main_banner;
if(/^\s*class\s*=\s*(\S.*?)\s*$/s){need_main_banner=0;
return $fail=1 if(defined($class) && lc($class) ne lc("{{$1))main_banner}}";
}, $class=$1@merge_banners);
if(ref($outtxt) eq }'HASH'){
if$api->warn(/^\s*importance\s*=\s*(\S"Preprocessing $title failed: ".*?)$outtxt->{'error'}."\s*$/sn"){;
$fail=1 if(defined($imp) && lc($imp) ne lc($1))next;
$imp=$1;}
}if(@merge){
if($wpj && /^\s*tfmerge[23-1]?\s*=\s*(\S'and '.*?)\s*$/s){merge[-1] if @merge>1;
push @summary, "merging ".join((@merge>2)?', my':' $x=lc($1', @merge)." into $main_banner" if @merge;
$no_summary = $tf{'baseball'}=1 if $x eq 'baseball'@merge;
} else $tf{'car'}=1 if $x eq 'car';
# $api->warn("$title contains ".$tf{'CJKV'}=1iter->iterval.", but not in section if $x eq 'cjkv'0\n");
$tf{'dist-muni'}=1 if $x eq 'districts and municipalities'next;
$tf{'gaijin'}=1 if $x eq 'gaijin tarento';
$tf{'milhist'}=1 if $x eq 'military history';
$tf{'music'}=1 if $x eq 'music';
$tf{'myth'}=1 if $x eq 'mythology';
$tf{'owarai'}=1 if $x eq 'owarai';
$tf{'phototf'}=1 if $x eq 'photo';
$tf{'prefectures'}=1 if $x eq 'prefectures';
$tf{'royalty'}=1 if $x eq 'royalty and nobility';
$tf{'shinto'}=1 if $x eq 'shinto';
$tf{'tokyo'}=1 if $x eq 'tokyo';
$tf{'update'}=1 if $x eq 'update';
}
}
return undef if $banner eq 'WikiProject Japan';
return '' unless $need_WPJ;
$need_WPJ=0;
return '{{WikiProject Japan}}';
}, @templates);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
 
#if Second,( add@bio_wg (or replace) {{WikiProject Japan}}
my @tf=map "$_=yes", keys my %tfadded_wg=();
my @assess= (undef,$outtxt);=$api->WPBcheck($outtxt, sub {
if( my $fail){banner=shift;
$api->store->{'conflicting assessments'}.="* [[: my $title]]\n"name=shift;
} else { my $oname=shift;
push @assess, "class=$class" if defined(my $class)params=shift;
push @assess, "importance=$imp" if defined(my $imp)wikitext=shift;
 
$api->store->{'NA assessments'}.="* [[:$title]]\n" if ($class // '') eq 'na';
} my %have = ();
my foreach ($assess=undef;api->process_paramlist(@$params)) {
unless(defined( $class))have{$_->{'name'}} = 1;
$assess=$api->WPBassess($title); }
if(ref( my $assess)any eq= 'HASH'){0;
$api->warn("Processingforeach my $titlep failed: ".$outtxt->(@bio_wg){'error'}."\n");
next if exists($have{$p});
push @$params, "$p=yes";
$added_wg{"$p=yes"}=1;
$any = 1;
}
return undef unless $any;
 
my $out="{{$oname";
$out.="|".join("|", @$params) if @$params;
$out.="}}";
return $out;
}, 'WikiProject Biography');
if(ref($outtxt) eq 'HASH'){
$api->warn("WPBIO workgroups in $title failed: ".$outtxt->{'error'}."\n");
next;
}
if(%added_wg){
my @added_wg = keys %added_wg;
$added_wg[-1]='and '.$added_wg[-1] if @added_wg>1;
push @summary, "added " . join((@added_wg>2)?', ':' ', @added_wg) . " to {{WikiProject Biography}}";
}
}
$outtxt=$api->WPBadd($outtxt, $assess, sub {
shift; # $banner
shift; # $name
my $oname=shift;
my $params=shift;
shift; # $wikitext
my $new=shift;
return undef if $new;
 
foreach my $tf (keys %tf) {tag;
my $pg=$title;
push @$params, "$tf=yes" unless(grep(s/^(\s*\Q$tf\E\s*=(?:\s*(?=\S))?).*?(\s*)$/${1}yes$2/s, @$params));
$pg=~s/^Talk://;
if($page->{'title'} ne $pg){
$page=$api->query(
titles => $pg,
prop => 'info',
redirects => 1,
);
if($page->{'code'} ne 'success'){
$api->warn("Could not load $pg info: ".$page->{'error'}."\n");
return 60;
}
 
if$page=(@assess)values %{$page->{'query'}{'pages'}})[0];
if(defined($class)){}
 
push @$params, "class=$class" unless(grep(s/^(\s*class\s*=(?:\s*(?=\S))?).*?(\s*)$/$1$class$2/s, @$params));
my @process_banners = ();
$api->WPBcheck( $outtxt, sub { push @process_banners, $_[0]; }, @main_banners );
@process_banners = ( $main_banner ) unless @process_banners;
for my $process_banner (@process_banners) {
$outtxt=$api->WPBadd($outtxt, $assess, sub {
my $banner=shift; # banner
my $name=shift; # name
my $oname=shift;
my $params=shift;
my $wikitext=shift;
my $new=shift;
#return '' if $new;
 
return undef unless(grep $banner eq $_, @main_banners);
my %cfg=%{$banner_cfgs{$banner}};
 
my $any=0;
foreach my $p (@params){
next unless $p=~/^(.+?)=(.*)$/;
my ($k,$v)=($1,$2);
my $kre=qr/\Q$k\E/;
if ( defined( $extra_param_aliases{$k} ) ) {
my $aliasre = $extra_param_aliases{$k};
$kre = qr/(?:$kre|$aliasre)/;
}
my $re=qr/\S.*?/;
unless(grep(/^\s*$kre\s*=\s*$re\s*$/, @$params)){
next if(grep(/^\s*$kre\s*=\s*(?i:\Q$v\E)\s*$/s, @$params));
unshift @$params, "$k=$v" unless(grep(s/^(\s*$kre\s*=\s*?)(?:\S.*?)?(\s*)$/$1$v$2/s, @$params));
$any=1 unless $v eq '';
if($k eq 'class' && exists($cfg{'meta'}) && ($cfg{'stubauto'}//'')){
my $aa=$cfg{'stubauto'};
$aa=~s/\s*=.*//;
push @$params, "$aa=inherit" unless(grep(s/^(\s*\Q$aa\E\s*=\s*?)(?:\S.*?)?(\s*)$/$1inherit$2/s, @$params));
}
}
}
if(defined$new && $class && (grep /^class=/, @$params) && exists($cfg{'meta'}) && ($impcfg{'stubauto'}//'')){
pushmy @$params, "importanceaa=$imp" unless(grep(s/^(\s*importance\s*=(?:\s*(?=\S))?).*?(\s*)$/$1$imp$2/s, @$params))cfg{'stubauto'};
$aa=~s/\s*=.*//;
push @$params, "$aa=inherit" unless(grep(s/^(\s*\Q$aa\E\s*=\s*?)(?:\S.*?)?(\s*)$/$1inherit$2/s, @$params));
$any=1;
}
} return $wikitext unless $any;
 
return "{{$oname}}" unless @ if(defined($params;cfg{'canonicalize'})){
return "{{$oname|".join("|", @ my $params)."}n=$cfg{'canonicalize'}";
}, 'WikiProject Japan', @tf, @assess) $oname=~s/_/ /g;
if $oname=~s/^(ref\s*)\S($outtxt?:.*\S) eq 'HASH'?(\s*){$/$1$n$2/is;
$api->warn("Processing $title failed: ".$outtxt->{'error' }."\n");
next my $out="{{$oname";
$out.="|".join("|", @$params) if @$params;
$out.="}}";
return $out;
}, $process_banner, @params);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
push @summary, "Tagging with {{$process_banner$taggingwith}}" unless $no_summary;
}
 
Line 291 ⟶ 411:
# Need to edit?
if($outtxt ne $intxt){
$outtxt=$api->WPBfixshellif($outtxt!@summary);{
$api->warn("$title changed, but nothing in \@summary\n");
next;
}
my $cat=$iter->iterval;
$summary[-1]='and '.$summary[-1] if @summary>1;
my $summary = ucfirst(join((@summary>2)?', ':' ', @summary))." per $req";
 
my @cleanup=();
$outtxt=$api->WPBfixshell($outtxt, \@cleanup);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
$summary.="; general banner cleanup (".join(', ', @cleanup).")" if @cleanup;
$summary.=". $errto";
 
my $api->log("$summary="Adjusting WikiProject tagging for WikiProject Japan perin $reqtitle");
$api->warn("$summary in $title\n");
my $r=$api->edit($tok, $outtxt, $summary, 1, 1);
if($r->{'code'} ne 'success'){
Line 305 ⟶ 435:
}
} else {
$api->warnlog("Nothing to do in $title\n");
}
 
Line 314 ⟶ 444:
return 0 if time()>=$endtime;
}
$self->{'iter'}=undef;
}
 
# No more pages to check, try again in 10 minutes or so in case of errors.
$self->{'iter'}=undef;
$self->{'iterators'}=[@iterators];
$api->log("WikiProjectWorker may be DONE!");
return 600;
}
 
1;
</source>
 
</syntaxhighlight>