User:WJ-Bot/Core

维基百科,自由的百科全书

本代码为WJ-Bot的支持类,用于控制刷新频率、检查Bot模板以及避免重复更新操作。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Text;
using System.Text.RegularExpressions;

namespace WJBot
{
    public class BotWorker
    {
        public delegate string PageModifier(DotNetWikiBot.Page page);

        public event EventHandler PageUpdated;
        public event EventHandler PageLoaded;

        public int TotalPages { get; private set; }
        public int EditedPages { get; private set; }
        public int LoadedPages { get; private set; }
        public int LingerTime { get; set; }
        public string EditSummary { get; set; }

        public BotWorker()
        {
            LingerTime = 60000;
            EditSummary = string.Empty;
        }

        private Thread _thread;

        private bool AllowBots(string text, string user)
        {
            return !Regex.IsMatch(text, @"\{\{(nobots|bots\|(allow=none|deny=(?!none).*(" + user.Normalize() + @"|all)|optout=all))\}\}", RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Main bot function
        /// </summary>
        /// <param name="Pages">Page list for editing.</param>
        /// <param name="TitleSelector">Title selection delegate.</param>
        /// <param name="Modifier">Page modifier delegate.</param>
        /// <param name="IsTest">True if results are not submitted.</param>
        public void Start(DotNetWikiBot.PageList Pages, Func<string, bool> TitleSelector, PageModifier Modifier, bool IsTest)
        {
            if (EditSummary == string.Empty)
            {
                throw new ArgumentException("No edit summary");
            }
            if (_thread != null)
                _thread.Abort();
            _thread = new Thread(() =>
            {
                try
                {
                    TotalPages = Pages.Count();
                    LoadedPages = 0; EditedPages = 0;

                    HashSet<string> visited_list = new HashSet<string>();
                    if (File.Exists("visited.txt"))
                    {
                        StreamReader vs_reader = new StreamReader("visited.txt");
                        while (true)
                        {
                            string line = vs_reader.ReadLine();
                            if (line == null) break;
                            visited_list.Add(line.Trim('\r', '\n', ' '));
                        }
                        vs_reader.Close();
                    }

                    DateTime last_submission = DateTime.Now;
                    using (StreamWriter vs_writer = new StreamWriter("visited.txt", true))
                    {
                        foreach (DotNetWikiBot.Page pg_iter in Pages)
                        {
                            if (visited_list.Contains(pg_iter.title)) continue;
                            if (!TitleSelector(pg_iter.title)) continue;

                            pg_iter.Load();
                            LoadedPages++;
                            if (PageLoaded != null)
                            {
                                PageLoaded(this, new EventArgs());
                            }

                            visited_list.Add(pg_iter.title);
                            vs_writer.WriteLine(pg_iter.title);
                            vs_writer.Flush();

                            if (pg_iter.text == null) continue;
                            if (!AllowBots(pg_iter.text, pg_iter.site.userName)) continue;

                            string old_text = pg_iter.text;
                            string new_text = Modifier(pg_iter);
                            if (new_text != null && new_text != old_text)
                            {
                                EditedPages++;

                                StreamWriter stwriter = new StreamWriter("Depository\\" + pg_iter.title.Replace("/", "_").Replace(":", "_") + ".txt");
                                stwriter.Write(new_text);
                                stwriter.Close();

                                if (!IsTest)
                                {
                                    long linger = (long)(DateTime.Now - last_submission).TotalMilliseconds;
                                    if (linger < LingerTime)
                                    {
                                        Thread.Sleep((int)(LingerTime + 100 - linger));
                                    }
                                    try
                                    {
                                        pg_iter.Save(new_text, "机器人:" + EditSummary, true);
                                    }
                                    catch (Exception) { }
                                }
                                if (PageUpdated != null)
                                {
                                    PageUpdated(this, new EventArgs());
                                }
                                last_submission = DateTime.Now;
                            }
                        }
                    }
                }
                catch (ThreadAbortException)
                {
                }
            });
            _thread.Start();
        }
    }
}