Utilisateur:Darkoneko/ImageLinkErasor.py

Un article de Wikipédia, l'encyclopédie libre.

# -*- coding: utf-8      -*-
# Image Terminator
 
# Code : fr:User:Dake - 2005 
#Ameliorations des regex et debug : Darkonko (aout 2006), Baro (dec 2006), Phe (janiver 2007), Louperivois (mai 2007)
#refonte pour utiliser /w/api.php, fusion avec le script listant les images : fr:user:Darkoneko, avril 2008
# Basé sur le code "replace.py" de PyWikipedia
# Distributed under the terms of the PSF license.


import wikipedia, pagegenerators, catlib
import config, replace, re, sys, urllib, codecs

#========================================== PARAMETRES ========================
#Namespaces in which we can remove dead media links 
allowedNamespaces = [
    '0', # (main)
        '10', #template
        '12', #aide
        '14', #category
        '100', #portal
        '102', #projet
        '104' #reference
]


site = wikipedia.getSite()



#======================================== FIN PARAMETRES



def build_regex_from_title(title):
    result = u''
    for ch in title:
        # |[] is invalid in title no need to quote it
        if ch in u'()*.':
            result += u'\\'
        result += ch
    result = result.replace(u' ', u'[ _]?')
    result = u'[' + result[0].lower() + result[0].upper() + u']' + result[1:]
    return result


class ReplaceRobotModified:
    """
    A bot that can do text replacements.
    """
    def __init__(self, generator, replacements, exceptions = [], acceptall = False, regex = False):
        self.generator = generator
        self.replacements = replacements
        self.exceptions = exceptions
        self.acceptall = acceptall
        self.regex = regex

    def checkExceptions(self, original_text):
        """
        If one of the exceptions applies for the given text, returns the 
        substring which matches the exception. Otherwise it returns None.
        """
        for exception in self.exceptions:
            hit = exception.search(original_text)
            if hit:
                return hit.group(0)
        return None

    # réalise un seul remplacement, en utilisant seulement les paramètres
    def doSingleReplacement(self, original_text, old, new, acceptall):
        new_text = original_text
        
        if self.regex:
            # TODO: compiling the regex each time might be inefficient
            oldR = re.compile(old, re.UNICODE)
            new_text = oldR.sub(new, new_text)
        else:
            new_text = wikipedia.replaceExceptMathNowikiAndComments(new_text, old, new)

        # wikipedia.output(u'\n>>> %s <<<' % page.title())
        wikipedia.showDiff(original_text, new_text)
        
        if original_text != new_text:
            choice = ''
            if not acceptall:
                choice = wikipedia.inputChoice(u'Do you want to accept these changes?',  ['Yes', 'No'], ['y', 'N'], 'N')
            if acceptall or choice in ['y', 'Y']:
                return new_text

        return original_text
    
    # réalise l'ensemble des remplacement
    def doReplacements(self, original_text):
        """
        Returns the text which is generated by applying all replacements to the
        given text.
        """
        new_text = original_text
        for old, new, acceptall in self.replacements:
            new_text = self.doSingleReplacement(new_text, old, new, acceptall)
        return new_text
        
    def run(self):
        """
        Starts the robot.
        """
        # Run the generator which will yield Pages which might need to be
        # changed.
        page = wikipedia.Page(site, self.generator)
        original_text = ''
        try:
                # Load the page's text from the wiki
            original_text = page.get()
            if not page.canBeEdited():
                wikipedia.output(u'Skipping locked page %s' % page.title())
                return
        except wikipedia.NoPage:
            wikipedia.output(u'Page %s not found' % page.title())
            return
        except wikipedia.IsRedirectPage:
            original_text = page.get(get_redirect=True)
        match = self.checkExceptions(original_text)
        # skip all pages that contain certain texts
        if match:
            wikipedia.output(u'Skipping %s because it contains %s' % (page.title(), match))
            return
        
        new_text = self.doReplacements(original_text)
        if new_text == original_text:
            wikipedia.output('No changes were necessary in %s' % page.title())
            return
                
        try:
            page.put(new_text)
        except wikipedia.EditConflict:
            wikipedia.output(u'Skipping %s because of edit conflict' % (page.title()))


logUrl = "/w/api.php?format=xml&action=query&letype=delete&list=logevents&leprop=title&lelimit=5000"
txt = wikipedia.getSite().getUrl(logUrl)
findDeleted = re.compile(u'"6" title="[^"]+"')
deletedPics = findDeleted.findall(txt)


