Skip to content

Instantly share code, notes, and snippets.

@0x00000FF
Last active May 23, 2019 06:05
Show Gist options
  • Save 0x00000FF/3a4ba00dfee15a9062b7aff491d13d31 to your computer and use it in GitHub Desktop.
Save 0x00000FF/3a4ba00dfee15a9062b7aff491d13d31 to your computer and use it in GitHub Desktop.
Everytime Article Fetch/Delete Class
/*
* Article/Comment Deletion Agent for Everytime service
* Available for .NET Framework/Core
*
* Newtonsoft.Json Required for Json Deserialization
* Json Types for Deserialization is under the Cleaner class
*/
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using Newtonsoft.Json;
namespace EverytimeCleanerCore
{
/// <summary>
/// Main abstraction of Cleaner, Fetch and Delete implemented
/// </summary>
class Cleaner
{
/// <summary>
/// Cookie container for HttpWebRequest
/// </summary>
CookieContainer cc;
/// <summary>
/// ETag seems the name of JWT, need to be stored.
/// </summary>
string etag;
/// <summary>
/// Alias for UTF-8 Encoding
/// </summary>
static readonly Encoding enc = Encoding.UTF8;
/// <summary>
/// Is Cleaner available?
/// </summary>
public bool Status { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="id">Username</param>
/// <param name="password">Password</param>
public Cleaner(string id, string password)
{
var wr = CreateHttpRequest("https://everytime.kr/user/login");
WritePostData(wr, $"userid={id}&password={password}&redirect=%2F");
try
{
var res = (HttpWebResponse)wr.GetResponse();
var html = ReadAllFromResponse(res);
// Everytime API does not inform you to success or not with status code, but redirect to main page or display error message.
if (html.Contains("아이디나 비밀번호를 바르게 입력해주세요.") || html.Contains("알수없는 오류가 발생하였습니다."))
{
Status = false;
}
else
{
etag = res.Headers["ETag"];
Status = true;
}
}
catch (WebException)
{
Status = false;
}
}
/// <summary>
/// Creates set of header entities for each request
/// </summary>
/// <returns>WebheaderCollection</returns>
WebHeaderCollection CreateRequestHeader()
{
var header = new WebHeaderCollection
{
{ "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3" },
{ "Accept-Language", "en-US,en;q=0.9" },
{ "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36" },
{ "X-Requested-With", "XMLHttpRequest" }
};
if (etag != null)
header.Add("ETag", etag);
return header;
}
/// <summary>
/// Write string data into request stream in UTF-8 encoding.
/// </summary>
/// <param name="wr">Request object</param>
/// <param name="str">String data to be written</param>
void WritePostData(HttpWebRequest wr, string str)
{
if (wr.Method != "POST") wr.Method = "POST";
wr.Referer = "https://everytime.kr";
wr.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
using (var stream = wr.GetRequestStream())
{
var sendData = enc.GetBytes(str);
stream.Write(sendData);
wr.ContentLength = sendData.Length;
}
}
/// <summary>
/// Create HttpWebRequest object that contains data should be contained in common.
/// </summary>
/// <param name="uri">URI to be requested</param>
/// <param name="cc">CookieContainer. If null, will create new one.</param>
/// <returns>Returns a HttpWebRequest object</returns>
HttpWebRequest CreateHttpRequest(string uri, CookieContainer cc = null)
{
var wr = WebRequest.CreateHttp(uri);
wr.Headers = CreateRequestHeader();
wr.CookieContainer = cc ?? new CookieContainer();
wr.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
return wr;
}
/// <summary>
/// Read all data in string from response
/// </summary>
/// <param name="response">Response object to be read</param>
/// <returns>Returns string data if succeed</returns>
string ReadAllFromResponse(HttpWebResponse response)
{
using (var res = response)
{
Encoding encoding;
try { encoding = Encoding.GetEncoding(res.ContentEncoding); }
catch (ArgumentException) { encoding = enc; }
using (var reader = new StreamReader(res.GetResponseStream(), encoding))
{
try { return reader.ReadToEnd(); }
catch { return null; }
}
}
}
/// <summary>
/// Deserialize given XML into Root object.
/// Convert to XML is not required, you can deserialize directly from XML.
/// </summary>
/// <param name="data">XML string</param>
/// <returns>Root object that contains a collection of articles if succeed</returns>
ResponseRoot DeserializeResult(string data)
{
var doc = new XmlDocument();
doc.LoadXml(data);
var sr = JsonConvert.SerializeXmlNode(doc.ChildNodes[1], Newtonsoft.Json.Formatting.Indented);
return JsonConvert.DeserializeObject<ResponseRoot>(sr);
}
/// <summary>
/// Fetch all of articles for specified types
/// </summary>
/// <param name="type">Type of article(including comments), default is myarticle</param>
/// <returns>Actual list of article if succeed</returns>
public List<Article> FetchArticles(string type = "myarticle")
{
var startNum = 0;
var articles = new List<Article>();
// Everytime API does not emit over 20 articles at once, so fetching process need to be repeated.
while (true)
{
var req = CreateHttpRequest("https://everytime.kr/find/board/article/list", cc);
WritePostData(req, $"id={type}&limit_num=20&start_num={startNum}&moiminfo=true");
var res = (HttpWebResponse)req.GetResponse();
var html = ReadAllFromResponse(res);
var art = DeserializeResult(html).response.article;
articles.AddRange(art);
if (art.Length < 20) break;
else startNum += 20;
}
return articles;
}
/// <summary>
/// Delete article/comment for specified type and id.
/// </summary>
/// <param name="type">type of article/comment</param>
/// <param name="id">Article/Comment id</param>
/// <returns>Returns true if succeed</returns>
public bool DeleteArticle(string type, int id)
{
var req = CreateHttpRequest($"https://everytime.kr/remove/board/{type}", cc);
WritePostData(req, $"id={id}");
var res = (HttpWebResponse)req.GetResponse();
return ReadAllFromResponse(res).Contains("<response>1</response>");
}
}
// --------------------------------------------------------------------------------------------
public class ResponseRoot
{
public Response response { get;set; }
}
public class Response
{
public Article[] article { get; set; }
}
public class Article
{
[JsonProperty(PropertyName = "@id")]
public string id { get; set; }
[JsonProperty(PropertyName = "@is_mine")]
public string is_mine { get; set; }
[JsonProperty(PropertyName = "@title")]
public string title { get; set; }
[JsonProperty(PropertyName = "@text")]
public string text { get; set; }
[JsonProperty(PropertyName = "@created_at")]
public string created_at { get; set; }
[JsonProperty(PropertyName = "@posvote")]
public string posvote { get; set; }
[JsonProperty(PropertyName = "@comment")]
public string comment { get; set; }
[JsonProperty(PropertyName = "@comment_anonym")]
public string comment_anonym { get; set; }
[JsonProperty(PropertyName = "@scrap_count")]
public string scrap_count { get; set; }
[JsonProperty(PropertyName = "@board_id")]
public string board_id { get; set; }
[JsonProperty(PropertyName = "@board_name")]
public string board_name { get; set; }
[JsonProperty(PropertyName = "@user_type")]
public string user_type { get; set; }
[JsonProperty(PropertyName = "@user_id")]
public string user_id { get; set; }
[JsonProperty(PropertyName = "@user_nickname")]
public string user_nickname { get; set; }
[JsonProperty(PropertyName = "@user_picture")]
public string user_picture { get; set; }
[JsonProperty(PropertyName = "@attach")]
public object attach { get; set; }
}
}
@0x00000FF
Copy link
Author

Completed try-catch block through Ln 144 to Ln 151

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment