Gebruiker:Wikiwernerbot/sinebot.py

Uit Wikipedia, de vrije encyclopedie

Script voor het toevoegen van {{Afzender}} aan niet-ondertekende overlegbijdrages, naar aanleiding van een botverzoek. Dit script is gedeeltelijk gebaseerd op en:User:Ritchie333/arcsinebot.py en en:User:SineBot/ChangeLog.

import pywikibot
import re
import datetime
site = pywikibot.Site()

pagesignedre = re.compile(r'^Wikipedia:(Samenvoegen|Te beoordelen|Verzoekpagina)[^/]*/[^/]+$')

def ispagesigned(page, edittype):
    ns = page.namespace().id
    if ns%2 == 1 and not 'rchief' in page.title():
        return True # Overlegnaamruimtes hebben een oneven nummer.
    if page.title() in ['Help:Helpdesk', 'Wikipedia:Achterkamertje', 'Wikipedia:Misbruikfilter/Foutieve meldingen']:
        return True
    if pagesignedre.search(page.title()) and edittype != 'new':
        return True
    if ns == 4: # Wikipedianaamruimte
        istalkpage = False
        cats = page.categories()
        for cat in cats:
            if cat.title() == 'Categorie:Wikipedia:Overlegruimte':
                istalkpage = True
            elif cat.title() in ['Categorie:Wikipedia:Nuweg', 'Categorie:Wikipedia:Afgehandeld']:
                return False
        if istalkpage:
            return True
    return False

nosigntags = ['AWB', 'OAuth CID: 429', 'mw-new-redirect', 'mw-changed-redirect-target', 'mw-undo', 'mw-rollback', 'mw-manual-revert', 'mw-reverted', 'twinkle', 'massmessage-delivery']
# Zie [[Speciaal:Labels]].

def hasnosigntag(tags):
    for tag in tags:
        if tag in nosigntags:
            return True
    return False

idre = re.compile(r'\| (\d+) \|\|')

def alluseredits(pagehistory, revid, user):
    histlines = pagehistory.split('\n|----\n')
    for l in range(len(histlines)):
        if '| ' + str(revid) + ' ||' in histlines[l]:
            revidline = l
            break
    # Zoek navolgende bewerkingen van dezelfde gebruiker:
    lastid = revid
    while l > 0:
        if not '|| ' + user + ' ||' in histlines[l]:
            lastid = idre.search(histlines[l + 1]).group(1)
            break
        l -= 1 # De eerste regels van de bewerkingsgeschiedenis zijn de recentste.
    # Zoek voorgaande bewerkingen van dezelfde gebruiker:
    l = revidline
    oldid = 0
    while l < len(histlines):
        if not '|| ' + user + ' ||' in histlines[l]:
            oldid = idre.search(histlines[l]).group(1)
            break
        l += 1
    return int(oldid), int(lastid)
# = de laatste bewerking van de vorige gebruiker en de laatste bewerking van de huidige gebruiker.

trre = re.compile(r'<tr>.*?</tr>', re.DOTALL)
messagelinere = re.compile(r'<td class="diff-addedline diff-side-added">(<div>)?(.*?)(</div>)?</td>')

def findmessages(diff):
    messages = []
    message = ''
    trmatches = trre.finditer(diff)
    for trmatch in trmatches:
        messagelinematch = messagelinere.search(trmatch.group(0))
        # Als er een match is die niet een verplaatste regel is:
        if messagelinematch and '<td colspan="2" class="diff-empty diff-side-deleted"></td>\n  <td class="diff-marker" data-marker="+"></td>' in trmatch.group(0):
            if not messagelinematch.group(2) == '<br />':
                message += messagelinematch.group(2)
            message += '\n'
        elif '<td colspan="2" class="diff-empty diff-side-added"></td>' in trmatch.group(0):
            continue # Beschouwt opeenvolgende toegevoegde en verwijderde regels als 1 bericht.
        elif message:
            message = message.strip()
            message = message.replace('&lt;', '<')
            message = message.replace('&gt;', '>')
            message = message.replace('&amp;', '&')
            # Deze als laatste, voor als de brontekst &lt; bevat: de html in m bevat dan &amp;lt;
            messages.append(message)
            message = ''
    return messages

galleryre = re.compile(r'<gallery>.*?</gallery>', re.DOTALL)
headingre = re.compile(r'^=.*=$', re.MULTILINE)
htmlcommre = re.compile(r'<\!--.*?-->', re.DOTALL)
htmltagsre = re.compile(r'</?(div|font|span|includeonly|noinclude).*?>', re.IGNORECASE)
timestampre = re.compile(r'\d\d? [A-Za-z][a-z]{2,8} \d{4} (CES?T )?\d\d:\d\d')
nosignre = re.compile(r"""( [:;}*\s] | &nbsp; | ----+ | <[BbHh][Rr]\s?/?> | <references\s?/> |
                      \[\[\s*([Aa]fbeelding|[Bb]estand|[Cc]ategor(ie|y)|[Ff]ile|[Ii]mage):([^[\]]|\[\[[^\]]*\]\])*\]\] |
                      [#|].* | \{\{([^{}]|\{\{[^}]*\}\})*\}\} )* ( \{\{([^{}]|\{\{[^}])* )?""", re.VERBOSE)
