public void UpdatePages(Wiki wiki) { Regex closedRE = new Regex(@"(\{{2}ВПКПМ-Навигация\}{2}\s*\{{2}(Закрыто|Closed|закрыто|closed)\}{2})|(\{{2}(Закрыто|Closed|закрыто|closed)\}{2}\s*\{{2}ВПКПМ-Навигация\}{2})"); Regex wikiLinkRE = new Regex(@"\[{2}(.+?)(\|.+?)?]{2}"); Regex timeRE = new Regex(@"(\d{2}:\d{2}\, \d\d? [а-я]+ \d{4}) \(UTC\)"); ParameterCollection parameters = new ParameterCollection(); parameters.Add("generator", "categorymembers"); parameters.Add("gcmtitle", "Категория:Википедия:Незакрытые обсуждения переименования страниц"); parameters.Add("gcmlimit", "max"); parameters.Add("gcmnamespace", "4"); parameters.Add("prop", "info|revisions"); parameters.Add("intoken", "edit"); XmlDocument doc = wiki.Enumerate(parameters, true); string queryTimestamp = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"); XmlNodeList pages = doc.SelectNodes("//page"); foreach (XmlNode page in pages) { int results = 0; string pageName = page.Attributes["title"].Value; string date = pageName.Substring("Википедия:К переименованию/".Length); string basetimestamp = page.FirstChild.FirstChild.Attributes["timestamp"].Value; string editToken = page.Attributes["edittoken"].Value; Day day = new Day(); if (!DateTime.TryParse(date, CultureInfo.CreateSpecificCulture("ru-RU"), DateTimeStyles.AssumeUniversal, out day.Date)) { continue; } string fileName = _cacheDir + date + ".bin"; string text = ""; if (File.Exists(fileName)) { using (FileStream fs = new FileStream(fileName, FileMode.Open)) using (GZipStream gs = new GZipStream(fs, CompressionMode.Decompress)) using (TextReader sr = new StreamReader(gs)) { string revid = sr.ReadLine(); if (revid == page.Attributes["lastrevid"].Value) { Console.Out.WriteLine("Loading " + pageName + "..."); text = sr.ReadToEnd(); } } } if (string.IsNullOrEmpty(text)) { Console.Out.WriteLine("Downloading " + pageName + "..."); text = wiki.LoadText(pageName); using (FileStream fs = new FileStream(fileName, FileMode.Create)) using (GZipStream gs = new GZipStream(fs, CompressionMode.Compress)) using (StreamWriter sw = new StreamWriter(gs)) { sw.WriteLine(page.Attributes["lastrevid"].Value); sw.Write(text); } } day.Page = WikiPage.Parse(pageName, text); List<string> titlesWithResults = new List<string>(); foreach (WikiPageSection section in day.Page.Sections) { RemoveStrikeOut(section); StrikeOutSection(section); Match m = wikiLinkRE.Match(section.Title); if (m.Success && !m.Groups[1].Value.StartsWith(":Категория:")) { string link = m.Groups[1].Value; string movedTo; string movedBy; DateTime movedAt; DateTime start = day.Date; m = timeRE.Match(section.SectionText); if (m.Success) { start = DateTime.Parse(m.Groups[1].Value, CultureInfo.CreateSpecificCulture("ru-RU"), DateTimeStyles.AssumeUniversal); } bool moved = MovedTo(wiki, link, start, out movedTo, out movedBy, out movedAt); WikiPageSection autoVerdictSection = section.Subsections.FirstOrDefault(s => s.Title.Trim() == "Автоматический итог"); if (autoVerdictSection != null && !moved) { autoVerdictSection.Title = " Оспоренный итог "; RemoveStrikeOut(section); StrikeOutSection(section); } if (section.Subsections.Count(s => s.Title.Trim() == "Оспоренный итог") == 0 && section.Subsections.Count(s => s.Title.ToLower().Trim() == "итог") == 0 && section.Subsections.Count(s => s.Title.Trim() == "Автоматический итог") == 0 && moved && !string.IsNullOrEmpty(movedTo)) { string message = string.Format("Страница была переименована {2} в «[[{0}]]» участником [[User:{1}|]]. Данное сообщение было автоматически сгенерировано ботом ~~~~.\n", movedTo, movedBy, movedAt.ToUniversalTime().ToString("d MMMM yyyy в HH:mm (UTC)")); WikiPageSection verdict = new WikiPageSection(" Автоматический итог ", section.Level + 1, message); section.AddSubsection(verdict); StrikeOutSection(section); ++results; } } m = wikiLinkRE.Match(section.Title); if (m.Success && section.Title.Contains("<s>")) { titlesWithResults.Add(m.Groups[1].Value); } List<WikiPageSection> sections = new List<WikiPageSection>(); section.Reduce(sections, SubsectionsList); foreach (WikiPageSection subsection in sections) { m = wikiLinkRE.Match(subsection.Title); if (m.Success && subsection.Title.Contains("<s>")) { titlesWithResults.Add(m.Groups[1].Value.Trim()); } if (m.Success && !subsection.Title.Contains("<s>") && !m.Groups[1].Value.StartsWith(":Категория:")) { string link = m.Groups[1].Value; string movedTo; string movedBy; DateTime movedAt; DateTime start = day.Date; m = timeRE.Match(subsection.SectionText); if (m.Success) { start = DateTime.Parse(m.Groups[1].Value, CultureInfo.CreateSpecificCulture("ru-RU"), DateTimeStyles.AssumeUniversal); } bool moved = MovedTo(wiki, link, start, out movedTo, out movedBy, out movedAt); WikiPageSection verdictSection = subsection.Subsections.FirstOrDefault(s => s.Title.Trim() == "Автоматический итог"); if (verdictSection != null && !moved) { verdictSection.Title = " Оспоренный итог "; RemoveStrikeOut(subsection); StrikeOutSection(subsection); } if (subsection.Subsections.Count(s => s.Title.Trim() == "Оспоренный итог") == 0 && subsection.Subsections.Count(s => s.Title.ToLower().Trim() == "итог") == 0 && subsection.Subsections.Count(s => s.Title.Trim() == "Автоматический итог") == 0 && moved && !string.IsNullOrEmpty(movedTo)) { string message = string.Format("Страница была переименована {2} в «[[{0}]]» участником [[User:{1}|]]. Данное сообщение было автоматически сгенерировано ботом ~~~~.\n", movedTo, movedBy, movedAt.ToUniversalTime().ToString("d MMMM yyyy в HH:mm (UTC)")); WikiPageSection verdict = new WikiPageSection(" Автоматический итог ", subsection.Level + 1, message); subsection.AddSubsection(verdict); StrikeOutSection(subsection); ++results; } } } } Match matchClosed = closedRE.Match(text); if (matchClosed.Success) { List<TalkResult> talkResults = new List<TalkResult>(); foreach (string name in titlesWithResults) { if (wiki.PageNamespace(name) > 0) { continue; } string movedTo; string movedBy; DateTime movedAt; bool moved = MovedTo(wiki, name, day.Date, out movedTo, out movedBy, out movedAt); talkResults.Add(new TalkResult(name, movedTo, moved)); } parameters.Clear(); parameters.Add("prop", "info"); XmlDocument xml = wiki.Query(QueryBy.Titles, parameters, talkResults.ConvertAll(r => r.Moved ? r.MovedTo : r.Title)); List<string> notificationList = new List<string>(); foreach (XmlNode node in xml.SelectNodes("//page")) { if (node.Attributes["missing"] == null && node.Attributes["ns"].Value == "0") { notificationList.Add(node.Attributes["title"].Value); } } if (notificationList.Count > 0) { parameters.Clear(); parameters.Add("list", "backlinks"); parameters.Add("bltitle", pageName); parameters.Add("blfilterredir", "nonredirects"); parameters.Add("blnamespace", "1"); parameters.Add("bllimit", "max"); XmlDocument backlinks = wiki.Enumerate(parameters, true); foreach (string title in notificationList) { if (backlinks.SelectSingleNode("//bl[@title=\"Обсуждение:" + title + "\"]") == null) { TalkResult tr = talkResults.Find(r => r.Moved ? r.MovedTo == title : r.Title == title); PutNotification(wiki, tr, day.Date); } } } } string newText = day.Page.Text; if (newText.Trim() == text.Trim()) { continue; } try { Console.Out.WriteLine("Updating " + pageName + "..."); string revid = wiki.Save(pageName, "", newText, "зачёркивание заголовков" + (results > 0 ? ", сообщение об итогах" : ""), MinorFlags.Minor, CreateFlags.NoCreate, WatchFlags.None, SaveFlags.Replace, true, basetimestamp, "", editToken); using (FileStream fs = new FileStream(fileName, FileMode.Create)) using (GZipStream gs = new GZipStream(fs, CompressionMode.Compress)) using (StreamWriter sw = new StreamWriter(gs)) { sw.WriteLine(revid); sw.Write(newText); } } catch (WikiException) { } } }