-
-
Notifications
You must be signed in to change notification settings - Fork 16
[MediaWiki] Getting started
Applies to: WCL v0.6.0
- Note that since C# 7.1, you can write
static async Task Main()
for your application entry point. - Note that since C# 9.0, you can leverage top-level statements in order to start a MediaWiki bot really quick.
- If you are working with FANDOM / Wikia sites, prefer
WikiaSite
toWikiSite
since the former one provides some more Wikia-specific support.
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// A WikiClient has its own CookieContainer.
var client = new WikiClient
{
ClientUserAgent = "WCLQuickStart/1.0 (your user name or contact information here)"
};
// You can create multiple WikiSite instances on the same WikiClient to share the state.
var site = new WikiSite(client, "https://test2.wikipedia.org/w/api.php");
// Wait for initialization to complete.
// Throws error if any.
await site.Initialization;
try
{
await site.LoginAsync("User name", "password");
}
catch (WikiClientException ex)
{
Console.WriteLine(ex.Message);
// Add your exception handler for failed login attempt.
}
// Do what you want
Console.WriteLine(site.SiteInfo.SiteName);
Console.WriteLine(site.AccountInfo);
Console.WriteLine("{0} extensions", site.Extensions.Count);
Console.WriteLine("{0} interwikis", site.InterwikiMap.Count);
Console.WriteLine("{0} namespaces", site.Namespaces.Count);
// We're done here
await site.LogoutAsync();
client.Dispose(); // Or you may use `using` statement.
}
}
In WCL, pages on MediaWiki site is represented by WikiPage
. When you instantiates a WikiPage
, it contains no information other than the page title or ID given in constructor, until WikiPage.RefreshAsync
is invoked. Still, you can edit/move/delete the page without invoking RefreshAsync
beforehand since a page title/ID is sufficient for such operations.
static async Task GetPageInformationAsync()
{
var page = new WikiPage(myWikiSite, "france");
// Fetch basic information and content of 1 page from server
await page.RefreshAsync(PageQueryOptions.FetchContent
| PageQueryOptions.ResolveRedirects);
Console.WriteLine(page.Title);
Console.WriteLine(page.Content.Substring(0, 100));
// Suppose you do not know the page is a normal page, category page, or file page.
var catPage = new WikiPage(myWikiSite, "Category:Citation templates");
// Only fetch for basic information.
await catPage.RefreshAsync();
var catInfo = catPage.GetPropertyGroup<CategoryInfoPropertyGroup>();
// To list the pages under this category, see `generators` and CategoryMembersGenerator
Console.WriteLine("{0}: {1} members, {2} pages, {3} files, {4} sub-categories",
catPage, catInfo.MembersCount, catInfo.PagesCount, catInfo.FilesCount, catInfo.SubcategoriesCount);
// Instantiates a page from page ID
var pageFromId = new WikiPage(myWikiSite, 12345);
await pageFromId.RefreshAsync();
Console.WriteLine("Page: {0}, Id: {1}", pageFromId.Title, pageFromId.Id);
// Yes, we can refresh multiple pages in a batch.
var pages = new[] {"Main Page", "Project:Sandbox", "abcdef"}
.Select(title => new WikiPage(myWikiSite, title))
.ToArray();
await pages.RefreshAsync();
foreach (var p in pages)
{
Console.WriteLine("{0}: Exists? {1}", p, p.Exists);
}
}
static async Task EditPageAsync()
{
var page = new WikiPage(myWikiSite, "Project:Sandbox");
// If you want to remove all the content there before you came,
// you can UpdateContentAsync without RefreshAsync beforehand.
await page.RefreshAsync(PageQueryOptions.FetchContent);
page.Content += "\n\nThis is a test.";
await page.UpdateContentAsync("Test edit from WCL quick start.", minor: false, bot: true);
}
Note that the StreamUploadSource
below can be replaced with any other WikiUploadSource
-derived classes.
static async Task UploadFileAsync()
{
using (var s = File.OpenRead("AwesomeImage.png"))
{
var source = new StreamUploadSource(s);
var suppressWarnings = false;
RETRY:
try
{
var result = await myWikiSite.UploadAsync("File:Sandbox.png", source, @"{{Information
|description = Upload test
|permission = {{Fairuse}}
}}", suppressWarnings);
if (result.ResultCode == UploadResultCode.Warning)
{
Console.WriteLine(result.Warnings.ToString());
Console.WriteLine("Press any key to suppress the warnings and try again.");
Console.ReadKey();
suppressWarnings = true;
goto RETRY;
}
}
catch (OperationFailedException ex)
{
// Since MW 1.31, if you are uploading the exactly same content to the same title with ignoreWarnings set to true, you will reveive this exception with ErrorCode set to fileexists-no-change.
// See https://gerrit.wikimedia.org/r/378702.
Console.WriteLine(ex.Message);
}
}
}
Since MediaWiki 1.19+, you can stash a large file to the server by chunks using ChunkedUploadSource
, before uploading it. The following snippet is taken from the unit test project. Note that the default DefaultChunkSize
is 1024*1024 (1MB), which is suitable in most cases.
var chunked = new ChunkedUploadSource(site, file.ContentStream) { /* DefaultChunkSize = 1024 * 4 */ };
do
{
var result = await chunked.StashNextChunkAsync();
Assert.NotEqual(UploadResultCode.Warning, result.ResultCode);
if (result.ResultCode == UploadResultCode.Success)
{
// Some unit test assertions.
Assert.True(result.FileRevision.IsAnonymous);
Assert.Equal(file.Sha1, result.FileRevision.Sha1, StringComparer.OrdinalIgnoreCase);
}
} while (!chunked.IsStashed);
try
{
await site.UploadAsync("Test image.jpg", chunked, file.Description, true);
}
catch (OperationFailedException ex) when (ex.ErrorCode == "fileexists-no-change")
{
// We cannot suppress this error by setting ignoreWarnings = true.
Output.WriteLine(ex.Message);
}
You can MoveAsync
and DeleteAsync
a page, so long as you have the permission.
WikiPageStub
structure
If you would like only to determine whether a page exists, the namespace ID of the page, or convert the page title from/to page ID, without querying further information, you may use WikiPageStub.FromPageTitles
and WikiPageStub.FromPageIds
static methods.
WikiLink
class
If you would like only to normalize/parse/analyze a given page title consider using WikiLink.Parse
static method. See WikiLinkTests.cs for example.
You can find a demo in ConsoleTestApplication1
. It's also suggested that you take a look at UnitTestProject1
to find out what can be done with the library.
static async Task HelloWikiWorld()
{
// Create a MediaWiki API client.
var wikiClient = new WikiClient
{
// UA of Client Application. The UA of WikiClientLibrary will
// be append to the end of this when sending requests.
ClientUserAgent = "ConsoleTestApplication1/1.0",
};
// Create a MediaWiki Site instance with the URL of API endpoint.
var site = await WikiSite.CreateAsync(wikiClient, "https://test2.wikipedia.org/w/api.php");
// Access site information via WikiSite.SiteInfo
Console.WriteLine("API version: {0}", site.SiteInfo.Generator);
// Access user information via WikiSite.UserInfo
Console.WriteLine("Hello, {0}!", site.AccountInfo.Name);
// Site login
Console.WriteLine("We will edit [[Project:Sandbox]].");
if (Confirm($"Do you want to login into {site.SiteInfo.SiteName}?"))
{
LOGIN_RETRY:
try
{
await site.LoginAsync(Input("User name"), Input("Password"));
}
catch (OperationFailedException ex)
{
Console.WriteLine(ex.ErrorMessage);
goto LOGIN_RETRY;
}
Console.WriteLine("You have successfully logged in as {0}.", site.AccountInfo.Name);
Console.WriteLine("You're in the following groups: {0}.", string.Join(",", site.AccountInfo.Groups));
}
// Find out more members in Site class, such as
// page.Namespaces
// page.InterwikiMap
// Page Operations
// Fetch information and content
var page = new WikiPage(site, site.SiteInfo.MainPage);
Console.WriteLine("Retriving {0}...", page);
await page.RefreshAsync(PageQueryOptions.FetchContent);
Console.WriteLine("Last touched at {0}.", page.LastTouched);
Console.WriteLine("Last revision {0} by {1} at {2}.", page.LastRevisionId,
page.LastRevision.UserName, page.LastRevision.TimeStamp);
Console.WriteLine("Content length: {0} bytes ----------", page.ContentLength);
Console.WriteLine(page.Content);
// Purge the page
if (await page.PurgeAsync())
Console.WriteLine(" The page has been purged successfully.");
// Edit the page
page = new WikiPage(site, "Project:Sandbox");
await page.RefreshAsync(PageQueryOptions.FetchContent);
if (!page.Exists) Console.WriteLine("Warning: The page {0} doesn't exist.", page);
page.Content += "\n\n'''Hello''' ''world''!";
await page.UpdateContentAsync("Test edit from WikiClientLibrary.");
Console.WriteLine("{0} has been saved. RevisionId = {1}.", page, page.LastRevisionId);
// Find out more operations in WikiPage class, such as
// page.MoveAsync()
// page.DeleteAsync()
// Logout
await site.LogoutAsync();
Console.WriteLine("You have successfully logged out.");
}
Here's the output
API version: MediaWiki 1.30.0-wmf.17
Hello, 206.161.*.*!
We will edit [[Project:Sandbox]].
Do you want to login into Wikipedia?[Y/N]> Y
User name> XuesongBot
Password> ******
You have successfully logged in as XuesongBot.
You're in the following groups: bot,editor,*,user,autoconfirmed.
Retriving Main Page...
Last touched at 2017/8/27 PM 4:25:06.
Last revision 318038 by MacFan4000 at 2017/5/27 PM 1:07:11.
Content length: 3687 bytes ----------
Welcome to '''test2.wikipedia.org'''! This wiki is currently running a test release of the {{CURRENTVERSION}} version of MediaWiki.
== What is the purpose of Test2? ==
Test2 is primarily used to trial and debug global and cross-wiki features in conjunction with <span class="plainlinks">https://test.wikipedia.org</span> and <span class="plainlinks">https://test.wikidata.org</span>.
[more]
The page has been purged successfully.
Wikipedia:Sandbox has been saved. RevisionId = 327700.
You have successfully logged out.
Press any key to continue. . .