Bikarhêner:Balyozxane/skrîpt/py/templsubst.py

#!/usr/bin/env python3
"""
Skrîpta ji bo subst:kirina şablonan. Nimûne:
https://ku.wikipedia.org/w/index.php?title=Bikarh%C3%AAner:Balyozxane/ceribandin&diff=prev&oldid=1572867

Bikaranîn

python pwb.py templsubst -ns:0 -transcludes:"Modul:CS1 translator"  -always

python pwb.py templsubst -ns:0 -transcludes:"Modul:CS1 translator" -showdiff

The following parameters are supported:

-always           The bot won't ask for confirmation when putting a page.

-showdiff         The bot will show the differences in the console.

-async            Edits will be performed asynchronously.

-summary:         Set the action summary message for the edit.

Use global -simulate option for test purposes. No changes to live wiki
will be done.

"""
#
# (C) w:ku:User:Balyozxane :)
#
# Distributed under the terms of the MIT license.
#

import pywikibot
from pywikibot import pagegenerators
from pywikibot.bot import (
    AutomaticTWSummaryBot,
    ConfigParserBot,
    ExistingPageBot,
    SingleSiteBot,
)
from kucosmetics import CANCEL, CosmeticChangesToolkit
import mwparserfromhell

# This is required for the text that is shown when you run this script
# with the parameter -help.
docuReplacements = {'&params;': pagegenerators.parameterHelp}  # noqa: N816

TESTING = False
VERBOSE = False


class TemplSubstBot(
    # Refer pywikobot.bot for generic bot classes
    SingleSiteBot,  # A bot only working on one site
    ConfigParserBot,  # A bot which reads options from scripts.ini setting file
    # CurrentPageBot,  # Sets 'current_page'. Process it in treat_page method.
    #                  # Not needed here because we have subclasses
    ExistingPageBot,  # CurrentPageBot which only treats existing pages
    AutomaticTWSummaryBot,  # Automatically defines summary; needs summary_key
):
    use_redirects = False  # treats non-redirects only
    summary_key = 'basic-changing'

    def __init__(self, **kwargs):
        self.templates = kwargs.pop('templates', [])
        self.bot_name = "Bikarhêner:Balyozxane/skrîpt/py/templsubst.py"
        self.cat_title = "Kategorî:Şablonên ku otomatîk were substkirin"

        super().__init__(**kwargs)

    update_options = {
        'async': False,
        'showdiff': False,
        'ignore': CANCEL.MATCH,
    }

    @staticmethod
    def log_to_page(page_title, ref_content):
        site = pywikibot.Site("ku", "wikipedia")
        log_page = pywikibot.Page(site, "User:Balyozbot/kontrol/tempsubst")

        log_text = f"\n\nPage title: {page_title}\nRef content causing ValueError: {ref_content}"

        # Append the log text to the existing content of the log page
        log_page.text += log_text

        # Save the changes to the log page
        log_page.save(summary="Logging ValueError")

    def subst_ref_tags(self, parsed_wikitext):
        for index, tag in enumerate(parsed_wikitext.filter_tags()):
            if tag.tag == "ref":
                ref_content = tag.contents.strip()

                sablon_heye = self.check_template(ref_content)

                if sablon_heye:
                    if tag.has("name"):
                        name = tag.get("name").value.strip()
                        replaced_content = f'{{{{safesubst:#tag:ref|{ref_content}|name="{name}"}}}}'
                    else:
                        replaced_content = f'{{{{safesubst:#tag:ref|{ref_content}}}}}'
                    try:
                        # Attempt to replace the tag content
                        parsed_wikitext.replace(tag, replaced_content)
                    except ValueError as e:
                        # If ValueError occurs, log the error and skip replacement
                        pywikibot.error(f"Error replacing tag: {e}. Skipping replacement.")
                        ref_log = f"{{{{subst:codenowiki |1={str(tag)}}}}}"
                        self.log_to_page(self.current_page.title(), ref_log)
                        return

    def check_template(self, ref_content):
        parsed_content = mwparserfromhell.parse(ref_content)
        templates = parsed_content.filter_templates()
        for template in templates:
            template_name = template.name.strip()
            if template_name.lower() in map(str.lower, self.templates):
                return True

        return False

    def subst_templates(self, parsed_wikitext):
        for template in parsed_wikitext.filter_templates():
            template_name = template.name.strip()
            if template_name.lower() in map(str.lower, self.templates):
                template.name = "subst:" + template_name

    def do_kozmetik(self, old_text):
        kozmetik_cebu = ""
        cc_toolkit = CosmeticChangesToolkit(self.current_page,
                                            ignore=self.opt.ignore)
        new_text, summaries = cc_toolkit.change(old_text)
        applied_summaries = ', '.join(summaries.values())
        if new_text is not False and new_text != old_text:
            kozmetik_cebu = "; paqijiyên kozmetîk"
            if applied_summaries:
                kozmetik_cebu += f' ({applied_summaries}.)'

        return new_text, kozmetik_cebu

    def treat_page(self) -> None:
        """Load the given page, do some changes, and save it."""

        if self.current_page.namespace() != 0 and self.current_page.title() != 'Bikarhêner:Balyozxane/ceribandin':
            pywikibot.output(f"Skipping page '{self.current_page.title()}' because it is not in namespace 0")
            return

        text = self.current_page.text
        old_text = text
        parsed_wikitext = mwparserfromhell.parse(text)
        self.subst_ref_tags(parsed_wikitext)
        self.subst_templates(parsed_wikitext)

        new_text = str(parsed_wikitext)

        kozmetik_cebu = ""

        if old_text != new_text:
            if TESTING:
                new_text = new_text
            else:
                cleaned_new_text, kozmetik_cebu = self.do_kozmetik(new_text)
                new_text = cleaned_new_text

            summary = f'[[{self.bot_name}|Bot]]: Şablonên ku otomatîk were [[{self.cat_title}|subst:kirin]] hat subst:kirin{kozmetik_cebu}'

            self.put_current(
                new_text,
                summary=summary,
                asynchronous=self.opt['async'],
                show_diff=self.opt['showdiff']
            )


