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&amp;diff=522163989&amp;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&amp;diff=252317088&amp;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, "&lt;", $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, "&lt;<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(&lt;INFILE&gt;)</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(&lt;INFILE&gt;)</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, "&gt;", $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, "&gt;<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 &#039;&lt;pre&gt;&lt;nowiki&gt; #!/usr/bin/perl # libBot: A Perl module of useful routines for running a bot ########## WARNING: NOT ALL OF THESE FUNCTIONS WIL...&#039;</p> <p><b>New page</b></p><div>&lt;pre&gt;&lt;nowiki&gt;<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 = &quot;&quot;;<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&#039;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 = &quot;Logging warning message&quot; if(!defined($summary));<br /> <br /> # We&#039;ve been handed an editing session<br /> Pearle::myLog(4, &quot;Warning with existing edit session\n&quot;);<br /> <br /> if($test_only)<br /> {<br /> print STDERR $_[0];<br /> return;<br /> }<br /> <br /> if($wikipage-&gt;getWikiText() =~ /^#redirect/i)<br /> {<br /> botwarnlog(&quot;*User talk page [[User talk:$user]] is a redirect\n&quot;);<br /> return;<br /> }<br /> $text = $wikipage-&gt;getEditableText();<br /> $text .= $_[0];<br /> $wikipage-&gt;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] || &quot;Logging note&quot;;<br /> <br /> $wikipage = Pearle::getPage($target);<br /> <br /> if($test_only)<br /> {<br /> print STDERR $_[1];<br /> return;<br /> }<br /> <br /> $text = $wikipage-&gt;getEditableText();<br /> $text .= $_[1];<br /> $wikipage-&gt;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 = &quot;Logging warning message&quot; if(!defined($summary));<br /> $page = &quot;User talk:${username}/log&quot;;<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&#039;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 = &#039;&#039;;<br /> <br /> foreach my $char (@chars)<br /> {<br /> # Escape metacharacters, and add percent-encoding for certain characters<br /> if($char eq &#039;\\&#039;) {$result .= &#039;\\\\&#039;;}<br /> elsif($char eq &#039;.&#039;) {$result .= &#039;\.&#039;;}<br /> elsif($char eq &#039;(&#039;) {$result .= &#039;(?:\(|%28)&#039;;}<br /> elsif($char eq &#039;)&#039;) {$result .= &#039;(?:\)|%29)&#039;;}<br /> elsif($char eq &#039;[&#039;) {$result .= &#039;\[&#039;;}<br /> elsif($char eq &#039;]&#039;) {$result .= &#039;\]&#039;;}<br /> elsif($char eq &#039;+&#039;) {$result .= &#039;\+&#039;;}<br /> elsif($char eq &#039;*&#039;) {$result .= &#039;\*&#039;;}<br /> elsif($char eq &#039;?&#039;) {$result .= &#039;(?:\?|%3F)&#039;;}<br /> elsif($char eq &#039;^&#039;) {$result .= &#039;\^&#039;;}<br /> elsif($char eq &#039;$&#039;) {$result .= &#039;\$&#039;;}<br /> elsif($char eq &#039;&amp;&#039;) {$result .= &#039;(?:&amp;|%26)&#039;;}<br /> elsif($char eq &#039;!&#039;) {$result .= &#039;(?:!|%21)&#039;;}<br /> elsif($char eq &#039;~&#039;) {$result .= &#039;(?:~|%7E)&#039;;}<br /> elsif($char eq &quot;&#039;&quot;) {$result .= &quot;(?:&#039;|%27)&quot;;}<br /> elsif($char eq &#039;&quot;&#039;) {$result .= &#039;(?:&quot;|%22)&#039;;}<br /> elsif($char eq &#039;,&#039;) {$result .= &#039;(?:,|%2C)&#039;;}<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/^(.)/&quot;[$1&quot;.lc($1).&quot;]&quot;/e;<br /> }<br /> return $result;<br /> }<br /> <br /> sub HTMLEncode<br /> {<br /> my $char = shift;<br /> return sprintf(&quot;&amp;X%X;&quot;, 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 &#039;\\&#039;)<br /> {<br /> $result .= &quot;(\\\\|%5C|%5c|&amp;x5C;)&quot;;<br /> }<br /> elsif($char eq &#039;.&#039;)<br /> {<br /> }<br /> elsif($char eq &#039;(&#039;)<br /> {<br /> }<br /> elsif($char eq &#039;)&#039;)<br /> {<br /> }<br /> else<br /> {<br /> $result .= &quot;($char|&quot; . uri_escape_utf8($char) . &quot;|&quot; . lc(uri_escape_utf8($char)) . &quot;|&quot; . HTMLEncode($char) . &quot;|&quot; . lc(HTMLEncode($char)) . &quot;)&quot;;<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()-&gt;XMLin($xml);<br /> if(exists($parsed_xml-&gt;{query}-&gt;{userinfo}-&gt;{messages}) and defined($parsed_xml-&gt;{query}-&gt;{userinfo}-&gt;{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()-&gt;XMLin($image_data);<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{categories}-&gt;{cl}) and defined($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{categories}-&gt;{cl}))<br /> {<br /> if(ref($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{categories}-&gt;{cl}) eq &#039;ARRAY&#039;)<br /> {<br /> my @all_pages = @{$parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{categories}-&gt;{cl}};<br /> <br /> @pages = map {$_-&gt;{title}} @all_pages;<br /> }<br /> else<br /> {<br /> @pages = ($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{categories}-&gt;{cl}-&gt;{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()-&gt;XMLin($image_data);<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{links}-&gt;{pl}) and defined($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{links}-&gt;{pl}))<br /> {<br /> if(ref($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{links}-&gt;{pl}) eq &#039;ARRAY&#039;)<br /> {<br /> my @all_pages = @{$parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{links}-&gt;{pl}};<br /> <br /> @pages = map {$_-&gt;{title}} @all_pages;<br /> }<br /> else<br /> {<br /> @pages = ($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{links}-&gt;{pl}-&gt;{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()-&gt;XMLin($image_data);<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{revisions}-&gt;{rev}) and defined($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{revisions}-&gt;{rev}))<br /> {<br /> $text = $parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{revisions}-&gt;{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()-&gt;XMLin($image_data);<br /> my $image = $parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{title};<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}) and defined($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}))<br /> {<br /> if(ref($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}) eq &#039;ARRAY&#039;)<br /> {<br /> my @bad_pages = grep {$_-&gt;{ns} == 10 or $_-&gt;{ns} == 12} @{$parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}};<br /> my @good_pages = grep {$_-&gt;{ns} != 10 and $_-&gt;{ns} != 12} @{$parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}};<br /> <br /> @pages = map {$_-&gt;{title}} @good_pages;<br /> <br /> if(scalar(@bad_pages) &gt; 0 and defined($image)) # If &quot;image&quot; is undefined, we&#039;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 .= &quot;*Found image [[:$image]] in [[$page-&gt;{title}]]\n&quot;;<br /> }<br /> botwarnlog($notice);<br /> }<br /> }<br /> else<br /> {<br /> if($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}-&gt;{ns} != 10 and $parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}-&gt;{ns} != 12)<br /> {<br /> @pages = $parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}-&gt;{title};<br /> }<br /> else<br /> {<br /> if(defined($image))<br /> {<br /> botwarnlog(&quot;*Found image [[:$image]] in [[$parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}-&gt;{title}]]\n&quot;);<br /> }<br /> }<br /> }<br /> }<br /> }<br /> <br /> return @pages;<br /> }<br /> <br /> # Get all pages. Don&#039;t filter for bad namespaces.<br /> sub GetFullPageList<br /> {<br /> my $image = shift;<br /> my @pages = ();<br /> <br /> my $xml = Pearle::APIQuery(list =&gt; &#039;imageusage&#039;, iutitle =&gt; $image);<br /> if(defined($xml))<br /> {<br /> my $parsed_xml = Pearle::getXMLParser()-&gt;XMLin($xml);<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}) and defined($parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}))<br /> {<br /> if(ref() eq &#039;ARRAY&#039;)<br /> {<br /> @pages = map {$_-&gt;{title}} @{$parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}};<br /> }<br /> else<br /> {<br /> @pages = $parsed_xml-&gt;{query}-&gt;{imageusage}-&gt;{iu}-&gt;{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 &quot;No page to edit&quot; if(!defined($page));<br /> die &quot;No link to change&quot; if(!defined($from));<br /> die &quot;No new link&quot; if(!defined($to));<br /> <br /> Pearle::myLog(3, &quot;Updating link from $from to $to\n&quot;);<br /> <br /> my $wikipage = Pearle::getPage($page);<br /> $wikipage-&gt;canonicalizeLinks();<br /> my $text = $wikipage-&gt;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-&gt;setEditableText($text);<br /> Pearle::postPage( $wikipage, &quot;Updating link to bypass a redirect or disambiguation page&quot;, 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-&gt;canonicalizeLinks();<br /> $text = $wikipage-&gt;getEditableText();<br /> <br /> if(!defined($text))<br /> {<br /> Pearle::myLog(1, &quot;Error: Bad edit page [[$page]]\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Error: Bad edit page [[$page]]\n&quot;));<br /> sleep(300);<br /> return 0;<br /> }<br /> <br /> if($text =~ /^\s*$/)<br /> {<br /> # Might be protected instead of empty<br /> Pearle::myLog(1, &quot;Error: Empty or protected page [[$page]]\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Error: Empty or protected page [[$page]]\n&quot;));<br /> sleep(300);<br /> return 0;<br /> }<br /> <br /> if($text =~ /^#redirect/i)<br /> {<br /> Pearle::myLog(1, &quot;Redirect found for page [[$page]] (image [[:$image]])\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Redirect found for page [[$page]] (image [[:$image]])\n&quot;));<br /> print $text;<br /> return 0;<br /> }<br /> <br /> # Remove the image<br /> my $regex3 = &quot;(\x01${image_regex}[^\x01]*?(\x01[^\x02]*?\x02[^\x01]*?|)+\x02[ \\t]*)&quot;; # Regex to match images<br /> <br /> #my $regex3 = &quot;(<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 /> # &quot;;<br /> <br /> my $regex3ex = &quot;\\w[ \\t]*${regex3}[ \\t]*\\w&quot;; # Regex to try to spot inline images<br /> my $regex3g = &quot;(${image_regex}.*)&quot;; # Regex to match gallery images<br /> my ($raw_image) = $image =~ /Image:(.*)/; <br /> <br /> my $regex4m = &quot;\x01[ _]*[Mm]edia[ _]*:[ _]*&quot; . MakeWikiRegex($raw_image) . &quot;[ _]*\\|([^]]*)\x02&quot;; # Regex to match inline Media: links<br /> <br /> Pearle::myLog(3, &quot;Regex 3: $regex3\n&quot;);<br /> notelog(&quot;Regex 3: $regex3\n&quot;);<br /> notelog(&quot;Regex 3 extended: $regex3ex\n&quot;);<br /> notelog(&quot;Regex 3 gallery: $regex3g\n&quot;);<br /> Pearle::myLog(3, &quot;Raw regex: $raw_image\n&quot;);<br /> notelog(&quot;Regex 4 Media: $regex4m\n&quot;);<br /> <br /> if($text =~ /$regex3ex/)<br /> {<br /> Pearle::myLog(1, &quot;Possible inline image in [[$page]]\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Possible inline image [[:$image]] in [[$page]]\n&quot;));<br /> return 0; # Can&#039;t do gallery matching because that also matches regular images, and odds are, we don&#039;t have an infobox<br /> }<br /> <br /> if($text =~ /--&gt;/) # With the new editing markup, any close-comment means that somebody fucked up their wikimarkup<br /> {<br /> Pearle::myLog(3, &quot;Fractional comment in page [[$page]]\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Fractional comment in page [[$page]]\n&quot;));<br /> }<br /> <br /> $text =~ /$regex3/;<br /> $match_len = length($1);<br /> $match2 = $text =~ s/$regex3/&lt;!-- $removal_prefix $1 --&gt;/g;<br /> <br /> $new_length = length($text);<br /> print &quot;Num: $match2 Len: $match_len\n&quot;;<br /> if($match2)<br /> {<br /> # If a whole lot of text was removed, log a warning<br /> if($match_len &gt; (500 + length($image)))<br /> {<br /> botwarnlog(FixupLinks(&quot;*Long caption of $match_len bytes replaced in [[$page]]\n&quot;));<br /> if($match_len &gt; (1000 + length($image)))<br /> {<br /> Pearle::myLog(2, &quot;Unusually long caption of $match_len found in [[$page]] ($match2 matches).\n&quot;);<br /> print $text, &quot;\n&quot;;<br /> # exit;<br /> return 0;<br /> }<br /> }<br /> if($match_len &lt; (2 + length($image)))<br /> {<br /> Pearle::myLog(0, &quot;Short replacement of $match_len bytes (min &quot; . (length($image) + 2) . &quot;) in [[$page]] ($match2 matches). Exiting.\n&quot;);<br /> Pearle::myLog(0, &quot;Text:\n$text\n&quot;);<br /> exit;<br /> }<br /> # If many matches, log a warning<br /> if($match2 &gt; 2)<br /> {<br /> Pearle::myLog(3, &quot;More than one match ($match2) in page [[$page]]\n&quot;);<br /> # botwarnlog(FixupLinks(&quot;*More than one match ($match2) in page [[$page]]\n&quot;));<br /> }<br /> if($match2 &gt; 100)<br /> {<br /> Pearle::myLog(1, &quot;Too many matches ($match2) in page [[$page]]. Skipping.\n&quot;);<br /> botwarnlog(&quot;*Too many matches ($match2) in page [[$page]]. Skipping.\n&quot;);<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-&gt;setEditableText($text);<br /> $text = $wikipage-&gt;getEditableText();<br /> <br /> if($text =~ /&lt;gallery/i)<br /> {<br /> Pearle::myLog(3, &quot;*Possible image gallery in page [[$page]]\n&quot;);<br /> if($text =~ s/$regex3g/&lt;!-- $removal_prefix $1 --&gt;/g)<br /> {<br /> # if($match2 != 0)<br /> # {<br /> # botwarnlog(&quot;*Both a gallery and a non-gallery in [[$page]]\n&quot;);<br /> # }<br /> $match2 += 1;<br /> }<br /> }<br /> <br /> if($match2 &gt; 0)<br /> {<br /> if($text =~ /\[\[(?: |)&lt;!--/)<br /> {<br /> Pearle::myLog(2, &quot;Possible multiline image in page [[$page]]\n&quot;);<br /> botwarnlog(FixupLinks(&quot;*Possible multiline image in page [[$page]]\n&quot;));<br /> }<br /> }<br /> <br /> # Improved infobox removal<br /> my $infobox_regex = &quot;([-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}]*&quot; . &quot;[ _]*&quot; . MakeWikiRegex($raw_image) . &quot;[ _]*&quot;;<br /> my $infobox_regex_full = &quot;([-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}]*&quot; . &#039;[Ii]mage[ _]*:[ _]*&#039; . MakeWikiRegex($raw_image);<br /> if($text =~ /$infobox_regex/)<br /> {<br /> Pearle::myLog(3, &quot;Matched on infobox regex: $infobox_regex\n&quot;);<br /> Pearle::myLog(3, &quot;Infobox parameter: $1\n&quot;);<br /> if($&amp; =~ /puic/)<br /> {<br /> botwarnlog(FixupLinks(&quot;*PUIC in page [[$page]]\n&quot;));<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, &quot;Matched on infobox regex: $infobox_regex_full\n&quot;);<br /> Pearle::myLog(3, &quot;Infobox parameter: $1\n&quot;);<br /> if($&amp; =~ /puic/)<br /> {<br /> botwarnlog(FixupLinks(&quot;*PUIC in page [[$page]]\n&quot;));<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(&quot;Test removal from page succeeded\n&quot;);<br /> }<br /> else<br /> {<br /> # Submit the changes<br /> $wikipage-&gt;setEditableText($text);<br /> eval<br /> {<br /> Pearle::postPage($wikipage, $removal_comment, 0);<br /> };<br /> if($@)<br /> {<br /> if($@ =~ /^924 Spam filter: (.*)$/)<br /> {<br /> botwarnlog(&quot;*Spam filter on page [[$page]], url &lt;nowiki&gt;$1&lt;/nowiki&gt;\n&quot;);<br /> $match2 = 0; # We weren&#039;t able to remove it<br /> }<br /> elsif($@ =~ /^922/)<br /> {<br /> # Edit conflict. Try editing the page again.<br /> botwarnlog(&quot;*Edit conflict on page [[$page]]\n&quot;);<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&#039;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-&gt;{&quot;$uploader,$image_name&quot;})<br /> {<br /> Pearle::myLog(3, &quot;Already notified for this image\n&quot;);<br /> return 1;<br /> }<br /> <br /> if($donts_ref-&gt;{$uploader})<br /> {<br /> Pearle::myLog(3, &quot;On exception list: $uploader\n&quot;);<br /> return 1;<br /> }<br /> <br /> # # Check uploader&#039;s talkpage<br /> my $page_data = Pearle::APIQuery(titles =&gt; &quot;User talk:$uploader&quot;, prop =&gt; &#039;links&#039;, plnamespace =&gt; 6);<br /> if($page_data =~ /$image_regex/)<br /> {<br /> Pearle::myLog(3, &quot;Has a link from userpage\n&quot;);<br /> return 1;<br /> }<br /> # my $wikipage = Pearle::getPage(&quot;User talk:$uploader&quot;);<br /> # my $text = $wikipage-&gt;getWikiText();<br /> # if($text =~ /$image_regex/)<br /> # {<br /> # Pearle::myLog(3, &quot;Already notified by someone else\n&quot;);<br /> # $donts_ref-&gt;{&quot;$uploader,$image_name&quot;} = 1;<br /> # return 1;<br /> # }<br /> # else<br /> # {<br /> # Pearle::myLog(3, &quot;Not already notified\n&quot;);<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, &quot;Dated tag $1 $2 $3\n&quot;);<br /> return 1;<br /> }<br /> # as of 6 October 2006&quot;&gt;<br /> elsif($image_text =~ /as of (\d\d?) (\w*) (\d\d\d\d)/) # Template borked, working off category<br /> {<br /> myLog(4, &quot;Template borked; category $1 $2 $3\n&quot;);<br /> return 1;<br /> }<br /> elsif($image_text =~ /{{{day}}} {{{month}}} \d\d\d\d/ or $image_text =~ /\( 2006\)/) # Generic template<br /> {<br /> myLog(4, &quot;Generic tag\n&quot;);<br /> return 0;<br /> }<br /> else<br /> {<br /> myLog(4, &quot;No tag match\n&quot;);<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, &quot;Template date $1-$2-$3\n&quot;);<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, &quot;Category date $1-$2-$3\n&quot;);<br /> return ($1, $2, $3);<br /> }<br /> elsif($image_text =~ /&gt;\d\d?:\d\d, (\d\d?) (\w*) (\d\d\d\d)&lt;/)<br /> {<br /> myLog(4, &quot;Upload date $1-$2-$3\n&quot;);<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, &quot;No date\n&quot;);<br /> return (1, &quot;January&quot;, 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 =~ /&gt;\d\d?:\d\d, (\d\d?) (\w*) (\d\d\d\d)&lt;/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()-&gt;XMLin($image_data);<br /> <br /> Pearle::myLog(4, Dumper($parsed_xml));<br /> <br /> if(exists($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{imageinfo}-&gt;{ii}) and defined($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{imageinfo}-&gt;{ii}))<br /> {<br /> if(ref($parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{imageinfo}-&gt;{ii}) eq &#039;ARRAY&#039;)<br /> {<br /> @uploaders = @{$parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{imageinfo}-&gt;{ii}};<br /> }<br /> else<br /> {<br /> return $parsed_xml-&gt;{query}-&gt;{pages}-&gt;{page}-&gt;{imageinfo}-&gt;{ii}-&gt;{user};<br /> }<br /> }<br /> else<br /> {<br /> return undef;<br /> }<br /> <br /> $uploader = $uploaders[0]-&gt;{user};<br /> $sha1 = $uploaders[0]-&gt;{sha1};<br /> $comment = $uploaders[0]-&gt;{comment} || &quot;&quot;;<br /> <br /> my $done = 0;<br /> while(!$done)<br /> {<br /> if($comment =~ /^Reverted/)<br /> {<br /> Pearle::myLog(4, &quot;Revert found\n&quot;);<br /> $i += 1;<br /> while($uploaders[$i]-&gt;{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, &quot;Tweak found\n&quot;);<br /> $i = $i + 1;<br /> }<br /> elsif(!defined($uploader))<br /> {<br /> Pearle::myLog(4, &quot;Something went wrong with finding the uploader\n&quot;);<br /> $done = 1;<br /> }<br /> elsif($count &gt; 500)<br /> {<br /> Pearle::myLog(4, &quot;Took too long finding the uploader\n&quot;);<br /> $uploader = undef;<br /> $done = 1;<br /> }<br /> else<br /> {<br /> $done = 1;<br /> }<br /> $uploader = $uploaders[$i]-&gt;{user};<br /> $sha1 = $uploaders[$i]-&gt;{sha1};<br /> $comment = $uploaders[$i]-&gt;{comment} || &quot;&quot;;<br /> $count = $count + 1;<br /> }<br /> if(defined($uploader))<br /> {<br /> Pearle::myLog(4, &quot;Uploader: $uploader\n&quot;);<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(&quot;File: $file\n&quot;);<br /> open INFILE, &quot;&lt;&quot;, $file;<br /> while(&lt;INFILE&gt;)<br /> {<br /> $_ =~ s/\s*#.*$//g;<br /> chomp;<br /> $notelist{$_} = 1;<br /> $i++;<br /> }<br /> close INFILE;<br /> notelog(&quot;$i notifications loaded\n&quot;);<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, &quot;&gt;&quot;, $file;<br /> foreach $key (keys(%notelist))<br /> {<br /> print OUTFILE &quot;$key\n&quot;;<br /> }<br /> close OUTFILE;<br /> }<br /> <br /> 1;<br /> &lt;/nowiki&gt;&lt;/pre&gt;</div> Carnildo