Example #1
0
        private static async Task <bool> _editPageAsync(MediaWikiClient client, EditHistory history, string pageTitle, string pageContent)
        {
            // Check to see if we've made this edit before.
            // If we've already made this page before, don't do anything.

            EditRecord record = await history.GetEditRecordAsync(pageTitle, pageContent);

            if (record is null)
            {
                // Get existing page content.
                // This allows us to make sure that no one has removed the "{{BotGenerated}}" flag.
                // If it has been removed, do not modify the page.

                MediaWikiApiParseRequestResult parse_result = client.Parse(pageTitle, new ParseParameters());

                if (parse_result.ErrorCode == ErrorCode.MissingTitle || parse_result.Text.Contains(BotFlag))
                {
                    if (parse_result.ErrorCode == ErrorCode.MissingTitle)
                    {
                        _log(string.Format("creating page \"{0}\"", pageTitle));
                    }
                    else
                    {
                        _log(string.Format("editing page \"{0}\"", pageTitle));
                    }

                    try {
                        client.Edit(pageTitle, new EditParameters {
                            Action = EditAction.Text,
                            Text   = pageContent
                        });

                        // Make a record of the edit.
                        await history.AddEditRecordAsync(pageTitle, pageContent);

                        // Return true to indicate that edits have occurred.
                        return(true);
                    }
                    catch (Exception ex) {
                        _log(ex.ToString());
                    }
                }
                else
                {
                    _log(string.Format("skipping page \"{0}\" (manually edited)", pageTitle));
                }
            }
            else
            {
                _log(string.Format("skipping page \"{0}\" (previously edited)", pageTitle));
            }

            // Return false to indicate that no edits have occurred.
            return(false);
        }
Example #2
0
        private static async Task _editSpeciesPageAsync(MediaWikiClient client, EditHistory history, Species species, string pageTitle, string pageContent)
        {
            if (await _editPageAsync(client, history, pageTitle, pageContent))
            {
                // If the edit was successful, associated it with this species.

                EditRecord record = await history.GetEditRecordAsync(pageTitle, pageContent);

                if (record != null)
                {
                    await history.AddEditRecordAsync(species.Id, record);

                    // Because it's possible that the species was renamed, we need to look at past edits to find previous titles of the same page.
                    // Old pages for renamed species will be deleted.

                    EditRecord[] edit_records = (await history.GetEditRecordsAsync(species.Id))
                                                .Where(x => x.Id != record.Id && x.Title.ToLower() != record.Title.ToLower())
                                                .ToArray();

                    // Delete all created pages where the old title does not match the current title.

                    foreach (EditRecord i in edit_records)
                    {
                        MediaWikiApiParseRequestResult parse_result = client.Parse(i.Title, new ParseParameters());

                        if (parse_result.Text.Contains(BotFlag))
                        {
                            // Only delete pages that haven't been manually edited.

                            client.Delete(i.Title, new DeleteParameters {
                                Reason = "species page moved to " + pageTitle
                            });

                            // Add an edit record for this page so that we can restore the content later without it thinking we've already made this edit.
                            // This is important, because this step can delete redirects when a page with redirects is updated. By creating a new edit record, the redirect will be recreated.

                            await history.AddEditRecordAsync(i.Title, string.Empty);
                        }
                    }

                    // We also need to delete any redirect pages that are now invalid (i.e. when specific epithet that points to a common name is changed).
                    // Delete all redirects that point to this page (or one of this page's previous titles).

                    RedirectRecord[] redirect_records = (await history.GetRedirectRecordsAsync())
                                                        .Where(i => i.Target == pageTitle || edit_records.Any(j => j.Title == i.Target)) // points to the title of this page, or one of its previous titles
                                                        .Where(i => i.Title != species.FullName)                                         // the title doesn't match this species' full name (the species has been renamed)
                                                        .ToArray();

                    foreach (RedirectRecord j in redirect_records)
                    {
                        MediaWikiApiParseRequestResult parse_result = client.Parse(j.Title, new ParseParameters());

                        if (parse_result.IsRedirect && parse_result.Text.Contains(BotFlag))
                        {
                            // Only delete pages that haven't been manually edited.

                            client.Delete(j.Title, new DeleteParameters {
                                Reason = "outdated redirect"
                            });
                        }
                    }
                }
            }
        }
