User:Botgo50/Link changer

From Tardis Wiki, the free Doctor Who reference

Link changer is an advanced tool to assist in changing links following a move using Botgo50. It should be used with extreme care: while current edits with the tool are all checked manually by Bongolium500, this may change in future to changes being performed fully automatically without review.

Usage

To add a link to be changed the next time the bot is run, edit User:Botgo50/Link changer/list. Add each instruction on a new line. Note that newlines are not displayed in the page output but they are clearly visible in the source editor. Basic syntax for an instruction is as follows:

Old name|New name

This will change all links for Old name to New name without touching any of the display text. Slightly more advanced usage would be as follows:

Old name|New name|Old display text|New display text

Not only would this change all links for Old name to New name but it would also switch any uses of the display text "Old display text" over to "New display text". You can miss out the old display text and only include the new display text as follows:

Old name|New name||New display text

This will change any occurances of [[Old name]] to [[New name|New display text]]. You can also miss out the new display text as follows:

Old name|New name|Old display text

This will remove any occurances of "Old display text" being used as display text, meaning that [[Old name|Old display text]] is changed to [[New name]].

In all of these cases, no display text other than "Old display text" or "New display text" is added or removed.

There is a fifth option that can be set to delete redirects if they have 0 links left after the bot is finished (as the bot does not actually currently have admin permissions, these pages are added to User:Botgo50/Link changer/delete). You can set it to any value, although "1" is recomended. For example:

Old name|New name|||1
Old name|New name|Old display text||1
Old name|New name||New display text|1
Old name|New name|Old display text|New display text|1

Leave this fifth option blank or leave it out entirely to keep the old name as a redirect for searchability.

Examples

To move links for John Simth to John Smith, you'd use the following:

John Simth|John Smith||1

To move links for John to John Smith while ensuring that links display as "John" instead of "John Smith" (such as if a character appears in Source A by their first name only but later has their surname revealed in Source B, meaning that pages relating to Source A still only refer to the character by their first name), you'd use the following:

John|John Smith||John|1

To move links for Bob to Bob (disambiguation), you'd use the following (note that no new display text is set as links to Bob (disambiguation) shouldn't generally exist and this makes them easier to spot):

Bob|Bob (disambiguation)

To move links for Wrong title (short story) to Correct title (short story) while updating the display text, you'd use the following:

Wrong title (short story)|Correct title (short story)|Wrong title|Correct title|1

To move links for Name (story title) to Name while changing any occurances of [[Name (story title)|Name]] to just [[Name]], you'd use the following:

Name (story title)|Name|Name||1

Human follow-up

Some links can't be changed by the bot, such as those appearing in templates. These are listed at User:Botgo50/Link changer/human needed and should be handled manually.

If the redirect for the old name has been marked as to be deleted and the page has no links left, it will be listed at User:Botgo50/Link changer/delete and should be deleted by an admin.

Code

Requires Python (newer versions are better and more likely to work) and Pywikibot to run.

# update_links.py
# version 1.0.1
# written by User:Bongolium500 for use on User:Botgo50 at tardis.wiki

import pywikibot
from pywikibot.pagegenerators import LinkedPageGenerator
import re
from scripts import replace

def capital(s):
    try:
        return s[0].upper() + s[1:]
    except IndexError:
        return s
def decapital(s):
    try:
        return s[0].lower() + s[1:]
    except IndexError:
        return s
        
site = pywikibot.Site()

linksPage = pywikibot.Page(site, 'User:Botgo50/Link changer/list')
linksPageText = linksPage.get(force=True)
linksToMove = []
for line in linksPageText.split("\n"):
    array = []
    for option in line.split("|"):
        array.append(option)
    for i in range(len(array)-1,5):
        array.append("")
    linksToMove.append(array)

