User:Theleekycauldron/Scripts/DYK move protector.py

"""
Copyright (c) 2023 theleekycauldron

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"""
import pywikibot as pwb
import datetime as dt
from datetime import datetime
import re

list_file = "C:\\Users\\claud\\Desktop\\Programming\\Toolforge\\moveprotectorlist.txt" #This file stores a list of protected page if updates are necessary – change my path!
site = pwb.Site('en','wikipedia')
update_time = dt.timedelta(seconds=int(pwb.Page(site,"User:DYKUpdateBot/Time Between Updates").text)) #time between DYK updates
next_update = datetime.strptime(pwb.Page(site,"Template:Did you know/Next update/Time").text,"%Y-%m-%dT%H:%M:%SZ")+update_time #next update time
next_queue = pwb.Page(site,"Template:Did you know/Queue/Next").text #next queue on the main page
tag = " [DYK move protector v1.0.0]"

def load_list(): #gets the list of protected articles and their expiration dates from the list
    f = open(list_file,'r').read().splitlines()
    res = {}
    for line in f: #should look like "C. J. Cregg || 2023-02-02 11:17:31"
        line = line.split(" || ")
        res[line[0]] = datetime.strptime(line[1],"%Y-%m-%d %H:%M:%S")
    return res

def load_queues(): #gets a dictionary of all bolded articles from the queues
    page_list = ["Template:Did you know"] + [f"Template:Did you know/Queue/{i}" for i in range(1,8)]
    res = {}
    for page_title in page_list:
        res[page_title] = []
        page = pwb.Page(site,page_title)
        text = page.text
        try:
            hooktext = text[text.index("<!--Hooks-->"):text.index("<!--HooksEnd-->")].splitlines()[1:]
        except ValueError as e:
            print("error analyzing queue")
            continue
        for hook in hooktext:
            res[page_title] += [a[0].capitalize() + a[1:] for a in re.findall(r"'''\[\[([^\|\]]+)(?:\||\]\])",hook)] #find all bolded articles and stick 'em in
    return res

def queue_multiplier(a): #Returns the number to multiply the timedelta by to get the expiry time; Main Page is 0, next queue is 1, next-but-one queue is 2, etc.
    res = 0 if a == "w" else 7-(6-int(a)+int(next_queue))%7
    print("Main Page:" if a == "w" else f"Queue {a}:",res)
    return res #"w" is the last letter of "Template:Did you know", the rest of the formula derives the queue's place in the line of succession
    
def main():
    queues = load_queues()
    articles_protected = load_list()
    articles_to_unprotect = load_list() #We need two copies of the dict to run concurrent modification
    list_write = {} #Creating loading on the list
    for queue in queues: #Applying protection, queue-by-queue
        expiry_time = next_update + update_time*queue_multiplier(queue[-1]) #Calculates the expiry time
        for article in queues[queue]: #protecting pages
            site.protect(pwb.Page(article),{'move': 'sysop'},"Protecting page for upcoming DYK appearance"+tag,expiry=expiry_time)
            print("protection for",article,"until",expiry_time)
            list_write[article] = datetime.strftime(expiry_time,"%Y-%m-%d %H:%M:%S") 
            
        for article in articles_protected: #culling a list of articles that need to be unprotected
            if article in queues[queue]:
                del articles_to_unprotect[article] #if we've just protected it, it doesn't need to be unprotected
    
    for article in articles_to_unprotect: #unprotecting articles that have been pulled from queue
        now = datetime.now()
        if articles_to_unprotect[article]<=now: #if the expiry point has passed, no need to unprotect
            continue
        site.protect(site.protect(pwb.Page(article),{'move': ''},"Unprotecting pulled DYK article"+tag)
        print("unprotection for",article)
    
    list_write = "\n".join([f"{n} || {list_write[n]}" for n in list_write])
    f = open(list_file,'w')
    f.write(list_write)
    f.close()
        
if __name__ == "__main__":
    main()