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

#!/usr/bin/env python3
"""
Şablona Bêkategorî lê zêde dike an radike.
Eger hemû kategoriya rûpelê veşartî be, lê zêde dike. Wekî din radike. Tenê li ser gotaran dixebite.

Bikaranîn

python pwb.py addbekategori -ns:0 -cat:"Kategorî:Hemû rûpelên bêkategorî"  -always

python pwb.py addbekategori -ns:0 -cat:"Kategorî:Hemû rûpelên bêkategorî" -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.

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


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


"""
#
# (C) Pywikibot team, 2006-2022
#
# Distributed under the terms of the MIT license.
#

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

VERBOSE = False

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


class BekategoriBot(
    # 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'

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

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Retrieve redirects for templates
        self.bekat_redirects = [redirect.lower() for redirect in self.get_template_redirects("Bêkategorî")]
        self.bot_name = "User:Balyozxane/skrîpt/py/addbekategori.py"

    def get_template_redirects(self, template_title):
        template_title = "Şablon:" + template_title
        template_page = pywikibot.Page(self.site, template_title)
        redirects = template_page.backlinks(filter_redirects=True, namespaces=[10])
        redirect_titles = [redirect.title(with_ns=False) for redirect in redirects]
        redirect_titles.append(template_title.split(":")[-1])

        if VERBOSE:
            print(f"{template_title} redirects:\n{redirect_titles}")
        return redirect_titles

    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 bekat_inpage(self, parsed):

        bekat_inpage = False
        for template in parsed.filter_templates():
            template_name = template.name.strip().lower()  # Convert template name to lowercase
            if template_name in self.bekat_redirects:
                bekat_inpage = True

        return bekat_inpage

    def remove_template(self, parsed):
        for template in parsed.filter_templates():
            template_name = template.name.strip().lower()  # Convert template name to lowercase
            if template_name in self.bekat_redirects:
                parsed.remove(template)

        new_next = str(parsed)
        return new_next

    @staticmethod
    def are_categories_hidden(categories):
        ku_months = {
            'January': 'kanûna paşîn',
            'February': 'sibat',
            'March': 'adar',
            'April': 'nîsan',
            'May': 'gulan',
            'June': 'hezîran',
            'July': 'tîrmeh',
            'August': 'tebax',
            'September': 'îlon',
            'October': 'çiriya pêşîn',
            'November': 'çiriya paşîn',
            'December': 'kanûna pêşîn'
        }

        # Check if any of the categories are not hidden
        for category in categories:

            if VERBOSE:
                print(f"Checking category: {category.title(with_ns=False)}")

            if category.exists():
                if not category.isHiddenCategory():
                    if VERBOSE:
                        print(f"Category '{category.title(with_ns=False)}' is not hidden.")
                    return False
            else:
                # Check if the category matches any of the patterns
                pattern_matched = False
                for month_name, kurdish_month in ku_months.items():
                    pattern = fr".+ ji {kurdish_month} \d+"

                    if re.search(pattern, category.title(with_ns=False)):
                        if VERBOSE:
                            print(f"Match found for category '{category.title(with_ns=False)}'.")
                        pattern_matched = True
                        break

                # If no match is found, continue to the next category
                if not pattern_matched:
                    if VERBOSE:
                        print(f"No match found for category '{category.title(with_ns=False)}'.")
                    continue

                if VERBOSE:
                    print("Match found. Returning True.")
                return True
        if VERBOSE:
            print("All categories checked. Returning True.")
        return True

    def treat_page(self) -> None:

        if self.current_page.namespace() != 0:
            if VERBOSE:
                print("Skipping Namespace not 0.")
            return

        text = self.current_page.text
        parsed = mwparserfromhell.parse(text)

        categories = self.current_page.categories()

        if self.are_categories_hidden(categories):
            if VERBOSE:
                print("All categories of the page are hidden.")
            cats_hidden = True

        else:
            if VERBOSE:
                print("Not all categories of the page are hidden.")
            cats_hidden = False

        if self.bekat_inpage(parsed):
            if VERBOSE:
                print("Bêkategorî di rûpelê de heye.")
            bekat_inpage = True
        else:
            if VERBOSE:
                print("Bêkategorî tine ye.")
            bekat_inpage = False

        if cats_hidden and not bekat_inpage:
            new_template = "\n{{subst:Bêkategorî}}"
            updated_text = text + new_template
            done = "lê hat zêdekirin"
        elif not cats_hidden and bekat_inpage:
            updated_text = self.remove_template(parsed)
            done = "hat rakirin"

        else:
            if VERBOSE:
                print("Skipping... All categories are hidden and Bêkategorî is in page.")
            return

        cleaned_new_text, kozmetik_cebu = self.do_kozmetik(updated_text)

        summary = f'[[{self.bot_name}|Bot]]: Şablona {{{{[[Şablon:Bêkategorî|bêkategorî]]}}}} {done}{kozmetik_cebu}'

        self.put_current(
            cleaned_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
    # 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 = BekategoriBot(generator=gen, **options)
        bot.run()  # guess what it does


if __name__ == '__main__':
    main()