public static string GetMessage(RecentChange change, string format, string lang) { // Parse length of the diff string strLength = ""; int length = (change.LengthNew - change.LengthOld); strLength = length.ToString(); if (length > 0) { strLength = "+" + strLength; } strLength = $"({strLength})"; if (length > 500 || length < -500) { strLength = $"**{strLength}**"; } // Markdownify link string link = format.Replace("/wiki/$1", string.Format("/?{0}{1}", (change.OldID != 0 ? "diff=" : "oldid="), change.RevID)); link = string.Format("([{0}]({1}))", Locale.GetMessage("eventstreams-diff", lang), link); // Markdownify user string user = "******" + change.User; string talk = "User_talk:" + change.User; string contribs = "Special:Contributions/" + change.User; user = Linking.GetLink(user, format, true); talk = Linking.GetLink(talk, format, true); contribs = Linking.GetLink(contribs, format, true); talk = string.Format("[{0}]({1})", Locale.GetMessage("eventstreams-talk", lang), talk); IPAddress address; if (IPAddress.TryParse(change.User, out address)) { user = $"[{change.User}]({contribs}) ({talk})"; } else { contribs = string.Format("[{0}]({1})", Locale.GetMessage("eventstreams-contribs", lang), contribs); user = $"[{change.User}]({user}) ({talk} | {contribs})"; } // Parse comment, adjusting for its length string comment = ParseComment(change.Summary, format); string msg = $"{link} . . {strLength} . . {user}"; if (msg.Length + comment.Length > 2000) { comment = ParseComment(change.Summary, format, false); } msg += comment; return(msg); }
public static DiscordEmbedBuilder GetEmbed(RecentChange change, string format, string lang) { DiscordEmbedBuilder embed = new DiscordEmbedBuilder() .WithTimestamp(change.Timestamp); DiscordColor embedColor = new DiscordColor(0x72777d); string embedIcon = "2/25/MobileFrontend_bytes-neutral.svg/512px-MobileFrontend_bytes-neutral.svg.png"; // Parse statuses from the diff string status = ""; if (change.Type == RecentChange.ChangeType.New) { status += Locale.GetMessage("eventstreams-new", lang); } if (change.Minor == true) { status += Locale.GetMessage("eventstreams-minor", lang); } if (status != "") { embed.WithFooter(status); } // Parse length of the diff int length = (change.LengthNew - change.LengthOld); if (length > 0) { embedColor = new DiscordColor(0x00af89); embedIcon = "a/ab/MobileFrontend_bytes-added.svg/512px-MobileFrontend_bytes-added.svg.png"; } else if (length < 0) { embedIcon = "7/7c/MobileFrontend_bytes-removed.svg/512px-MobileFrontend_bytes-removed.svg.png"; embedColor = new DiscordColor(0xdd3333); } embed .WithAuthor( change.Title, Linking.GetLink(change.Title, format, true), string.Format("https://upload.wikimedia.org/wikipedia/commons/thumb/{0}", embedIcon) ) .WithColor(embedColor) .WithDescription(GetMessage(change, format, lang)); return(embed); }
private static string ParseComment(string summary, string format, bool linkify = true) { if (summary.Length == 0) { return(""); } string linkPattern = "\\[{2}([^\\[\\]\\|\n]+)\\]{2}"; string linkPatternPipe = "\\[{2}([^\\[\\]\\|\n]+)\\|([^\\[\\]\n]+)\\]{2}"; // Transform code for section to simpler version string comment = summary.ToString().Replace("/* ", "→"); comment = Regex.Replace(comment, " \\*/$", string.Empty).Replace(" */", ":"); if (linkify) { // Linkify every wiki link in comment text comment = Regex.Replace(comment, linkPattern, m => { string title = m.Groups[1].Value; string link = string.Format("[{0}]({1})", title, Linking.GetLink(title, format, true)); return(link); }); comment = Regex.Replace(comment, linkPatternPipe, m => { string title = m.Groups[1].Value; string text = m.Groups[2].Value; string link = string.Format("[{0}]({1})", text, Linking.GetLink(title, format, true)); return(link); }); } else { // Display wiki links as plain text comment = Regex.Replace(comment, linkPattern, "$1"); comment = Regex.Replace(comment, linkPatternPipe, "$2"); } // Add italic and parentheses comment = $" *({comment})*"; return(comment); }
public static async Task React(JToken[] list, string lang) { // List of MediaWiki/Wikimedia-related projects string[] twProjects = new string[] { "8", // MediaWiki "1206", // Wikimedia "1238", // Pywikibot "1244", // Kiwix "1248", // Huggle "1274", // Phabricator }; Dictionary <string, string> twNames = new Dictionary <string, string>() { { "8", "MediaWiki" }, { "1206", "Wikimedia" }, { "1238", "Pywikibot" }, { "1244", "Kiwix" }, { "1248", "Huggle" }, { "1274", "Phabricator" }, }; // Filter only translations from projects above bool gotToLatest = false; List <JToken> query = list.Where(jt => jt.Type == JTokenType.Object).Select(item => { string key = item["key"].ToString(); if (twProjects.Where(x => key.StartsWith(x + ":")).ToList().Count > 0) { // Check if matches with latest fetch if (key == LatestFetchKey[lang]) { gotToLatest = true; } // Return if no there is still no match if (gotToLatest == false) { return(item); } } return(null); }).Where(i => i != null).ToList(); if (query.Count == 0) { return; } // Fetch every author for future message int count = query.Count; Dictionary <string, List <string> > authors = new Dictionary <string, List <string> >(); List <string> allAuthors = new List <string>(); foreach (var item in query) { string key = item["key"].ToString(); string ns = twProjects.Where(x => key.StartsWith(x + ":")).ToList().First().ToString(); string translator = item["properties"]["last-translator-text"].ToString(); if (!authors.ContainsKey(ns)) { authors[ns] = new List <string>(); } if (!authors[ns].Contains(translator)) { authors[ns].Add(translator); } if (!allAuthors.Contains(translator)) { allAuthors.Add(translator); } } // Send Discord messages to guilds DiscordClient client = Program.Client; foreach (string chan in Channels[lang]) { DiscordEmbedBuilder embed = new DiscordEmbedBuilder() .WithColor(new DiscordColor(0x013467)) .WithFooter("translatewiki.net"); // Fetch info about channel ulong chanId = ulong.Parse(chan); DiscordChannel channel = await client.GetChannelAsync(chanId); string guildLang = Config.GetLang(channel.GuildId.ToString()); // Remember the key of first message Config.SetInternal(channel.Id.ToString(), "translatewiki-key", query[0]["key"].ToString()); // Inform about deadline if needed string deadlineInfo = null; if (UpdateDeadline) { deadlineInfo = Locale.GetMessage("translatewiki-deadline", guildLang); UpdateDeadline = false; UpdateDeadlineDone = true; } // Build messages string headerCount = (gotToLatest ? count.ToString() : count.ToString() + "+"); string header = Locale.GetMessage("translatewiki-header", guildLang, headerCount, count, allAuthors.Count); embed.WithAuthor( header, string.Format("https://translatewiki.net/wiki/Special:RecentChanges?translations=only&namespace={0}&limit=500&trailer=/ru", string.Join("%3B", twProjects)), "https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Translatewiki.net_logo.svg/512px-Translatewiki.net_logo.svg.png" ); // Check if authors list doesn’t exceed string desc = string.Join("\n", authors.Select(ns => { string str = twNames[ns.Key] + ": "; str += string.Join(", ", ns.Value.Select(author => { return(string.Format("[{0}]({1})", author, Linking.GetLink(author, "https://translatewiki.net/wiki/Special:Contribs/$1", true))); })); return(str); })); if (desc.Length > 2000) { desc = string.Join("\n", authors.Select(ns => { string str = twNames[ns.Key] + ": "; str += string.Join(", ", ns.Value.Select(author => { return(author); })); return(str); })); } embed.WithDescription(desc); await client.SendMessageAsync(channel, deadlineInfo, embed : embed); } // Write down new first key LatestFetchKey[lang] = query.First()["key"].ToString(); }
/// <summary> /// Form description of the changes for the project. /// </summary> /// <param name="authors">List of authors with their messages.</param> /// <returns>Changes in the project.</returns> private static string FormSimpleDescription(Dictionary <string, List <string> > authors) { var keys = authors.Keys.ToList(); var list = keys.Select(author => { return(string.Format("{0} ([{1}]({2}))", authors[author].Count, author, Linking.GetLink(author, "https://translatewiki.net/wiki/Special:Contribs/$1", true))); }); string result = string.Join(", ", list); if (result.Length > MAX_EMBED_LENGTH) { result = string.Join(", ", keys.Select(author => { return($"{authors[author].Count} ({author})"); })); if (result.Length > MAX_EMBED_LENGTH) { string ellipsis = " […]"; result = result.Substring(0, MAX_EMBED_LENGTH - ellipsis.Length) + ellipsis; } } return(result); }
/// <summary> /// Form description of the changes for the project. /// </summary> /// <param name="authors">List of authors with their messages.</param> /// <param name="includeIds">Whether to include message IDs in the result.</param> /// <returns>Changes in the project.</returns> private static string FormDescription(Dictionary <string, List <string> > authors, bool includeIds = true) { if (!includeIds) { return(FormSimpleDescription(authors)); } Dictionary <string, string[]> storage = new Dictionary <string, string[]>(); // Calculate how much links cost int authorLinkLength = 0; int authorNameLength = 0; foreach (var item in authors) { var arr = new string[3]; arr[0] = string.Format("[{0}]({1})", item.Key, Linking.GetLink(item.Key, "https://translatewiki.net/wiki/Special:Contribs/$1", true)); arr[1] = item.Value.Count.ToString(); arr[2] = ""; authorLinkLength += arr[0].Length; authorNameLength += item.Key.Length; storage.Add(item.Key, arr); } // Add as many message IDs as we can int msgLength = 0; bool useLinks = (authorLinkLength < (MAX_EMBED_LENGTH / 2)); Dictionary <string, int> msgNumbers = new Dictionary <string, int>(); Dictionary <string, bool> finished = new Dictionary <string, bool>(); while (msgLength < MAX_EMBED_LENGTH) { foreach (var item in authors) { if (msgLength > MAX_EMBED_LENGTH || item.Key == "1274") { break; } if (!msgNumbers.ContainsKey(item.Key)) { msgNumbers[item.Key] = 0; } var num = msgNumbers[item.Key]; if (finished.ContainsKey(item.Key) || num >= item.Value.Count) { if (!finished.ContainsKey(item.Key)) { finished[item.Key] = true; } continue; } ; var arr = storage[item.Key]; if (num == 0) { arr[0] = string.Format(" ({0})\n", (useLinks ? arr[0] : item.Key)); msgLength += arr[0].Length; msgLength += arr[1].Length; } string str = (arr[2].Length > 0 ? ", " : "") + item.Value[num].Replace("_", @"\_"); if (msgLength + str.Length + arr[0].Length <= MAX_EMBED_LENGTH) { arr[2] += str; msgLength += str.Length; } else { finished[item.Key] = true; continue; } msgNumbers[item.Key]++; } // Break if foreach has ended for all elements if (finished.Values.Select(x => x).ToList().Count == msgNumbers.Count) { break; } } // Build the resulting string while accounting for unknown problems StringBuilder result = new StringBuilder(); foreach (var item in storage) { int trim = (authors[item.Key].Count - msgNumbers[item.Key]); string trimmed = (trim > 0 ? $" + {trim}" : ""); result.Append(item.Value[2]); result.Append(trimmed); if (useLinks) { result.Append((result.Length + item.Value[0].Length > MAX_EMBED_LENGTH ? $" ({item.Key})\n" : item.Value[0])); } else { result.Append(item.Value[0]); } } return(result.ToString().TrimEnd('\n')); }