/// <summary> /// Create a wiki site, login if necessary. /// </summary> private async Task <WikiSite> CreateWikiSiteAsync(IWikiClient wikiClient, string url) { WikiSite site; if (url.Contains(".wikia.com")) { var uri = new Uri(url, UriKind.Absolute); var options = new WikiaSiteOptions(uri.GetLeftPart(UriPartial.Authority) + "/") { AccountAssertion = AccountAssertionBehavior.AssertAll, }; site = new WikiaSite(wikiClient, options) { Logger = OutputLoggerFactory.CreateLogger <WikiaSite>() }; } else { var options = new SiteOptions(url) { AccountAssertion = AccountAssertionBehavior.AssertAll, }; site = new WikiSite(wikiClient, options) { Logger = OutputLoggerFactory.CreateLogger <WikiSite>() }; } await site.Initialization; if (sitesNeedsLogin.Contains(url)) { await CredentialManager.LoginAsync(site); } return(site); }
/// <summary> /// Initializes a new instance of <see cref="Board"/> from site and page title. /// </summary> /// <param name="site">The Wikia site.</param> /// <param name="title">Full page title of the board.</param> /// <param name="defaultNamespaceId">The default namespace ID to be used for the <paramref name="title"/>.</param> /// <exception cref="ArgumentNullException"><paramref name="site"/> or <paramref name="title"/> is <c>null</c>.</exception> public Board(WikiaSite site, string title, int defaultNamespaceId) { Site = site ?? throw new ArgumentNullException(nameof(site)); var link = WikiLink.Parse(site, title, defaultNamespaceId); Page = new WikiPageStub(link.FullTitle, link.Namespace.Id); }
public static async Task <Post> PostCommentAsync(WikiaSite site, object scopeInst, WikiPageStub owner, int?parentId, string content, CancellationToken cancellationToken) { Debug.Assert(site != null); Debug.Assert(owner.HasTitle); using (site.BeginActionScope(scopeInst, owner, parentId)) { var jresult = await site.InvokeWikiaAjaxAsync(new WikiaQueryRequestMessage(new { article = owner.Id, rs = "ArticleCommentsAjax", method = "axPost", token = await site.GetTokenAsync("edit", cancellationToken), convertToFormat = "", parentId = parentId, wpArticleComment = content, }, true), WikiaJsonResponseParser.Default, cancellationToken); if (((int?)jresult["error"] ?? 0) != 0) { throw new OperationFailedException((string)jresult["msg"]); } var text = (string)jresult["text"]; var doc = new HtmlDocument(); doc.LoadHtml(text); var node = doc.DocumentNode.SelectSingleNode("li"); if (node == null) { throw new UnexpectedDataException("Cannot locate the text node in the Wikia API response."); } return(Post.FromHtmlNode(site, owner, node)); } }
internal static Post FromHtmlNode(WikiaSite site, WikiPageStub owner, HtmlNode listItem) { Debug.Assert(listItem.Name == "li"); var id = listItem.GetAttributeValue("data-id", 0); if (id > 0) { } if (listItem.Id.StartsWith("comm-")) { id = Convert.ToInt32(listItem.Id.Substring(5)); } else { var sep = listItem.Id.LastIndexOf('-'); if (sep >= 0) { id = Convert.ToInt32(listItem.Id.Substring(sep + 1)); } } if (id == 0) { throw new UnexpectedDataException($"Cannot infer comment ID from <li> node. @id={listItem.Id}."); } return(new Post(site, owner, id)); }
/// <summary> /// Initializes a new instance of <see cref="Post"/>. /// </summary> /// <param name="site">The Wikia site.</param> /// <param name="ownerPage">Stub of the page/board that owns the post.</param> /// <param name="id">ID of the post.</param> /// <exception cref="ArgumentNullException"><paramref name="site"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException"><paramref name="ownerPage"/>.<see cref="WikiPageStub.IsEmpty"/> is <c>true</c>.</exception> /// <remarks> /// For now, it is not possible to get the replies by using the constructor provided here. /// To achieve this, you need to invoke <see cref="Board.EnumPostsAsync()"/> on a <see cref="Board"/> instance. /// </remarks> public Post(WikiaSite site, WikiPageStub ownerPage, int id) { if (ownerPage.IsEmpty) { throw new ArgumentException("ownerPage is empty.", nameof(ownerPage)); } Site = site ?? throw new ArgumentNullException(nameof(site)); OwnerPage = ownerPage; Id = id; }
internal static Post FromHtmlNode(WikiaSite site, WikiPageStub owner, HtmlNode listItem) { Debug.Assert(listItem.Name == "li"); var id = listItem.GetAttributeValue("data-id", 0); if (id > 0) { } if (listItem.Id.StartsWith("comm-")) { id = Convert.ToInt32(listItem.Id[5..]);
public static async Task <Post> PostWallMessageAsync(WikiaSite site, object scopeInst, WikiPageStub owner, string messageTitle, string messageBody, IEnumerable <string> relatedPages, CancellationToken cancellationToken) { Debug.Assert(site != null); Debug.Assert(owner.HasTitle); using (site.BeginActionScope(scopeInst, owner)) { var tokenPurged = false; var pageTitle = owner.Title; var pageNamespaceId = owner.NamespaceId; if (pageTitle.StartsWith("Message Wall:", StringComparison.OrdinalIgnoreCase)) { pageTitle = pageTitle[13..];
public static async Task <Post> ReplyWallMessageAsync(WikiaSite site, object scopeInst, WikiPageStub owner, int parentId, string messageBody, CancellationToken cancellationToken) { Debug.Assert(site != null); using (site.BeginActionScope(scopeInst, owner, parentId)) { var tokenPurged = false; BEGIN: var jresult = await site.InvokeNirvanaAsync(new WikiaQueryRequestMessage(new { controller = "WallExternal", method = "replyToMessage", format = "json", token = await site.GetTokenAsync("edit", cancellationToken), pagenamespace = WikiaNamespaces.Thread, pagetitle = parentId, parent = parentId, body = messageBody, convertToFormat = "", }, true), WikiaJsonResonseParser.Default, cancellationToken); if (!string.Equals((string)jresult["status"], "True", StringComparison.OrdinalIgnoreCase)) { var errorMessage = (string)jresult["errormsg"]; if (errorMessage != null) { if (!tokenPurged) { if (errorMessage.IndexOf("There seems to be a problem with your login session", StringComparison.OrdinalIgnoreCase) >= 0) { await site.GetTokenAsync("edit", true, cancellationToken); tokenPurged = true; goto BEGIN; } } } errorMessage = "Status code indicates a failure: " + (string)jresult["status"]; throw new OperationFailedException(errorMessage); } var text = (string)jresult["message"]; var doc = new HtmlDocument(); doc.LoadHtml(text); var node = doc.DocumentNode.SelectSingleNode("li"); if (node == null) { throw new UnexpectedDataException("Cannot locate the comment text node in the Wikia API response."); } return(Post.FromHtmlNode(site, owner, node)); } }
/// <summary> /// Asynchronously fetches the specified users' information. /// </summary> /// <param name="site">The site to issue the request.</param> /// <param name="userNames">The user names to be fetched.</param> /// <exception cref="ArgumentNullException">Either <paramref name="site"/> or <paramref name="userNames"/> is <c>null</c>.</exception> /// <returns> /// An asynchronous sequence containing the detailed user information. /// The user names are normalized by the server. Inexistent user names are skipped. /// </returns> public static async IAsyncEnumerable <UserInfo> FetchUsersAsync(this WikiaSite site, IEnumerable <string> userNames, [EnumeratorCancellation] CancellationToken cancellationToken = default) { if (site == null) { throw new ArgumentNullException(nameof(site)); } if (userNames == null) { throw new ArgumentNullException(nameof(userNames)); } using (site.BeginActionScope(null, (object)(userNames as ICollection))) { foreach (var names in userNames.Partition(100)) { JToken jresult; try { jresult = await site.InvokeWikiaApiAsync("/User/Details", new WikiaQueryRequestMessage(new { ids = string.Join(", ", names) }), cancellationToken); } catch (WikiaApiException ex) when(ex.ErrorType == "NotFoundApiException") { // All the usesers in this batch are not found. // Pity. continue; } var basePath = (string)jresult["basepath"]; var users = jresult["items"].ToObject <ICollection <UserInfo> >(); if (basePath != null) { foreach (var user in users) { user.ApplyBasePath(basePath); } } using (ExecutionContextStash.Capture()) foreach (var user in users) { yield return(user); } } } }
/// <summary> /// Asynchronously fetches the specified users' information. /// </summary> /// <param name="site">The site to issue the request.</param> /// <param name="userNames">The user names to be fetched.</param> /// <exception cref="ArgumentNullException">Either <paramref name="site"/> or <paramref name="userNames"/> is <c>null</c>.</exception> /// <returns> /// An asynchronous sequence containing the detailed user information. /// The user names are normalized by the server. Inexistent user names are skipped. /// </returns> public static IAsyncEnumerable <UserInfo> FetchUsersAsync(this WikiaSite site, IEnumerable <string> userNames) { if (site == null) { throw new ArgumentNullException(nameof(site)); } if (userNames == null) { throw new ArgumentNullException(nameof(userNames)); } return(AsyncEnumerableFactory.FromAsyncGenerator <UserInfo>(async(sink, ct) => { using (site.BeginActionScope(null, (object)(userNames as ICollection))) { foreach (var names in userNames.Partition(100)) { JToken jresult; try { jresult = await site.InvokeWikiaApiAsync("/User/Details", new WikiaQueryRequestMessage(new { ids = string.Join(", ", names) }), ct); } catch (WikiaApiException ex) when(ex.ErrorType == "NotFoundApiException") { // All the usesers in this batch are not found. // Pity. continue; } var basePath = (string)jresult["basepath"]; var users = jresult["items"].ToObject <ICollection <UserInfo> >(); if (basePath != null) { foreach (var user in users) { user.ApplyBasePath(basePath); } } await sink.YieldAndWait(users); } } })); }
/// <summary> /// Asynchronously fetches the specified user's information. /// </summary> /// <param name="site">The site to issue the request.</param> /// <param name="userName">The user name to be fetched.</param> /// <param name="cancellationToken">A token used to cancel the request.</param> /// <exception cref="ArgumentNullException">Either <paramref name="site"/> or <paramref name="userName"/> is <c>null</c>.</exception> /// <returns>A task that returns the requested user information, or <c>null</c> for inexistent user.</returns> public static async Task <UserInfo> FetchUserAsync(this WikiaSite site, string userName, CancellationToken cancellationToken) { if (site == null) { throw new ArgumentNullException(nameof(site)); } if (userName == null) { throw new ArgumentNullException(nameof(userName)); } if (userName.Contains(',')) { throw new ArgumentException("User name cannot contain comma (,).", nameof(userName)); } using (site.BeginActionScope(null, (object)userName)) { JToken jresult; try { jresult = await site.InvokeWikiaApiAsync("/User/Details", new WikiaQueryRequestMessage(new { ids = userName }), cancellationToken); } catch (NotFoundApiException) { return(null); } var user = jresult["items"][0].ToObject <UserInfo>(); if (user == null) { return(null); } var basePath = (string)jresult["basepath"]; if (basePath != null) { user.ApplyBasePath(basePath); } return(user); } }
/// <summary> /// Asynchronously fetches the specified page's related pages. /// </summary> /// <param name="site">The site to issue the request.</param> /// <param name="pageId">ID of the page to find the related ones.</param> /// <param name="maxCount">Maximum count of the returned items.</param> /// <param name="cancellationToken">A token used to cancel the operation.</param> /// <exception cref="ArgumentNullException"><paramref name="site"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="pageId"/> is less than or equals to 0.</exception> /// <exception cref="NotFoundApiException"><c>Related Pages</c> extension is not available.</exception> /// <returns></returns> public static async Task <IList <RelatedPageItem> > FetchRelatedPagesAsync(this WikiaSite site, int pageId, int maxCount, CancellationToken cancellationToken) { if (site == null) { throw new ArgumentNullException(nameof(site)); } if (maxCount <= 0) { throw new ArgumentOutOfRangeException(nameof(maxCount)); } using (site.BeginActionScope(null, pageId, maxCount)) { var jresult = await site.InvokeWikiaApiAsync("/RelatedPages/List", new WikiaQueryRequestMessage(new { ids = pageId, limit = maxCount }), cancellationToken); var jitems = jresult["items"][pageId.ToString(CultureInfo.InvariantCulture)]; if (jitems == null) { jitems = ((JProperty)jresult["items"].First)?.Value; } if (jitems == null || !jitems.HasValues) { return(Array.Empty <RelatedPageItem>()); } var items = jitems.ToObject <IList <RelatedPageItem> >(); var basePath = (string)jresult["basepath"]; if (basePath != null) { foreach (var i in items) { i.ApplyBasePath(basePath); } } return(items); } }
/// <summary> /// Create a wiki site, login if necessary. /// </summary> private async Task <WikiSite> CreateWikiSiteAsync(IWikiClient wikiClient, string url) { WikiSite site; if (url.Contains(".wikia.com") || url.Contains(".wikia.org") || url.Contains(".fandom.com")) { var uri = new Uri(url, UriKind.Absolute); var rootUrl = new Uri(uri, ".").ToString(); var options = new WikiaSiteOptions(rootUrl) { AccountAssertion = AccountAssertionBehavior.AssertAll, }; site = new WikiaSite(wikiClient, options) { Logger = OutputLoggerFactory.CreateLogger <WikiaSite>() }; } else { var options = new SiteOptions(url) { AccountAssertion = AccountAssertionBehavior.AssertAll, }; site = new WikiSite(wikiClient, options) { Logger = OutputLoggerFactory.CreateLogger <WikiSite>() }; } await site.Initialization; if (sitesNeedsLogin.Contains(url)) { await CredentialManager.LoginAsync(site); } return(site); }
/// <inheritdoc cref="Board(WikiaSite,string,int)"/> public Board(WikiaSite site, string title) : this(site, title, BuiltInNamespaces.Main) { }
/// <inheritdoc cref="FetchUserAsync(WikiaSite,string,CancellationToken)"/> public static Task <UserInfo> FetchUserAsync(this WikiaSite site, string userName) { return(FetchUserAsync(site, userName, CancellationToken.None)); }
/// <inheritdoc cref="FetchRelatedPagesAsync(WikiaSite,int,int,CancellationToken)"/> public static Task <IList <RelatedPageItem> > FetchRelatedPagesAsync(this WikiaSite site, int pageId, int maxCount) { return(FetchRelatedPagesAsync(site, pageId, maxCount, CancellationToken.None)); }
/// <summary> /// Initializes a new instance of <see cref="LocalWikiSearchList"/> using the target /// Wikia site. /// </summary> /// <inheritdoc cref="LocalWikiSearchList(WikiaSite,string)"/> public LocalWikiSearchList(WikiaSite site) : this(site, null) { }
/// <summary> /// Initializes a new instance of <see cref="LocalWikiSearchList"/> using the target /// Wikia site and search keyword. /// </summary> /// <param name="site">The Wikia site this list-like object is applied to.</param> /// <param name="keyword">Search for all page titles (or content) that have this value.</param> public LocalWikiSearchList(WikiaSite site, string keyword) { Site = site ?? throw new ArgumentNullException(nameof(site)); Keyword = keyword; }
/// <summary> /// Initializes a new instance of <see cref="Board"/> from site and page ID. /// </summary> /// <param name="site">The Wikia site.</param> /// <param name="pageId">Page ID of the board.</param> /// <exception cref="ArgumentNullException"><paramref name="site"/> is <c>null</c>.</exception> public Board(WikiaSite site, int pageId) { Site = site ?? throw new ArgumentNullException(nameof(site)); Page = new WikiPageStub(pageId); }
public static async Task <Post> PostWallMessageAsync(WikiaSite site, object scopeInst, WikiPageStub owner, string messageTitle, string messageBody, IEnumerable <string> relatedPages, CancellationToken cancellationToken) { Debug.Assert(site != null); Debug.Assert(owner.HasTitle); using (site.BeginActionScope(scopeInst, owner)) { var tokenPurged = false; var pageTitle = owner.Title; var pageNamespaceId = owner.NamespaceId; if (pageTitle.StartsWith("Message Wall:", StringComparison.OrdinalIgnoreCase)) { pageTitle = pageTitle.Substring(13); if (!owner.HasNamespaceId) { pageNamespaceId = WikiaNamespaces.MessageWall; } } else if (pageTitle.StartsWith("Board:", StringComparison.OrdinalIgnoreCase)) { pageTitle = pageTitle.Substring(6); if (!owner.HasNamespaceId) { pageNamespaceId = WikiaNamespaces.Thread; } } else { var link = WikiLink.Parse(site, owner.Title); pageTitle = link.Title; pageNamespaceId = link.Namespace.Id; } var queryParams = new OrderedKeyValuePairs <string, object> { { "token", null }, { "controller", "WallExternal" }, { "method", "postNewMessage" }, { "format", "json" }, { "pagenamespace", pageNamespaceId }, { "pagetitle", pageTitle }, { "messagetitle", messageTitle }, { "body", messageBody }, { "notifyeveryone", 0 }, { "convertToFormat", "" }, }; if (relatedPages != null) { foreach (var title in relatedPages) { queryParams.Add("relatedTopics[]", title); } } BEGIN: queryParams["token"] = await site.GetTokenAsync("edit", cancellationToken); var jresult = await site.InvokeNirvanaAsync(new WikiaQueryRequestMessage(queryParams, true), WikiaJsonResonseParser.Default, cancellationToken); if (!string.Equals((string)jresult["status"], "True", StringComparison.OrdinalIgnoreCase)) { var errorMessage = (string)jresult["errormsg"]; if (errorMessage != null) { if (!tokenPurged) { if (errorMessage.IndexOf("There seems to be a problem with your login session", StringComparison.OrdinalIgnoreCase) >= 0) { await site.GetTokenAsync("edit", true, cancellationToken); tokenPurged = true; goto BEGIN; } } } errorMessage = "Status code indicates a failure: " + (string)jresult["status"]; throw new OperationFailedException(errorMessage); } var text = (string)jresult["message"]; var doc = new HtmlDocument(); doc.LoadHtml(text); var node = doc.DocumentNode.SelectSingleNode("li"); if (node == null) { throw new UnexpectedDataException("Cannot locate the comment text node in the Wikia API response."); } return(Post.FromHtmlNode(site, owner, node)); } }
public async Task Issue39() { // Cause: cacheBuster=7030077030012 in /api/v1/Mercury/WikiVariables request exceeds Int32 limit. var site = new WikiaSite(WikiClient, "https://theedgechronicles.fandom.com/"); await site.Initialization; }