https://en.wikipedia.org/w/index.php?action=history&feed=atom&title=User%3AFairuseBot%2FlibBot.pm
User:FairuseBot/libBot.pm - Revision history
2025-06-06T04:36:44Z
Revision history for this page on the wiki
MediaWiki 1.45.0-wmf.4
https://en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=522163989&oldid=prev
Carnildo: Updated
2012-11-09T11:54:00Z
<p>Updated</p>
<a href="//en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=522163989&oldid=252317088">Show changes</a>
Carnildo
https://en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=252317088&oldid=prev
Carnildo: New version
2008-11-17T06:45:35Z
<p>New version</p>
<a href="//en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=252317088&oldid=201756285">Show changes</a>
Carnildo
https://en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=201756285&oldid=prev
Carnildo: New version
2008-03-29T05:36:17Z
<p>New version</p>
<table style="background-color: #fff; color: #202122;" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Previous revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 05:36, 29 March 2008</td>
</tr><tr>
<td colspan="2" class="diff-lineno">Line 3:</td>
<td colspan="2" class="diff-lineno">Line 3:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br /></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br /></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div># libBot: A Perl module of useful routines for running a bot</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div># libBot: A Perl module of useful routines for running a bot</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><br /></td>
<td colspan="2" class="diff-empty diff-side-added"></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div>########## WARNING: NOT ALL OF THESE FUNCTIONS WILL WORK PROPERLY WITH Pearle.pm ##########</div></td>
<td colspan="2" class="diff-empty diff-side-added"></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br /></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><br /></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>package libBot;</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>package libBot;</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 825:</td>
<td colspan="2" class="diff-lineno">Line 823:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> my $i = 0;</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> my $i = 0;</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> notelog("File: $file\n");</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> notelog("File: $file\n");</div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> open INFILE, "<", $file;</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> open INFILE, "<<ins style="font-weight: bold; text-decoration: none;">:utf8</ins>", $file;</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> while(<INFILE>)</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> while(<INFILE>)</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> {</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> {</div></td>
</tr>
<tr>
<td colspan="2" class="diff-lineno">Line 846:</td>
<td colspan="2" class="diff-lineno">Line 844:</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> my $key;</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> my $key;</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> </div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> </div></td>
</tr>
<tr>
<td class="diff-marker" data-marker="−"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div> open OUTFILE, ">", $file;</div></td>
<td class="diff-marker" data-marker="+"></td>
<td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> open OUTFILE, "><ins style="font-weight: bold; text-decoration: none;">:utf8</ins>", $file;</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> foreach $key (keys(%notelist))</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> foreach $key (keys(%notelist))</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> {</div></td>
<td class="diff-marker"></td>
<td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div> {</div></td>
</tr>
</table>
Carnildo
https://en.wikipedia.org/w/index.php?title=User:FairuseBot/libBot.pm&diff=201497746&oldid=prev
Carnildo: ←Created page with '<pre><nowiki> #!/usr/bin/perl # libBot: A Perl module of useful routines for running a bot ########## WARNING: NOT ALL OF THESE FUNCTIONS WIL...'
2008-03-28T03:46:55Z
<p><a href="/wiki/Wikipedia:Automatic_edit_summaries" class="mw-redirect" title="Wikipedia:Automatic edit summaries">←</a>Created page with '<pre><nowiki> #!/usr/bin/perl # libBot: A Perl module of useful routines for running a bot ########## WARNING: NOT ALL OF THESE FUNCTIONS WIL...'</p>
<p><b>New page</b></p><div><pre><nowiki><br />
#!/usr/bin/perl<br />
<br />
# libBot: A Perl module of useful routines for running a bot<br />
<br />
########## WARNING: NOT ALL OF THESE FUNCTIONS WILL WORK PROPERLY WITH Pearle.pm ##########<br />
<br />
package libBot;<br />
<br />
use strict;<br />
use warnings;<br />
<br />
use Pearle;<br />
use Data::Dumper;<br />
<br />
require Exporter;<br />
<br />
our @ISA = qw(Exporter);<br />
our @EXPORT = qw(config usernotify wikilog botwarnlog notelog LoadInfoboxPatterns FixupLinks MakeWikiRegex DoIHaveMessages GetPageCategories GetPageLinks GetPageText GetPageList GetFullPageList SaveImage UpdateLink RemoveImageFromPage IsNotified isDated getDate getUploadDates getLastEditDate GetImageUploader loadNotificationList saveNotificationList);<br />
our $VERSION = 1.00;<br />
<br />
my $test_only = 0;<br />
my $username = "";<br />
my @infobox_patterns = ();<br />
<br />
sub config<br />
{<br />
my %params = @_;<br />
<br />
$test_only = $params{test_only} if(defined($params{test_only}));<br />
$username = $params{username} if(defined($params{username}));<br />
}<br />
<br />
# Log a warning on a user's talkpage, using an existing edit session<br />
sub usernotify<br />
{<br />
my ($wikipage, $text, $user, $summary);<br />
$wikipage = $_[1];<br />
$summary = $_[2];<br />
$summary = "Logging warning message" if(!defined($summary));<br />
<br />
# We've been handed an editing session<br />
Pearle::myLog(4, "Warning with existing edit session\n");<br />
<br />
if($test_only)<br />
{<br />
print STDERR $_[0];<br />
return;<br />
}<br />
<br />
if($wikipage->getWikiText() =~ /^#redirect/i)<br />
{<br />
botwarnlog("*User talk page [[User talk:$user]] is a redirect\n");<br />
return;<br />
}<br />
$text = $wikipage->getEditableText();<br />
$text .= $_[0];<br />
$wikipage->setEditableText($text);<br />
Pearle::postPage($wikipage, $summary, 0);<br />
print STDERR $_[0];<br />
}<br />
<br />
# General-purpose on-Wiki logging routine<br />
sub wikilog<br />
{<br />
my($target, $text, $wikipage, $summary);<br />
$target = $_[0];<br />
$summary = $_[2] || "Logging note";<br />
<br />
$wikipage = Pearle::getPage($target);<br />
<br />
if($test_only)<br />
{<br />
print STDERR $_[1];<br />
return;<br />
}<br />
<br />
$text = $wikipage->getEditableText();<br />
$text .= $_[1];<br />
$wikipage->setEditableText($text);<br />
<br />
Pearle::postPage($wikipage, $summary, 0);<br />
print STDERR $_[1];<br />
}<br />
<br />
# Log a warning on the talk page of the bot<br />
sub botwarnlog<br />
{<br />
my ($page, $text, $summary);<br />
$text = $_[0];<br />
$summary = $_[1];<br />
$summary = "Logging warning message" if(!defined($summary));<br />
$page = "User talk:${username}/log";<br />
<br />
wikilog($page, $text, $summary);<br />
}<br />
<br />
# Log a notification message to the console<br />
sub notelog<br />
{<br />
print STDERR @_;<br />
}<br />
<br />
# Fix all wikilinks in a string so that they shows as a link, not inline, if it's for a category or image<br />
sub FixupLinks<br />
{<br />
my $link = shift;<br />
$link =~ s/\[\[(Category|Image)/[[:$1/g;<br />
return $link;<br />
}<br />
<br />
# Make a string into a Wikipedia-compatible regex<br />
sub MakeWikiRegex<br />
{<br />
my $string = shift;<br />
my @chars = split //, $string;<br />
my $result = '';<br />
<br />
foreach my $char (@chars)<br />
{<br />
# Escape metacharacters, and add percent-encoding for certain characters<br />
if($char eq '\\') {$result .= '\\\\';}<br />
elsif($char eq '.') {$result .= '\.';}<br />
elsif($char eq '(') {$result .= '(?:\(|%28)';}<br />
elsif($char eq ')') {$result .= '(?:\)|%29)';}<br />
elsif($char eq '[') {$result .= '\[';}<br />
elsif($char eq ']') {$result .= '\]';}<br />
elsif($char eq '+') {$result .= '\+';}<br />
elsif($char eq '*') {$result .= '\*';}<br />
elsif($char eq '?') {$result .= '(?:\?|%3F)';}<br />
elsif($char eq '^') {$result .= '\^';}<br />
elsif($char eq '$') {$result .= '\$';}<br />
elsif($char eq '&') {$result .= '(?:&|%26)';}<br />
elsif($char eq '!') {$result .= '(?:!|%21)';}<br />
elsif($char eq '~') {$result .= '(?:~|%7E)';}<br />
elsif($char eq "'") {$result .= "(?:'|%27)";}<br />
elsif($char eq '"') {$result .= '(?:"|%22)';}<br />
elsif($char eq ',') {$result .= '(?:,|%2C)';}<br />
else {$result .= $char;}<br />
}<br />
# Process the string to match both with spaces and with underscores<br />
$result =~ s/[ _]/[ _]+/g;<br />
<br />
# Process the string to match both upcase and lowercase first characters<br />
if($result =~ /^[A-Za-z]/)<br />
{<br />
$result =~ s/^(.)/"[$1".lc($1)."]"/e;<br />
}<br />
return $result;<br />
}<br />
<br />
sub HTMLEncode<br />
{<br />
my $char = shift;<br />
return sprintf("&X%X;", ord($char));<br />
}<br />
<br />
# Make a string into something that can match most image name formats<br />
sub MakeFancyRegex<br />
{<br />
my $string = shift;<br />
my @chars = split //, $string;<br />
my $result;<br />
<br />
foreach my $char (@chars)<br />
{<br />
if($char eq '\\')<br />
{<br />
$result .= "(\\\\|%5C|%5c|&x5C;)";<br />
}<br />
elsif($char eq '.')<br />
{<br />
}<br />
elsif($char eq '(')<br />
{<br />
}<br />
elsif($char eq ')')<br />
{<br />
}<br />
else<br />
{<br />
$result .= "($char|" . uri_escape_utf8($char) . "|" . lc(uri_escape_utf8($char)) . "|" . HTMLEncode($char) . "|" . lc(HTMLEncode($char)) . ")";<br />
}<br />
}<br />
<br />
return $result;<br />
}<br />
<br />
# Check for new talk page messages<br />
sub DoIHaveMessages<br />
{<br />
my $xml = shift;<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($xml);<br />
if(exists($parsed_xml->{query}->{userinfo}->{messages}) and defined($parsed_xml->{query}->{userinfo}->{messages}))<br />
{<br />
return 1;<br />
}<br />
else<br />
{<br />
return 0;<br />
}<br />
}<br />
<br />
<br />
sub GetPageCategories<br />
{<br />
my $image_data = shift;<br />
my @pages = ();<br />
<br />
if(defined($image_data))<br />
{<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($image_data);<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{pages}->{page}->{categories}->{cl}) and defined($parsed_xml->{query}->{pages}->{page}->{categories}->{cl}))<br />
{<br />
if(ref($parsed_xml->{query}->{pages}->{page}->{categories}->{cl}) eq 'ARRAY')<br />
{<br />
my @all_pages = @{$parsed_xml->{query}->{pages}->{page}->{categories}->{cl}};<br />
<br />
@pages = map {$_->{title}} @all_pages;<br />
}<br />
else<br />
{<br />
@pages = ($parsed_xml->{query}->{pages}->{page}->{categories}->{cl}->{title});<br />
}<br />
}<br />
}<br />
return @pages;<br />
}<br />
<br />
sub GetPageLinks<br />
{<br />
my $image_data = shift;<br />
my @pages = ();<br />
<br />
if(defined($image_data))<br />
{<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($image_data);<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{pages}->{page}->{links}->{pl}) and defined($parsed_xml->{query}->{pages}->{page}->{links}->{pl}))<br />
{<br />
if(ref($parsed_xml->{query}->{pages}->{page}->{links}->{pl}) eq 'ARRAY')<br />
{<br />
my @all_pages = @{$parsed_xml->{query}->{pages}->{page}->{links}->{pl}};<br />
<br />
@pages = map {$_->{title}} @all_pages;<br />
}<br />
else<br />
{<br />
@pages = ($parsed_xml->{query}->{pages}->{page}->{links}->{pl}->{title});<br />
}<br />
}<br />
}<br />
return @pages;<br />
}<br />
<br />
sub GetPageText<br />
{<br />
my $image_data = shift;<br />
my $text = undef;<br />
<br />
if(defined($image_data))<br />
{<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($image_data);<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{pages}->{page}->{revisions}->{rev}) and defined($parsed_xml->{query}->{pages}->{page}->{revisions}->{rev}))<br />
{<br />
$text = $parsed_xml->{query}->{pages}->{page}->{revisions}->{rev};<br />
}<br />
}<br />
return $text;<br />
}<br />
<br />
sub GetPageList<br />
{<br />
my $image_data = shift;<br />
my $image;<br />
my @pages = ();<br />
<br />
if(defined($image_data))<br />
{<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($image_data);<br />
my $image = $parsed_xml->{query}->{pages}->{page}->{title};<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{imageusage}->{iu}) and defined($parsed_xml->{query}->{imageusage}->{iu}))<br />
{<br />
if(ref($parsed_xml->{query}->{imageusage}->{iu}) eq 'ARRAY')<br />
{<br />
my @bad_pages = grep {$_->{ns} == 10 or $_->{ns} == 12} @{$parsed_xml->{query}->{imageusage}->{iu}};<br />
my @good_pages = grep {$_->{ns} != 10 and $_->{ns} != 12} @{$parsed_xml->{query}->{imageusage}->{iu}};<br />
<br />
@pages = map {$_->{title}} @good_pages;<br />
<br />
if(scalar(@bad_pages) > 0 and defined($image)) # If "image" is undefined, we're probably doing a pure usage check, rather than one in preparation for removal<br />
{<br />
my $notice;<br />
foreach my $page (@bad_pages)<br />
{<br />
$notice .= "*Found image [[:$image]] in [[$page->{title}]]\n";<br />
}<br />
botwarnlog($notice);<br />
}<br />
}<br />
else<br />
{<br />
if($parsed_xml->{query}->{imageusage}->{iu}->{ns} != 10 and $parsed_xml->{query}->{imageusage}->{iu}->{ns} != 12)<br />
{<br />
@pages = $parsed_xml->{query}->{imageusage}->{iu}->{title};<br />
}<br />
else<br />
{<br />
if(defined($image))<br />
{<br />
botwarnlog("*Found image [[:$image]] in [[$parsed_xml->{query}->{imageusage}->{iu}->{title}]]\n");<br />
}<br />
}<br />
}<br />
}<br />
}<br />
<br />
return @pages;<br />
}<br />
<br />
# Get all pages. Don't filter for bad namespaces.<br />
sub GetFullPageList<br />
{<br />
my $image = shift;<br />
my @pages = ();<br />
<br />
my $xml = Pearle::APIQuery(list => 'imageusage', iutitle => $image);<br />
if(defined($xml))<br />
{<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($xml);<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{imageusage}->{iu}) and defined($parsed_xml->{query}->{imageusage}->{iu}))<br />
{<br />
if(ref() eq 'ARRAY')<br />
{<br />
@pages = map {$_->{title}} @{$parsed_xml->{query}->{imageusage}->{iu}};<br />
}<br />
else<br />
{<br />
@pages = $parsed_xml->{query}->{imageusage}->{iu}->{title};<br />
}<br />
}<br />
}<br />
<br />
return @pages;<br />
}<br />
<br />
sub UpdateLink<br />
{<br />
my $page = shift;<br />
my $from = shift;<br />
my $to = shift;<br />
<br />
die "No page to edit" if(!defined($page));<br />
die "No link to change" if(!defined($from));<br />
die "No new link" if(!defined($to));<br />
<br />
Pearle::myLog(3, "Updating link from $from to $to\n");<br />
<br />
my $wikipage = Pearle::getPage($page);<br />
$wikipage->canonicalizeLinks();<br />
my $text = $wikipage->getEditableText();<br />
my $link_regex = MakeWikiRegex($from);<br />
<br />
my $matches = $text =~ s/\x01($link_regex)\x02/\x01${to}|${1}\x02/gi;<br />
$matches += $text =~ s/\x01$link_regex\|/\x01${to}|/gi;<br />
<br />
$wikipage->setEditableText($text);<br />
Pearle::postPage( $wikipage, "Updating link to bypass a redirect or disambiguation page", 0);<br />
<br />
return $matches;<br />
}<br />
<br />
sub RemoveImageFromPage<br />
{<br />
my $image = shift;<br />
my $page = shift;<br />
my $image_regex = shift;<br />
my $removal_prefix = shift;<br />
my $removal_comment = shift;<br />
<br />
my $wikipage;<br />
my $text;<br />
my ($match1, $match2);<br />
my $old_length;<br />
my $new_length;<br />
my $change_len;<br />
my $match_len;<br />
<br />
tryagain:<br />
# Fetch an article page<br />
$wikipage = Pearle::getPage($page);<br />
$wikipage->canonicalizeLinks();<br />
$text = $wikipage->getEditableText();<br />
<br />
if(!defined($text))<br />
{<br />
Pearle::myLog(1, "Error: Bad edit page [[$page]]\n");<br />
botwarnlog(FixupLinks("*Error: Bad edit page [[$page]]\n"));<br />
sleep(300);<br />
return 0;<br />
}<br />
<br />
if($text =~ /^\s*$/)<br />
{<br />
# Might be protected instead of empty<br />
Pearle::myLog(1, "Error: Empty or protected page [[$page]]\n");<br />
botwarnlog(FixupLinks("*Error: Empty or protected page [[$page]]\n"));<br />
sleep(300);<br />
return 0;<br />
}<br />
<br />
if($text =~ /^#redirect/i)<br />
{<br />
Pearle::myLog(1, "Redirect found for page [[$page]] (image [[:$image]])\n");<br />
botwarnlog(FixupLinks("*Redirect found for page [[$page]] (image [[:$image]])\n"));<br />
print $text;<br />
return 0;<br />
}<br />
<br />
# Remove the image<br />
my $regex3 = "(\x01${image_regex}[^\x01]*?(\x01[^\x02]*?\x02[^\x01]*?|)+\x02[ \\t]*)"; # Regex to match images<br />
<br />
#my $regex3 = "(<br />
# \x01 # Open double-bracket for the image<br />
# ${image_regex} # The image itself<br />
# [^\x01]*? # Anything up to the first link in the caption, or a closing double bracket (minimal match)<br />
# (\x01 # Open double-bracket for a link in the caption<br />
# [^\x02]*? # Anything but a closing double-bracket<br />
# \x02 # The closing double-bracket for the link<br />
# [^\x01]*?|) # Any non-link text, or nothing<br />
# + # Matches one or more times<br />
# \x02 # The closing double-bracket for the image<br />
# [ \\t]*) # Any trailing whitespace<br />
# ";<br />
<br />
my $regex3ex = "\\w[ \\t]*${regex3}[ \\t]*\\w"; # Regex to try to spot inline images<br />
my $regex3g = "(${image_regex}.*)"; # Regex to match gallery images<br />
my ($raw_image) = $image =~ /Image:(.*)/; <br />
<br />
my $regex4m = "\x01[ _]*[Mm]edia[ _]*:[ _]*" . MakeWikiRegex($raw_image) . "[ _]*\\|([^]]*)\x02"; # Regex to match inline Media: links<br />
<br />
Pearle::myLog(3, "Regex 3: $regex3\n");<br />
notelog("Regex 3: $regex3\n");<br />
notelog("Regex 3 extended: $regex3ex\n");<br />
notelog("Regex 3 gallery: $regex3g\n");<br />
Pearle::myLog(3, "Raw regex: $raw_image\n");<br />
notelog("Regex 4 Media: $regex4m\n");<br />
<br />
if($text =~ /$regex3ex/)<br />
{<br />
Pearle::myLog(1, "Possible inline image in [[$page]]\n");<br />
botwarnlog(FixupLinks("*Possible inline image [[:$image]] in [[$page]]\n"));<br />
return 0; # Can't do gallery matching because that also matches regular images, and odds are, we don't have an infobox<br />
}<br />
<br />
if($text =~ /-->/) # With the new editing markup, any close-comment means that somebody fucked up their wikimarkup<br />
{<br />
Pearle::myLog(3, "Fractional comment in page [[$page]]\n");<br />
botwarnlog(FixupLinks("*Fractional comment in page [[$page]]\n"));<br />
}<br />
<br />
$text =~ /$regex3/;<br />
$match_len = length($1);<br />
$match2 = $text =~ s/$regex3/<!-- $removal_prefix $1 -->/g;<br />
<br />
$new_length = length($text);<br />
print "Num: $match2 Len: $match_len\n";<br />
if($match2)<br />
{<br />
# If a whole lot of text was removed, log a warning<br />
if($match_len > (500 + length($image)))<br />
{<br />
botwarnlog(FixupLinks("*Long caption of $match_len bytes replaced in [[$page]]\n"));<br />
if($match_len > (1000 + length($image)))<br />
{<br />
Pearle::myLog(2, "Unusually long caption of $match_len found in [[$page]] ($match2 matches).\n");<br />
print $text, "\n";<br />
# exit;<br />
return 0;<br />
}<br />
}<br />
if($match_len < (2 + length($image)))<br />
{<br />
Pearle::myLog(0, "Short replacement of $match_len bytes (min " . (length($image) + 2) . ") in [[$page]] ($match2 matches). Exiting.\n");<br />
Pearle::myLog(0, "Text:\n$text\n");<br />
exit;<br />
}<br />
# If many matches, log a warning<br />
if($match2 > 2)<br />
{<br />
Pearle::myLog(3, "More than one match ($match2) in page [[$page]]\n");<br />
# botwarnlog(FixupLinks("*More than one match ($match2) in page [[$page]]\n"));<br />
}<br />
if($match2 > 100)<br />
{<br />
Pearle::myLog(1, "Too many matches ($match2) in page [[$page]]. Skipping.\n");<br />
botwarnlog("*Too many matches ($match2) in page [[$page]]. Skipping.\n");<br />
return 0;<br />
}<br />
}<br />
<br />
# Put the text back and get it again in order to fold any comments resulting from removing non-gallery images.<br />
# This is because gallery image matching will also match commented images.<br />
$wikipage->setEditableText($text);<br />
$text = $wikipage->getEditableText();<br />
<br />
if($text =~ /<gallery/i)<br />
{<br />
Pearle::myLog(3, "*Possible image gallery in page [[$page]]\n");<br />
if($text =~ s/$regex3g/<!-- $removal_prefix $1 -->/g)<br />
{<br />
# if($match2 != 0)<br />
# {<br />
# botwarnlog("*Both a gallery and a non-gallery in [[$page]]\n");<br />
# }<br />
$match2 += 1;<br />
}<br />
}<br />
<br />
if($match2 > 0)<br />
{<br />
if($text =~ /\[\[(?: |)<!--/)<br />
{<br />
Pearle::myLog(2, "Possible multiline image in page [[$page]]\n");<br />
botwarnlog(FixupLinks("*Possible multiline image in page [[$page]]\n"));<br />
}<br />
}<br />
<br />
# Improved infobox removal<br />
my $infobox_regex = "([-A-Za-z0-9_]+[\\p{IsSpace}\x{200E}\x{200F}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}]*=)[\\p{IsSpace}\x{200E}\x{200F}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}]*" . "[ _]*" . MakeWikiRegex($raw_image) . "[ _]*";<br />
my $infobox_regex_full = "([-A-Za-z0-9_]+[\\p{IsSpace}\x{200E}\x{200F}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}]*=)[\\p{IsSpace}\x{200E}\x{200F}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}]*" . '[Ii]mage[ _]*:[ _]*' . MakeWikiRegex($raw_image);<br />
if($text =~ /$infobox_regex/)<br />
{<br />
Pearle::myLog(3, "Matched on infobox regex: $infobox_regex\n");<br />
Pearle::myLog(3, "Infobox parameter: $1\n");<br />
if($& =~ /puic/)<br />
{<br />
botwarnlog(FixupLinks("*PUIC in page [[$page]]\n"));<br />
}<br />
else<br />
{<br />
my $sub = $1;<br />
$text =~ s/$infobox_regex/$sub/g;<br />
$match2 += 1;<br />
}<br />
}<br />
if($text =~ /$infobox_regex_full/)<br />
{<br />
Pearle::myLog(3, "Matched on infobox regex: $infobox_regex_full\n");<br />
Pearle::myLog(3, "Infobox parameter: $1\n");<br />
if($& =~ /puic/)<br />
{<br />
botwarnlog(FixupLinks("*PUIC in page [[$page]]\n"));<br />
}<br />
else<br />
{<br />
my $sub = $1;<br />
$text =~ s/$infobox_regex_full/$sub/g;<br />
$match2 += 1;<br />
}<br />
}<br />
<br />
if($match2) # No need to null-edit articles anymore<br />
{<br />
if($test_only)<br />
{<br />
notelog("Test removal from page succeeded\n");<br />
}<br />
else<br />
{<br />
# Submit the changes<br />
$wikipage->setEditableText($text);<br />
eval<br />
{<br />
Pearle::postPage($wikipage, $removal_comment, 0);<br />
};<br />
if($@)<br />
{<br />
if($@ =~ /^924 Spam filter: (.*)$/)<br />
{<br />
botwarnlog("*Spam filter on page [[$page]], url <nowiki>$1</nowiki>\n");<br />
$match2 = 0; # We weren't able to remove it<br />
}<br />
elsif($@ =~ /^922/)<br />
{<br />
# Edit conflict. Try editing the page again.<br />
botwarnlog("*Edit conflict on page [[$page]]\n");<br />
goto tryagain;<br />
}<br />
else<br />
{<br />
die;<br />
}<br />
}<br />
}<br />
}<br />
<br />
return ($match2)<br />
}<br />
<br />
# Returns 1 if the user has been notified, or 0 if they haven't<br />
sub IsNotified<br />
{<br />
my $uploader = shift;<br />
my $image_regex = shift;<br />
my $image_name = shift;<br />
my $notes_ref = shift;<br />
my $donts_ref = shift;<br />
<br />
# Check notification list<br />
if($notes_ref->{"$uploader,$image_name"})<br />
{<br />
Pearle::myLog(3, "Already notified for this image\n");<br />
return 1;<br />
}<br />
<br />
if($donts_ref->{$uploader})<br />
{<br />
Pearle::myLog(3, "On exception list: $uploader\n");<br />
return 1;<br />
}<br />
<br />
# # Check uploader's talkpage<br />
my $page_data = Pearle::APIQuery(titles => "User talk:$uploader", prop => 'links', plnamespace => 6);<br />
if($page_data =~ /$image_regex/)<br />
{<br />
Pearle::myLog(3, "Has a link from userpage\n");<br />
return 1;<br />
}<br />
# my $wikipage = Pearle::getPage("User talk:$uploader");<br />
# my $text = $wikipage->getWikiText();<br />
# if($text =~ /$image_regex/)<br />
# {<br />
# Pearle::myLog(3, "Already notified by someone else\n");<br />
# $donts_ref->{"$uploader,$image_name"} = 1;<br />
# return 1;<br />
# }<br />
# else<br />
# {<br />
# Pearle::myLog(3, "Not already notified\n");<br />
# return $wikipage;<br />
# }<br />
return 0;<br />
}<br />
<br />
sub isDated<br />
{<br />
my $image_text = shift;<br />
if($image_text =~ /\((\d\d?) (\w*) (\d\d\d\d)\)/) # Dated template<br />
{<br />
myLog(4, "Dated tag $1 $2 $3\n");<br />
return 1;<br />
}<br />
# as of 6 October 2006"><br />
elsif($image_text =~ /as of (\d\d?) (\w*) (\d\d\d\d)/) # Template borked, working off category<br />
{<br />
myLog(4, "Template borked; category $1 $2 $3\n");<br />
return 1;<br />
}<br />
elsif($image_text =~ /{{{day}}} {{{month}}} \d\d\d\d/ or $image_text =~ /\( 2006\)/) # Generic template<br />
{<br />
myLog(4, "Generic tag\n");<br />
return 0;<br />
}<br />
else<br />
{<br />
myLog(4, "No tag match\n");<br />
return 0;<br />
}<br />
}<br />
<br />
# Return the tag date if there is one, the upload date if not<br />
# Returns in (day, month, year) format<br />
sub getDate<br />
{<br />
my $image_text = shift;<br />
if($image_text =~ /\((\d\d?) (\w*) (\d\d\d\d)\)/)<br />
{<br />
myLog(4, "Template date $1-$2-$3\n");<br />
return ($1, $2, $3);<br />
}<br />
elsif($image_text =~ /as of (\d\d?) (\w*) (\d\d\d\d)/) # Template borked, working off category<br />
{<br />
myLog(4, "Category date $1-$2-$3\n");<br />
return ($1, $2, $3);<br />
}<br />
elsif($image_text =~ />\d\d?:\d\d, (\d\d?) (\w*) (\d\d\d\d)</)<br />
{<br />
myLog(4, "Upload date $1-$2-$3\n");<br />
# return ($1, $2, $3);<br />
# For now, be conservative:<br />
my ($year, $month, $day) = Today();<br />
return ($day, Month_to_Text($month), $year);<br />
}<br />
else<br />
{<br />
myLog(4, "No date\n");<br />
return (1, "January", 2007);<br />
}<br />
}<br />
<br />
# Return a list of upload dates<br />
sub getUploadDates<br />
{<br />
my @dates;<br />
my $image_text = shift;<br />
while($image_text =~ />\d\d?:\d\d, (\d\d?) (\w*) (\d\d\d\d)</g)<br />
{<br />
push @dates, [$1, $2, $3];<br />
}<br />
return @dates;<br />
}<br />
<br />
sub getLastEditDate<br />
{<br />
my ($day, $month, $year);<br />
my $image = shift;<br />
<br />
my @history = Pearle::parseHistory($image);<br />
(undef, $day, $month, $year) = @{$history[0]};<br />
<br />
return ($day, $month, $year);<br />
}<br />
<br />
# Find the most recent non-vandal, non-revert uploader<br />
sub GetImageUploader<br />
{<br />
my $image_data = shift;<br />
my ($uploader, $sha1, $comment);<br />
my @uploaders;<br />
my $uploader_data;<br />
my $i = 0;<br />
my $count = 0;<br />
<br />
my $parsed_xml = Pearle::getXMLParser()->XMLin($image_data);<br />
<br />
Pearle::myLog(4, Dumper($parsed_xml));<br />
<br />
if(exists($parsed_xml->{query}->{pages}->{page}->{imageinfo}->{ii}) and defined($parsed_xml->{query}->{pages}->{page}->{imageinfo}->{ii}))<br />
{<br />
if(ref($parsed_xml->{query}->{pages}->{page}->{imageinfo}->{ii}) eq 'ARRAY')<br />
{<br />
@uploaders = @{$parsed_xml->{query}->{pages}->{page}->{imageinfo}->{ii}};<br />
}<br />
else<br />
{<br />
return $parsed_xml->{query}->{pages}->{page}->{imageinfo}->{ii}->{user};<br />
}<br />
}<br />
else<br />
{<br />
return undef;<br />
}<br />
<br />
$uploader = $uploaders[0]->{user};<br />
$sha1 = $uploaders[0]->{sha1};<br />
$comment = $uploaders[0]->{comment} || "";<br />
<br />
my $done = 0;<br />
while(!$done)<br />
{<br />
if($comment =~ /^Reverted/)<br />
{<br />
Pearle::myLog(4, "Revert found\n");<br />
$i += 1;<br />
while($uploaders[$i]->{sha1} ne $sha1)<br />
{<br />
$i = $i + 1;<br />
}<br />
}<br />
elsif($comment =~ /optimi(z|s)ed|adjust|tweak|scale|crop|change|resize|remove/i)<br />
{<br />
Pearle::myLog(4, "Tweak found\n");<br />
$i = $i + 1;<br />
}<br />
elsif(!defined($uploader))<br />
{<br />
Pearle::myLog(4, "Something went wrong with finding the uploader\n");<br />
$done = 1;<br />
}<br />
elsif($count > 500)<br />
{<br />
Pearle::myLog(4, "Took too long finding the uploader\n");<br />
$uploader = undef;<br />
$done = 1;<br />
}<br />
else<br />
{<br />
$done = 1;<br />
}<br />
$uploader = $uploaders[$i]->{user};<br />
$sha1 = $uploaders[$i]->{sha1};<br />
$comment = $uploaders[$i]->{comment} || "";<br />
$count = $count + 1;<br />
}<br />
if(defined($uploader))<br />
{<br />
Pearle::myLog(4, "Uploader: $uploader\n");<br />
return $uploader;<br />
}<br />
else<br />
{<br />
return undef;<br />
}<br />
}<br />
<br />
sub loadNotificationList<br />
{<br />
my $file = shift;<br />
my %notelist;<br />
my $i = 0;<br />
notelog("File: $file\n");<br />
open INFILE, "<", $file;<br />
while(<INFILE>)<br />
{<br />
$_ =~ s/\s*#.*$//g;<br />
chomp;<br />
$notelist{$_} = 1;<br />
$i++;<br />
}<br />
close INFILE;<br />
notelog("$i notifications loaded\n");<br />
return %notelist;<br />
}<br />
<br />
sub saveNotificationList<br />
{<br />
return if($test_only);<br />
<br />
my $file = shift;<br />
my %notelist = @_;<br />
my $key;<br />
<br />
open OUTFILE, ">", $file;<br />
foreach $key (keys(%notelist))<br />
{<br />
print OUTFILE "$key\n";<br />
}<br />
close OUTFILE;<br />
}<br />
<br />
1;<br />
</nowiki></pre></div>
Carnildo