wikipedia.output(u"%s images trouvees sur 5000 suppression. " % ( len(deletedPics))  )

listInput = []
for pic in deletedPics:
    pic = re.sub(u'"6" title="([^"]+)"','\g<1>', pic ) 
    pic = urllib.unquote(pic)
    listInput.append( pic ) #on rempli un tableau avec les noms d'image traités 
  
#listInput = []
#listInput.append( "Image:Pistons.jpg" )

nbre = len(listInput)
for compteur in range(0, nbre) :
        nom_image = listInput[compteur]
        nom_image = urllib.unquote(nom_image.strip())
        
        #phe janvier 2007
        regexed_image = build_regex_from_title(nom_image[6:])   

        #Neko : Permet de detecter les cas du genre [[ Image : blabla.gif]] qui reviennent souvent
        regexed_namespace = '[ _]*([Ii]mage|[Mm]edia)[ _]*:[ _]*'

        #detection d'un lien du type [[ Image : blabla.gif | blablabla [[eventuel lien]] ]]
        regexp = '\[\[%s%s.*?(\[\[.*?\]\].*?)*\]\]' % (regexed_namespace, regexed_image)

        #ce regex repere les lignes du type "Image:blablabla|commentaire" que contiennent les <gallery>.
        #un \n est ajouté lors du remplacement pour pallier au fait qu'il y en ai 2 detectés ici
        regexpTagNoLinkGallery = '\n%s%s([ \t]*\|[^\n]*)?\n' % (regexed_namespace, regexed_image)
        replaceTagNoLinkGallery = u'\n'

        #ce regex detecte les <gallery> vides, le suivant les <center> vides (regulierement present autour des images, j'ai remarqué
        regexpEmptyGallery = '<gallery>\s*</gallery>'
        regexpEmptyCenter = '<center>\s*</center>'


        #ce regex detecte si l'image a été passée en parametre à un modele
        #possibilités : |Image:blabla.jpg ; |blabla.jpg ; |img=Image:blabla.jpg ; |img=blabla.jpg
        regexpNoTag = u'(?P<beforeZone>\||=)[ \t]*(?:%s|)%s[ \t]*(?P<afterZone>(\}\}|\||\n|\rd))' % ( regexed_namespace, regexed_image)
        replaceNoTag = r'\g<beforeZone>\g<afterZone>'
        #on verifie si l'image sur laquelle on travaille n'existe bien ni ici ni sur commons. l'API permet de voir les deux d'un coup d'oeil
        url = u"/w/api.php?format=xml&action=query&prop=imageinfo&titles=%s" % urllib.quote(nom_image.encode("utf-8"))
        if not u'imagerepository=""' in wikipedia.getSite().getUrl(url): # "shared" si sur commons, "local" si en local, ?? si les deux, "" si n'existe sur ni l'un ni l'autre.
            wikipedia.output(u"\03{lightblue}%s\03{default} existe." % nom_image)
            continue
                
        #utilisation de l'image :
        url = u"/w/api.php?format=xml&action=query&list=imageusage&iutitle=%s" % urllib.quote(nom_image.encode("utf-8"))
        txt = wikipedia.getSite().getUrl(url)
        regexRelatedPages = re.compile(u'ns="(?P<ns>[0-9]+)" title="(?P<title>[^"]+)"')
        relatedPages = regexRelatedPages.findall(txt)

        #aucun lien trouvé
        nb_pages = len(relatedPages)
        if nb_pages == 0:
            wikipedia.output(u"Aucun lien ne pointe sur \03{lightblue}%s\03{default}" % nom_image)
            continue   

        wikipedia.output(u"Liens trouvés vers \03{lightyellow}%s\03{default}" % nom_image)       

        #suppression pour chaque page
        for i in range(0, nb_pages) : 
            if not relatedPages[i][0] in allowedNamespaces : 
                wikipedia.output(u"    \03{lightblue}%s\03{default} non traité" % relatedPages[i][1])
                continue          

            wikipedia.setAction(u"Robot: retrait lien vers média effacé (%s); ménage dans les <tag> vides" % nom_image)
            replaceList = [
                        (regexp, u'', True), #sans confirmation
                        (regexpTagNoLinkGallery, replaceTagNoLinkGallery, True), #sans confirmation
                        (regexpNoTag, replaceNoTag, True), #sans confirmation
                        (regexpEmptyGallery, u'', True), #sans confirmation
                        (regexpEmptyCenter, u'', True), #sans confirmation
            ]

            bot = ReplaceRobotModified( relatedPages[i][1], replaceList, [], False, regex=True)
            bot.run()