Showing preview only (222K chars total). Download the full file or copy to clipboard to get everything.
Repository: SirCmpwn/RedditSharp
Branch: master
Commit: a5e1e6afb729
Files: 62
Total size: 205.8 KB
Directory structure:
gitextract_p863b84s/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── RedditSharp/
│ ├── AuthProvider.cs
│ ├── Captcha.cs
│ ├── CaptchaFailedException.cs
│ ├── CaptchaResponse.cs
│ ├── ConsoleCaptchaSolver.cs
│ ├── Domain.cs
│ ├── DuplicateLinkException.cs
│ ├── Extensions.cs
│ ├── FlairTemplate.cs
│ ├── FlairType.cs
│ ├── ICaptchaSolver.cs
│ ├── IWebAgent.cs
│ ├── LinkData.cs
│ ├── Listing.cs
│ ├── ModActionType.cs
│ ├── ModeratorPermission.cs
│ ├── ModeratorUser.cs
│ ├── MultipartFormBuilder.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── RateLimitException.cs
│ ├── Reddit.cs
│ ├── RedditAPINameAttribute.cs
│ ├── RedditException.cs
│ ├── RedditSharp.csproj
│ ├── SpamFilterSettings.cs
│ ├── SubmitData.cs
│ ├── SubredditImage.cs
│ ├── SubredditSettings.cs
│ ├── SubredditStyle.cs
│ ├── TBUserNote.cs
│ ├── TextData.cs
│ ├── Things/
│ │ ├── AuthenticatedUser.cs
│ │ ├── Comment.cs
│ │ ├── Contributor.cs
│ │ ├── CreatedThing.cs
│ │ ├── ModAction.cs
│ │ ├── Post.cs
│ │ ├── PrivateMessage.cs
│ │ ├── RedditUser.cs
│ │ ├── Subreddit.cs
│ │ ├── Thing.cs
│ │ ├── VotableThing.cs
│ │ └── WikiPageRevision.cs
│ ├── ToolBoxUserNotes.cs
│ ├── ToolBoxUserNotesException.cs
│ ├── UnixTimeStamp.cs
│ ├── UnixTimestampConverter.cs
│ ├── UrlParser.cs
│ ├── Utils/
│ │ └── DateTimeExtensions.cs
│ ├── WebAgent.cs
│ ├── Wiki.cs
│ ├── WikiPage.cs
│ └── WikiPageSettings.cs
├── RedditSharp.sln
└── TestRedditSharp/
├── App.config
├── Program.cs
├── Properties/
│ └── AssemblyInfo.cs
└── TestRedditSharp.csproj
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
*.cs text diff=csharp
*.sln text eol=crlf
*.csproj text eol=crlf
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .gitignore
================================================
bin/
obj/
*.user
*.userprefs
*.suo
*.pidb
_ReSharper*/
TestResults/
*.mdf
*.psess
*.vsp
# StyleCop files
StyleCop.Cache
================================================
FILE: LICENSE
================================================
Copyright (c) 2013 Drew DeVault
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# RedditSharp
A partial implementation of the [Reddit](http://reddit.com) API. Includes support for many API endpoints, as well as
LINQ-style paging of results.
```csharp
var reddit = new Reddit();
var user = reddit.LogIn("username", "password");
var subreddit = reddit.GetSubreddit("/r/example");
subreddit.Subscribe();
foreach (var post in subreddit.New.Take(25))
{
if (post.Title == "What is my karma?")
{
// Note: This is an example. Bots are not permitted to cast votes automatically.
post.Upvote();
var comment = post.Comment(string.Format("You have {0} link karma!", post.Author.LinkKarma));
comment.Distinguish(DistinguishType.Moderator);
}
}
```
**Important note**: Make sure you use `.Take(int)` when working with pagable content. For example, don't do this:
```csharp
var all = reddit.RSlashAll;
foreach (var post in all) // BAD
{
// ...
}
```
This will cause you to page through everything that has ever been posted on Reddit. Better:
```csharp
var all = reddit.RSlashAll;
foreach (var post in all.Take(25))
{
// ...
}
```
## Development
RedditSharp is developed with the following workflow:
1. Nothing happens for weeks/months/years
2. Someone needs it to do something it doesn't already do
3. That person implements that something and submits a pull request
4. Repeat
If it doesn't have a feature that you want it to have, add it! The code isn't that scary.
================================================
FILE: RedditSharp/AuthProvider.cs
================================================
using System;
using System.Net;
using System.Security.Authentication;
using System.Text;
using Newtonsoft.Json.Linq;
using RedditSharp.Things;
namespace RedditSharp
{
public class AuthProvider
{
private const string AccessUrl = "https://ssl.reddit.com/api/v1/access_token";
private const string OauthGetMeUrl = "https://oauth.reddit.com/api/v1/me";
private const string RevokeUrl = "https://www.reddit.com/api/v1/revoke_token";
public static string OAuthToken { get; set; }
public static string RefreshToken { get; set; }
[Flags]
public enum Scope
{
none = 0x0,
identity = 0x1,
edit = 0x2,
flair = 0x4,
history = 0x8,
modconfig = 0x10,
modflair = 0x20,
modlog = 0x40,
modposts = 0x80,
modwiki = 0x100,
mysubreddits = 0x200,
privatemessages = 0x400,
read = 0x800,
report = 0x1000,
save = 0x2000,
submit = 0x4000,
subscribe = 0x8000,
vote = 0x10000,
wikiedit = 0x20000,
wikiread = 0x40000
}
private IWebAgent _webAgent;
private readonly string _redirectUri;
private readonly string _clientId;
private readonly string _clientSecret;
/// <summary>
/// Allows use of reddit's OAuth interface, using an app set up at https://ssl.reddit.com/prefs/apps/.
/// </summary>
/// <param name="clientId">Granted by reddit as part of app.</param>
/// <param name="clientSecret">Granted by reddit as part of app.</param>
/// <param name="redirectUri">Selected as part of app. Reddit will send users back here.</param>
public AuthProvider(string clientId, string clientSecret, string redirectUri)
{
_clientId = clientId;
_clientSecret = clientSecret;
_redirectUri = redirectUri;
_webAgent = new WebAgent();
}
/// <summary>
/// Allows use of reddit's OAuth interface, using an app set up at https://ssl.reddit.com/prefs/apps/.
/// </summary>
/// <param name="clientId">Granted by reddit as part of app.</param>
/// <param name="clientSecret">Granted by reddit as part of app.</param>
/// <param name="redirectUri">Selected as part of app. Reddit will send users back here.</param>
/// <param name="agent">Implementation of IWebAgent to use to make requests.</param>
public AuthProvider(string clientId, string clientSecret, string redirectUri,IWebAgent agent)
{
_clientId = clientId;
_clientSecret = clientSecret;
_redirectUri = redirectUri;
_webAgent = agent;
}
/// <summary>
/// Creates the reddit OAuth2 Url to redirect the user to for authorization.
/// </summary>
/// <param name="state">Used to verify that the user received is the user that was sent</param>
/// <param name="scope">Determines what actions can be performed against the user.</param>
/// <param name="permanent">Set to true for access lasting longer than one hour.</param>
/// <returns></returns>
public string GetAuthUrl(string state, Scope scope, bool permanent = false)
{
return String.Format("https://ssl.reddit.com/api/v1/authorize?client_id={0}&response_type=code&state={1}&redirect_uri={2}&duration={3}&scope={4}", _clientId, state, _redirectUri, permanent ? "permanent" : "temporary", scope.ToString().Replace(" ",""));
}
/// <summary>
/// Gets the OAuth token for the user associated with the provided code.
/// </summary>
/// <param name="code">Sent by reddit as a parameter in the return uri.</param>
/// <param name="isRefresh">Set to true for refresh requests.</param>
/// <returns></returns>
public string GetOAuthToken(string code, bool isRefresh = false)
{
if (Type.GetType("Mono.Runtime") != null)
ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;
_webAgent.Cookies = new CookieContainer();
var request = _webAgent.CreatePost(AccessUrl);
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + ":" + _clientSecret));
var stream = request.GetRequestStream();
if (isRefresh)
{
_webAgent.WritePostBody(stream, new
{
grant_type = "refresh_token",
refresh_token = code
});
}
else
{
_webAgent.WritePostBody(stream, new
{
grant_type = "authorization_code",
code,
redirect_uri = _redirectUri
});
}
stream.Close();
var json = _webAgent.ExecuteRequest(request);
if (json["access_token"] != null)
{
if (json["refresh_token"] != null)
RefreshToken = json["refresh_token"].ToString();
OAuthToken = json["access_token"].ToString();
return json["access_token"].ToString();
}
throw new AuthenticationException("Could not log in.");
}
/// <summary>
/// Gets the OAuth token for the user.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="password">The user's password.</param>
/// <returns>The access token</returns>
public string GetOAuthToken(string username, string password)
{
if (Type.GetType("Mono.Runtime") != null)
ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;
_webAgent.Cookies = new CookieContainer();
var request = _webAgent.CreatePost(AccessUrl);
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + ":" + _clientSecret));
var stream = request.GetRequestStream();
_webAgent.WritePostBody(stream, new
{
grant_type = "password",
username,
password,
redirect_uri = _redirectUri
});
stream.Close();
var json = _webAgent.ExecuteRequest(request);
if (json["access_token"] != null)
{
if (json["refresh_token"] != null)
RefreshToken = json["refresh_token"].ToString();
OAuthToken = json["access_token"].ToString();
return json["access_token"].ToString();
}
throw new AuthenticationException("Could not log in.");
}
public void RevokeToken(string token, bool isRefresh)
{
string tokenType = isRefresh ? "refresh_token" : "access_token";
var request = _webAgent.CreatePost(RevokeUrl);
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + ":" + _clientSecret));
var stream = request.GetRequestStream();
_webAgent.WritePostBody(stream, new
{
token = token,
token_type = tokenType
});
stream.Close();
_webAgent.ExecuteRequest(request);
}
/// <summary>
/// Gets a user authenticated by OAuth2.
/// </summary>
/// <param name="accessToken">Obtained using GetOAuthToken</param>
/// <returns></returns>
[Obsolete("Reddit.InitOrUpdateUser is preferred")]
public AuthenticatedUser GetUser(string accessToken)
{
var request = _webAgent.CreateGet(OauthGetMeUrl);
request.Headers["Authorization"] = String.Format("bearer {0}", accessToken);
var response = (HttpWebResponse)request.GetResponse();
var result = _webAgent.GetResponseString(response.GetResponseStream());
var thingjson = "{\"kind\": \"t2\", \"data\": " + result + "}";
var json = JObject.Parse(thingjson);
return new AuthenticatedUser().Init(new Reddit(), json, _webAgent);
}
}
}
================================================
FILE: RedditSharp/Captcha.cs
================================================
using System;
namespace RedditSharp
{
public struct Captcha
{
private const string UrlFormat = "http://www.reddit.com/captcha/{0}";
public readonly string Id;
public readonly Uri Url;
internal Captcha(string id)
{
Id = id;
Url = new Uri(string.Format(UrlFormat, Id), UriKind.Absolute);
}
}
}
================================================
FILE: RedditSharp/CaptchaFailedException.cs
================================================
using System;
namespace RedditSharp
{
public class CaptchaFailedException : RedditException
{
public CaptchaFailedException()
{
}
public CaptchaFailedException(string message)
: base(message)
{
}
public CaptchaFailedException(string message, Exception inner)
: base(message, inner)
{
}
}
}
================================================
FILE: RedditSharp/CaptchaResponse.cs
================================================
namespace RedditSharp
{
public class CaptchaResponse
{
public readonly string Answer;
public bool Cancel { get { return string.IsNullOrEmpty(Answer); } }
public CaptchaResponse(string answer = null)
{
Answer = answer;
}
}
}
================================================
FILE: RedditSharp/ConsoleCaptchaSolver.cs
================================================
using System;
namespace RedditSharp
{
public class ConsoleCaptchaSolver : ICaptchaSolver
{
public CaptchaResponse HandleCaptcha(Captcha captcha)
{
Console.WriteLine("Captcha required! The captcha ID is {0}", captcha.Id);
Console.WriteLine("You can find the captcha image at this url: {0}", captcha.Url);
Console.WriteLine("Please input your captcha response or empty string to cancel:");
var response = Console.ReadLine();
CaptchaResponse captchaResponse = new CaptchaResponse(string.IsNullOrEmpty(response) ? null : response);
return captchaResponse;
}
}
}
================================================
FILE: RedditSharp/Domain.cs
================================================
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RedditSharp.Things;
namespace RedditSharp
{
public class Domain
{
private const string DomainPostUrl = "/domain/{0}.json";
private const string DomainNewUrl = "/domain/{0}/new.json?sort=new";
private const string DomainHotUrl = "/domain/{0}/hot.json";
private const string FrontPageUrl = "/.json";
[JsonIgnore]
private Reddit Reddit { get; set; }
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
[JsonIgnore]
public string Name { get; set; }
public Listing<Post> Posts
{
get
{
return new Listing<Post>(Reddit, string.Format(DomainPostUrl, Name), WebAgent);
}
}
public Listing<Post> New
{
get
{
return new Listing<Post>(Reddit, string.Format(DomainNewUrl, Name), WebAgent);
}
}
public Listing<Post> Hot
{
get
{
return new Listing<Post>(Reddit, string.Format(DomainHotUrl, Name), WebAgent);
}
}
protected internal Domain(Reddit reddit, Uri domain, IWebAgent webAgent)
{
Reddit = reddit;
WebAgent = webAgent;
Name = domain.Host;
}
public override string ToString()
{
return "/domain/" + Name;
}
}
}
================================================
FILE: RedditSharp/DuplicateLinkException.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RedditSharp
{
/// <summary>
/// Exception that gets thrown if you try and submit a duplicate link to a SubReddit
/// </summary>
public class DuplicateLinkException : RedditException
{
public DuplicateLinkException()
{
}
public DuplicateLinkException(string message)
: base(message)
{
}
public DuplicateLinkException(string message, Exception inner)
: base(message, inner)
{
}
}
}
================================================
FILE: RedditSharp/Extensions.cs
================================================
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
namespace RedditSharp
{
public static class Extensions
{
public static T ValueOrDefault<T>(this IEnumerable<JToken> enumerable)
{
if (enumerable == null)
return default(T);
return enumerable.Value<T>();
}
}
}
================================================
FILE: RedditSharp/FlairTemplate.cs
================================================
namespace RedditSharp
{
public class UserFlairTemplate // TODO: Consider using this class to set templates as well
{
public string Text { get; set; }
public string CssClass { get; set; }
}
}
================================================
FILE: RedditSharp/FlairType.cs
================================================
namespace RedditSharp
{
public enum FlairType
{
Link,
User
}
}
================================================
FILE: RedditSharp/ICaptchaSolver.cs
================================================
namespace RedditSharp
{
public interface ICaptchaSolver
{
CaptchaResponse HandleCaptcha(Captcha captcha);
}
}
================================================
FILE: RedditSharp/IWebAgent.cs
================================================
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;
namespace RedditSharp
{
public interface IWebAgent
{
CookieContainer Cookies { get; set; }
string AuthCookie { get; set; }
string AccessToken { get; set; }
HttpWebRequest CreateRequest(string url, string method);
HttpWebRequest CreateGet(string url);
HttpWebRequest CreatePost(string url);
string GetResponseString(Stream stream);
void WritePostBody(Stream stream, object data, params string[] additionalFields);
JToken CreateAndExecuteRequest(string url);
JToken ExecuteRequest(HttpWebRequest request);
}
}
================================================
FILE: RedditSharp/LinkData.cs
================================================
namespace RedditSharp
{
internal class LinkData : SubmitData
{
[RedditAPIName("extension")]
internal string Extension { get; set; }
[RedditAPIName("url")]
internal string URL { get; set; }
internal LinkData()
{
Extension = "json";
Kind = "link";
}
}
}
================================================
FILE: RedditSharp/Listing.cs
================================================
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using RedditSharp.Things;
namespace RedditSharp
{
public enum Sorting
{
Relevance,
New,
Top,
Comments
}
public enum TimeSorting
{
All,
Hour,
Day,
Week,
Month,
Year
}
public class Listing<T> : IEnumerable<T> where T : Thing
{
/// <summary>
/// Gets the default number of listings returned per request
/// </summary>
internal const int DefaultListingPerRequest = 25;
private IWebAgent WebAgent { get; set; }
private Reddit Reddit { get; set; }
private string Url { get; set; }
/// <summary>
/// Creates a new Listing instance
/// </summary>
/// <param name="reddit"></param>
/// <param name="url"></param>
/// <param name="webAgent"></param>
internal Listing(Reddit reddit, string url, IWebAgent webAgent)
{
WebAgent = webAgent;
Reddit = reddit;
Url = url;
}
/// <summary>
/// Returns an enumerator that iterates through a collection, using the specified number of listings per
/// request and optionally the maximum number of listings
/// </summary>
/// <param name="limitPerRequest">The number of listings to be returned per request</param>
/// <param name="maximumLimit">The maximum number of listings to return</param>
/// <returns></returns>
public IEnumerator<T> GetEnumerator(int limitPerRequest, int maximumLimit = -1)
{
return new ListingEnumerator<T>(this, limitPerRequest, maximumLimit);
}
/// <summary>
/// Returns an enumerator that iterates through a collection, using the default number of listings per request
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return GetEnumerator(DefaultListingPerRequest);
}
/// <summary>
/// Returns an enumerator that iterates through a collection
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Returns an IEnumerable instance which will return the specified maximum number of listings
/// </summary>
/// <param name="maximumLimit"></param>
/// <returns></returns>
public IEnumerable<T> GetListing(int maximumLimit)
{
return GetListing(maximumLimit, DefaultListingPerRequest);
}
/// <summary>
/// Returns an IEnumerable instance which will return the specified maximum number of listings
/// with the limited number per request
/// </summary>
/// <param name="maximumLimit"></param>
/// <param name="limitPerRequest"></param>
/// <returns></returns>
public IEnumerable<T> GetListing(int maximumLimit, int limitPerRequest)
{
// Get the enumerator with the specified maximum and per request limits
var enumerator = GetEnumerator(limitPerRequest, maximumLimit);
return GetEnumerator(enumerator);
}
/// <summary>
/// Converts an IEnumerator instance to an IEnumerable
/// </summary>
/// <param name="enumerator"></param>
/// <returns></returns>
private static IEnumerable<T> GetEnumerator(IEnumerator<T> enumerator)
{
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
#pragma warning disable 0693
private class ListingEnumerator<T> : IEnumerator<T> where T : Thing
{
private Listing<T> Listing { get; set; }
private int CurrentPageIndex { get; set; }
private string After { get; set; }
private string Before { get; set; }
private Thing[] CurrentPage { get; set; }
private int Count { get; set; }
private int LimitPerRequest { get; set; }
private int MaximumLimit { get; set; }
/// <summary>
/// Creates a new ListingEnumerator instance
/// </summary>
/// <param name="listing"></param>
/// <param name="limitPerRequest">The number of listings to be returned per request. -1 will exclude this parameter and use the Reddit default (25)</param>
/// <param name="maximumLimit">The maximum number of listings to return, -1 will not add a limit</param>
public ListingEnumerator(Listing<T> listing, int limitPerRequest, int maximumLimit)
{
Listing = listing;
CurrentPageIndex = -1;
CurrentPage = new Thing[0];
// Set the listings per page (if not specified, use the Reddit default of 25) and the maximum listings
LimitPerRequest = (limitPerRequest <= 0 ? DefaultListingPerRequest : limitPerRequest);
MaximumLimit = maximumLimit;
}
public T Current
{
get
{
return (T)CurrentPage[CurrentPageIndex];
}
}
private void FetchNextPage()
{
var url = Listing.Url;
if (After != null)
{
url += (url.Contains("?") ? "&" : "?") + "after=" + After;
}
if (LimitPerRequest != -1)
{
int limit = LimitPerRequest;
if (limit > MaximumLimit)
{
// If the limit is more than the maximum number of listings, adjust
limit = MaximumLimit;
}
else if (Count + limit > MaximumLimit)
{
// If a smaller subset of listings are needed, adjust the limit
limit = MaximumLimit - Count;
}
if (limit > 0)
{
// Add the limit, the maximum number of items to be returned per page
url += (url.Contains("?") ? "&" : "?") + "limit=" + limit;
}
}
if (Count > 0)
{
// Add the count, the number of items already seen in this listing
// The Reddit API uses this to determine when to give values for before and after fields
url += (url.Contains("?") ? "&" : "?") + "count=" + Count;
}
var request = Listing.WebAgent.CreateGet(url);
var response = request.GetResponse();
var data = Listing.WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
if (json["kind"].ValueOrDefault<string>() != "Listing")
throw new FormatException("Reddit responded with an object that is not a listing.");
Parse(json);
}
private void Parse(JToken json)
{
var children = json["data"]["children"] as JArray;
CurrentPage = new Thing[children.Count];
for (int i = 0; i < CurrentPage.Length; i++)
CurrentPage[i] = Thing.Parse<T>(Listing.Reddit, children[i], Listing.WebAgent);
// Increase the total count of items returned
Count += CurrentPage.Length;
After = json["data"]["after"].Value<string>();
Before = json["data"]["before"].Value<string>();
}
public void Dispose()
{
// ...
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
CurrentPageIndex++;
if (CurrentPageIndex == CurrentPage.Length)
{
if (After == null && CurrentPageIndex != 0)
{
// No more pages to return
return false;
}
if (MaximumLimit != -1 && Count >= MaximumLimit)
{
// Maximum listing count returned
return false;
}
// Get the next page
FetchNextPage();
CurrentPageIndex = 0;
if (CurrentPage.Length == 0)
{
// No listings were returned in the page
return false;
}
}
return true;
}
public void Reset()
{
After = Before = null;
CurrentPageIndex = -1;
CurrentPage = new Thing[0];
}
}
#pragma warning restore
}
}
================================================
FILE: RedditSharp/ModActionType.cs
================================================
using Newtonsoft.Json;
using System;
namespace RedditSharp
{
public enum ModActionType
{
BanUser,
UnBanUser,
RemoveLink,
ApproveLink,
RemoveComment,
ApproveComment,
AddModerator,
InviteModerator,
UnInviteModerator,
AcceptModeratorInvite,
RemoveModerator,
AddContributor,
RemoveContributor,
EditSettings,
EditFlair,
Distinguish,
MarkNSFW,
WikiBanned,
WikiContributor,
WikiUnBanned,
WikiPageListed,
RemoveWikiContributor,
WikiRevise,
WikiPermlevel,
IgnoreReports,
UnIgnoreReports,
SetPermissions,
SetSuggestedsort,
Sticky,
UnSticky,
SetContestMode,
UnSetContestMode,
LockPost, //actual value is "Lock" but it's a reserved word
Unlock,
MuteUser,
UnMuteUser
}
public class ModActionTypeConverter : JsonConverter
{
/// <summary>
/// Replaces "LockPost" with "lock" since "lock" is a reserved word and can't be used in the enum
/// </summary>
/// <returns>String representation of enum value recognized by Reddit's api</returns>
public static string GetRedditParamName(ModActionType action)
{
if (action == ModActionType.LockPost) return "lock";
else return action.ToString("g").ToLower();
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ModActionType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string value = reader.Value.ToString();
if (value.ToLower() == "lock")
{
return ModActionType.LockPost;
}
else
{
return Enum.Parse(typeof(ModActionType), value, true);
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null) writer.WriteNull();
else writer.WriteValue(GetRedditParamName((ModActionType) value));
}
}
}
================================================
FILE: RedditSharp/ModeratorPermission.cs
================================================
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp
{
[Flags]
public enum ModeratorPermission
{
None = 0x00,
Access = 0x01,
Config = 0x02,
Flair = 0x04,
Mail = 0x08,
Posts = 0x10,
Wiki = 0x20,
All = Access | Config | Flair | Mail | Posts | Wiki
}
internal class ModeratorPermissionConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var data = String.Join(",", JArray.Load(reader).Select(t => t.ToString()));
ModeratorPermission result;
var valid = Enum.TryParse(data, true, out result);
if (!valid)
result = ModeratorPermission.None;
return result;
}
public override bool CanConvert(Type objectType)
{
// NOTE: Not sure if this is what is supposed to be returned
// This method wasn't called in my (Sharparam) tests so unsure what it does
return objectType == typeof (ModeratorPermission);
}
}
}
================================================
FILE: RedditSharp/ModeratorUser.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp
{
public class ModeratorUser
{
public ModeratorUser(Reddit reddit, JToken json)
{
JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);
}
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("mod_permissions")]
[JsonConverter(typeof (ModeratorPermissionConverter))]
public ModeratorPermission Permissions { get; set; }
public override string ToString()
{
return Name;
}
}
}
================================================
FILE: RedditSharp/MultipartFormBuilder.cs
================================================
using System;
using System.IO;
using System.Net;
namespace RedditSharp
{
public class MultipartFormBuilder
{
public HttpWebRequest Request { get; set; }
private string Boundary { get; set; }
private MemoryStream Buffer { get; set; }
private TextWriter TextBuffer { get; set; }
public MultipartFormBuilder(HttpWebRequest request)
{
// TODO: See about regenerating the boundary when needed
Request = request;
var random = new Random();
Boundary = "----------" + CreateRandomBoundary();
request.ContentType = "multipart/form-data; boundary=" + Boundary;
Buffer = new MemoryStream();
TextBuffer = new StreamWriter(Buffer);
}
private string CreateRandomBoundary()
{
// TODO: There's probably a better way to go about this
const string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
string value = "";
var random = new Random();
for (int i = 0; i < 10; i++)
value += characters[random.Next(characters.Length)];
return value;
}
public void AddDynamic(object data)
{
var type = data.GetType();
var properties = type.GetProperties();
foreach (var property in properties)
{
var entry = Convert.ToString(property.GetValue(data, null));
AddString(property.Name, entry);
}
}
public void AddString(string name, string value)
{
TextBuffer.Write("{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n",
"--" + Boundary, name, value);
TextBuffer.Flush();
}
public void AddFile(string name, string filename, byte[] value, string contentType)
{
TextBuffer.Write("{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
"--" + Boundary, name, filename, contentType);
TextBuffer.Flush();
Buffer.Write(value, 0, value.Length);
Buffer.Flush();
TextBuffer.Write("\r\n");
TextBuffer.Flush();
}
public void Finish()
{
TextBuffer.Write("--" + Boundary + "--");
TextBuffer.Flush();
var stream = Request.GetRequestStream();
Buffer.Seek(0, SeekOrigin.Begin);
Buffer.WriteTo(stream);
stream.Close();
}
}
}
================================================
FILE: RedditSharp/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RedditSharp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RedditSharp")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5b1e351d-35b7-443e-9341-52c069a14886")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: RedditSharp/RateLimitException.cs
================================================
using System;
namespace RedditSharp
{
public class RateLimitException : Exception
{
public TimeSpan TimeToReset { get; set; }
public RateLimitException(TimeSpan timeToReset)
{
TimeToReset = timeToReset;
}
}
}
================================================
FILE: RedditSharp/Reddit.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using RedditSharp.Things;
using System.Threading.Tasks;
using DefaultWebAgent = RedditSharp.WebAgent;
namespace RedditSharp
{
/// <summary>
/// Class to communicate with Reddit.com
/// </summary>
public class Reddit
{
#region Constant Urls
private const string SslLoginUrl = "https://ssl.reddit.com/api/login";
private const string LoginUrl = "/api/login/username";
private const string UserInfoUrl = "/user/{0}/about.json";
private const string MeUrl = "/api/me.json";
private const string OAuthMeUrl = "/api/v1/me.json";
private const string SubredditAboutUrl = "/r/{0}/about.json";
private const string ComposeMessageUrl = "/api/compose";
private const string RegisterAccountUrl = "/api/register";
private const string GetThingUrl = "/api/info.json?id={0}";
private const string GetCommentUrl = "/r/{0}/comments/{1}/foo/{2}";
private const string GetPostUrl = "{0}.json";
private const string DomainUrl = "www.reddit.com";
private const string OAuthDomainUrl = "oauth.reddit.com";
private const string SearchUrl = "/search.json?q={0}&restrict_sr=off&sort={1}&t={2}";
private const string UrlSearchPattern = "url:'{0}'";
private const string NewSubredditsUrl = "/subreddits/new.json";
private const string PopularSubredditsUrl = "/subreddits/popular.json";
private const string GoldSubredditsUrl = "/subreddits/gold.json";
private const string DefaultSubredditsUrl = "/subreddits/default.json";
private const string SearchSubredditsUrl = "/subreddits/search.json?q={0}";
#endregion
#region Static Variables
static Reddit()
{
DefaultWebAgent.UserAgent = "";
DefaultWebAgent.RateLimit = DefaultWebAgent.RateLimitMode.Pace;
DefaultWebAgent.Protocol = "https";
DefaultWebAgent.RootDomain = "www.reddit.com";
}
#endregion
internal IWebAgent WebAgent { get; set; }
/// <summary>
/// Captcha solver instance to use when solving captchas.
/// </summary>
public ICaptchaSolver CaptchaSolver;
/// <summary>
/// The authenticated user for this instance.
/// </summary>
public AuthenticatedUser User { get; set; }
/// <summary>
/// Sets the Rate Limiting Mode of the underlying WebAgent
/// </summary>
public DefaultWebAgent.RateLimitMode RateLimit
{
get { return DefaultWebAgent.RateLimit; }
set { DefaultWebAgent.RateLimit = value; }
}
internal JsonSerializerSettings JsonSerializerSettings { get; set; }
/// <summary>
/// Gets the FrontPage using the current Reddit instance.
/// </summary>
public Subreddit FrontPage
{
get { return Subreddit.GetFrontPage(this); }
}
/// <summary>
/// Gets /r/All using the current Reddit instance.
/// </summary>
public Subreddit RSlashAll
{
get { return Subreddit.GetRSlashAll(this); }
}
public Reddit()
: this(true) { }
public Reddit(bool useSsl)
{
DefaultWebAgent defaultAgent = new DefaultWebAgent();
JsonSerializerSettings = new JsonSerializerSettings
{
CheckAdditionalContent = false,
DefaultValueHandling = DefaultValueHandling.Ignore
};
DefaultWebAgent.Protocol = useSsl ? "https" : "http";
WebAgent = defaultAgent;
CaptchaSolver = new ConsoleCaptchaSolver();
}
public Reddit(DefaultWebAgent.RateLimitMode limitMode, bool useSsl = true)
: this(useSsl)
{
DefaultWebAgent.UserAgent = "";
DefaultWebAgent.RateLimit = limitMode;
DefaultWebAgent.RootDomain = "www.reddit.com";
}
public Reddit(string username, string password, bool useSsl = true)
: this(useSsl)
{
LogIn(username, password, useSsl);
}
public Reddit(string accessToken)
: this(true)
{
DefaultWebAgent.RootDomain = OAuthDomainUrl;
WebAgent.AccessToken = accessToken;
InitOrUpdateUser();
}
/// <summary>
/// Creates a Reddit instance with the given WebAgent implementation
/// </summary>
/// <param name="agent">Implementation of IWebAgent interface. Used to generate requests.</param>
public Reddit(IWebAgent agent)
{
WebAgent = agent;
JsonSerializerSettings = new JsonSerializerSettings
{
CheckAdditionalContent = false,
DefaultValueHandling = DefaultValueHandling.Ignore
};
CaptchaSolver = new ConsoleCaptchaSolver();
}
/// <summary>
/// Creates a Reddit instance with the given WebAgent implementation
/// </summary>
/// <param name="agent">Implementation of IWebAgent interface. Used to generate requests.</param>
/// <param name="initUser">Whether to run InitOrUpdateUser, requires <paramref name="agent"/> to have credentials first.</param>
public Reddit(IWebAgent agent, bool initUser)
{
WebAgent = agent;
JsonSerializerSettings = new JsonSerializerSettings
{
CheckAdditionalContent = false,
DefaultValueHandling = DefaultValueHandling.Ignore
};
CaptchaSolver = new ConsoleCaptchaSolver();
if(initUser) InitOrUpdateUser();
}
/// <summary>
/// Logs in the current Reddit instance.
/// </summary>
/// <param name="username">The username of the user to log on to.</param>
/// <param name="password">The password of the user to log on to.</param>
/// <param name="useSsl">Whether to use SSL or not. (default: true)</param>
/// <returns></returns>
public AuthenticatedUser LogIn(string username, string password, bool useSsl = true)
{
if (Type.GetType("Mono.Runtime") != null)
ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;
WebAgent.Cookies = new CookieContainer();
HttpWebRequest request;
if (useSsl)
request = WebAgent.CreatePost(SslLoginUrl);
else
request = WebAgent.CreatePost(LoginUrl);
var stream = request.GetRequestStream();
if (useSsl)
{
WebAgent.WritePostBody(stream, new
{
user = username,
passwd = password,
api_type = "json"
});
}
else
{
WebAgent.WritePostBody(stream, new
{
user = username,
passwd = password,
api_type = "json",
op = "login"
});
}
stream.Close();
var response = (HttpWebResponse)request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(result)["json"];
if (json["errors"].Count() != 0)
throw new AuthenticationException("Incorrect login.");
InitOrUpdateUser();
return User;
}
public RedditUser GetUser(string name)
{
var request = WebAgent.CreateGet(string.Format(UserInfoUrl, name));
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(result);
return new RedditUser().Init(this, json, WebAgent);
}
/// <summary>
/// Initializes the User property if it's null,
/// otherwise replaces the existing user object
/// with a new one fetched from reddit servers.
/// </summary>
public void InitOrUpdateUser()
{
var request = WebAgent.CreateGet(string.IsNullOrEmpty(WebAgent.AccessToken) ? MeUrl : OAuthMeUrl);
var response = (HttpWebResponse)request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(result);
User = new AuthenticatedUser().Init(this, json, WebAgent);
}
#region Obsolete Getter Methods
[Obsolete("Use User property instead")]
public AuthenticatedUser GetMe()
{
return User;
}
#endregion Obsolete Getter Methods
public Subreddit GetSubreddit(string name)
{
if (name.StartsWith("r/"))
name = name.Substring(2);
if (name.StartsWith("/r/"))
name = name.Substring(3);
name = name.TrimEnd('/');
return GetThing<Subreddit>(string.Format(SubredditAboutUrl, name));
}
/// <summary>
/// Returns the subreddit.
/// </summary>
/// <param name="name">The name of the subreddit</param>
/// <returns>The Subreddit by given name</returns>
public async Task<Subreddit> GetSubredditAsync(string name)
{
if (name.StartsWith("r/"))
name = name.Substring(2);
if (name.StartsWith("/r/"))
name = name.Substring(3);
name = name.TrimEnd('/');
return await GetThingAsync<Subreddit>(string.Format(SubredditAboutUrl, name));
}
public Domain GetDomain(string domain)
{
if (!domain.StartsWith("http://") && !domain.StartsWith("https://"))
domain = "http://" + domain;
var uri = new Uri(domain);
return new Domain(this, uri, WebAgent);
}
public JToken GetToken(Uri uri)
{
var url = uri.AbsoluteUri;
if (url.EndsWith("/"))
url = url.Remove(url.Length - 1);
var request = WebAgent.CreateGet(string.Format(GetPostUrl, url));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return json[0]["data"]["children"].First;
}
public Post GetPost(Uri uri)
{
return new Post().Init(this, GetToken(uri), WebAgent);
}
/// <summary>
///
/// </summary>
/// <param name="subject"></param>
/// <param name="body"></param>
/// <param name="to"></param>
/// <param name="fromSubReddit">The subreddit to send the message as (optional).</param>
/// <param name="captchaId"></param>
/// <param name="captchaAnswer"></param>
/// <remarks>If <paramref name="fromSubReddit"/> is passed in then the message is sent from the subreddit. the sender must be a mod of the specified subreddit.</remarks>
/// <exception cref="AuthenticationException">Thrown when a subreddit is passed in and the user is not a mod of that sub.</exception>
public void ComposePrivateMessage(string subject, string body, string to, string fromSubReddit = "", string captchaId = "", string captchaAnswer = "")
{
if (User == null)
throw new Exception("User can not be null.");
if (!String.IsNullOrWhiteSpace(fromSubReddit))
{
var subReddit = this.GetSubreddit(fromSubReddit);
var modNameList = subReddit.Moderators.Select(b => b.Name).ToList();
if (!modNameList.Contains(User.Name))
throw new AuthenticationException(
String.Format(
@"User {0} is not a moderator of subreddit {1}.",
User.Name,
subReddit.Name));
}
var request = WebAgent.CreatePost(ComposeMessageUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
subject,
text = body,
to,
from_sr = fromSubReddit,
uh = User.Modhash,
iden = captchaId,
captcha = captchaAnswer
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(result);
ICaptchaSolver solver = CaptchaSolver; // Prevent race condition
if (json["json"]["errors"].Any() && json["json"]["errors"][0][0].ToString() == "BAD_CAPTCHA" && solver != null)
{
captchaId = json["json"]["captcha"].ToString();
CaptchaResponse captchaResponse = solver.HandleCaptcha(new Captcha(captchaId));
if (!captchaResponse.Cancel) // Keep trying until we are told to cancel
ComposePrivateMessage(subject, body, to, captchaId, captchaResponse.Answer);
}
}
/// <summary>
/// Registers a new Reddit user
/// </summary>
/// <param name="userName">The username for the new account.</param>
/// <param name="passwd">The password for the new account.</param>
/// <param name="email">The optional recovery email for the new account.</param>
/// <returns>The newly created user account</returns>
public AuthenticatedUser RegisterAccount(string userName, string passwd, string email = "")
{
var request = WebAgent.CreatePost(RegisterAccountUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
email = email,
passwd = passwd,
passwd2 = passwd,
user = userName
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(result);
return new AuthenticatedUser().Init(this, json, WebAgent);
// TODO: Error
}
public Thing GetThingByFullname(string fullname)
{
var request = WebAgent.CreateGet(string.Format(GetThingUrl, fullname));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return Thing.Parse(this, json["data"]["children"][0], WebAgent);
}
public Comment GetComment(string subreddit, string name, string linkName)
{
try
{
if (linkName.StartsWith("t3_"))
linkName = linkName.Substring(3);
if (name.StartsWith("t1_"))
name = name.Substring(3);
var url = string.Format(GetCommentUrl, subreddit, linkName, name);
return GetComment(new Uri(url));
}
catch (WebException)
{
return null;
}
}
public Comment GetComment(Uri uri)
{
var url = string.Format(GetPostUrl, uri.AbsoluteUri);
var request = WebAgent.CreateGet(url);
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
var sender = new Post().Init(this, json[0]["data"]["children"][0], WebAgent);
return new Comment().Init(this, json[1]["data"]["children"][0], WebAgent, sender);
}
public Listing<T> SearchByUrl<T>(string url) where T : Thing
{
var urlSearchQuery = string.Format(UrlSearchPattern, url);
return Search<T>(urlSearchQuery);
}
public Listing<T> Search<T>(string query, Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All) where T : Thing
{
string sort = sortE.ToString().ToLower();
string time = timeE.ToString().ToLower();
return new Listing<T>(this, string.Format(SearchUrl, query, sort, time), WebAgent);
}
public Listing<T> SearchByTimestamp<T>(DateTime from, DateTime to, string query = "", string subreddit = "", Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All) where T : Thing
{
string sort = sortE.ToString().ToLower();
string time = timeE.ToString().ToLower();
var fromUnix = (from - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
var toUnix = (to - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
string searchQuery = "(and+timestamp:" + fromUnix + ".." + toUnix + "+'" + query + "'+" + "subreddit:'" + subreddit + "')&syntax=cloudsearch";
return new Listing<T>(this, string.Format(SearchUrl, searchQuery, sort, time), WebAgent);
}
#region SubredditSearching
/// <summary>
/// Returns a Listing of newly created subreddits.
/// </summary>
/// <returns></returns>
public Listing<Subreddit> GetNewSubreddits()
{
return new Listing<Subreddit>(this, NewSubredditsUrl, WebAgent);
}
/// <summary>
/// Returns a Listing of the most popular subreddits.
/// </summary>
/// <returns></returns>
public Listing<Subreddit> GetPopularSubreddits()
{
return new Listing<Subreddit>(this, PopularSubredditsUrl, WebAgent);
}
/// <summary>
/// Returns a Listing of Gold-only subreddits. This endpoint will not return anything if the authenticated Reddit account does not currently have gold.
/// </summary>
/// <returns></returns>
public Listing<Subreddit> GetGoldSubreddits()
{
return new Listing<Subreddit>(this, GoldSubredditsUrl, WebAgent);
}
/// <summary>
/// Returns the Listing of default subreddits.
/// </summary>
/// <returns></returns>
public Listing<Subreddit> GetDefaultSubreddits()
{
return new Listing<Subreddit>(this, DefaultSubredditsUrl, WebAgent);
}
/// <summary>
/// Returns the Listing of subreddits related to a query.
/// </summary>
/// <returns></returns>
public Listing<Subreddit> SearchSubreddits(string query)
{
return new Listing<Subreddit>(this, string.Format(SearchSubredditsUrl, query), WebAgent);
}
#endregion SubredditSearching
#region Helpers
protected async internal Task<T> GetThingAsync<T>(string url) where T : Thing
{
var request = WebAgent.CreateGet(url);
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
var ret = await Thing.ParseAsync(this, json, WebAgent);
return (T)ret;
}
protected internal T GetThing<T>(string url) where T : Thing
{
var request = WebAgent.CreateGet(url);
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return (T)Thing.Parse(this, json, WebAgent);
}
#endregion
}
}
================================================
FILE: RedditSharp/RedditAPINameAttribute.cs
================================================
using System;
namespace RedditSharp
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
internal class RedditAPINameAttribute : Attribute
{
internal string Name { get; private set; }
internal RedditAPINameAttribute(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
}
================================================
FILE: RedditSharp/RedditException.cs
================================================
using System;
using System.Runtime.Serialization;
namespace RedditSharp
{
/// <summary>
/// Represents an error that occurred during accessing or manipulating data on Reddit.
/// </summary>
[Serializable]
public class RedditException : Exception
{
/// <summary>
/// Initializes a new instance of the RedditException class.
/// </summary>
public RedditException()
{
}
/// <summary>
/// Initializes a new instance of the RedditException class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public RedditException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the RedditException class with a specified error message and
/// a referenced inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="inner">The exception that is the cause of the current exception, or a null
/// reference (Nothing in Visual Basic) if no inner exception is specified.</param>
public RedditException(string message, Exception inner)
: base(message, inner)
{
}
/// <summary>
/// Initializes a new instance of the RedditException class with serialized data.
/// </summary>
/// <param name="info">The System.Runtime.Serialization.SerializationInfo that holds the
/// serialized object data about the exception being thrown.</param>
/// <param name="context">The System.Runtime.Serialization.StreamingContext that contains
/// contextual information about the source or destination.</param>
/// <exception cref="System.ArgumentNullException">The info parameter is null.</exception>
/// <exception cref="System.Runtime.Serialization.SerializationException">The class name
/// is null or System.Exception.HResult is zero (0).</exception>
protected RedditException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
================================================
FILE: RedditSharp/RedditSharp.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A368CB75-75F0-4489-904D-B5CEBB0FE624}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RedditSharp</RootNamespace>
<AssemblyName>RedditSharp</AssemblyName>
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup />
<ItemGroup>
<Reference Include="HtmlAgilityPack">
<HintPath>..\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ModActionType.cs" />
<Compile Include="Things\Contributor.cs" />
<Compile Include="Things\ModAction.cs" />
<Compile Include="Utils\DateTimeExtensions.cs" />
<Compile Include="SpamFilterSettings.cs" />
<Compile Include="Things\AuthenticatedUser.cs" />
<Compile Include="AuthProvider.cs" />
<Compile Include="Captcha.cs" />
<Compile Include="CaptchaFailedException.cs" />
<Compile Include="CaptchaResponse.cs" />
<Compile Include="ConsoleCaptchaSolver.cs" />
<Compile Include="DuplicateLinkException.cs" />
<Compile Include="ICaptchaSolver.cs" />
<Compile Include="Things\Comment.cs" />
<Compile Include="Things\CreatedThing.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="FlairTemplate.cs" />
<Compile Include="IWebAgent.cs" />
<Compile Include="LinkData.cs" />
<Compile Include="Listing.cs" />
<Compile Include="ModeratorPermission.cs" />
<Compile Include="ModeratorUser.cs" />
<Compile Include="MultipartFormBuilder.cs" />
<Compile Include="FlairType.cs" />
<Compile Include="Things\Post.cs" />
<Compile Include="Things\PrivateMessage.cs" />
<Compile Include="Reddit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RedditAPINameAttribute.cs" />
<Compile Include="RedditException.cs" />
<Compile Include="Things\RedditUser.cs" />
<Compile Include="SubmitData.cs" />
<Compile Include="Things\Subreddit.cs" />
<Compile Include="SubredditImage.cs" />
<Compile Include="SubredditSettings.cs" />
<Compile Include="SubredditStyle.cs" />
<Compile Include="TextData.cs" />
<Compile Include="Things\Thing.cs" />
<Compile Include="UnixTimeStamp.cs" />
<Compile Include="UnixTimestampConverter.cs" />
<Compile Include="UrlParser.cs" />
<Compile Include="Things\VotableThing.cs" />
<Compile Include="RateLimitException.cs" />
<Compile Include="WebAgent.cs" />
<Compile Include="Wiki.cs" />
<Compile Include="WikiPage.cs" />
<Compile Include="Things\WikiPageRevision.cs" />
<Compile Include="WikiPageSettings.cs" />
<Compile Include="Domain.cs" />
<Compile Include="TBUserNote.cs" />
<Compile Include="ToolBoxUserNotes.cs" />
<Compile Include="ToolBoxUserNotesException.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
================================================
FILE: RedditSharp/SpamFilterSettings.cs
================================================
namespace RedditSharp
{
public class SpamFilterSettings
{
public SpamFilterStrength LinkPostStrength { get; set; }
public SpamFilterStrength SelfPostStrength { get; set; }
public SpamFilterStrength CommentStrength { get; set; }
public SpamFilterSettings()
{
LinkPostStrength = SpamFilterStrength.High;
SelfPostStrength = SpamFilterStrength.High;
CommentStrength = SpamFilterStrength.High;
}
}
}
================================================
FILE: RedditSharp/SubmitData.cs
================================================
namespace RedditSharp
{
internal abstract class SubmitData
{
[RedditAPIName("api_type")]
internal string APIType { get; set; }
[RedditAPIName("kind")]
internal string Kind { get; set; }
[RedditAPIName("sr")]
internal string Subreddit { get; set; }
[RedditAPIName("uh")]
internal string UserHash { get; set; }
[RedditAPIName("title")]
internal string Title { get; set; }
[RedditAPIName("iden")]
internal string Iden { get; set; }
[RedditAPIName("captcha")]
internal string Captcha { get; set; }
[RedditAPIName("resubmit")]
internal bool Resubmit { get; set; }
protected SubmitData()
{
APIType = "json";
}
}
}
================================================
FILE: RedditSharp/SubredditImage.cs
================================================
using System;
namespace RedditSharp
{
public class SubredditImage
{
private const string DeleteImageUrl = "/api/delete_sr_img";
private Reddit Reddit { get; set; }
private IWebAgent WebAgent { get; set; }
public SubredditImage(Reddit reddit, SubredditStyle subredditStyle,
string cssLink, string name, IWebAgent webAgent)
{
Reddit = reddit;
WebAgent = webAgent;
SubredditStyle = subredditStyle;
Name = name;
CssLink = cssLink;
}
public SubredditImage(Reddit reddit, SubredditStyle subreddit,
string cssLink, string name, string url, IWebAgent webAgent)
: this(reddit, subreddit, cssLink, name, webAgent)
{
Url = new Uri(url);
// Handle legacy image urls
// http://thumbs.reddit.com/FULLNAME_NUMBER.png
int discarded;
if (int.TryParse(url, out discarded))
Url = new Uri(string.Format("http://thumbs.reddit.com/{0}_{1}.png", subreddit.Subreddit.FullName, url), UriKind.Absolute);
}
public string CssLink { get; set; }
public string Name { get; set; }
public Uri Url { get; set; }
public SubredditStyle SubredditStyle { get; set; }
public void Delete()
{
var request = WebAgent.CreatePost(DeleteImageUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
img_name = Name,
uh = Reddit.User.Modhash,
r = SubredditStyle.Subreddit.Name
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
SubredditStyle.Images.Remove(this);
}
}
}
================================================
FILE: RedditSharp/SubredditSettings.cs
================================================
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RedditSharp.Things;
namespace RedditSharp
{
public class SubredditSettings
{
private const string SiteAdminUrl = "/api/site_admin";
private const string DeleteHeaderImageUrl = "/api/delete_sr_header";
private Reddit Reddit { get; set; }
private IWebAgent WebAgent { get; set; }
[JsonIgnore]
public Subreddit Subreddit { get; set; }
public SubredditSettings(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)
{
Subreddit = subreddit;
Reddit = reddit;
WebAgent = webAgent;
// Default settings, for use when reduced information is given
AllowAsDefault = true;
Domain = null;
Sidebar = string.Empty;
Language = "en";
Title = Subreddit.DisplayName;
WikiEditKarma = 100;
WikiEditAge = 10;
UseDomainCss = false;
UseDomainSidebar = false;
HeaderHoverText = string.Empty;
NSFW = false;
PublicDescription = string.Empty;
WikiEditMode = WikiEditMode.None;
SubredditType = SubredditType.Public;
ShowThumbnails = true;
ContentOptions = ContentOptions.All;
SpamFilter = new SpamFilterSettings();
}
public SubredditSettings(Subreddit subreddit, Reddit reddit, JObject json, IWebAgent webAgent) : this(reddit, subreddit, webAgent)
{
var data = json["data"];
AllowAsDefault = data["default_set"].ValueOrDefault<bool>();
Domain = data["domain"].ValueOrDefault<string>();
Sidebar = HttpUtility.HtmlDecode(data["description"].ValueOrDefault<string>() ?? string.Empty);
Language = data["language"].ValueOrDefault<string>();
Title = data["title"].ValueOrDefault<string>();
WikiEditKarma = data["wiki_edit_karma"].ValueOrDefault<int>();
UseDomainCss = data["domain_css"].ValueOrDefault<bool>();
UseDomainSidebar = data["domain_sidebar"].ValueOrDefault<bool>();
HeaderHoverText = data["header_hover_text"].ValueOrDefault<string>();
NSFW = data["over_18"].ValueOrDefault<bool>();
PublicDescription = HttpUtility.HtmlDecode(data["public_description"].ValueOrDefault<string>() ?? string.Empty);
SpamFilter = new SpamFilterSettings
{
LinkPostStrength = GetSpamFilterStrength(data["spam_links"].ValueOrDefault<string>()),
SelfPostStrength = GetSpamFilterStrength(data["spam_selfposts"].ValueOrDefault<string>()),
CommentStrength = GetSpamFilterStrength(data["spam_comments"].ValueOrDefault<string>())
};
if (data["wikimode"] != null)
{
var wikiMode = data["wikimode"].ValueOrDefault<string>();
switch (wikiMode)
{
case "disabled":
WikiEditMode = WikiEditMode.None;
break;
case "modonly":
WikiEditMode = WikiEditMode.Moderators;
break;
case "anyone":
WikiEditMode = WikiEditMode.All;
break;
}
}
if (data["subreddit_type"] != null)
{
var type = data["subreddit_type"].ValueOrDefault<string>();
switch (type)
{
case "public":
SubredditType = SubredditType.Public;
break;
case "private":
SubredditType = SubredditType.Private;
break;
case "restricted":
SubredditType = SubredditType.Restricted;
break;
}
}
ShowThumbnails = data["show_media"].ValueOrDefault<bool>();
WikiEditAge = data["wiki_edit_age"].ValueOrDefault<int>();
if (data["content_options"] != null)
{
var contentOptions = data["content_options"].ValueOrDefault<string>();
switch (contentOptions)
{
case "any":
ContentOptions = ContentOptions.All;
break;
case "link":
ContentOptions = ContentOptions.LinkOnly;
break;
case "self":
ContentOptions = ContentOptions.SelfOnly;
break;
}
}
}
public bool AllowAsDefault { get; set; }
public string Domain { get; set; }
public string Sidebar { get; set; }
public string Language { get; set; }
public string Title { get; set; }
public int WikiEditKarma { get; set; }
public bool UseDomainCss { get; set; }
public bool UseDomainSidebar { get; set; }
public string HeaderHoverText { get; set; }
public bool NSFW { get; set; }
public string PublicDescription { get; set; }
public WikiEditMode WikiEditMode { get; set; }
public SubredditType SubredditType { get; set; }
public bool ShowThumbnails { get; set; }
public int WikiEditAge { get; set; }
public ContentOptions ContentOptions { get; set; }
public SpamFilterSettings SpamFilter { get; set; }
public void UpdateSettings()
{
var request = WebAgent.CreatePost(SiteAdminUrl);
var stream = request.GetRequestStream();
string link_type;
string type;
string wikimode;
switch (ContentOptions)
{
case ContentOptions.All:
link_type = "any";
break;
case ContentOptions.LinkOnly:
link_type = "link";
break;
default:
link_type = "self";
break;
}
switch (SubredditType)
{
case SubredditType.Public:
type = "public";
break;
case SubredditType.Private:
type = "private";
break;
default:
type = "restricted";
break;
}
switch (WikiEditMode)
{
case WikiEditMode.All:
wikimode = "anyone";
break;
case WikiEditMode.Moderators:
wikimode = "modonly";
break;
default:
wikimode = "disabled";
break;
}
WebAgent.WritePostBody(stream, new
{
allow_top = AllowAsDefault,
description = Sidebar,
domain = Domain,
lang = Language,
link_type,
over_18 = NSFW,
public_description = PublicDescription,
show_media = ShowThumbnails,
sr = Subreddit.FullName,
title = Title,
type,
uh = Reddit.User.Modhash,
wiki_edit_age = WikiEditAge,
wiki_edit_karma = WikiEditKarma,
wikimode,
spam_links = SpamFilter == null ? null : SpamFilter.LinkPostStrength.ToString().ToLowerInvariant(),
spam_selfposts = SpamFilter == null ? null : SpamFilter.SelfPostStrength.ToString().ToLowerInvariant(),
spam_comments = SpamFilter == null ? null : SpamFilter.CommentStrength.ToString().ToLowerInvariant(),
api_type = "json"
}, "header-title", HeaderHoverText);
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
/// <summary>
/// Resets the subreddit's header image to the Reddit logo
/// </summary>
public void ResetHeaderImage()
{
var request = WebAgent.CreatePost(DeleteHeaderImageUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
uh = Reddit.User.Modhash,
r = Subreddit.Name
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
private SpamFilterStrength GetSpamFilterStrength(string rawValue)
{
switch(rawValue)
{
case "low":
return SpamFilterStrength.Low;
case "high":
return SpamFilterStrength.High;
case "all":
return SpamFilterStrength.All;
default:
return SpamFilterStrength.High;
}
}
}
public enum WikiEditMode
{
None,
Moderators,
All
}
public enum SubredditType
{
Public,
Restricted,
Private
}
public enum ContentOptions
{
All,
LinkOnly,
SelfOnly
}
public enum SpamFilterStrength
{
Low,
High,
All
}
}
================================================
FILE: RedditSharp/SubredditStyle.cs
================================================
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.Web;
using RedditSharp.Things;
namespace RedditSharp
{
public class SubredditStyle
{
private const string UploadImageUrl = "/api/upload_sr_img";
private const string UpdateCssUrl = "/api/subreddit_stylesheet";
private Reddit Reddit { get; set; }
private IWebAgent WebAgent { get; set; }
public SubredditStyle(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)
{
Reddit = reddit;
Subreddit = subreddit;
WebAgent = webAgent;
}
public SubredditStyle(Reddit reddit, Subreddit subreddit, JToken json, IWebAgent webAgent) : this(reddit, subreddit, webAgent)
{
Images = new List<SubredditImage>();
var data = json["data"];
CSS = HttpUtility.HtmlDecode(data["stylesheet"].Value<string>());
foreach (var image in data["images"])
{
Images.Add(new SubredditImage(
Reddit, this, image["link"].Value<string>(),
image["name"].Value<string>(), image["url"].Value<string>(), WebAgent));
}
}
public string CSS { get; set; }
public List<SubredditImage> Images { get; set; }
public Subreddit Subreddit { get; set; }
public void UpdateCss()
{
var request = WebAgent.CreatePost(UpdateCssUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
op = "save",
stylesheet_contents = CSS,
uh = Reddit.User.Modhash,
api_type = "json",
r = Subreddit.Name
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
}
public void UploadImage(string name, ImageType imageType, byte[] file)
{
var request = WebAgent.CreatePost(UploadImageUrl);
var formData = new MultipartFormBuilder(request);
formData.AddDynamic(new
{
name,
uh = Reddit.User.Modhash,
r = Subreddit.Name,
formid = "image-upload",
img_type = imageType == ImageType.PNG ? "png" : "jpg",
upload = ""
});
formData.AddFile("file", "foo.png", file, imageType == ImageType.PNG ? "image/png" : "image/jpeg");
formData.Finish();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
// TODO: Detect errors
}
}
public enum ImageType
{
PNG,
JPEG
}
}
================================================
FILE: RedditSharp/TBUserNote.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedditSharp
{
public class TBUserNote
{
public int NoteTypeIndex { get; set; }
public string NoteType { get; set; }
public string SubName { get; set; }
public string Submitter { get; set; }
public int SubmitterIndex { get; set; }
public string Message { get; set; }
public string AppliesToUsername { get; set; }
public string Url { get; set; }
private DateTime _timestamp;
public DateTime Timestamp
{
get { return _timestamp; }
set
{
_timestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc);
}
}
}
}
================================================
FILE: RedditSharp/TextData.cs
================================================
namespace RedditSharp
{
internal class TextData : SubmitData
{
[RedditAPIName("text")]
internal string Text { get; set; }
internal TextData()
{
Kind = "self";
}
}
}
================================================
FILE: RedditSharp/Things/AuthenticatedUser.cs
================================================
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class AuthenticatedUser : RedditUser
{
private const string ModeratorUrl = "/reddits/mine/moderator.json";
private const string UnreadMessagesUrl = "/message/unread.json?mark=true&limit=25";
private const string ModQueueUrl = "/r/mod/about/modqueue.json";
private const string UnmoderatedUrl = "/r/mod/about/unmoderated.json";
private const string ModMailUrl = "/message/moderator.json";
private const string MessagesUrl = "/message/messages.json";
private const string InboxUrl = "/message/inbox.json";
private const string SentUrl = "/message/sent.json";
public new AuthenticatedUser Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json["name"] == null ? json["data"].ToString() : json.ToString(), this,
reddit.JsonSerializerSettings);
return this;
}
public async new Task<AuthenticatedUser> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["name"] == null ? json["data"].ToString() : json.ToString(), this,
reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(reddit, json, webAgent);
}
public Listing<Subreddit> ModeratorSubreddits
{
get
{
return new Listing<Subreddit>(Reddit, ModeratorUrl, WebAgent);
}
}
public Listing<Thing> UnreadMessages
{
get
{
return new Listing<Thing>(Reddit, UnreadMessagesUrl, WebAgent);
}
}
public Listing<VotableThing> ModerationQueue
{
get
{
return new Listing<VotableThing>(Reddit, ModQueueUrl, WebAgent);
}
}
public Listing<Post> UnmoderatedLinks
{
get
{
return new Listing<Post>(Reddit, UnmoderatedUrl, WebAgent);
}
}
public Listing<PrivateMessage> ModMail
{
get
{
return new Listing<PrivateMessage>(Reddit, ModMailUrl, WebAgent);
}
}
public Listing<PrivateMessage> PrivateMessages
{
get
{
return new Listing<PrivateMessage>(Reddit, MessagesUrl, WebAgent);
}
}
public Listing<PrivateMessage> Inbox
{
get
{
return new Listing<PrivateMessage>(Reddit, InboxUrl, WebAgent);
}
}
public Listing<PrivateMessage> Sent
{
get
{
return new Listing<PrivateMessage>(Reddit, SentUrl, WebAgent);
}
}
#region Obsolete Getter Methods
[Obsolete("Use ModeratorSubreddits property instead")]
public Listing<Subreddit> GetModeratorReddits()
{
return ModeratorSubreddits;
}
[Obsolete("Use UnreadMessages property instead")]
public Listing<Thing> GetUnreadMessages()
{
return UnreadMessages;
}
[Obsolete("Use ModerationQueue property instead")]
public Listing<VotableThing> GetModerationQueue()
{
return new Listing<VotableThing>(Reddit, ModQueueUrl, WebAgent);
}
public Listing<Post> GetUnmoderatedLinks()
{
return new Listing<Post>(Reddit, UnmoderatedUrl, WebAgent);
}
[Obsolete("Use ModMail property instead")]
public Listing<PrivateMessage> GetModMail()
{
return new Listing<PrivateMessage>(Reddit, ModMailUrl, WebAgent);
}
[Obsolete("Use PrivateMessages property instead")]
public Listing<PrivateMessage> GetPrivateMessages()
{
return new Listing<PrivateMessage>(Reddit, MessagesUrl, WebAgent);
}
[Obsolete("Use Inbox property instead")]
public Listing<PrivateMessage> GetInbox()
{
return new Listing<PrivateMessage>(Reddit, InboxUrl, WebAgent);
}
#endregion Obsolete Getter Methods
[JsonProperty("modhash")]
public string Modhash { get; set; }
[JsonProperty("has_mail")]
public bool HasMail { get; set; }
[JsonProperty("has_mod_mail")]
public bool HasModMail { get; set; }
}
}
================================================
FILE: RedditSharp/Things/Comment.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class Comment : VotableThing
{
private const string CommentUrl = "/api/comment";
private const string EditUserTextUrl = "/api/editusertext";
private const string RemoveUrl = "/api/remove";
private const string DelUrl = "/api/del";
private const string SetAsReadUrl = "/api/read_message";
[JsonIgnore]
private Reddit Reddit { get; set; }
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
public Comment Init(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)
{
var data = CommonInit(reddit, json, webAgent, sender);
ParseComments(reddit, json, webAgent, sender);
JsonConvert.PopulateObject(data.ToString(), this, reddit.JsonSerializerSettings);
return this;
}
public async Task<Comment> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)
{
var data = CommonInit(reddit, json, webAgent, sender);
await ParseCommentsAsync(reddit, json, webAgent, sender);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(data.ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private JToken CommonInit(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)
{
base.Init(reddit, webAgent, json);
var data = json["data"];
Reddit = reddit;
WebAgent = webAgent;
this.Parent = sender;
// Handle Reddit's API being horrible
if (data["context"] != null)
{
var context = data["context"].Value<string>();
LinkId = context.Split('/')[4];
}
return data;
}
private void ParseComments(Reddit reddit, JToken data, IWebAgent webAgent, Thing sender)
{
// Parse sub comments
var replies = data["data"]["replies"];
var subComments = new List<Comment>();
if (replies != null && replies.Count() > 0)
{
foreach (var comment in replies["data"]["children"])
subComments.Add(new Comment().Init(reddit, comment, webAgent, sender));
}
Comments = subComments.ToArray();
}
private async Task ParseCommentsAsync(Reddit reddit, JToken data, IWebAgent webAgent, Thing sender)
{
// Parse sub comments
var replies = data["data"]["replies"];
var subComments = new List<Comment>();
if (replies != null && replies.Count() > 0)
{
foreach (var comment in replies["data"]["children"])
subComments.Add(await new Comment().InitAsync(reddit, comment, webAgent, sender));
}
Comments = subComments.ToArray();
}
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("banned_by")]
public string BannedBy { get; set; }
[JsonProperty("body")]
public string Body { get; set; }
[JsonProperty("body_html")]
public string BodyHtml { get; set; }
[JsonProperty("parent_id")]
public string ParentId { get; set; }
[JsonProperty("subreddit")]
public string Subreddit { get; set; }
[JsonProperty("approved_by")]
public string ApprovedBy { get; set; }
[JsonProperty("author_flair_css_class")]
public string AuthorFlairCssClass { get; set; }
[JsonProperty("author_flair_text")]
public string AuthorFlairText { get; set; }
[JsonProperty("gilded")]
public int Gilded { get; set; }
[JsonProperty("link_id")]
public string LinkId { get; set; }
[JsonProperty("link_title")]
public string LinkTitle { get; set; }
[JsonProperty("num_reports")]
public int? NumReports { get; set; }
[JsonIgnore]
public IList<Comment> Comments { get; private set; }
[JsonIgnore]
public Thing Parent { get; internal set; }
public override string Shortlink
{
get
{
// Not really a "short" link, but you can't actually use short links for comments
string linkId = "";
int index = this.LinkId.IndexOf('_');
if (index > -1)
{
linkId = this.LinkId.Substring(index + 1);
}
return String.Format("{0}://{1}/r/{2}/comments/{3}/_/{4}",
RedditSharp.WebAgent.Protocol, RedditSharp.WebAgent.RootDomain,
this.Subreddit, this.Parent != null ? this.Parent.Id : linkId, this.Id);
}
}
public Comment Reply(string message)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(CommentUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
text = message,
thing_id = FullName,
uh = Reddit.User.Modhash,
api_type = "json"
//r = Subreddit
});
stream.Close();
try
{
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
if (json["json"]["ratelimit"] != null)
throw new RateLimitException(TimeSpan.FromSeconds(json["json"]["ratelimit"].ValueOrDefault<double>()));
return new Comment().Init(Reddit, json["json"]["data"]["things"][0], WebAgent, this);
}
catch (WebException ex)
{
var error = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
return null;
}
}
/// <summary>
/// Replaces the text in this comment with the input text.
/// </summary>
/// <param name="newText">The text to replace the comment's contents</param>
public void EditText(string newText)
{
if (Reddit.User == null)
throw new Exception("No user logged in.");
var request = WebAgent.CreatePost(EditUserTextUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
text = newText,
thing_id = FullName,
uh = Reddit.User.Modhash
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
JToken json = JToken.Parse(result);
if (json["json"].ToString().Contains("\"errors\": []"))
Body = newText;
else
throw new Exception("Error editing text.");
}
private string SimpleAction(string endpoint)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(endpoint);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
return data;
}
public void Del()
{
var data = SimpleAction(DelUrl);
}
public void Remove()
{
RemoveImpl(false);
}
public void RemoveSpam()
{
RemoveImpl(true);
}
private void RemoveImpl(bool spam)
{
var request = WebAgent.CreatePost(RemoveUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
spam = spam,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void SetAsRead()
{
var request = WebAgent.CreatePost(SetAsReadUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
id = FullName,
uh = Reddit.User.Modhash,
api_type = "json"
});
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
}
}
================================================
FILE: RedditSharp/Things/Contributor.cs
================================================
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class Contributor : Thing
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("date")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime DateAdded { get; set; }
public Contributor Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(json);
JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);
return this;
}
private void CommonInit(JToken json)
{
base.Init(json);
}
}
}
================================================
FILE: RedditSharp/Things/CreatedThing.cs
================================================
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class CreatedThing : Thing
{
private Reddit Reddit { get; set; }
protected CreatedThing Init(Reddit reddit, JToken json)
{
CommonInit(reddit, json);
JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings);
return this;
}
protected async Task<CreatedThing> InitAsync(Reddit reddit, JToken json)
{
CommonInit(reddit, json);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json)
{
base.Init(json);
Reddit = reddit;
}
[JsonProperty("created")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime Created { get; set; }
[JsonProperty("created_utc")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime CreatedUTC { get; set; }
}
}
================================================
FILE: RedditSharp/Things/ModAction.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedditSharp.Things
{
public class ModAction : Thing
{
[JsonProperty("action")]
[JsonConverter(typeof(ModActionTypeConverter))]
public ModActionType Action { get; set; }
[JsonProperty("created_utc")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime? TimeStamp { get; set; }
[JsonProperty("details")]
public string Details { get; set; }
[JsonProperty("mod")]
public string ModeratorName { get; set; }
[JsonProperty("target_author")]
public string TargetAuthorName { get; set; }
[JsonProperty("target_fullname")]
public string TargetThingFullname { get; set; }
[JsonProperty("target_permalink")]
public string TargetThingPermalink { get; set; }
[JsonIgnore]
public RedditUser TargetAuthor
{
get
{
return Reddit.GetUser(TargetAuthorName);
}
}
[JsonIgnore]
public Thing TargetThing
{
get
{
return Reddit.GetThingByFullname(TargetThingFullname);
}
}
[JsonIgnore]
private Reddit Reddit { get; set; }
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
public ModAction Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings);
return this;
}
public async Task<ModAction> InitAsync(Reddit reddit, JToken post, IWebAgent webAgent)
{
CommonInit(reddit, post, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(post["data"].ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(json);
Reddit = reddit;
WebAgent = webAgent;
}
}
}
================================================
FILE: RedditSharp/Things/Post.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class Post : VotableThing
{
private const string CommentUrl = "/api/comment";
private const string RemoveUrl = "/api/remove";
private const string DelUrl = "/api/del";
private const string GetCommentsUrl = "/comments/{0}.json";
private const string ApproveUrl = "/api/approve";
private const string EditUserTextUrl = "/api/editusertext";
private const string HideUrl = "/api/hide";
private const string UnhideUrl = "/api/unhide";
private const string SetFlairUrl = "/r/{0}/api/flair";
private const string MarkNSFWUrl = "/api/marknsfw";
private const string UnmarkNSFWUrl = "/api/unmarknsfw";
private const string ContestModeUrl = "/api/set_contest_mode";
private const string StickyModeUrl = "/api/set_subreddit_sticky";
[JsonIgnore]
private Reddit Reddit { get; set; }
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
public Post Init(Reddit reddit, JToken post, IWebAgent webAgent)
{
CommonInit(reddit, post, webAgent);
JsonConvert.PopulateObject(post["data"].ToString(), this, reddit.JsonSerializerSettings);
return this;
}
public async Task<Post> InitAsync(Reddit reddit, JToken post, IWebAgent webAgent)
{
CommonInit(reddit, post, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(post["data"].ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken post, IWebAgent webAgent)
{
base.Init(reddit, webAgent, post);
Reddit = reddit;
WebAgent = webAgent;
}
[JsonProperty("author")]
public string AuthorName { get; set; }
[JsonIgnore]
public RedditUser Author
{
get
{
return Reddit.GetUser(AuthorName);
}
}
public Comment[] Comments
{
get
{
return ListComments().ToArray();
}
}
[JsonProperty("approved_by")]
public string ApprovedBy { get; set; }
[JsonProperty("author_flair_css_class")]
public string AuthorFlairCssClass { get; set; }
[JsonProperty("author_flair_text")]
public string AuthorFlairText { get; set; }
[JsonProperty("banned_by")]
public string BannedBy { get; set; }
[JsonProperty("domain")]
public string Domain { get; set; }
[JsonProperty("edited")]
public bool Edited { get; set; }
[JsonProperty("is_self")]
public bool IsSelfPost { get; set; }
[JsonProperty("link_flair_css_class")]
public string LinkFlairCssClass { get; set; }
[JsonProperty("link_flair_text")]
public string LinkFlairText { get; set; }
[JsonProperty("num_comments")]
public int CommentCount { get; set; }
[JsonProperty("over_18")]
public bool NSFW { get; set; }
[JsonProperty("permalink")]
[JsonConverter(typeof(UrlParser))]
public Uri Permalink { get; set; }
[JsonProperty("score")]
public int Score { get; set; }
[JsonProperty("selftext")]
public string SelfText { get; set; }
[JsonProperty("selftext_html")]
public string SelfTextHtml { get; set; }
[JsonProperty("thumbnail")]
[JsonConverter(typeof(UrlParser))]
public Uri Thumbnail { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("subreddit")]
public string SubredditName { get; set; }
[JsonIgnore]
public Subreddit Subreddit
{
get
{
return Reddit.GetSubreddit("/r/" + SubredditName);
}
}
[JsonProperty("url")]
[JsonConverter(typeof(UrlParser))]
public Uri Url { get; set; }
[JsonProperty("num_reports")]
public int? Reports { get; set; }
public Comment Comment(string message)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(CommentUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
text = message,
thing_id = FullName,
uh = Reddit.User.Modhash,
api_type = "json"
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
if (json["json"]["ratelimit"] != null)
throw new RateLimitException(TimeSpan.FromSeconds(json["json"]["ratelimit"].ValueOrDefault<double>()));
return new Comment().Init(Reddit, json["json"]["data"]["things"][0], WebAgent, this);
}
private string SimpleAction(string endpoint)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(endpoint);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
return data;
}
private string SimpleActionToggle(string endpoint, bool value, bool requiresModAction = false)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var modNameList = this.Subreddit.Moderators.Select(b => b.Name).ToList();
if (requiresModAction && !modNameList.Contains(Reddit.User.Name))
throw new AuthenticationException(
String.Format(
@"User {0} is not a moderator of subreddit {1}.",
Reddit.User.Name,
this.Subreddit.Name));
var request = WebAgent.CreatePost(endpoint);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
state = value,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
return data;
}
public void Approve()
{
var data = SimpleAction(ApproveUrl);
}
public void Remove()
{
RemoveImpl(false);
}
public void RemoveSpam()
{
RemoveImpl(true);
}
private void RemoveImpl(bool spam)
{
var request = WebAgent.CreatePost(RemoveUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
spam = spam,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void Del()
{
var data = SimpleAction(DelUrl);
}
public void Hide()
{
var data = SimpleAction(HideUrl);
}
public void Unhide()
{
var data = SimpleAction(UnhideUrl);
}
public void MarkNSFW()
{
var data = SimpleAction(MarkNSFWUrl);
}
public void UnmarkNSFW()
{
var data = SimpleAction(UnmarkNSFWUrl);
}
public void ContestMode(bool state)
{
var data = SimpleActionToggle(ContestModeUrl, state);
}
public void StickyMode(bool state)
{
var data = SimpleActionToggle(StickyModeUrl, state, true);
}
#region Obsolete Getter Methods
[Obsolete("Use Comments property instead")]
public Comment[] GetComments()
{
return Comments;
}
#endregion Obsolete Getter Methods
/// <summary>
/// Replaces the text in this post with the input text.
/// </summary>
/// <param name="newText">The text to replace the post's contents</param>
public void EditText(string newText)
{
if (Reddit.User == null)
throw new Exception("No user logged in.");
if (!IsSelfPost)
throw new Exception("Submission to edit is not a self-post.");
var request = WebAgent.CreatePost(EditUserTextUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
text = newText,
thing_id = FullName,
uh = Reddit.User.Modhash
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
JToken json = JToken.Parse(result);
if (json["json"].ToString().Contains("\"errors\": []"))
SelfText = newText;
else
throw new Exception("Error editing text.");
}
public void Update()
{
JToken post = Reddit.GetToken(this.Url);
JsonConvert.PopulateObject(post["data"].ToString(), this, Reddit.JsonSerializerSettings);
}
public void SetFlair(string flairText, string flairClass)
{
if (Reddit.User == null)
throw new Exception("No user logged in.");
var request = WebAgent.CreatePost(string.Format(SetFlairUrl,SubredditName));
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
css_class = flairClass,
link = FullName,
name = Reddit.User.Name,
text = flairText,
uh = Reddit.User.Modhash
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(result);
LinkFlairText = flairText;
}
public List<Comment> ListComments(int? limit = null)
{
var url = string.Format(GetCommentsUrl, Id);
if (limit.HasValue)
{
var query = HttpUtility.ParseQueryString(string.Empty);
query.Add("limit", limit.Value.ToString());
url = string.Format("{0}?{1}", url, query);
}
var request = WebAgent.CreateGet(url);
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JArray.Parse(data);
var postJson = json.Last()["data"]["children"];
var comments = new List<Comment>();
foreach (var comment in postJson)
{
comments.Add(new Comment().Init(Reddit, comment, WebAgent, this));
}
return comments;
}
}
}
================================================
FILE: RedditSharp/Things/PrivateMessage.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class PrivateMessage : Thing
{
private const string SetAsReadUrl = "/api/read_message";
private const string CommentUrl = "/api/comment";
private Reddit Reddit { get; set; }
private IWebAgent WebAgent { get; set; }
[JsonProperty("body")]
public string Body { get; set; }
[JsonProperty("body_html")]
public string BodyHtml { get; set; }
[JsonProperty("was_comment")]
public bool IsComment { get; set; }
[JsonProperty("created")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime Sent { get; set; }
[JsonProperty("created_utc")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime SentUTC { get; set; }
[JsonProperty("dest")]
public string Destination { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("subreddit")]
public string Subreddit { get; set; }
[JsonProperty("new")]
public bool Unread { get; set; }
[JsonProperty("subject")]
public string Subject { get; set; }
[JsonProperty("parent_id")]
public string ParentID { get; set; }
[JsonProperty("first_message_name")]
public string FirstMessageName { get; set; }
[JsonIgnore]
public PrivateMessage[] Replies { get; set; }
[JsonIgnore]
public PrivateMessage Parent
{
get
{
if (string.IsNullOrEmpty(ParentID))
return null;
var id = ParentID.Remove(0, 3);
var listing = new Listing<PrivateMessage>(Reddit, "/message/messages/" + id + ".json", WebAgent);
var firstMessage = listing.First();
if (firstMessage.FullName == ParentID)
return listing.First();
else
return firstMessage.Replies.First(x => x.FullName == ParentID);
}
}
public Listing<PrivateMessage> Thread
{
get
{
if (string.IsNullOrEmpty(ParentID))
return null;
var id = ParentID.Remove(0, 3);
return new Listing<PrivateMessage>(Reddit, "/message/messages/" + id + ".json", WebAgent);
}
}
public PrivateMessage Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings);
return this;
}
public async Task<PrivateMessage> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(json);
Reddit = reddit;
WebAgent = webAgent;
var data = json["data"];
if (data["replies"] != null && data["replies"].Any())
{
if (data["replies"]["data"] != null)
{
if (data["replies"]["data"]["children"] != null)
{
var replies = new List<PrivateMessage>();
foreach (var reply in data["replies"]["data"]["children"])
replies.Add(new PrivateMessage().Init(reddit, reply, webAgent));
Replies = replies.ToArray();
}
}
}
}
#region Obsolete Getter Methods
[Obsolete("Use Thread property instead")]
public Listing<PrivateMessage> GetThread()
{
return Thread;
}
#endregion Obsolete Gettter Methods
public void SetAsRead()
{
var request = WebAgent.CreatePost(SetAsReadUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
id = FullName,
uh = Reddit.User.Modhash,
api_type = "json"
});
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void Reply(string message)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(CommentUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
text = message,
thing_id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
}
}
}
================================================
FILE: RedditSharp/Things/RedditUser.cs
================================================
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class RedditUser : Thing
{
private const string OverviewUrl = "/user/{0}.json";
private const string CommentsUrl = "/user/{0}/comments.json";
private const string LinksUrl = "/user/{0}/submitted.json";
private const string SubscribedSubredditsUrl = "/subreddits/mine.json";
private const string LikedUrl = "/user/{0}/liked.json";
private const string DislikedUrl = "/user/{0}/disliked.json";
private const int MAX_LIMIT = 100;
public RedditUser Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json["name"] == null ? json["data"].ToString() : json.ToString(), this,
reddit.JsonSerializerSettings);
return this;
}
public async Task<RedditUser> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["name"] == null ? json["data"].ToString() : json.ToString(), this,
reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(json);
Reddit = reddit;
WebAgent = webAgent;
}
[JsonIgnore]
protected Reddit Reddit { get; set; }
[JsonIgnore]
protected IWebAgent WebAgent { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("is_gold")]
public bool HasGold { get; set; }
[JsonProperty("is_mod")]
public bool IsModerator { get; set; }
[JsonProperty("link_karma")]
public int LinkKarma { get; set; }
[JsonProperty("comment_karma")]
public int CommentKarma { get; set; }
[JsonProperty("created")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime Created { get; set; }
public Listing<VotableThing> Overview
{
get
{
return new Listing<VotableThing>(Reddit, string.Format(OverviewUrl, Name), WebAgent);
}
}
public Listing<Post> LikedPosts
{
get
{
return new Listing<Post>(Reddit, string.Format(LikedUrl, Name), WebAgent);
}
}
public Listing<Post> DislikedPosts
{
get
{
return new Listing<Post>(Reddit, string.Format(DislikedUrl, Name), WebAgent);
}
}
public Listing<Comment> Comments
{
get
{
return new Listing<Comment>(Reddit, string.Format(CommentsUrl, Name), WebAgent);
}
}
public Listing<Post> Posts
{
get
{
return new Listing<Post>(Reddit, string.Format(LinksUrl, Name), WebAgent);
}
}
public Listing<Subreddit> SubscribedSubreddits
{
get
{
return new Listing<Subreddit>(Reddit, SubscribedSubredditsUrl, WebAgent);
}
}
/// <summary>
/// Get a listing of comments and posts from the user sorted by <paramref name="sorting"/>, from time <paramref name="fromTime"/>
/// and limited to <paramref name="limit"/>.
/// </summary>
/// <param name="sorting">How to sort the comments (hot, new, top, controversial).</param>
/// <param name="limit">How many comments to fetch per request. Max is 100.</param>
/// <param name="fromTime">What time frame of comments to show (hour, day, week, month, year, all).</param>
/// <returns>The listing of comments requested.</returns>
public Listing<VotableThing> GetOverview(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)
{
if ((limit < 1) || (limit > MAX_LIMIT))
throw new ArgumentOutOfRangeException("limit", "Valid range: [1," + MAX_LIMIT + "]");
string overviewUrl = string.Format(OverviewUrl, Name);
overviewUrl += string.Format("?sort={0}&limit={1}&t={2}", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));
return new Listing<VotableThing>(Reddit, overviewUrl, WebAgent);
}
/// <summary>
/// Get a listing of comments from the user sorted by <paramref name="sorting"/>, from time <paramref name="fromTime"/>
/// and limited to <paramref name="limit"/>.
/// </summary>
/// <param name="sorting">How to sort the comments (hot, new, top, controversial).</param>
/// <param name="limit">How many comments to fetch per request. Max is 100.</param>
/// <param name="fromTime">What time frame of comments to show (hour, day, week, month, year, all).</param>
/// <returns>The listing of comments requested.</returns>
public Listing<Comment> GetComments(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)
{
if ((limit < 1) || (limit > MAX_LIMIT))
throw new ArgumentOutOfRangeException("limit", "Valid range: [1," + MAX_LIMIT + "]");
string commentsUrl = string.Format(CommentsUrl, Name);
commentsUrl += string.Format("?sort={0}&limit={1}&t={2}", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));
return new Listing<Comment>(Reddit, commentsUrl, WebAgent);
}
/// <summary>
/// Get a listing of posts from the user sorted by <paramref name="sorting"/>, from time <paramref name="fromTime"/>
/// and limited to <paramref name="limit"/>.
/// </summary>
/// <param name="sorting">How to sort the posts (hot, new, top, controversial).</param>
/// <param name="limit">How many posts to fetch per request. Max is 100.</param>
/// <param name="fromTime">What time frame of posts to show (hour, day, week, month, year, all).</param>
/// <returns>The listing of posts requested.</returns>
public Listing<Post> GetPosts(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)
{
if ((limit < 1) || (limit > 100))
throw new ArgumentOutOfRangeException("limit", "Valid range: [1,100]");
string linksUrl = string.Format(LinksUrl, Name);
linksUrl += string.Format("?sort={0}&limit={1}&t={2}", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));
return new Listing<Post>(Reddit, linksUrl, WebAgent);
}
public override string ToString()
{
return Name;
}
#region Obsolete Getter Methods
[Obsolete("Use Overview property instead")]
public Listing<VotableThing> GetOverview()
{
return Overview;
}
[Obsolete("Use Comments property instead")]
public Listing<Comment> GetComments()
{
return Comments;
}
[Obsolete("Use Posts property instead")]
public Listing<Post> GetPosts()
{
return Posts;
}
[Obsolete("Use SubscribedSubreddits property instead")]
public Listing<Subreddit> GetSubscribedSubreddits()
{
return SubscribedSubreddits;
}
#endregion Obsolete Getter Methods
}
public enum Sort
{
New,
Hot,
Top,
Controversial
}
public enum FromTime
{
All,
Year,
Month,
Week,
Day,
Hour
}
}
================================================
FILE: RedditSharp/Things/Subreddit.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using HtmlAgilityPack;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RedditSharp.Utils;
namespace RedditSharp.Things
{
public class Subreddit : Thing
{
private const string SubredditPostUrl = "/r/{0}.json";
private const string SubredditNewUrl = "/r/{0}/new.json?sort=new";
private const string SubredditHotUrl = "/r/{0}/hot.json";
private const string SubredditRisingUrl = "/r/{0}/rising.json";
private const string SubredditTopUrl = "/r/{0}/top.json?t={1}";
private const string SubscribeUrl = "/api/subscribe";
private const string GetSettingsUrl = "/r/{0}/about/edit.json";
private const string GetReducedSettingsUrl = "/r/{0}/about.json";
private const string ModqueueUrl = "/r/{0}/about/modqueue.json";
private const string UnmoderatedUrl = "/r/{0}/about/unmoderated.json";
private const string FlairTemplateUrl = "/api/flairtemplate";
private const string ClearFlairTemplatesUrl = "/api/clearflairtemplates";
private const string SetUserFlairUrl = "/api/flair";
private const string StylesheetUrl = "/r/{0}/about/stylesheet.json";
private const string UploadImageUrl = "/api/upload_sr_img";
private const string FlairSelectorUrl = "/api/flairselector";
private const string AcceptModeratorInviteUrl = "/api/accept_moderator_invite";
private const string LeaveModerationUrl = "/api/unfriend";
private const string BanUserUrl = "/api/friend";
private const string AddModeratorUrl = "/api/friend";
private const string AddContributorUrl = "/api/friend";
private const string ModeratorsUrl = "/r/{0}/about/moderators.json";
private const string FrontPageUrl = "/.json";
private const string SubmitLinkUrl = "/api/submit";
private const string FlairListUrl = "/r/{0}/api/flairlist.json";
private const string CommentsUrl = "/r/{0}/comments.json";
private const string SearchUrl = "/r/{0}/search.json?q={1}&restrict_sr=on&sort={2}&t={3}";
private const string SearchUrlDate = "/r/{0}/search.json?q=timestamp:{1}..{2}&restrict_sr=on&sort={3}&syntax=cloudsearch";
private const string ModLogUrl = "/r/{0}/about/log.json";
private const string ContributorsUrl = "/r/{0}/about/contributors.json";
[JsonIgnore]
private Reddit Reddit { get; set; }
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
[JsonIgnore]
public Wiki Wiki { get; private set; }
[JsonProperty("created")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime? Created { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("description_html")]
public string DescriptionHTML { get; set; }
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("header_img")]
public string HeaderImage { get; set; }
[JsonProperty("header_title")]
public string HeaderTitle { get; set; }
[JsonProperty("over_18")]
public bool NSFW { get; set; }
[JsonProperty("public_description")]
public string PublicDescription { get; set; }
[JsonProperty("subscribers")]
public int? Subscribers { get; set; }
[JsonProperty("accounts_active")]
public int? ActiveUsers { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("url")]
[JsonConverter(typeof(UrlParser))]
public Uri Url { get; set; }
/// <summary>
/// Property determining whether the current logged in user is a moderator on this subreddit.
/// </summary>
[JsonProperty("user_is_moderator")]
public bool? UserIsModerator { get; set; }
/// <summary>
/// Property giving the moderator permissions of the logged in user on this subreddit.
/// </summary>
[JsonProperty("mod_permissions")]
[JsonConverter(typeof(ModeratorPermissionConverter))]
public ModeratorPermission ModPermissions { get; set; }
/// <summary>
/// Property determining whether the current logged in user is banned from the subreddit.
/// </summary>
[JsonProperty("user_is_banned")]
public bool? UserIsBanned { get; set; }
[JsonIgnore]
public string Name { get; set; }
public Listing<Post> GetTop(FromTime timePeriod)
{
if (Name == "/")
{
return new Listing<Post>(Reddit, "/top.json?t=" + Enum.GetName(typeof(FromTime), timePeriod).ToLower(), WebAgent);
}
return new Listing<Post>(Reddit, string.Format(SubredditTopUrl, Name, Enum.GetName(typeof(FromTime), timePeriod)).ToLower(), WebAgent);
}
public Listing<Post> Posts
{
get
{
if (Name == "/")
return new Listing<Post>(Reddit, "/.json", WebAgent);
return new Listing<Post>(Reddit, string.Format(SubredditPostUrl, Name), WebAgent);
}
}
public Listing<Comment> Comments
{
get
{
if (Name == "/")
return new Listing<Comment>(Reddit, "/comments.json", WebAgent);
return new Listing<Comment>(Reddit, string.Format(CommentsUrl, Name), WebAgent);
}
}
public Listing<Post> New
{
get
{
if (Name == "/")
return new Listing<Post>(Reddit, "/new.json", WebAgent);
return new Listing<Post>(Reddit, string.Format(SubredditNewUrl, Name), WebAgent);
}
}
public Listing<Post> Hot
{
get
{
if (Name == "/")
return new Listing<Post>(Reddit, "/.json", WebAgent);
return new Listing<Post>(Reddit, string.Format(SubredditHotUrl, Name), WebAgent);
}
}
public Listing<Post> Rising
{
get
{
if (Name == "/")
return new Listing<Post>(Reddit, "/.json", WebAgent);
return new Listing<Post>(Reddit, string.Format(SubredditRisingUrl, Name), WebAgent);
}
}
public Listing<VotableThing> ModQueue
{
get
{
return new Listing<VotableThing>(Reddit, string.Format(ModqueueUrl, Name), WebAgent);
}
}
public Listing<Post> UnmoderatedLinks
{
get
{
return new Listing<Post>(Reddit, string.Format(UnmoderatedUrl, Name), WebAgent);
}
}
public Listing<Post> Search(string terms, Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All)
{
string sort = sortE.ToString().ToLower();
string time = timeE.ToString().ToLower();
return new Listing<Post>(Reddit, string.Format(SearchUrl, Name, Uri.EscapeUriString(terms), sort, time), WebAgent);
}
public Listing<Post> Search(DateTime from, DateTime to, Sorting sortE = Sorting.New)
{
string sort = sortE.ToString().ToLower();
return new Listing<Post>(Reddit, string.Format(SearchUrlDate, Name, from.DateTimeToUnixTimestamp(), to.DateTimeToUnixTimestamp(), sort), WebAgent);
}
public SubredditSettings Settings
{
get
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
try
{
var request = WebAgent.CreateGet(string.Format(GetSettingsUrl, Name));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
return new SubredditSettings(this, Reddit, json, WebAgent);
}
catch // TODO: More specific catch
{
// Do it unauthed
var request = WebAgent.CreateGet(string.Format(GetReducedSettingsUrl, Name));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
return new SubredditSettings(this, Reddit, json, WebAgent);
}
}
}
public UserFlairTemplate[] UserFlairTemplates // Hacky, there isn't a proper endpoint for this
{
get
{
var request = WebAgent.CreatePost(FlairSelectorUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
name = Reddit.User.Name,
r = Name,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var document = new HtmlDocument();
document.LoadHtml(data);
if (document.DocumentNode.Descendants("div").First().Attributes["error"] != null)
throw new InvalidOperationException("This subreddit does not allow users to select flair.");
var templateNodes = document.DocumentNode.Descendants("li");
var list = new List<UserFlairTemplate>();
foreach (var node in templateNodes)
{
list.Add(new UserFlairTemplate
{
CssClass = node.Descendants("span").First().Attributes["class"].Value.Split(' ')[1],
Text = node.Descendants("span").First().InnerText
});
}
return list.ToArray();
}
}
public SubredditStyle Stylesheet
{
get
{
var request = WebAgent.CreateGet(string.Format(StylesheetUrl, Name));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return new SubredditStyle(Reddit, this, json, WebAgent);
}
}
public IEnumerable<ModeratorUser> Moderators
{
get
{
var request = WebAgent.CreateGet(string.Format(ModeratorsUrl, Name));
var response = request.GetResponse();
var responseString = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(responseString);
var type = json["kind"].ToString();
if (type != "UserList")
throw new FormatException("Reddit responded with an object that is not a user listing.");
var data = json["data"];
var mods = data["children"].ToArray();
var result = new ModeratorUser[mods.Length];
for (var i = 0; i < mods.Length; i++)
{
var mod = new ModeratorUser(Reddit, mods[i]);
result[i] = mod;
}
return result;
}
}
public IEnumerable<TBUserNote> UserNotes
{
get
{
return ToolBoxUserNotes.GetUserNotes(WebAgent, Name);
}
}
public Listing<Contributor> Contributors
{
get
{
return new Listing<Contributor>( Reddit, string.Format( ContributorsUrl, Name ), WebAgent );
}
}
public Subreddit Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings);
SetName();
return this;
}
public async Task<Subreddit> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["data"].ToString(), this, reddit.JsonSerializerSettings));
SetName();
return this;
}
private void SetName()
{
Name = Url.ToString();
if (Name.StartsWith("/r/"))
Name = Name.Substring(3);
if (Name.StartsWith("r/"))
Name = Name.Substring(2);
Name = Name.TrimEnd('/');
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(json);
Reddit = reddit;
WebAgent = webAgent;
Wiki = new Wiki(reddit, this, webAgent);
}
public static Subreddit GetRSlashAll(Reddit reddit)
{
var rSlashAll = new Subreddit
{
DisplayName = "/r/all",
Title = "/r/all",
Url = new Uri("/r/all", UriKind.Relative),
Name = "all",
Reddit = reddit,
WebAgent = reddit.WebAgent
};
return rSlashAll;
}
public static Subreddit GetFrontPage(Reddit reddit)
{
var frontPage = new Subreddit
{
DisplayName = "Front Page",
Title = "reddit: the front page of the internet",
Url = new Uri("/", UriKind.Relative),
Name = "/",
Reddit = reddit,
WebAgent = reddit.WebAgent
};
return frontPage;
}
public void Subscribe()
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(SubscribeUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
action = "sub",
sr = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
// Discard results
}
public void Unsubscribe()
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(SubscribeUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
action = "unsub",
sr = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
// Discard results
}
public void ClearFlairTemplates(FlairType flairType)
{
var request = WebAgent.CreatePost(ClearFlairTemplatesUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
flair_type = flairType == FlairType.Link ? "LINK_FLAIR" : "USER_FLAIR",
uh = Reddit.User.Modhash,
r = Name
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void AddFlairTemplate(string cssClass, FlairType flairType, string text, bool userEditable)
{
var request = WebAgent.CreatePost(FlairTemplateUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
css_class = cssClass,
flair_type = flairType == FlairType.Link ? "LINK_FLAIR" : "USER_FLAIR",
text = text,
text_editable = userEditable,
uh = Reddit.User.Modhash,
r = Name,
api_type = "json"
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
}
public string GetFlairText(string user)
{
var request = WebAgent.CreateGet(String.Format(FlairListUrl + "?name=" + user, Name));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return (string)json["users"][0]["flair_text"];
}
public string GetFlairCssClass(string user)
{
var request = WebAgent.CreateGet(String.Format(FlairListUrl + "?name=" + user, Name));
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(data);
return (string)json["users"][0]["flair_css_class"];
}
public void SetUserFlair(string user, string cssClass, string text)
{
var request = WebAgent.CreatePost(SetUserFlairUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
css_class = cssClass,
text = text,
uh = Reddit.User.Modhash,
r = Name,
name = user
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void UploadHeaderImage(string name, ImageType imageType, byte[] file)
{
var request = WebAgent.CreatePost(UploadImageUrl);
var formData = new MultipartFormBuilder(request);
formData.AddDynamic(new
{
name,
uh = Reddit.User.Modhash,
r = Name,
formid = "image-upload",
img_type = imageType == ImageType.PNG ? "png" : "jpg",
upload = "",
header = 1
});
formData.AddFile("file", "foo.png", file, imageType == ImageType.PNG ? "image/png" : "image/jpeg");
formData.Finish();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
// TODO: Detect errors
}
public void AddModerator(string user)
{
var request = WebAgent.CreatePost(AddModeratorUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name,
type = "moderator",
name = user
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
public void AcceptModeratorInvite()
{
var request = WebAgent.CreatePost(AcceptModeratorInviteUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
public void RemoveModerator(string id)
{
var request = WebAgent.CreatePost(LeaveModerationUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name,
type = "moderator",
id
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
public override string ToString()
{
return "/r/" + DisplayName;
}
public void AddContributor(string user)
{
var request = WebAgent.CreatePost(AddContributorUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name,
type = "contributor",
name = user
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
public void RemoveContributor(string id)
{
var request = WebAgent.CreatePost(LeaveModerationUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name,
type = "contributor",
id
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
public void BanUser(string user, string reason)
{
var request = WebAgent.CreatePost(BanUserUrl);
WebAgent.WritePostBody(request.GetRequestStream(), new
{
api_type = "json",
uh = Reddit.User.Modhash,
r = Name,
type = "banned",
id = "#banned",
name = user,
note = reason,
action = "add",
container = FullName
});
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
}
private Post Submit(SubmitData data)
{
if (Reddit.User == null)
throw new RedditException("No user logged in.");
var request = WebAgent.CreatePost(SubmitLinkUrl);
WebAgent.WritePostBody(request.GetRequestStream(), data);
var response = request.GetResponse();
var result = WebAgent.GetResponseString(response.GetResponseStream());
var json = JToken.Parse(result);
ICaptchaSolver solver = Reddit.CaptchaSolver;
if (json["json"]["errors"].Any() && json["json"]["errors"][0][0].ToString() == "BAD_CAPTCHA"
&& solver != null)
{
data.Iden = json["json"]["captcha"].ToString();
CaptchaResponse captchaResponse = solver.HandleCaptcha(new Captcha(data.Iden));
// We throw exception due to this method being expected to return a valid Post object, but we cannot
// if we got a Captcha error.
if (captchaResponse.Cancel)
throw new CaptchaFailedException("Captcha verification failed when submitting " + data.Kind + " post");
data.Captcha = captchaResponse.Answer;
return Submit(data);
}
else if (json["json"]["errors"].Any() && json["json"]["errors"][0][0].ToString() == "ALREADY_SUB")
{
throw new DuplicateLinkException(String.Format("Post failed when submitting. The following link has already been submitted: {0}", SubmitLinkUrl));
}
return new Post().Init(Reddit, json["json"], WebAgent);
}
/// <summary>
/// Submits a link post in the current subreddit using the logged-in user
/// </summary>
/// <param name="title">The title of the submission</param>
/// <param name="url">The url of the submission link</param>
public Post SubmitPost(string title, string url, string captchaId = "", string captchaAnswer = "", bool resubmit = false)
{
return
Submit(
new LinkData
{
Subreddit = Name,
UserHash = Reddit.User.Modhash,
Title = title,
URL = url,
Resubmit = resubmit,
Iden = captchaId,
Captcha = captchaAnswer
});
}
/// <summary>
/// Submits a text post in the current subreddit using the logged-in user
/// </summary>
/// <param name="title">The title of the submission</param>
/// <param name="text">The raw markdown text of the submission</param>
public Post SubmitTextPost(string title, string text, string captchaId = "", string captchaAnswer = "")
{
return
Submit(
new TextData
{
Subreddit = Name,
UserHash = Reddit.User.Modhash,
Title = title,
Text = text,
Iden = captchaId,
Captcha = captchaAnswer
});
}
/// <summary>
/// Gets the moderation log of the current subreddit
/// </summary>
public Listing<ModAction> GetModerationLog()
{
return new Listing<ModAction>(Reddit, string.Format(ModLogUrl, this.Name), WebAgent);
}
/// <summary>
/// Gets the moderation log of the current subreddit filtered by the action taken
/// </summary>
/// <param name="action">ModActionType of action performed</param>
public Listing<ModAction> GetModerationLog(ModActionType action)
{
return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + "?type={1}", Name, ModActionTypeConverter.GetRedditParamName(action)), WebAgent);
}
/// <summary>
/// Gets the moderation log of the current subreddit filtered by moderator(s) who performed the action
/// </summary>
/// <param name="mods">String array of mods to filter by</param>
public Listing<ModAction> GetModerationLog(string[] mods)
{
return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + "?mod={1}", Name, string.Join(",", mods)), WebAgent);
}
/// <summary>
/// Gets the moderation log of the current subreddit filtered by the action taken and moderator(s) who performed the action
/// </summary>
/// <param name="action">ModActionType of action performed</param>
/// <param name="mods">String array of mods to filter by</param>
/// <returns></returns>
public Listing<ModAction> GetModerationLog(ModActionType action, string[] mods)
{
return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + "?type={1}&mod={2}", Name, ModActionTypeConverter.GetRedditParamName(action), string.Join(",", mods)), WebAgent);
}
#region Obsolete Getter Methods
[Obsolete("Use Posts property instead")]
public Listing<Post> GetPosts()
{
return Posts;
}
[Obsolete("Use New property instead")]
public Listing<Post> GetNew()
{
return New;
}
[Obsolete("Use Hot property instead")]
public Listing<Post> GetHot()
{
return Hot;
}
[Obsolete("Use ModQueue property instead")]
public Listing<VotableThing> GetModQueue()
{
return ModQueue;
}
[Obsolete("Use UnmoderatedLinks property instead")]
public Listing<Post> GetUnmoderatedLinks()
{
return UnmoderatedLinks;
}
[Obsolete("Use Settings property instead")]
public SubredditSettings GetSettings()
{
return Settings;
}
[Obsolete("Use UserFlairTemplates property instead")]
public UserFlairTemplate[] GetUserFlairTemplates() // Hacky, there isn't a proper endpoint for this
{
return UserFlairTemplates;
}
[Obsolete("Use Stylesheet property instead")]
public SubredditStyle GetStylesheet()
{
return Stylesheet;
}
[Obsolete("Use Moderators property instead")]
public IEnumerable<ModeratorUser> GetModerators()
{
return Moderators;
}
#endregion Obsolete Getter Methods
}
}
================================================
FILE: RedditSharp/Things/Thing.cs
================================================
using System;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
namespace RedditSharp.Things
{
public class Thing
{
public static Thing Parse(Reddit reddit, JToken json, IWebAgent webAgent)
{
var kind = json["kind"].ValueOrDefault<string>();
switch (kind)
{
case "t1":
return new Comment().Init(reddit, json, webAgent, null);
case "t2":
return new RedditUser().Init(reddit, json, webAgent);
case "t3":
return new Post().Init(reddit, json, webAgent);
case "t4":
return new PrivateMessage().Init(reddit, json, webAgent);
case "t5":
return new Subreddit().Init(reddit, json, webAgent);
case "modaction":
return new ModAction().Init(reddit, json, webAgent);
default:
return null;
}
}
// if we can't determine the type of thing by "kind", try by type
public static Thing Parse<T>(Reddit reddit, JToken json, IWebAgent webAgent) where T : Thing
{
Thing result = Parse(reddit, json, webAgent);
if (result == null)
{
if (typeof(T) == typeof(WikiPageRevision))
{
return new WikiPageRevision().Init(reddit, json, webAgent);
}
else if (typeof(T) == typeof(ModAction))
{
return new ModAction().Init(reddit, json, webAgent);
}
else if (typeof(T) == typeof(Contributor))
{
return new Contributor().Init(reddit, json, webAgent);
}
}
return result;
}
internal void Init(JToken json)
{
if (json == null)
return;
var data = json["name"] == null ? json["data"] : json;
FullName = data["name"].ValueOrDefault<string>();
Id = data["id"].ValueOrDefault<string>();
Kind = json["kind"].ValueOrDefault<string>();
FetchedAt = DateTime.Now;
}
public virtual string Shortlink
{
get { return "http://redd.it/" + Id; }
}
public string Id { get; set; }
public string FullName { get; set; }
public string Kind { get; set; }
/// <summary>
/// The time at which this object was fetched from reddit servers.
/// </summary>
public DateTime FetchedAt { get; private set; }
/// <summary>
/// Gets the time since last fetch from reddit servers.
/// </summary>
public TimeSpan TimeSinceFetch
{
get
{
return DateTime.Now - FetchedAt;
}
}
public static async Task<Thing> ParseAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
var kind = json["kind"].ValueOrDefault<string>();
switch (kind)
{
case "t1":
return await new Comment().InitAsync(reddit, json, webAgent, null);
case "t2":
return await new RedditUser().InitAsync(reddit, json, webAgent);
case "t3":
return await new Post().InitAsync(reddit, json, webAgent);
case "t4":
return await new PrivateMessage().InitAsync(reddit, json, webAgent);
case "t5":
return await new Subreddit().InitAsync(reddit, json, webAgent);
case "modaction":
return await new ModAction().InitAsync(reddit, json, webAgent);
default:
return null;
}
}
// if we can't determine the type of thing by "kind", try by type
public static async Task<Thing> ParseAsync<T>(Reddit reddit, JToken json, IWebAgent webAgent) where T : Thing
{
Thing result = await ParseAsync(reddit, json, webAgent);
if (result == null)
{
if (typeof(T) == typeof(WikiPageRevision))
{
return await new WikiPageRevision().InitAsync(reddit, json, webAgent);
}
else if (typeof(T) == typeof(ModAction))
{
return await new ModAction().InitAsync(reddit, json, webAgent);
}
}
return result;
}
}
}
================================================
FILE: RedditSharp/Things/VotableThing.cs
================================================
using System;
using System.Threading.Tasks;
using System.Linq;
using System.Security.Authentication;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class VotableThing : CreatedThing
{
public enum VoteType
{
Upvote = 1,
None = 0,
Downvote = -1
}
public enum ReportType
{
Spam = 0,
VoteManipulation = 1,
PersonalInformation = 2,
SexualizingMinors = 3,
BreakingReddit = 4,
Other = 5
}
public enum DistinguishType
{
Moderator,
Admin,
Special,
None
}
private const string VoteUrl = "/api/vote";
private const string SaveUrl = "/api/save";
private const string UnsaveUrl = "/api/unsave";
private const string ReportUrl = "/api/report";
private const string DistinguishUrl = "/api/distinguish";
[JsonIgnore]
private IWebAgent WebAgent { get; set; }
[JsonIgnore]
private Reddit Reddit { get; set; }
protected VotableThing Init(Reddit reddit, IWebAgent webAgent, JToken json)
{
CommonInit(reddit, webAgent, json);
JsonConvert.PopulateObject(json["data"].ToString(), this, Reddit.JsonSerializerSettings);
return this;
}
protected async Task<VotableThing> InitAsync(Reddit reddit, IWebAgent webAgent, JToken json)
{
CommonInit(reddit, webAgent, json);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json["data"].ToString(), this, Reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, IWebAgent webAgent, JToken json)
{
base.Init(reddit, json);
Reddit = reddit;
WebAgent = webAgent;
}
[JsonProperty("downs")]
public int Downvotes { get; set; }
[JsonProperty("ups")]
public int Upvotes { get; set; }
[JsonProperty("score")]
public int Score { get; set; }
[JsonProperty("saved")]
public bool Saved { get; set; }
[JsonProperty("distinguished")]
[JsonConverter(typeof(DistinguishConverter))]
public DistinguishType Distinguished { get; set; }
/// <summary>
/// True if the logged in user has upvoted this.
/// False if they have not.
/// Null if they have not cast a vote.
/// </summary>
[JsonProperty("likes")]
public bool? Liked { get; set; }
/// <summary>
/// Gets or sets the vote for the current VotableThing.
/// </summary>
[JsonIgnore]
public VoteType Vote
{
get
{
switch (this.Liked)
{
case true: return VoteType.Upvote;
case false: return VoteType.Downvote;
default: return VoteType.None;
}
}
set { this.SetVote(value); }
}
public void Upvote()
{
this.SetVote(VoteType.Upvote);
}
public void Downvote()
{
this.SetVote(VoteType.Downvote);
}
public void SetVote(VoteType type)
{
if (this.Vote == type) return;
var request = WebAgent.CreatePost(VoteUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
dir = (int)type,
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
if (Liked == true) Upvotes--;
if (Liked == false) Downvotes--;
switch(type)
{
case VoteType.Upvote: Liked = true; Upvotes++; return;
case VoteType.None: Liked = null; return;
case VoteType.Downvote: Liked = false; Downvotes++; return;
}
}
public void Save()
{
var request = WebAgent.CreatePost(SaveUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
Saved = true;
}
public void Unsave()
{
var request = WebAgent.CreatePost(UnsaveUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
Saved = false;
}
public void ClearVote()
{
var request = WebAgent.CreatePost(VoteUrl);
var stream = request.GetRequestStream();
WebAgent.WritePostBody(stream, new
{
dir = 0,
id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void Report(ReportType reportType, string otherReason = null)
{
var request = WebAgent.CreatePost(ReportUrl);
var stream = request.GetRequestStream();
string reportReason;
switch (reportType)
{
case ReportType.Spam:
reportReason = "spam"; break;
case ReportType.VoteManipulation:
reportReason = "vote manipulation"; break;
case ReportType.PersonalInformation:
reportReason = "personal information"; break;
case ReportType.BreakingReddit:
reportReason = "breaking reddit"; break;
case ReportType.SexualizingMinors:
reportReason = "sexualizing minors"; break;
default:
reportReason = "other"; break;
}
WebAgent.WritePostBody(stream, new
{
api_type = "json",
reason = reportReason,
other_reason = otherReason ?? "",
thing_id = FullName,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
}
public void Distinguish(DistinguishType distinguishType)
{
if (Reddit.User == null)
throw new AuthenticationException("No user logged in.");
var request = WebAgent.CreatePost(DistinguishUrl);
var stream = request.GetRequestStream();
string how;
switch (distinguishType)
{
case DistinguishType.Admin:
how = "admin";
break;
case DistinguishType.Moderator:
how = "yes";
break;
case DistinguishType.None:
how = "no";
break;
default:
how = "special";
break;
}
WebAgent.WritePostBody(stream, new
{
how,
id = Id,
uh = Reddit.User.Modhash
});
stream.Close();
var response = request.GetResponse();
var data = WebAgent.GetResponseString(response.GetResponseStream());
var json = JObject.Parse(data);
if (json["jquery"].Count(i => i[0].Value<int>() == 11 && i[1].Value<int>() == 12) == 0)
throw new AuthenticationException("You are not permitted to distinguish this comment.");
}
internal class DistinguishConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DistinguishType) || objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
var value = token.Value<string>();
if (value == null)
return DistinguishType.None;
switch (value)
{
case "moderator": return DistinguishType.Moderator;
case "admin": return DistinguishType.Admin;
case "special": return DistinguishType.Special;
default: return DistinguishType.None;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var d = (DistinguishType)value;
if (d == DistinguishType.None)
{
writer.WriteNull();
return;
}
writer.WriteValue(d.ToString().ToLower());
}
}
}
}
================================================
FILE: RedditSharp/Things/WikiPageRevision.cs
================================================
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RedditSharp.Things
{
public class WikiPageRevision : Thing
{
[JsonProperty("id")]
new public string Id { get; private set; }
[JsonProperty("timestamp")]
[JsonConverter(typeof(UnixTimestampConverter))]
public DateTime? TimeStamp { get; set; }
[JsonProperty("reason")]
public string Reason { get; private set; }
[JsonProperty("page")]
public string Page { get; private set; }
[JsonIgnore]
public RedditUser Author { get; set; }
protected internal WikiPageRevision() { }
internal WikiPageRevision Init(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);
return this;
}
internal async Task<WikiPageRevision> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)
{
CommonInit(reddit, json, webAgent);
await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings));
return this;
}
private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
{
base.Init(json);
Author = new RedditUser().Init(reddit, json["author"], webAgent);
}
}
}
================================================
FILE: RedditSharp/ToolBoxUserNotes.cs
================================================
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;
namespace RedditSharp
{
public static class ToolBoxUserNotes
{
private const string ToolBoxUserNotesWiki = "/r/{0}/wiki/usernotes";
public static IEnumerable<TBUserNote> GetUserNotes(IWebAgent webAgent, string subName)
{
var request = webAgent.CreateGet(String.Format(ToolBoxUserNotesWiki, subName));
var reqResponse = webAgent.ExecuteRequest(request);
var response = JObject.Parse(reqResponse["data"]["content_md"].Value<string>());
int version = response["ver"].Value<int>();
string[] mods = response["constants"]["users"].Values<string>().ToArray();
string[] warnings = response["constants"]["warnings"].Values<string>().ToArray();
if (version < 6) throw new ToolBoxUserNotesException("Unsupported ToolBox version");
try
{
var data = Convert.FromBase64String(response["blob"].Value<string>());
string uncompressed;
using (System.IO.MemoryStream compressedStream = new System.IO.MemoryStream(data))
{
compressedStream.ReadByte();
compressedStream.ReadByte(); //skips first to bytes to fix zlib block size
using (DeflateStream blobStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
{
using (var decompressedReader = new System.IO.StreamReader(blobStream))
{
uncompressed = decompressedReader.ReadToEnd();
}
}
}
JObject users = JObject.Parse(uncompressed);
List<TBUserNote> toReturn = new List<TBUserNote>();
foreach (KeyValuePair<string, JToken> user in users)
{
var x = user.Value;
foreach (JToken note in x["ns"].Children())
{
TBUserNote uNote = new TBUserNote();
uNote.AppliesToUsername = user.Key;
uNote.SubName = subName;
uNote.SubmitterIndex = note["m"].Value<int>();
uNote.Submitter = mods[uNote.SubmitterIndex];
uNote.NoteTypeIndex = note["w"].Value<int>();
uNote.NoteType = warnings[uNote.NoteTypeIndex];
uNote.Message = note["n"].Value<string>();
uNote.Timestamp = UnixTimeStamp.UnixTimeStampToDateTime(note["t"].Value<long>());
uNote.Url = UnsquashLink(subName, note["l"].ValueOrDefault<string>());
toReturn.Add(uNote);
}
}
return toReturn;
}
catch (Exception e)
{
throw new ToolBoxUserNotesException("An error occured while processing Usernotes wiki. See inner exception for details", e);
}
}
public static string UnsquashLink(string subreddit, string permalink)
{
var link = "https://reddit.com/r/" + subreddit + "/";
if (string.IsNullOrEmpty(permalink))
{
return link;
}
var linkParams = permalink.Split(',');
if (linkParams[0] == "l")
{
link += "comments/" + linkParams[1] + "/";
if (linkParams.Length > 2)
link += "-/" + linkParams[2] + "/";
}
else if (linkParams[0] == "m")
{
link += "message/messages/" + linkParams[1];
}
return link;
}
}
}
================================================
FILE: RedditSharp/ToolBoxUserNotesException.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedditSharp
{
class ToolBoxUserNotesException : Exception
{
public ToolBoxUserNotesException()
{
}
public ToolBoxUserNotesException(string message)
: base(message)
{
}
public ToolBoxUserNotesException(string message, Exception inner)
: base(message, inner)
{
}
}
}
================================================
FILE: RedditSharp/UnixTimeStamp.cs
================================================
using System;
namespace RedditSharp
{
public static class UnixTimeStamp
{
public static DateTime UnixTimeStampToDateTime(this long unixTimeStamp)
{
// Unix timestamp is seconds past epoch
var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp);
return dtDateTime;
}
}
}
================================================
FILE: RedditSharp/UnixTimestampConverter.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace RedditSharp
{
public class UnixTimestampConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(double) || objectType == typeof(DateTime);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
return token.Value<long>().UnixTimeStampToDateTime();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value);
}
}
}
================================================
FILE: RedditSharp/UrlParser.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace RedditSharp
{
class UrlParser : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(String) || objectType == typeof(Uri);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.String)
{
if (Type.GetType("Mono.Runtime") == null)
return new Uri(token.Value<string>(), UriKind.RelativeOrAbsolute);
if (token.Value<string>().StartsWith("/"))
return new Uri(token.Value<string>(), UriKind.Relative);
return new Uri(token.Value<string>(), UriKind.RelativeOrAbsolute);
}
else
return token.Value<Uri>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value);
}
}
}
================================================
FILE: RedditSharp/Utils/DateTimeExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedditSharp.Utils
{
internal static class DateTimeExtensions
{
public static double DateTimeToUnixTimestamp(this DateTime dateTime)
{
double time = (dateTime - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds;
return Convert.ToInt32(time);
}
}
}
================================================
FILE: RedditSharp/WebAgent.cs
================================================
using System;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Web;
using Newtonsoft.Json.Linq;
namespace RedditSharp
{
public class WebAgent : IWebAgent
{
/// <summary>
/// Additional values to append to the default RedditSharp user agent.
/// </summary>
public static string UserAgent { get; set; }
/// <summary>
/// It is strongly advised that you leave this enabled. Reddit bans excessive
/// requests with extreme predjudice.
/// </summary>
public static bool EnableRateLimit { get; set; }
public static string Protocol { get; set; }
/// <summary>
/// It is strongly advised that you leave this set to Burst or Pace. Reddit bans excessive
/// requests with extreme predjudice.
/// </summary>
public static RateLimitMode RateLimit { get; set; }
/// <summary>
/// The method by which the WebAgent will limit request rate
/// </summary>
public enum RateLimitMode
{
/// <summary>
/// Limits requests to one every two seconds
/// </summary>
Pace,
/// <summary>
/// Restricts requests to five per ten seconds
/// </summary>
SmallBurst,
/// <summary>
/// Restricts requests to thirty per minute
/// </summary>
Burst,
/// <summary>
/// Does not restrict request rate. ***NOT RECOMMENDED***
/// </summary>
None
}
/// <summary>
/// The root domain RedditSharp uses to address Reddit.
/// www.reddit.com by default
/// </summary>
public static string RootDomain { get; set; }
/// <summary>
/// Used to make calls against Reddit's API using OAuth23
/// </summary>
public string AccessToken { get; set; }
public CookieContainer Cookies { get; set; }
public string AuthCookie { get; set; }
private static DateTime _lastRequest;
private static DateTime _burstStart;
private static int _requestsThisBurst;
/// <summary>
/// UTC DateTime of last request made to Reddit API
/// </summary>
public DateTime LastRequest
{
get { return _lastRequest; }
}
/// <summary>
/// UTC DateTime of when the last burst started
/// </summary>
public DateTime BurstStart
{
get { return _burstStart; }
}
/// <summary>
/// Number of requests made during the current burst
/// </summary>
public int RequestsThisBurst
{
get { return _requestsThisBurst; }
}
public virtual JToken CreateAndExecuteRequest(string url)
{
Uri uri;
if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
{
if (!Uri.TryCreate(String.Format("{0}://{1}{2}", Protocol, RootDomain, url), UriKind.Absolute, out uri))
throw new Exception("Could not parse Uri");
}
var request = CreateGet(uri);
try { return ExecuteRequest(request); }
catch (Exception)
{
var tempProtocol = Protocol;
var tempRootDomain = RootDomain;
Protocol = "http";
RootDomain = "www.reddit.com";
var retval = CreateAndExecuteRequest(url);
Protocol = tempProtocol;
RootDomain = tempRootDomain;
return retval;
}
}
/// <summary>
/// Executes the web request and handles errors in the response
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual JToken ExecuteRequest(HttpWebRequest request)
{
EnforceRateLimit();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
var result = GetResponseString(response.GetResponseStream());
JToken json;
if (!string.IsNullOrEmpty(result))
{
json = JToken.Parse(result);
try
{
if (json["json"] != null)
{
json = json["json"]; //get json object if there is a root node
}
if (json["error"] != null)
{
switch (json["error"].ToString())
{
case "404":
throw new Exception("File Not Found");
case "403":
throw new Exception("Restricted");
case "invalid_grant":
//Refresh authtoken
//AccessToken = authProvider.GetRefreshToken();
//ExecuteRequest(request);
break;
}
}
}
catch
{
}
}
else
{
json = JToken.Parse("{'method':'" + response.Method + "','uri':'" + response.ResponseUri.AbsoluteUri + "','status':'" + response.StatusCode.ToString() + "'}");
}
return json;
}
[MethodImpl(MethodImplOptions.Synchronized)]
protected virtual void EnforceRateLimit()
{
switch (RateLimit)
{
case RateLimitMode.Pace:
while ((DateTime.UtcNow - _lastRequest).TotalSeconds < 2)// Rate limiting
Thread.Sleep(250);
_lastRequest = DateTime.UtcNow;
break;
case RateLimitMode.SmallBurst:
if (_requestsThisBurst == 0 || (DateTime.UtcNow - _burstStart).TotalSeconds >= 10) //this is first request OR the burst expired
{
_burstStart = DateTime.UtcNow;
_requestsThisBurst = 0;
}
if (_requestsThisBurst >= 5) //limit has been reached
{
while ((DateTime.UtcNow - _burstStart).TotalSeconds < 10)
Thread.Sleep(250);
_burstStart = DateTime.UtcNow;
_requestsThisBurst = 0;
}
_lastRequest = DateTime.UtcNow;
_requestsThisBurst++;
break;
case RateLimitMode.Burst:
if (_requestsThisBurst == 0 || (DateTime.UtcNow - _burstStart).TotalSeconds >= 60) //this is first request OR the burst expired
{
_burstStart = DateTime.UtcNow;
_requestsThisBurst = 0;
}
if (_requestsThisBurst >= 30) //limit has been reached
{
while ((DateTime.UtcNow - _burstStart).TotalSeconds < 60)
Thread.Sleep(250);
_burstStart = DateTime.UtcNow;
_requestsThisBurst = 0;
}
_lastRequest = DateTime.UtcNow;
_requestsThisBurst++;
break;
}
}
public virtual HttpWebRequest CreateRequest(string url, string method)
{
EnforceRateLimit();
bool prependDomain;
// IsWellFormedUriString returns true on Mono for some reason when using a string like "/api/me"
if (Type.GetType("Mono.Runtime") != null)
prependDomain = !url.StartsWith("http://") && !url.StartsWith("https://");
else
prependDomain = !Uri.IsWellFormedUriString(url, UriKind.Absolute);
HttpWebRequest request;
if (prependDomain)
request = (HttpWebRequest)WebRequest.Create(String.Format("{0}://{1}{2}", Protocol, RootDomain, url));
else
request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = Cookies;
if (Type.GetType("Mono.Runtime") != null)
{
var cookieHeader = Cookies.GetCookieHeader(new Uri("http://reddit.com"));
request.Headers.Set("Cookie", cookieHeader);
}
if (RootDomain == "oauth.reddit.com")// use OAuth
{
request.Headers.Set("Authorization", "bearer " + AccessToken);//Must be included in OAuth calls
}
request.Method = method;
request.UserAgent = UserAgent + " - with RedditSharp by /u/sircmpwn";
return request;
}
protected virtual HttpWebRequest CreateRequest(Uri uri, string method)
{
EnforceRateLimit();
var request = (HttpWebRequest)WebRequest.Create(uri);
request.CookieContainer = Cookies;
if (Type.GetType("Mono.Runtime") != null)
{
var cookieHeader = Cookies.GetCookieHeader(new Uri("http://reddit.com"));
request.Headers.Set("Cookie", cookieHeader);
}
if (RootDomain == "oauth.reddit.com")// use OAuth
{
request.Headers.Set("Authorization", "bearer " + AccessToken);//Must be included in OAuth calls
}
request.Method = method;
request.UserAgent = UserAgent + " - with RedditSharp by /u/sircmpwn";
return request;
}
public virtual HttpWebRequest CreateGet(string url)
{
return CreateRequest(url, "GET");
}
private HttpWebRequest CreateGet(Uri url)
{
return CreateRequest(url, "GET");
}
public virtual HttpWebRequest CreatePost(string url)
{
var request = CreateRequest(url, "POST");
request.ContentType = "application/x-www-form-urlencoded";
return request;
}
public virtual string GetResponseString(Stream stream)
{
var data = new StreamReader(stream).ReadToEnd();
stream.Close();
return data;
}
public virtual void WritePostBody(Stream stream, object data, params string[] additionalFields)
{
var type = data.GetType();
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
string value = "";
foreach (var property in properties)
{
var attr = property.GetCustomAttributes(typeof(RedditAPINameAttribute), false).FirstOrDefault() as RedditAPINameAttribute;
string name = attr == null ? property.Name : attr.Name;
var entry = Convert.ToString(property.GetValue(data, null));
value += name + "=" + HttpUtility.UrlEncode(entry).Replace(";", "%3B").Replace("&", "%26") + "&";
}
for (int i = 0; i < additionalFields.Length; i += 2)
{
var entry = Convert.ToString(additionalFields[i + 1]) ?? string.Empty;
value += additionalFields[i] + "=" + HttpUtility.UrlEncode(entry).Replace(";", "%3B").Replace("&", "%26") + "&";
}
value = value.Remove(value.Length - 1); // Remove trailing &
var raw = Encoding.UTF8.GetBytes(value);
stream.Write(raw, 0, raw.Length);
stream.Close();
}
}
}
================================================
FILE: RedditSharp/Wiki.cs
================================================
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
using RedditSharp.Things;
namespace RedditSharp
{
using System;
public class Wiki
{
private Reddit Reddit { get; set; }
private Subreddit Subreddit { get; set; }
private IWebAgent WebAgent { get; set; }
private const string GetWikiPageUrl = "/r/{0}/wiki/{1}.json?v={2}";
private const string GetWikiPagesUrl = "/r/{0}/wiki/pages.json";
private const string WikiPageEditUrl = "/r/{0}/api/wiki/edit";
private const string HideWikiPageUrl = "/r/{0}/api/wiki/hide";
private const string RevertWikiPageUrl = "/r/{0}/api/wiki/revert";
private const string WikiPageAllowEditorAddUrl = "/r/{0}/api/wiki/alloweditor/add";
private const string WikiPageAllowEditorDelUrl = "/r/{0}/api/wiki/alloweditor/del";
private const string WikiPageSettingsUrl = "/r/{0}/wiki/settings/{1}.json";
private const string WikiRevisionsUrl = "/r/{0}/wiki/revisions.json";
private const string WikiPageRevisionsUrl = "/r/{0}/wiki/revisions/{1}.json";
private const string WikiPageDiscussionsUrl = "/r/{0}/wiki/discussions/{1}.json";
public IEnumerable<string> PageNames
{
get
{
var request = WebAgent.CreateGet(string.Format(GetWikiPagesUrl, Subreddit.Name));
var response = request.GetResponse();
string json = WebAgent.GetResponseString(response.GetResponseStream());
return JObject.Parse(json)["data"].Values<string>();
}
}
public Listing<WikiPageRevision> Revisions
{
get
{
return new Listing<WikiPageRevision>(Reddit, string.Format(WikiRevisionsUrl, Subreddit.Name), WebAgent);
}
}
protected internal Wiki(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)
{
Reddit = reddit;
Subreddit = subreddit;
WebAgent = webAgent;
}
public WikiPage GetPage(string
gitextract_p863b84s/
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── RedditSharp/
│ ├── AuthProvider.cs
│ ├── Captcha.cs
│ ├── CaptchaFailedException.cs
│ ├── CaptchaResponse.cs
│ ├── ConsoleCaptchaSolver.cs
│ ├── Domain.cs
│ ├── DuplicateLinkException.cs
│ ├── Extensions.cs
│ ├── FlairTemplate.cs
│ ├── FlairType.cs
│ ├── ICaptchaSolver.cs
│ ├── IWebAgent.cs
│ ├── LinkData.cs
│ ├── Listing.cs
│ ├── ModActionType.cs
│ ├── ModeratorPermission.cs
│ ├── ModeratorUser.cs
│ ├── MultipartFormBuilder.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── RateLimitException.cs
│ ├── Reddit.cs
│ ├── RedditAPINameAttribute.cs
│ ├── RedditException.cs
│ ├── RedditSharp.csproj
│ ├── SpamFilterSettings.cs
│ ├── SubmitData.cs
│ ├── SubredditImage.cs
│ ├── SubredditSettings.cs
│ ├── SubredditStyle.cs
│ ├── TBUserNote.cs
│ ├── TextData.cs
│ ├── Things/
│ │ ├── AuthenticatedUser.cs
│ │ ├── Comment.cs
│ │ ├── Contributor.cs
│ │ ├── CreatedThing.cs
│ │ ├── ModAction.cs
│ │ ├── Post.cs
│ │ ├── PrivateMessage.cs
│ │ ├── RedditUser.cs
│ │ ├── Subreddit.cs
│ │ ├── Thing.cs
│ │ ├── VotableThing.cs
│ │ └── WikiPageRevision.cs
│ ├── ToolBoxUserNotes.cs
│ ├── ToolBoxUserNotesException.cs
│ ├── UnixTimeStamp.cs
│ ├── UnixTimestampConverter.cs
│ ├── UrlParser.cs
│ ├── Utils/
│ │ └── DateTimeExtensions.cs
│ ├── WebAgent.cs
│ ├── Wiki.cs
│ ├── WikiPage.cs
│ └── WikiPageSettings.cs
├── RedditSharp.sln
└── TestRedditSharp/
├── App.config
├── Program.cs
├── Properties/
│ └── AssemblyInfo.cs
└── TestRedditSharp.csproj
SYMBOL INDEX (353 symbols across 52 files)
FILE: RedditSharp/AuthProvider.cs
class AuthProvider (line 10) | public class AuthProvider
type Scope (line 19) | [Flags]
method AuthProvider (line 54) | public AuthProvider(string clientId, string clientSecret, string redir...
method AuthProvider (line 68) | public AuthProvider(string clientId, string clientSecret, string redir...
method GetAuthUrl (line 83) | public string GetAuthUrl(string state, Scope scope, bool permanent = f...
method GetOAuthToken (line 94) | public string GetOAuthToken(string code, bool isRefresh = false)
method GetOAuthToken (line 141) | public string GetOAuthToken(string username, string password)
method RevokeToken (line 172) | public void RevokeToken(string token, bool isRefresh)
method GetUser (line 197) | [Obsolete("Reddit.InitOrUpdateUser is preferred")]
FILE: RedditSharp/Captcha.cs
type Captcha (line 5) | public struct Captcha
method Captcha (line 12) | internal Captcha(string id)
FILE: RedditSharp/CaptchaFailedException.cs
class CaptchaFailedException (line 5) | public class CaptchaFailedException : RedditException
method CaptchaFailedException (line 7) | public CaptchaFailedException()
method CaptchaFailedException (line 12) | public CaptchaFailedException(string message)
method CaptchaFailedException (line 18) | public CaptchaFailedException(string message, Exception inner)
FILE: RedditSharp/CaptchaResponse.cs
class CaptchaResponse (line 3) | public class CaptchaResponse
method CaptchaResponse (line 9) | public CaptchaResponse(string answer = null)
FILE: RedditSharp/ConsoleCaptchaSolver.cs
class ConsoleCaptchaSolver (line 5) | public class ConsoleCaptchaSolver : ICaptchaSolver
method HandleCaptcha (line 7) | public CaptchaResponse HandleCaptcha(Captcha captcha)
FILE: RedditSharp/Domain.cs
class Domain (line 8) | public class Domain
method Domain (line 48) | protected internal Domain(Reddit reddit, Uri domain, IWebAgent webAgent)
method ToString (line 55) | public override string ToString()
FILE: RedditSharp/DuplicateLinkException.cs
class DuplicateLinkException (line 11) | public class DuplicateLinkException : RedditException
method DuplicateLinkException (line 13) | public DuplicateLinkException()
method DuplicateLinkException (line 17) | public DuplicateLinkException(string message)
method DuplicateLinkException (line 22) | public DuplicateLinkException(string message, Exception inner)
FILE: RedditSharp/Extensions.cs
class Extensions (line 6) | public static class Extensions
method ValueOrDefault (line 8) | public static T ValueOrDefault<T>(this IEnumerable<JToken> enumerable)
FILE: RedditSharp/FlairTemplate.cs
class UserFlairTemplate (line 3) | public class UserFlairTemplate // TODO: Consider using this class to set...
FILE: RedditSharp/FlairType.cs
type FlairType (line 3) | public enum FlairType
FILE: RedditSharp/ICaptchaSolver.cs
type ICaptchaSolver (line 3) | public interface ICaptchaSolver
method HandleCaptcha (line 5) | CaptchaResponse HandleCaptcha(Captcha captcha);
FILE: RedditSharp/IWebAgent.cs
type IWebAgent (line 7) | public interface IWebAgent
method CreateRequest (line 12) | HttpWebRequest CreateRequest(string url, string method);
method CreateGet (line 13) | HttpWebRequest CreateGet(string url);
method CreatePost (line 14) | HttpWebRequest CreatePost(string url);
method GetResponseString (line 15) | string GetResponseString(Stream stream);
method WritePostBody (line 16) | void WritePostBody(Stream stream, object data, params string[] additio...
method CreateAndExecuteRequest (line 17) | JToken CreateAndExecuteRequest(string url);
method ExecuteRequest (line 18) | JToken ExecuteRequest(HttpWebRequest request);
FILE: RedditSharp/LinkData.cs
class LinkData (line 3) | internal class LinkData : SubmitData
method LinkData (line 11) | internal LinkData()
FILE: RedditSharp/Listing.cs
type Sorting (line 8) | public enum Sorting
type TimeSorting (line 16) | public enum TimeSorting
class Listing (line 26) | public class Listing<T> : IEnumerable<T> where T : Thing
method Listing (line 43) | internal Listing(Reddit reddit, string url, IWebAgent webAgent)
method GetEnumerator (line 57) | public IEnumerator<T> GetEnumerator(int limitPerRequest, int maximumLi...
method GetEnumerator (line 66) | public IEnumerator<T> GetEnumerator()
method GetEnumerator (line 75) | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnume...
method GetListing (line 85) | public IEnumerable<T> GetListing(int maximumLimit)
method GetListing (line 97) | public IEnumerable<T> GetListing(int maximumLimit, int limitPerRequest)
method GetEnumerator (line 110) | private static IEnumerable<T> GetEnumerator(IEnumerator<T> enumerator)
class ListingEnumerator (line 119) | private class ListingEnumerator<T> : IEnumerator<T> where T : Thing
method ListingEnumerator (line 136) | public ListingEnumerator(Listing<T> listing, int limitPerRequest, in...
method FetchNextPage (line 155) | private void FetchNextPage()
method Parse (line 202) | private void Parse(JToken json)
method Dispose (line 217) | public void Dispose()
method MoveNext (line 227) | public bool MoveNext()
method Reset (line 257) | public void Reset()
FILE: RedditSharp/ModActionType.cs
type ModActionType (line 6) | public enum ModActionType
class ModActionTypeConverter (line 46) | public class ModActionTypeConverter : JsonConverter
method GetRedditParamName (line 52) | public static string GetRedditParamName(ModActionType action)
method CanConvert (line 57) | public override bool CanConvert(Type objectType)
method ReadJson (line 62) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method WriteJson (line 76) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
FILE: RedditSharp/ModeratorPermission.cs
type ModeratorPermission (line 8) | [Flags]
class ModeratorPermissionConverter (line 21) | internal class ModeratorPermissionConverter : JsonConverter
method WriteJson (line 23) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
method ReadJson (line 28) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method CanConvert (line 42) | public override bool CanConvert(Type objectType)
FILE: RedditSharp/ModeratorUser.cs
class ModeratorUser (line 6) | public class ModeratorUser
method ModeratorUser (line 8) | public ModeratorUser(Reddit reddit, JToken json)
method ToString (line 23) | public override string ToString()
FILE: RedditSharp/MultipartFormBuilder.cs
class MultipartFormBuilder (line 7) | public class MultipartFormBuilder
method MultipartFormBuilder (line 15) | public MultipartFormBuilder(HttpWebRequest request)
method CreateRandomBoundary (line 26) | private string CreateRandomBoundary()
method AddDynamic (line 37) | public void AddDynamic(object data)
method AddString (line 48) | public void AddString(string name, string value)
method AddFile (line 55) | public void AddFile(string name, string filename, byte[] value, string...
method Finish (line 66) | public void Finish()
FILE: RedditSharp/RateLimitException.cs
class RateLimitException (line 5) | public class RateLimitException : Exception
method RateLimitException (line 9) | public RateLimitException(TimeSpan timeToReset)
FILE: RedditSharp/Reddit.cs
class Reddit (line 16) | public class Reddit
method Reddit (line 46) | static Reddit()
method Reddit (line 94) | public Reddit()
method Reddit (line 97) | public Reddit(bool useSsl)
method Reddit (line 111) | public Reddit(DefaultWebAgent.RateLimitMode limitMode, bool useSsl = t...
method Reddit (line 119) | public Reddit(string username, string password, bool useSsl = true)
method Reddit (line 125) | public Reddit(string accessToken)
method Reddit (line 136) | public Reddit(IWebAgent agent)
method Reddit (line 151) | public Reddit(IWebAgent agent, bool initUser)
method LogIn (line 170) | public AuthenticatedUser LogIn(string username, string password, bool ...
method GetUser (line 212) | public RedditUser GetUser(string name)
method InitOrUpdateUser (line 226) | public void InitOrUpdateUser()
method GetMe (line 237) | [Obsolete("Use User property instead")]
method GetSubreddit (line 245) | public Subreddit GetSubreddit(string name)
method GetSubredditAsync (line 260) | public async Task<Subreddit> GetSubredditAsync(string name)
method GetDomain (line 270) | public Domain GetDomain(string domain)
method GetToken (line 278) | public JToken GetToken(Uri uri)
method GetPost (line 293) | public Post GetPost(Uri uri)
method ComposePrivateMessage (line 309) | public void ComposePrivateMessage(string subject, string body, string ...
method RegisterAccount (line 362) | public AuthenticatedUser RegisterAccount(string userName, string passw...
method GetThingByFullname (line 380) | public Thing GetThingByFullname(string fullname)
method GetComment (line 389) | public Comment GetComment(string subreddit, string name, string linkName)
method GetComment (line 407) | public Comment GetComment(Uri uri)
method SearchByUrl (line 419) | public Listing<T> SearchByUrl<T>(string url) where T : Thing
method Search (line 425) | public Listing<T> Search<T>(string query, Sorting sortE = Sorting.Rele...
method SearchByTimestamp (line 432) | public Listing<T> SearchByTimestamp<T>(DateTime from, DateTime to, str...
method GetNewSubreddits (line 451) | public Listing<Subreddit> GetNewSubreddits()
method GetPopularSubreddits (line 460) | public Listing<Subreddit> GetPopularSubreddits()
method GetGoldSubreddits (line 469) | public Listing<Subreddit> GetGoldSubreddits()
method GetDefaultSubreddits (line 478) | public Listing<Subreddit> GetDefaultSubreddits()
method SearchSubreddits (line 487) | public Listing<Subreddit> SearchSubreddits(string query)
method GetThingAsync (line 496) | protected async internal Task<T> GetThingAsync<T>(string url) where T ...
method GetThing (line 506) | protected internal T GetThing<T>(string url) where T : Thing
FILE: RedditSharp/RedditAPINameAttribute.cs
class RedditAPINameAttribute (line 5) | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
method RedditAPINameAttribute (line 10) | internal RedditAPINameAttribute(string name)
method ToString (line 15) | public override string ToString()
FILE: RedditSharp/RedditException.cs
class RedditException (line 9) | [Serializable]
method RedditException (line 15) | public RedditException()
method RedditException (line 24) | public RedditException(string message)
method RedditException (line 37) | public RedditException(string message, Exception inner)
method RedditException (line 53) | protected RedditException(SerializationInfo info, StreamingContext con...
FILE: RedditSharp/SpamFilterSettings.cs
class SpamFilterSettings (line 3) | public class SpamFilterSettings
method SpamFilterSettings (line 9) | public SpamFilterSettings()
FILE: RedditSharp/SubmitData.cs
class SubmitData (line 3) | internal abstract class SubmitData
method SubmitData (line 29) | protected SubmitData()
FILE: RedditSharp/SubredditImage.cs
class SubredditImage (line 4) | public class SubredditImage
method SubredditImage (line 11) | public SubredditImage(Reddit reddit, SubredditStyle subredditStyle,
method SubredditImage (line 21) | public SubredditImage(Reddit reddit, SubredditStyle subreddit,
method Delete (line 38) | public void Delete()
FILE: RedditSharp/SubredditSettings.cs
class SubredditSettings (line 8) | public class SubredditSettings
method SubredditSettings (line 19) | public SubredditSettings(Reddit reddit, Subreddit subreddit, IWebAgent...
method SubredditSettings (line 44) | public SubredditSettings(Subreddit subreddit, Reddit reddit, JObject j...
method UpdateSettings (line 134) | public void UpdateSettings()
method ResetHeaderImage (line 207) | public void ResetHeaderImage()
method GetSpamFilterStrength (line 221) | private SpamFilterStrength GetSpamFilterStrength(string rawValue)
type WikiEditMode (line 237) | public enum WikiEditMode
type SubredditType (line 244) | public enum SubredditType
type ContentOptions (line 251) | public enum ContentOptions
type SpamFilterStrength (line 258) | public enum SpamFilterStrength
FILE: RedditSharp/SubredditStyle.cs
class SubredditStyle (line 8) | public class SubredditStyle
method SubredditStyle (line 16) | public SubredditStyle(Reddit reddit, Subreddit subreddit, IWebAgent we...
method SubredditStyle (line 23) | public SubredditStyle(Reddit reddit, Subreddit subreddit, JToken json,...
method UpdateCss (line 40) | public void UpdateCss()
method UploadImage (line 58) | public void UploadImage(string name, ImageType imageType, byte[] file)
type ImageType (line 79) | public enum ImageType
FILE: RedditSharp/TBUserNote.cs
class TBUserNote (line 9) | public class TBUserNote
FILE: RedditSharp/TextData.cs
class TextData (line 3) | internal class TextData : SubmitData
method TextData (line 8) | internal TextData()
FILE: RedditSharp/Things/AuthenticatedUser.cs
class AuthenticatedUser (line 8) | public class AuthenticatedUser : RedditUser
method Init (line 19) | public new AuthenticatedUser Init(Reddit reddit, JToken json, IWebAgen...
method InitAsync (line 26) | public async new Task<AuthenticatedUser> InitAsync(Reddit reddit, JTok...
method CommonInit (line 34) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
method GetModeratorReddits (line 105) | [Obsolete("Use ModeratorSubreddits property instead")]
method GetUnreadMessages (line 111) | [Obsolete("Use UnreadMessages property instead")]
method GetModerationQueue (line 117) | [Obsolete("Use ModerationQueue property instead")]
method GetUnmoderatedLinks (line 123) | public Listing<Post> GetUnmoderatedLinks()
method GetModMail (line 128) | [Obsolete("Use ModMail property instead")]
method GetPrivateMessages (line 134) | [Obsolete("Use PrivateMessages property instead")]
method GetInbox (line 140) | [Obsolete("Use Inbox property instead")]
FILE: RedditSharp/Things/Comment.cs
class Comment (line 13) | public class Comment : VotableThing
method Init (line 26) | public Comment Init(Reddit reddit, JToken json, IWebAgent webAgent, Th...
method InitAsync (line 33) | public async Task<Comment> InitAsync(Reddit reddit, JToken json, IWebA...
method CommonInit (line 41) | private JToken CommonInit(Reddit reddit, JToken json, IWebAgent webAge...
method ParseComments (line 59) | private void ParseComments(Reddit reddit, JToken data, IWebAgent webAg...
method ParseCommentsAsync (line 72) | private async Task ParseCommentsAsync(Reddit reddit, JToken data, IWeb...
method Reply (line 136) | public Comment Reply(string message)
method EditText (line 171) | public void EditText(string newText)
method SimpleAction (line 193) | private string SimpleAction(string endpoint)
method Del (line 210) | public void Del()
method Remove (line 215) | public void Remove()
method RemoveSpam (line 220) | public void RemoveSpam()
method RemoveImpl (line 225) | private void RemoveImpl(bool spam)
method SetAsRead (line 240) | public void SetAsRead()
FILE: RedditSharp/Things/Contributor.cs
class Contributor (line 7) | public class Contributor : Thing
method Init (line 16) | public Contributor Init(Reddit reddit, JToken json, IWebAgent webAgent)
method CommonInit (line 23) | private void CommonInit(JToken json)
FILE: RedditSharp/Things/CreatedThing.cs
class CreatedThing (line 8) | public class CreatedThing : Thing
method Init (line 12) | protected CreatedThing Init(Reddit reddit, JToken json)
method InitAsync (line 18) | protected async Task<CreatedThing> InitAsync(Reddit reddit, JToken json)
method CommonInit (line 25) | private void CommonInit(Reddit reddit, JToken json)
FILE: RedditSharp/Things/ModAction.cs
class ModAction (line 11) | public class ModAction : Thing
method Init (line 61) | public ModAction Init(Reddit reddit, JToken json, IWebAgent webAgent)
method InitAsync (line 67) | public async Task<ModAction> InitAsync(Reddit reddit, JToken post, IWe...
method CommonInit (line 74) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
FILE: RedditSharp/Things/Post.cs
class Post (line 12) | public class Post : VotableThing
method Init (line 34) | public Post Init(Reddit reddit, JToken post, IWebAgent webAgent)
method InitAsync (line 40) | public async Task<Post> InitAsync(Reddit reddit, JToken post, IWebAgen...
method CommonInit (line 47) | private void CommonInit(Reddit reddit, JToken post, IWebAgent webAgent)
method Comment (line 146) | public Comment Comment(string message)
method SimpleAction (line 168) | private string SimpleAction(string endpoint)
method SimpleActionToggle (line 185) | private string SimpleActionToggle(string endpoint, bool value, bool re...
method Approve (line 213) | public void Approve()
method Remove (line 218) | public void Remove()
method RemoveSpam (line 223) | public void RemoveSpam()
method RemoveImpl (line 228) | private void RemoveImpl(bool spam)
method Del (line 243) | public void Del()
method Hide (line 248) | public void Hide()
method Unhide (line 253) | public void Unhide()
method MarkNSFW (line 258) | public void MarkNSFW()
method UnmarkNSFW (line 263) | public void UnmarkNSFW()
method ContestMode (line 268) | public void ContestMode(bool state)
method StickyMode (line 273) | public void StickyMode(bool state)
method GetComments (line 280) | [Obsolete("Use Comments property instead")]
method EditText (line 292) | public void EditText(string newText)
method Update (line 315) | public void Update()
method SetFlair (line 321) | public void SetFlair(string flairText, string flairClass)
method ListComments (line 342) | public List<Comment> ListComments(int? limit = null)
FILE: RedditSharp/Things/PrivateMessage.cs
class PrivateMessage (line 11) | public class PrivateMessage : Thing
method Init (line 88) | public PrivateMessage Init(Reddit reddit, JToken json, IWebAgent webAg...
method InitAsync (line 94) | public async Task<PrivateMessage> InitAsync(Reddit reddit, JToken json...
method CommonInit (line 101) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
method GetThread (line 124) | [Obsolete("Use Thread property instead")]
method SetAsRead (line 132) | public void SetAsRead()
method Reply (line 145) | public void Reply(string message)
FILE: RedditSharp/Things/RedditUser.cs
class RedditUser (line 8) | public class RedditUser : Thing
method Init (line 19) | public RedditUser Init(Reddit reddit, JToken json, IWebAgent webAgent)
method InitAsync (line 26) | public async Task<RedditUser> InitAsync(Reddit reddit, JToken json, IW...
method CommonInit (line 34) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
method GetOverview (line 122) | public Listing<VotableThing> GetOverview(Sort sorting = Sort.New, int ...
method GetComments (line 140) | public Listing<Comment> GetComments(Sort sorting = Sort.New, int limit...
method GetPosts (line 158) | public Listing<Post> GetPosts(Sort sorting = Sort.New, int limit = 25,...
method ToString (line 168) | public override string ToString()
method GetOverview (line 175) | [Obsolete("Use Overview property instead")]
method GetComments (line 181) | [Obsolete("Use Comments property instead")]
method GetPosts (line 187) | [Obsolete("Use Posts property instead")]
method GetSubscribedSubreddits (line 193) | [Obsolete("Use SubscribedSubreddits property instead")]
type Sort (line 202) | public enum Sort
type FromTime (line 210) | public enum FromTime
FILE: RedditSharp/Things/Subreddit.cs
class Subreddit (line 13) | public class Subreddit : Thing
method GetTop (line 115) | public Listing<Post> GetTop(FromTime timePeriod)
method Search (line 189) | public Listing<Post> Search(string terms, Sorting sortE = Sorting.Rele...
method Search (line 197) | public Listing<Post> Search(DateTime from, DateTime to, Sorting sortE ...
method Init (line 314) | public Subreddit Init(Reddit reddit, JToken json, IWebAgent webAgent)
method InitAsync (line 323) | public async Task<Subreddit> InitAsync(Reddit reddit, JToken json, IWe...
method SetName (line 332) | private void SetName()
method CommonInit (line 342) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
method GetRSlashAll (line 350) | public static Subreddit GetRSlashAll(Reddit reddit)
method GetFrontPage (line 364) | public static Subreddit GetFrontPage(Reddit reddit)
method Subscribe (line 378) | public void Subscribe()
method Unsubscribe (line 396) | public void Unsubscribe()
method ClearFlairTemplates (line 414) | public void ClearFlairTemplates(FlairType flairType)
method AddFlairTemplate (line 429) | public void AddFlairTemplate(string cssClass, FlairType flairType, str...
method GetFlairText (line 449) | public string GetFlairText(string user)
method GetFlairCssClass (line 458) | public string GetFlairCssClass(string user)
method SetUserFlair (line 467) | public void SetUserFlair(string user, string cssClass, string text)
method UploadHeaderImage (line 484) | public void UploadHeaderImage(string name, ImageType imageType, byte[]...
method AddModerator (line 505) | public void AddModerator(string user)
method AcceptModeratorInvite (line 520) | public void AcceptModeratorInvite()
method RemoveModerator (line 533) | public void RemoveModerator(string id)
method ToString (line 548) | public override string ToString()
method AddContributor (line 553) | public void AddContributor(string user)
method RemoveContributor (line 568) | public void RemoveContributor(string id)
method BanUser (line 583) | public void BanUser(string user, string reason)
method Submit (line 602) | private Post Submit(SubmitData data)
method SubmitPost (line 642) | public Post SubmitPost(string title, string url, string captchaId = ""...
method SubmitTextPost (line 663) | public Post SubmitTextPost(string title, string text, string captchaId...
method GetModerationLog (line 680) | public Listing<ModAction> GetModerationLog()
method GetModerationLog (line 688) | public Listing<ModAction> GetModerationLog(ModActionType action)
method GetModerationLog (line 696) | public Listing<ModAction> GetModerationLog(string[] mods)
method GetModerationLog (line 706) | public Listing<ModAction> GetModerationLog(ModActionType action, strin...
method GetPosts (line 712) | [Obsolete("Use Posts property instead")]
method GetNew (line 718) | [Obsolete("Use New property instead")]
method GetHot (line 724) | [Obsolete("Use Hot property instead")]
method GetModQueue (line 730) | [Obsolete("Use ModQueue property instead")]
method GetUnmoderatedLinks (line 736) | [Obsolete("Use UnmoderatedLinks property instead")]
method GetSettings (line 742) | [Obsolete("Use Settings property instead")]
method GetUserFlairTemplates (line 748) | [Obsolete("Use UserFlairTemplates property instead")]
method GetStylesheet (line 754) | [Obsolete("Use Stylesheet property instead")]
method GetModerators (line 760) | [Obsolete("Use Moderators property instead")]
FILE: RedditSharp/Things/Thing.cs
class Thing (line 7) | public class Thing
method Parse (line 9) | public static Thing Parse(Reddit reddit, JToken json, IWebAgent webAgent)
method Parse (line 32) | public static Thing Parse<T>(Reddit reddit, JToken json, IWebAgent web...
method Init (line 53) | internal void Init(JToken json)
method ParseAsync (line 89) | public static async Task<Thing> ParseAsync(Reddit reddit, JToken json,...
method ParseAsync (line 112) | public static async Task<Thing> ParseAsync<T>(Reddit reddit, JToken js...
FILE: RedditSharp/Things/VotableThing.cs
class VotableThing (line 10) | public class VotableThing : CreatedThing
type VoteType (line 12) | public enum VoteType
type ReportType (line 19) | public enum ReportType
type DistinguishType (line 29) | public enum DistinguishType
method Init (line 49) | protected VotableThing Init(Reddit reddit, IWebAgent webAgent, JToken ...
method InitAsync (line 55) | protected async Task<VotableThing> InitAsync(Reddit reddit, IWebAgent ...
method CommonInit (line 62) | private void CommonInit(Reddit reddit, IWebAgent webAgent, JToken json)
method Upvote (line 109) | public void Upvote()
method Downvote (line 114) | public void Downvote()
method SetVote (line 119) | public void SetVote(VoteType type)
method Save (line 146) | public void Save()
method Unsave (line 161) | public void Unsave()
method ClearVote (line 176) | public void ClearVote()
method Report (line 191) | public void Report(ReportType reportType, string otherReason = null)
method Distinguish (line 226) | public void Distinguish(DistinguishType distinguishType)
class DistinguishConverter (line 262) | internal class DistinguishConverter : JsonConverter
method CanConvert (line 264) | public override bool CanConvert(Type objectType)
method ReadJson (line 269) | public override object ReadJson(JsonReader reader, Type objectType, ...
method WriteJson (line 284) | public override void WriteJson(JsonWriter writer, object value, Json...
FILE: RedditSharp/Things/WikiPageRevision.cs
class WikiPageRevision (line 8) | public class WikiPageRevision : Thing
method WikiPageRevision (line 26) | protected internal WikiPageRevision() { }
method Init (line 28) | internal WikiPageRevision Init(Reddit reddit, JToken json, IWebAgent w...
method InitAsync (line 35) | internal async Task<WikiPageRevision> InitAsync(Reddit reddit, JToken ...
method CommonInit (line 42) | private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)
FILE: RedditSharp/ToolBoxUserNotes.cs
class ToolBoxUserNotes (line 11) | public static class ToolBoxUserNotes
method GetUserNotes (line 14) | public static IEnumerable<TBUserNote> GetUserNotes(IWebAgent webAgent,...
method UnsquashLink (line 76) | public static string UnsquashLink(string subreddit, string permalink)
FILE: RedditSharp/ToolBoxUserNotesException.cs
class ToolBoxUserNotesException (line 9) | class ToolBoxUserNotesException : Exception
method ToolBoxUserNotesException (line 11) | public ToolBoxUserNotesException()
method ToolBoxUserNotesException (line 15) | public ToolBoxUserNotesException(string message)
method ToolBoxUserNotesException (line 20) | public ToolBoxUserNotesException(string message, Exception inner)
FILE: RedditSharp/UnixTimeStamp.cs
class UnixTimeStamp (line 5) | public static class UnixTimeStamp
method UnixTimeStampToDateTime (line 7) | public static DateTime UnixTimeStampToDateTime(this long unixTimeStamp)
FILE: RedditSharp/UnixTimestampConverter.cs
class UnixTimestampConverter (line 7) | public class UnixTimestampConverter : JsonConverter
method CanConvert (line 9) | public override bool CanConvert(Type objectType)
method ReadJson (line 14) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method WriteJson (line 20) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
FILE: RedditSharp/UrlParser.cs
class UrlParser (line 7) | class UrlParser : JsonConverter
method CanConvert (line 9) | public override bool CanConvert(Type objectType)
method ReadJson (line 14) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method WriteJson (line 30) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
FILE: RedditSharp/Utils/DateTimeExtensions.cs
class DateTimeExtensions (line 9) | internal static class DateTimeExtensions
method DateTimeToUnixTimestamp (line 11) | public static double DateTimeToUnixTimestamp(this DateTime dateTime)
FILE: RedditSharp/WebAgent.cs
class WebAgent (line 15) | public class WebAgent : IWebAgent
type RateLimitMode (line 39) | public enum RateLimitMode
method CreateAndExecuteRequest (line 99) | public virtual JToken CreateAndExecuteRequest(string url)
method ExecuteRequest (line 127) | public virtual JToken ExecuteRequest(HttpWebRequest request)
method EnforceRateLimit (line 171) | [MethodImpl(MethodImplOptions.Synchronized)]
method CreateRequest (line 216) | public virtual HttpWebRequest CreateRequest(string url, string method)
method CreateRequest (line 246) | protected virtual HttpWebRequest CreateRequest(Uri uri, string method)
method CreateGet (line 265) | public virtual HttpWebRequest CreateGet(string url)
method CreateGet (line 270) | private HttpWebRequest CreateGet(Uri url)
method CreatePost (line 275) | public virtual HttpWebRequest CreatePost(string url)
method GetResponseString (line 282) | public virtual string GetResponseString(Stream stream)
method WritePostBody (line 289) | public virtual void WritePostBody(Stream stream, object data, params s...
FILE: RedditSharp/Wiki.cs
class Wiki (line 10) | public class Wiki
method Wiki (line 47) | protected internal Wiki(Reddit reddit, Subreddit subreddit, IWebAgent ...
method GetPage (line 54) | public WikiPage GetPage(string page, string version = null)
method GetPageSettings (line 64) | public WikiPageSettings GetPageSettings(string name)
method SetPageSettings (line 73) | public void SetPageSettings(string name, WikiPageSettings settings)
method GetPageRevisions (line 89) | public Listing<WikiPageRevision> GetPageRevisions(string page)
method GetPageDiscussions (line 96) | public Listing<Post> GetPageDiscussions(string page)
method EditPage (line 102) | public void EditPage(string page, string content, string previous = nu...
method HidePage (line 126) | public void HidePage(string page, string revision)
method RevertPage (line 138) | public void RevertPage(string page, string revision)
method SetPageEditor (line 150) | public void SetPageEditor(string page, string username, bool allow)
method GetPageNames (line 164) | [Obsolete("Use PageNames property instead")]
method GetRevisions (line 170) | [Obsolete("Use Revisions property instead")]
FILE: RedditSharp/WikiPage.cs
class WikiPage (line 8) | public class WikiPage
method WikiPage (line 26) | protected internal WikiPage(Reddit reddit, JToken json, IWebAgent webA...
FILE: RedditSharp/WikiPageSettings.cs
class WikiPageSettings (line 9) | public class WikiPageSettings
method WikiPageSettings (line 20) | public WikiPageSettings()
method WikiPageSettings (line 24) | protected internal WikiPageSettings(Reddit reddit, JToken json, IWebAg...
FILE: TestRedditSharp/Program.cs
class Program (line 10) | class Program
method Main (line 12) | static void Main(string[] args)
method ReadPassword (line 78) | public static string ReadPassword()
Condensed preview — 62 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (223K chars).
[
{
"path": ".gitattributes",
"chars": 2579,
"preview": "###############################################################################\n# Set default behavior to automatically "
},
{
"path": ".gitignore",
"chars": 120,
"preview": "bin/\nobj/\n*.user\n*.userprefs\n*.suo\n*.pidb\n_ReSharper*/\nTestResults/\n*.mdf\n*.psess\n*.vsp\n\n# StyleCop files\nStyleCop.Cache"
},
{
"path": "LICENSE",
"chars": 1055,
"preview": "Copyright (c) 2013 Drew DeVault\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this so"
},
{
"path": "README.md",
"chars": 1434,
"preview": "# RedditSharp\n\nA partial implementation of the [Reddit](http://reddit.com) API. Includes support for many API endpoints,"
},
{
"path": "RedditSharp/AuthProvider.cs",
"chars": 8531,
"preview": "using System;\nusing System.Net;\nusing System.Security.Authentication;\nusing System.Text;\nusing Newtonsoft.Json.Linq;\nusi"
},
{
"path": "RedditSharp/Captcha.cs",
"chars": 380,
"preview": "using System;\n\nnamespace RedditSharp\n{\n public struct Captcha\n {\n private const string UrlFormat = \"http:/"
},
{
"path": "RedditSharp/CaptchaFailedException.cs",
"chars": 441,
"preview": "using System;\n\nnamespace RedditSharp\n{\n public class CaptchaFailedException : RedditException\n {\n public C"
},
{
"path": "RedditSharp/CaptchaResponse.cs",
"chars": 291,
"preview": "namespace RedditSharp\n{\n public class CaptchaResponse\n {\n public readonly string Answer;\n\n public b"
},
{
"path": "RedditSharp/ConsoleCaptchaSolver.cs",
"chars": 668,
"preview": "using System;\n\nnamespace RedditSharp\n{\n public class ConsoleCaptchaSolver : ICaptchaSolver\n {\n public Capt"
},
{
"path": "RedditSharp/Domain.cs",
"chars": 1498,
"preview": "using System;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n "
},
{
"path": "RedditSharp/DuplicateLinkException.cs",
"chars": 600,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nnamespace RedditSharp\n{\n /// "
},
{
"path": "RedditSharp/Extensions.cs",
"chars": 349,
"preview": "using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\n\nnamespace RedditSharp\n{\n public static class Extensio"
},
{
"path": "RedditSharp/FlairTemplate.cs",
"chars": 220,
"preview": "namespace RedditSharp\n{\n public class UserFlairTemplate // TODO: Consider using this class to set templates as well\n"
},
{
"path": "RedditSharp/FlairType.cs",
"chars": 92,
"preview": "namespace RedditSharp\n{\n public enum FlairType\n {\n Link,\n User\n }\n}\n"
},
{
"path": "RedditSharp/ICaptchaSolver.cs",
"chars": 131,
"preview": "namespace RedditSharp\n{\n public interface ICaptchaSolver\n {\n CaptchaResponse HandleCaptcha(Captcha captcha"
},
{
"path": "RedditSharp/IWebAgent.cs",
"chars": 664,
"preview": "using System.IO;\nusing System.Net;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n public interface IWebAgent\n "
},
{
"path": "RedditSharp/LinkData.cs",
"chars": 355,
"preview": "namespace RedditSharp\n{\n internal class LinkData : SubmitData\n {\n [RedditAPIName(\"extension\")]\n int"
},
{
"path": "RedditSharp/Listing.cs",
"chars": 9375,
"preview": "using Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing RedditSharp.Things;\n\nnamespace Reddit"
},
{
"path": "RedditSharp/ModActionType.cs",
"chars": 2301,
"preview": "using Newtonsoft.Json;\nusing System;\n\nnamespace RedditSharp\n{\n public enum ModActionType\n {\n BanUser,\n "
},
{
"path": "RedditSharp/ModeratorPermission.cs",
"chars": 1386,
"preview": "using System;\nusing System.Linq;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n [Flags"
},
{
"path": "RedditSharp/ModeratorUser.cs",
"chars": 690,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n public class ModeratorUser\n {\n "
},
{
"path": "RedditSharp/MultipartFormBuilder.cs",
"chars": 2626,
"preview": "using System;\nusing System.IO;\nusing System.Net;\n\nnamespace RedditSharp\n{\n public class MultipartFormBuilder\n {\n "
},
{
"path": "RedditSharp/Properties/AssemblyInfo.cs",
"chars": 1395,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "RedditSharp/RateLimitException.cs",
"chars": 268,
"preview": "using System;\n\nnamespace RedditSharp\n{\n public class RateLimitException : Exception\n {\n public TimeSpan Tim"
},
{
"path": "RedditSharp/Reddit.cs",
"chars": 20099,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Linq;\nusing System.Net;\nusing System.Secur"
},
{
"path": "RedditSharp/RedditAPINameAttribute.cs",
"chars": 419,
"preview": "using System;\n\nnamespace RedditSharp\n{\n [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n int"
},
{
"path": "RedditSharp/RedditException.cs",
"chars": 2302,
"preview": "using System;\nusing System.Runtime.Serialization;\n\nnamespace RedditSharp\n{\n /// <summary>\n /// Represents an error"
},
{
"path": "RedditSharp/RedditSharp.csproj",
"chars": 4992,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micro"
},
{
"path": "RedditSharp/SpamFilterSettings.cs",
"chars": 493,
"preview": "namespace RedditSharp\n{\n public class SpamFilterSettings\n {\n public SpamFilterStrength LinkPostStrength { "
},
{
"path": "RedditSharp/SubmitData.cs",
"chars": 792,
"preview": "namespace RedditSharp\n{\n internal abstract class SubmitData\n {\n [RedditAPIName(\"api_type\")]\n interna"
},
{
"path": "RedditSharp/SubredditImage.cs",
"chars": 1901,
"preview": "using System;\nnamespace RedditSharp\n{\n public class SubredditImage\n {\n private const string DeleteImageUrl"
},
{
"path": "RedditSharp/SubredditSettings.cs",
"chars": 9708,
"preview": "using System.Web;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{"
},
{
"path": "RedditSharp/SubredditStyle.cs",
"chars": 2934,
"preview": "using System.Collections.Generic;\nusing Newtonsoft.Json.Linq;\nusing System.Web;\nusing RedditSharp.Things;\n\nnamespace Re"
},
{
"path": "RedditSharp/TBUserNote.cs",
"chars": 802,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
},
{
"path": "RedditSharp/TextData.cs",
"chars": 231,
"preview": "namespace RedditSharp\n{\n internal class TextData : SubmitData\n {\n [RedditAPIName(\"text\")]\n internal"
},
{
"path": "RedditSharp/Things/AuthenticatedUser.cs",
"chars": 4852,
"preview": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Th"
},
{
"path": "RedditSharp/Things/Comment.cs",
"chars": 9394,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Secu"
},
{
"path": "RedditSharp/Things/Contributor.cs",
"chars": 706,
"preview": "using System;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things \n{\n public class Cont"
},
{
"path": "RedditSharp/Things/CreatedThing.cs",
"chars": 1196,
"preview": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.T"
},
{
"path": "RedditSharp/Things/ModAction.cs",
"chars": 2288,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nu"
},
{
"path": "RedditSharp/Things/Post.cs",
"chars": 11989,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.Th"
},
{
"path": "RedditSharp/Things/PrivateMessage.cs",
"chars": 5416,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.T"
},
{
"path": "RedditSharp/Things/RedditUser.cs",
"chars": 7977,
"preview": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Th"
},
{
"path": "RedditSharp/Things/Subreddit.cs",
"chars": 29339,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.Th"
},
{
"path": "RedditSharp/Things/Thing.cs",
"chars": 4657,
"preview": "using System;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp.Things\n{\n public class"
},
{
"path": "RedditSharp/Things/VotableThing.cs",
"chars": 9814,
"preview": "using System;\nusing System.Threading.Tasks;\nusing System.Linq;\nusing System.Security.Authentication;\nusing Newtonsoft.J"
},
{
"path": "RedditSharp/Things/WikiPageRevision.cs",
"chars": 1509,
"preview": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.T"
},
{
"path": "RedditSharp/ToolBoxUserNotes.cs",
"chars": 3957,
"preview": "using System;\nusing System.Collections.Generic;\nusing Newtonsoft.Json.Linq;\nusing System.Linq;\nusing System.Text;\nusing"
},
{
"path": "RedditSharp/ToolBoxUserNotesException.cs",
"chars": 503,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
},
{
"path": "RedditSharp/UnixTimeStamp.cs",
"chars": 423,
"preview": "using System;\n\nnamespace RedditSharp\n{\n public static class UnixTimeStamp\n {\n public static DateTime UnixT"
},
{
"path": "RedditSharp/UnixTimestampConverter.cs",
"chars": 736,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\n\nnamespace RedditSharp\n{\n public class UnixTimestam"
},
{
"path": "RedditSharp/UrlParser.cs",
"chars": 1147,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\n\nnamespace RedditSharp\n{\n class UrlParser : JsonCon"
},
{
"path": "RedditSharp/Utils/DateTimeExtensions.cs",
"chars": 437,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnam"
},
{
"path": "RedditSharp/WebAgent.cs",
"chars": 11976,
"preview": "using System;\nusing System.Dynamic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing"
},
{
"path": "RedditSharp/Wiki.cs",
"chars": 6650,
"preview": "using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSharp.Things;\n\nnamespace R"
},
{
"path": "RedditSharp/WikiPage.cs",
"chars": 925,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n "
},
{
"path": "RedditSharp/WikiPageSettings.cs",
"chars": 842,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSha"
},
{
"path": "RedditSharp.sln",
"chars": 2936,
"preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2010\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-"
},
{
"path": "TestRedditSharp/App.config",
"chars": 161,
"preview": "<?xml version=\"1.0\"?>\n<configuration>\n <startup> \n <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version"
},
{
"path": "TestRedditSharp/Program.cs",
"chars": 4385,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSharp;\nusing System.Security.Authenticat"
},
{
"path": "TestRedditSharp/Properties/AssemblyInfo.cs",
"chars": 1403,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Infor"
},
{
"path": "TestRedditSharp/TestRedditSharp.csproj",
"chars": 2969,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micro"
}
]
About this extraction
This page contains the full source code of the SirCmpwn/RedditSharp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 62 files (205.8 KB), approximately 44.9k tokens, and a symbol index with 353 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.