def main(*args: str) -> None:
    """
    Process command line arguments and invoke bot.

    If args is an empty list, sys.argv is used.

    :param args: command line arguments
    """
    options = {}
    # Process global arguments to determine desired site
    local_args = pywikibot.handle_args(args)

    # This factory is responsible for processing command line arguments
    # that are also used by other scripts and that determine on which pages
    # to work on.
    gen_factory = pagegenerators.GeneratorFactory()

    # Process pagegenerators arguments
    local_args = gen_factory.handle_args(local_args)

    # Parse your own command line arguments
    for arg in local_args:
        arg, _, value = arg.partition(':')
        option = arg[1:]
        if option in ('-always', '-async', '-showdiff'):
            options[option[1:]] = True
        elif option == '-ignore':
            value = value.upper()
            try:
                options['ignore'] = getattr(CANCEL, value)
            except AttributeError:
                raise ValueError(f'Unknown ignore mode {value!r}!')

        # take the remaining options as booleans.
        # You will get a hint if they aren't pre-defined in your bot class
        else:
            options[option] = True

    template_names = ['Cite book/Arabic', 'Cite book/Danish', 'Cite book/Dutch', 'Cite book/Finnish', 'Cite book/French', 'Cite book/German', 'Cite book/Italian or Spanish', 'Cite book/Norwegian', 'Cite book/Polish', 'Cite book/Portuguese', 'Cite book/Swedish', 'Cite book/Turkish', 'Cite journal/Danish', 'Cite journal/Dutch', 'Cite journal/Finnish', 'Cite journal/French', 'Cite journal/Italian', 'Cite journal/Norwegian', 'Cite journal/Polish', 'Cite journal/Russian', 'Cite journal/Spanish', 'Cite journal/Swedish', 'Cite news/Arabic', 'Cite news/Catalan', 'Cite news/Italian or Spanish', 'Cite news/Portuguese', 'Cite web/Arabic', 'Cite web/Catalan', 'Cite web/Danish', 'Cite web/Dutch', 'Cite web/Finnish', 'Cite web/French', 'Cite web/German', 'Cite web/Italian or Spanish', 'Cite web/Norwegian', 'Cite web/Polish', 'Cite web/Portuguese', 'Cite web/Swedish', 'Cite web/Turkish', 'استشهاد بكتاب', 'Kilde bog', 'Citeer boek', 'Kirjaviite', 'Ouvrage', 'Literatur', 'Cite book/Italian', 'Cite book/Spanish', 'Cita libro', 'Kilde bok', 'Cytuj książkę', 'Citar livro', 'Bokref', 'Kitap kaynağı', 'Citeer journal', 'Lehtiviite', 'Article', 'Cita pubblicazione', 'Kilde artikkel', 'Cytuj pismo', 'Статья', 'Cita publicación', 'Tidskriftsref', 'استشهاد بخبر', 'Ref-publicació', 'Cita news', 'Cite news/Italian', 'Cite news/Spanish', 'Citar jornal', 'استشهاد ويب', 'Ref-web', 'Citeer web', 'Verkkoviite', 'Lien web', 'Internetquelle', 'Internetquelle/subst', 'Cita web', 'Cytuj stronę', 'Cytuj', 'Citar web', 'Webbref', 'Web kaynağı'
                      ]
    if VERBOSE:
        if template_names:
            print(template_names)
        else:
            print("templates?")

    # The preloading option is responsible for downloading multiple
    # pages from the wiki simultaneously.
    gen = gen_factory.getCombinedGenerator(preload=True)

    # check if further help is needed
    if not pywikibot.bot.suggest_help(missing_generator=not gen):
        # pass generator and private options to the bot
        bot = TemplSubstBot(generator=gen, templates=template_names, **options)
        bot.run()  # guess what it does


if __name__ == '__main__':
    main()