Example #3
0
        private static async Task <string> UploadPictureAsync(MediaWikiClient client, EditHistory history, UploadParameters parameters, bool allowRetry)
        {
            // Check if we've already uploaded this file before.
            // If we've uploaded it before, return the filename that we uploaded it with.

            UploadRecord record = await history.GetUploadRecordAsync(parameters.FilePath);

            if (record is null)
            {
                // Get page for the file and check for the bot flag.
                // This prevents us from overwriting images that users uploaded manually.

                MediaWikiApiParseRequestResult page_content = client.Parse(parameters.PageTitle, new ParseParameters());

                if (page_content.ErrorCode == ErrorCode.MissingTitle || page_content.Text.Contains(BotFlag))
                {
                    // Attempt to upload the file.

                    try {
                        parameters.Text = BotFlag + '\n' + parameters.Text;

                        MediaWikiApiRequestResult result = client.Upload(parameters);

                        if (!result.Success)
                        {
                            _log(result.ErrorMessage);
                        }

                        if (result.ErrorCode == ErrorCode.VerificationError && allowRetry)
                        {
                            // This means that the file extension didn't match (e.g., filename has ".png" when the file format is actually ".jpg").
                            // Try changing the file extension and reuploading, because sometimes URLs stored in the bot will have this problem.

                            string ext = System.IO.Path.GetExtension(parameters.UploadFileName);
                            ext = (ext == ".png") ? ".jpg" : ".png";

                            parameters.UploadFileName = System.IO.Path.ChangeExtension(parameters.UploadFileName, ext);

                            _log("file extension didn't match, retrying upload");

                            return(await UploadPictureAsync(client, history, parameters, false));
                        }
                        else
                        {
                            if (result.Success || result.ErrorCode == ErrorCode.FileExistsNoChange)
                            {
                                // If the upload succeeded, record the file upload so that we can skip it in the future.
                                await history.AddUploadRecordAsync(parameters.FilePath, parameters.UploadFileName);

                                // Add the bot flag to the page content.
                                // client.Edit(parameters.PageTitle, new EditParameters { Text = BotFlag });
                            }
                            else
                            {
                                parameters.UploadFileName = string.Empty;
                            }
                        }
                    }
                    catch (Exception ex) {
                        parameters.UploadFileName = string.Empty;

                        _log(ex.ToString());
                    }
                }
                else
                {
                    _log(string.Format("skipping file \"{0}\" (manually edited)", parameters.UploadFileName));
                }
            }
            else
            {
                // This image has been uploaded previously, so just return its path.

                _log(string.Format("skipping file \"{0}\" (previously uploaded)", parameters.UploadFileName));

                parameters.UploadFileName = record.UploadFileName;
            }

            return(parameters.UploadFileName);
        }
Example #4
0
        private static async Task <string[]> UploadSpeciesGalleryAsync(MediaWikiClient client, EditHistory history, Species species)
        {
            // Upload all images in the given species' gallery.

            Picture[] pictures = await SpeciesUtils.GetPicturesAsync(species);

            List <string> uploadedFilenames = new List <string>();

            if (pictures != null)
            {
                foreach (Picture picture in pictures)
                {
                    // Skip the image if it's the same as the species' default image, because we would've already uploaded it

                    if (picture.url == species.Picture)
                    {
                        continue;
                    }

                    string uploadedFilename = GeneratePictureFilenameFromSpecies(species, picture.url);

                    if (!string.IsNullOrEmpty(uploadedFilename))
                    {
                        UploadParameters uploadParameters = new UploadParameters {
                            UploadFileName = uploadedFilename,
                            FilePath       = picture.url,
                            Text           = picture.description
                        };

                        uploadedFilename = await UploadPictureAsync(client, history, uploadParameters, true);

                        if (!string.IsNullOrEmpty(uploadedFilename))
                        {
                            uploadedFilenames.Add(uploadedFilename);
                        }
                    }
                    else
                    {
                        _log(string.Format("Failed to generate filename for picture: {0}", picture.url));
                    }
                }
            }

            return(uploadedFilenames.ToArray());
        }