for options in linksToMove:
    oldName = options[0] or ""
    newName = options[1] or ""
    oldDisplay = options[2] or ""
    newDisplay = options[3] or ""
    delete = True if options[4] != "" else False
    
    oldNameU = capital(oldName)
    newNameU = capital(newName)
    oldDisplayU = capital(oldDisplay)
    newDisplayU = capital(newDisplay)
    
    oldNameL = decapital(oldName)
    newNameL = decapital(newName)
    oldDisplayL = decapital(oldDisplay)
    newDisplayL = decapital(newDisplay)
    
    print("Changing links from {} to {}\nOld display text: {}\nNew display text: {}".format(oldName,newName,oldDisplay,newDisplay))
        
    if oldDisplay == "":
        if newDisplay == "":
            replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}]]', f'[[{newNameL}]]', f'[[{oldNameU}]]', f'[[{newNameU}]]')
        else:
            replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}]]', f'[[{newName}|{newDisplayL}]]', f'[[{oldNameU}]]', f'[[{newName}|{newDisplayU}]]')
        replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}|', f'[[{newNameL}|', f'[[{oldNameU}|', f'[[{newNameU}|')
    else:
        replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}]]', f'[[{newNameL}]]', f'[[{oldNameU}]]', f'[[{newNameU}]]')
        if newDisplay == "":
            replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}|{oldDisplayL}]]', f'[[{newNameL}]]', f'[[{oldNameL}|{oldDisplayU}]]', f'[[{newNameU}]]', f'[[{oldNameU}|{oldDisplayL}]]', f'[[{newNameL}]]', f'[[{oldNameU}|{oldDisplayU}]]', f'[[{newNameU}]]')
        else:
            replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', f'[[{oldNameL}|{oldDisplayL}]]', f'[[{newName}|{newDisplayL}]]', f'[[{oldNameL}|{oldDisplayU}]]', f'[[{newName}|{newDisplayU}]]', f'[[{oldNameU}|{oldDisplayL}]]', f'[[{newName}|{newDisplayL}]]', f'[[{oldNameU}|{oldDisplayU}]]', f'[[{newName}|{newDisplayU}]]')
        replace.main(f'-ref:{oldName}', f'-summary:Updating links from [[{oldName}]] to [[{newName}]]', '-regex', fr'\[\[{re.escape(oldNameL)}\|((?!{re.escape(oldDisplayL)}\]\]).*?)\]\]', fr'[[{newName}|\1]]', fr'\[\[{re.escape(oldNameL)}\|((?!{re.escape(oldDisplayU)}\]\]).*?)\]\]', fr'[[{newName}|\1]]', fr'\[\[{re.escape(oldNameU)}\|((?!{re.escape(oldDisplayL)}\]\]).*?)\]\]', fr'[[{newName}|\1]]', fr'\[\[{re.escape(oldNameU)}\|((?!{re.escape(oldDisplayU)}\]\]).*?)\]\]', fr'[[{newName}|\1]]')
        
        oldPage = pywikibot.Page(site, oldName)
        oldLinks = list(LinkedPageGenerator(oldPage))
        
        print(str(len(oldLinks)) + " links remaining.")
        
        if len(oldLinks) != 0:
            humanNeededPage = pywikibot.Page(site, 'User:Botgo50/Link changer/human needed')
            humanNeededPage.text = humanNeededPage.get(force=True) + "\n* [[Special:WhatLinksHere/" + oldPage.title() + "|" + oldPage.title() + "]]"
            humanNeededPage.save("adding {}".format(oldPage.title()))
            try:
                linksPage.text = linksPage.get(force=True).split("\n", 1)[1]
            except IndexError:
                linksPage.text = ""
            linksPage.save("Done. See [[User:Botgo50/Link changer/human needed]]")
        elif delete:
            toDeletePage = pywikibot.Page(site, 'User:Botgo50/Link changer/delete')
            toDeletePage.text = toDeletePage.get(force=True) + "\n* [[" + oldPage.title() + "]]"
            toDeletePage.save("adding {}".format(oldPage.title()))
            try:
                linksPage.text = linksPage.get(force=True).split("\n", 1)[1]
            except IndexError:
                linksPage.text = ""
            linksPage.save("Done. See [[User:Botgo50/Link changer/delete]]")
        else:
            try:
                linksPage.text = linksPage.get(force=True).split("\n", 1)[1]
            except IndexError:
                linksPage.text = ""
            linksPage.save("Done")