Участник:AdamantBot/Исходники/newpages.cpp

Материал из Википедии — свободной энциклопедии
Документация
#include "adabot.h"
#include "credentials.h"
#include <bits/stdc++.h>

using namespace std;
using namespace adabot;

r_client rcl("ruwiki_p", "ruwiki.labsdb", db_login, db_password, 3306);
w_client wcl("ru.wikipedia.org");
r_pages recents(rcl);
cl_graph cg(rcl);

const vector<string> templates = {
//    "Участник:NirvanaBot/Новые статьи",
    "Участник:ClaymoreBot/Новые статьи"
};

const unordered_set<string> aliases = {
//    "Участник:NirvanaBot/Новые статьи",
//    "User:NirvanaBot/Новые статьи",
    "Участник:ClaymoreBot/Новые статьи",
    "User:ClaymoreBot/Новые статьи"
};

const int def_depth = 6;
const int def_elems = 20;
const int def_space = 0;
const int def_recent = 350;
const string def_format = "[[%(название)]]";
const string def_separator = "\n";
const string def_header = "";
const string def_bottom = "\n<noinclude> "
                          "[[Категория:Википедия:Списки новых статей по темам|"
                          "{{PAGENAME}}]] </noinclude>";

const string time_pat = "%(дата)";
const string title_pat = "%(название)";
const string actor_pat = "%(автор)";

void update_page(string page, vector<tuple<string, string, string>> pages,
                 string format, string separator,
                 string header, string bottom) {
    string result = header;
    vector<string> page_list;
    for(auto it: pages) {
        string time, title, actor;
        tie(time, title, actor) = it;
        time = time.substr(0, 4) + "-" + time.substr(4, 2) + "-" // convert SQL
             + time.substr(6, 2) + "T" + time.substr(8, 2) + ":" // format to
             + time.substr(10, 2) + ":" + time.substr(12) + "Z"; // API format
        string row = format;
        row = str::replace(row, time_pat, time);
        row = str::replace(row, title_pat, title);
        row = str::replace(row, actor_pat, actor);
        page_list.push_back(row);
    }
    result += str::join(utils::map(page_list,
                                   str::replacer('_', " ")),
                                separator);
    result += bottom;
    result = str::replace(result, "\\n", "\n");
    result = str::replace(result, "&", "%26");
    wcl.edit(page, result, "обновление списка новых страниц");
}

void process(string str, bool triage = true) {
    auto parsed = w_parser::parse(str);
    for(auto it: parsed.get_tokens()) {
        if(it.get_type() == w_token::w_template &&
            aliases.count(it.get_name())) {
                auto args = it.get_args();
                string page = args["страница"].to_wikitext();
                if(page.empty()) {
                    cerr << "No page in this template, skipping it..." << endl;
                    continue;
                }
                auto cats = args["категории"].to_wikitext().size()
                          ? str::split(args["категории"].to_wikitext(), ',')
                          : args["категория"].to_wikitext().size()
                          ? str::split(args["категория"].to_wikitext(), ',')
                          : vector<string>{};
                if(cats.empty()) {
                    cerr << "Skipping page " << page
                         << ", no root categories provided" << endl;
                    continue;
                }
                auto forb = str::split(args["игнорировать"].to_wikitext(), ',');
                auto dequoter = [](string x) {
                    if(x[0] == '"' && x.back() == '"') {
                        x = x.substr(1);
                        x.pop_back();
                    }
                    return x;
                };
                auto trimmer = [&](string x) {
                    x = dequoter(str::replace(str::trim(x), ' ', "_"));
                    size_t idx = x.find('#');
                    if(idx != string::npos) {
                        x.erase(idx);
                    }
                    return x;
                };
                cats = utils::map(cats, trimmer);
                forb = utils::map(forb, trimmer);
                int depth = args["глубина"].to_wikitext().size()
                          ? stol(args["глубина"].to_wikitext())
                          : def_depth;
                int space = args["пространство имён"].to_wikitext().size()
                          ? stol(args["пространство имён"].to_wikitext())
                          : def_space;
                size_t elems = args["элементов"].to_wikitext().size()
                             ? stol(args["элементов"].to_wikitext())
                             : def_elems;
                string type = args["тип"].to_wikitext();
                if(type != "новые статьи" && type != "список новых статей") {
                    cerr << "Skipping page " << page << ", type "
                         << type << " is not supported yet" << endl;
                    continue;
                }
                string header = args.count("шапка")
                                ? dequoter(args["шапка"].to_wikitext())
                                : def_header;
                string format = args.count("формат элемента")
                                ? dequoter(args["формат элемента"].to_wikitext())
                                : def_format;
                string separator = args.count("разделитель")
                                 ? dequoter(args["разделитель"].to_wikitext())
                                 : def_separator;
                string bottom = args.count("подвал")
                                ? dequoter(args["подвал"].to_wikitext())
                                : def_bottom;

                auto subcats = cg.get_subcats(cats, forb, depth);
                auto pages = recents.pages(subcats, space);
                if(pages.size() > elems) {
                    pages.resize(elems);
                }
                if(triage) {
                    page = "Участник:AdamantBot/Песочница/" + page;
                }
                update_page(page, pages, format, separator, header, bottom);
        }
    }
}

int main(int argc, char *argv[]) {
    freopen("log_recent.txt", "w", stderr);
    wcl.login(botlogin, newpages_bot, botpass.at(newpages_bot));
    auto transcludes = wcl.transcludedin(templates);
    vector<string> pages;
    for(auto it: transcludes) {
        pages.insert(end(pages), begin(it.second), end(it.second));
    }
    auto texts = wcl.wikitext(pages);
    int count = 5000;
    for(auto it: pages) {
        cerr << "Processing params on " << it << "..." << endl;
        process(texts[it], false);
        if(count-- == 0) {
            break;
        }
    }
}