Example #5
0
        private static async Task <string> UploadSpeciesPictureAsync(MediaWikiClient client, EditHistory history, Species species)
        {
            // Generate a filename for the image, which will be the filename when it's uploaded to the wiki.

            string uploadedFilename = GeneratePictureFilenameFromSpecies(species);

            if (!string.IsNullOrEmpty(uploadedFilename))
            {
                // Attempt to upload the image.

                UploadParameters uploadParameters = new UploadParameters {
                    UploadFileName = uploadedFilename,
                    FilePath       = species.Picture
                };

                return(await UploadPictureAsync(client, history, uploadParameters, true));
            }

            return(string.Empty);
        }
Example #6
0
        public async Task MainAsync(string[] args)
        {
            _log("loading configuration");

            Config config = JsonConvert.DeserializeObject <Config>(System.IO.File.ReadAllText("wikibot-config.json"));

            _log("initializing mediawiki client");

            MediaWikiClient client = new MediaWikiClient {
                Protocol  = config.Protocol,
                Server    = config.Server,
                ApiPath   = config.ApiPath,
                UserAgent = config.UserAgent
            };

            client.Log += _log;

            EditHistory history = new EditHistory();

            if (client.Login(config.Username, config.Password).Success)
            {
                _log("generating link dictionary");

                WikiLinkList LinkifyList = await _generateLinkifyListAsync();

                _log("synchronizing species");
                _log("getting species from database");

                Species[] speciesList = await SpeciesUtils.GetSpeciesAsync();

                _log(string.Format("got {0} results", speciesList.Count()));

                foreach (Species species in speciesList)
                {
                    _log(string.Format("synchronizing species {0}", species.ShortName));

                    // Create the page builder.

                    SpeciesPageBuilder pageBuilder = new SpeciesPageBuilder(species, WikiPageTemplate.Open(SpeciesTemplateFilePath))
                    {
                        AllSpecies = speciesList,
                        LinkList   = LinkifyList
                    };

                    // Attempt to upload the species' picture.

                    pageBuilder.PictureFilenames.Add(await UploadSpeciesPictureAsync(client, history, species));
                    pageBuilder.PictureFilenames.AddRange(await UploadSpeciesGalleryAsync(client, history, species));
                    pageBuilder.PictureFilenames.RemoveAll(x => string.IsNullOrWhiteSpace(x));

                    // Generate page content.

                    WikiPage wikiPage = await pageBuilder.BuildAsync();

                    string pageTitle      = wikiPage.Title;
                    bool   createRedirect = pageTitle != species.FullName;

                    // Upload page content.

                    await _editSpeciesPageAsync(client, history, species, pageTitle, wikiPage.Body);

                    // Attempt to create the redirect page for the species (if applicable).

                    if (createRedirect)
                    {
                        string redirect_page_title = species.FullName;

                        if (await _editPageAsync(client, history, redirect_page_title, string.Format("#REDIRECT [[{0}]]", pageTitle) + "\n" + BotFlag))
                        {
                            await history.AddRedirectRecordAsync(redirect_page_title, pageTitle);
                        }
                    }

                    _log(string.Format("finished synchronizing species {0}", species.ShortName));
                }
            }
            else
            {
                _log("mediawiki login failed");
            }

            _log("synchronizing complete");

            await Task.Delay(-1);
        }