# bestanden en categorieën, met eventueel [[wikilinks]] erin,
# regels van een vandalismedossier, tabel- of sjabloonregels, en/of (geneste) sjablonen,
# met als laatste eventueel een sjabloon dat niet afgesloten wordt (bijv. afsluiting van {{Uitklappen}})

def needssign(m):
    if not m:
        return False
    m = galleryre.sub('', m)
    m = headingre.sub('', m)
    m = htmlcommre.sub('', m)
    m = htmltagsre.sub('', m)
    if timestampre.search(m) or nosignre.fullmatch(m):
        return False
    return True

def afzender(timestamp, user): # 'timestamp': '2022-06-14T17:40:05Z'
    y = int(timestamp[0:4])
    month = int(timestamp[5:7])
    d = int(timestamp[8:10])
    h = int(timestamp[11:13])
    minutes = int(timestamp[14:16])
    s = int(timestamp[17:19])
    sign_utc = datetime.datetime(y, month, d, h, minutes, s)
    issummertime = True
    if month in [1, 2, 11, 12]:
        issummertime = False
    elif month == 3:
        March31 = datetime.datetime(y, 3, 31, 1, 0, 0)
        if March31.weekday() == 6:
            startsummertime = March31
        else:
            startsummertime = March31 - datetime.timedelta(days = March31.weekday() + 1)
        if sign_utc < startsummertime:
            issummertime = False
    elif month == 10:
        October31 = datetime.datetime(y, 10, 31, 1, 0, 0)
        if October31.weekday() == 6:
            endsummertime = October31
        else:
            endsummertime = October31 - datetime.timedelta(days = October31.weekday() + 1)
        if sign_utc >= endsummertime:
            issummertime = False
    if issummertime:
        diffhours = 2
        tzname = ' (CEST)'
    else:
        diffhours = 1
        tzname = ' (CET)'
    signtime = sign_utc + datetime.timedelta(hours = diffhours)
    monthabb = site.months_names[int(signtime.strftime('%m')) - 1][1]
    signtimestring = signtime.strftime('%d ' + monthabb + ' %Y %H:%M').removeprefix('0') + tzname
    return '{{Afzender|' + signtimestring + '|' + user + '}}'

start = site.server_time() - datetime.timedelta(hours=1) # Te snel signen kan leiden tot bewerkingsconflicten.
end = start - datetime.timedelta(hours=23)
# Doorzoek alle overlegnaamruimtes + Wikipedia + Help:
recentchanges = site.recentchanges(namespaces=u'4|12|1|3|5|7|9|11|13|15|101|711|829', bot=False, start=start, end=end)
pagehistsdone = dict()
for rc in recentchanges:
    if not rc['type'] in ['new', 'edit'] or 'Overleg gebruiker:' + rc['user'] in rc['title'] or hasnosigntag(rc['tags']):
        continue
    pages = site.load_pages_from_pageids([rc['pageid']]) # Dit houdt rekening met navolgende titelwijzigingen.
    for p in pages:
        page = p
    if not page.exists() or page.isRedirectPage() or not ispagesigned(page, rc['type']):
        continue
    print(rc['title'] + ', [[Speciaal:Diff/' + str(rc['revid']) + ']]')
    if rc['pageid'] in pagehistsdone:
        hist = pagehistsdone[rc['pageid']]
    else:
        hist = page.getVersionHistoryTable(total = 1000) # Kan lang duren, dus bewaren:
        pagehistsdone[rc['pageid']] = hist
    oldid, lastid = alluseredits(hist, rc['revid'], rc['user'])
    if lastid != rc['revid'] or not page.getOldVersion(lastid):
        continue # De navolgende bewerking(en) zijn van dezelfde gebruiker, of verborgen versie.
    if oldid == 0:
        messages = [page.getOldVersion(lastid)]
    else:
        if not page.getOldVersion(oldid):
            continue
        userdiff = site.compare(oldid, lastid)
        messages = findmessages(userdiff)
    issignadded = False
    for m in messages:
        if not needssign(m):
            continue
        mre = re.compile('^' + re.escape(m) + r' *$', re.MULTILINE)
        if mre.search(page.text):
            print('* Bericht:')
            print(m + ' ' + afzender(rc['timestamp'], rc['user']))
            page.text = mre.sub(m + ' ' + afzender(rc['timestamp'], rc['user']), page.text)
            issignadded = True
    if issignadded:
        opslaan = input('Wil je deze opslaan? ')
        if opslaan == 'ja':
            page.save('Script: +{{Afzender}}')