RedditRaffle

Choses a list of winners by certain criteria

当前为 2014-07-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name RedditRaffle
  3. // @namespace redditraffle
  4. // @description Choses a list of winners by certain criteria
  5. // @include http://www.reddit.com/r/*/comments/*
  6. // @version 1.4
  7. // @grant GM_xmlhttpRequest
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11. var link,
  12. url,
  13. winner_count,
  14. author_exclude,
  15. keyword_included,
  16. keyword_excluded,
  17. karma_link,
  18. karma_comment,
  19. age = 0.,
  20. total_comments,
  21. comments = [],
  22. more = [],
  23. more_lock = false,
  24. parse_lock = false,
  25. names = [],
  26. chosen = [],
  27. userinfo,
  28. query_timeout,
  29. connection_count = 0;
  30.  
  31. function render_results() {
  32. progress.innerHTML = "Rendering:";
  33. var html = [];
  34. html.push("<!doctype html><meta charset=\"utf-8\" /><title>Raffle results</title>" +
  35. "<style>table{overflow:hidden;border:1px solid #d3d3d3;background:#fefefe;" +
  36. "width:70%;margin:5% auto 0;-moz-border-radius:5px;-webkit-border-radius:5px;" +
  37. "border-radius:5px;-moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);" +
  38. "-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);}th,td{text-align:center;}" +
  39. "th{padding:14px 22px;text-shadow: 1px 1px 1px #fff;background:#e8eaeb;}" +
  40. "td{border-top:1px solid #e0e0e0;border-right:1px solid #e0e0e0;}" +
  41. "tr:nth-child(odd) td{background:#f6f6f6;}td:last-child{border-right:none;" +
  42. "text-align:left;padding:8px 18px;}</style><table><tr><th>No.</th><th>User</th>" +
  43. "<th>Comment</th></tr>");
  44. var winner_length = Math.min(winner_count, chosen.length);
  45. for(var i = 0; i < winner_length; i++) {
  46. html.push("<tr><td>" + (i + 1) + ".</td><td><a href=\"http://www.reddit.com/user/" +
  47. chosen[i].author + "\">" + chosen[i].author + "</a></td><td>");
  48. html.push(chosen[i].body_html.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&'));
  49. html.push("<br /><a href=\"" + url + chosen[i].id + "\">Show</a></td><tr>");
  50. }
  51. html.push("</table>");
  52. progress.innerHTML = "<a href=\"" + URL.createObjectURL(new Blob(html, {type : 'text/html'})) +
  53. "\" target=\"_new\">Show results</a>";
  54. }
  55.  
  56. function query_users() {
  57. if(more_lock || parse_lock) return;
  58. query_interval = window.setInterval(function() {
  59. if(chosen.length >= winner_count || !comments.length) {
  60. window.clearInterval(query_interval);
  61. render_results();
  62. return;
  63. }
  64. if(connection_count > 10) return;
  65. var comment = comments.splice(Math.floor(Math.random() * comments.length), 1)[0];
  66. if(comment === undefined ||
  67. comment.body.toLowerCase().indexOf(keyword_included) < 0 ||
  68. (keyword_excluded && !(comment.body.toLowerCase().indexOf(keyword_excluded) < 0)) ||
  69. (author_exclude && comment.author === author_exclude) ||
  70. !(names.indexOf(comment.author) < 0))
  71. return;
  72. if(age || karma_link || karma_comment) {
  73. GM_xmlhttpRequest({
  74. method: 'GET',
  75. url: 'http://www.reddit.com/user/' + comment.author + '/about.json',
  76. context: comment,
  77. onload: function(response) {
  78. connection_count--;
  79. userinfo = JSON.parse(response.responseText).data;
  80. if((!age || userinfo.created_utc <= age) &&
  81. userinfo.link_karma >= karma_link &&
  82. userinfo.comment_karma >= karma_comment &&
  83. chosen.length < winner_count &&
  84. names.indexOf(comment.author) < 0) {
  85. names.push(userinfo.name);
  86. chosen.push(response.context);
  87. progress.innerHTML = "Querying Users: " + chosen.length + "/" + winner_count;
  88. }
  89. },
  90. onerror: function(error) {
  91. connection_count--;
  92. console.log(error);
  93. },
  94. });
  95. connection_count++;
  96. } else {
  97. names.push(comment.author);
  98. chosen.push(comment);
  99. progress.innerHTML = "Querying Users: " + chosen.length + "/" + winner_count;
  100. }
  101. }, 100);
  102. }
  103.  
  104. function add_comment(comment) {
  105. comments.push(comment);
  106. if(comment.replies && comment.replies.kind === "Listing")
  107. parse_listing(comment.replies.data.children);
  108. }
  109.  
  110. function add_more(children) {
  111. more.push.apply(more, children);
  112. if(!more_lock) parse_more();
  113. }
  114.  
  115. function parse_more() {
  116. if(!more.length) {
  117. more_lock = false;
  118. query_users();
  119. return;
  120. }
  121. more_lock = true;
  122. var children = more.splice(0, 20);
  123. GM_xmlhttpRequest({
  124. method: 'POST',
  125. url: 'http://www.reddit.com/api/morechildren.json',
  126. headers: {
  127. "Content-Type": "application/x-www-form-urlencoded"
  128. },
  129. data: 'link_id=' + link + '&api_type=json&children=' + children.join(),
  130. onload: function(response) {
  131. parse_listing(JSON.parse(response.responseText).json.data.things);
  132. progress.innerHTML = "Parsing Comments: " + comments.length + "/" + total_comments;
  133. parse_more();
  134. },
  135. enerror: function(error) {
  136. more.push.apply(more, children);
  137. console.log("Error:", error);
  138. parse_more();
  139. }
  140. });
  141. }
  142.  
  143. function parse_listing(listing) {
  144. var listingLength = listing.length;
  145. for(var child = 0; child < listingLength; child++) {
  146. if (listing[child].kind === 't1')
  147. add_comment(listing[child].data);
  148. else if (listing[child].kind === 't3') {
  149. link = listing[child].data.name;
  150. author_exclude = form.elements.author_exclude.checked ? listing[child].data.author : "";
  151. total_comments = listing[child].data.num_comments;
  152. progress.innerHTML = "Parsing Comments: 0/" + total_comments;
  153. }
  154. else if (listing[child].kind === 'more')
  155. add_more(listing[child].data.children);
  156. }
  157. }
  158.  
  159. function do_raffle() {
  160. progress.innerHTML = "Parsing Comments:";
  161. winner_count = parseInt(form.elements.winner_count.value) || 20;
  162. keyword_included = form.elements.keyword_included.value.toLowerCase();
  163. keyword_excluded = form.elements.keyword_excluded.value.toLowerCase();
  164. karma_link = parseInt(form.elements.karma_link.value) || 0;
  165. karma_comment = parseInt(form.elements.karma_comment.value) || 0;
  166. if(form.elements.age_days.value ||
  167. form.elements.age_month.value ||
  168. form.elements.age_years.value) {
  169. var date = new Date();
  170. date.setDate(date.getDate() - (parseInt(form.elements.age_days.value) || 0));
  171. date.setMonth(date.getMonth() - (parseInt(form.elements.age_month.value) || 0));
  172. date.setFullYear(date.getFullYear() - (parseInt(form.elements.age_years.value) || 0));
  173. age = date.getTime()/1000;
  174. }
  175. url = window.location.href;
  176. if(!(url.indexOf("?") < 0)) {
  177. url = url.substring(0, url.indexOf("?"));
  178. }
  179. parse_lock = true;
  180. GM_xmlhttpRequest({
  181. method: 'POST',
  182. url: url + '.json',
  183. headers: {
  184. "Content-Type": "application/x-www-form-urlencoded"
  185. },
  186. data: 'limit=500',
  187. onload: function(response) {
  188. var things = JSON.parse(response.responseText),
  189. thingsLength = things.length
  190. for(var thing = 0; thing < thingsLength; thing++)
  191. if (things[thing].kind === 'Listing')
  192. parse_listing(things[thing].data.children);
  193. parse_lock = false;
  194. query_users();
  195. },
  196. });
  197. }
  198.  
  199.  
  200.  
  201. GM_addStyle("#raffle_form input[type=text]{\
  202. width:265px;\
  203. border:1px solid #DBDADA;\
  204. -moz-border-radius:2px;\
  205. -webkit-border-radius:2px;\
  206. -o-border-radius:2px;\
  207. -ms-border-radius:2px;\
  208. -khtml-border-radius:2px;\
  209. border-radius:2px;\
  210. font-size:14px;\
  211. font-style:italic;\
  212. padding:4px\
  213. }");
  214. var spacer = document.createElement("div");
  215. spacer.classList.add("spacer");
  216. spacer.innerHTML = "<div class=\"sidecontentbox \">\
  217. <div class=\"title\"><h1>Raffle</h1></div>\
  218. <form id=\"raffle_form\">\
  219. <ul class=\"content\">\
  220. <li><input type=\"text\" placeholder=\"Number of Winners\" name=\"winner_count\" /></li>\
  221. <li><input type=\"text\" placeholder=\"Comments containing\" name=\"keyword_included\" /></li>\
  222. <li><input type=\"text\" placeholder=\"Comments not containing\" name=\"keyword_excluded\" /></li>\
  223. <li><input type=\"text\" placeholder=\"Required Link Karma\" name=\"karma_link\" /></li>\
  224. <li><input type=\"text\" placeholder=\"Required Comment Karma\" name=\"karma_comment\" /></li>\
  225. <li><input type=\"text\" placeholder=\"Age in Days\" name=\"age_days\" /></li>\
  226. <li><input type=\"text\" placeholder=\"Age in Months\" name=\"age_month\" /></li>\
  227. <li><input type=\"text\" placeholder=\"Age in Years\" name=\"age_years\" /></li>\
  228. <li>\
  229. <button class=\"save\" type=\"button\">Raffle</button>\
  230. <input type=\"checkbox\" name=\"author_exclude\" id=\"author_exclude\" checked=\"checked\"/>\
  231. <label for=\"author_exclude\">Exclude Author</label>\
  232. </li>\
  233. <li><span id=\"raffle_progress\"></span></li>\
  234. </ul>\
  235. </form>\
  236. </div>";
  237. var form = spacer.querySelector("form#raffle_form"),
  238. progress = spacer.querySelector("span#raffle_progress");
  239. document.querySelector("div.side").appendChild(spacer);
  240. form.querySelector("button").addEventListener("click", do_raffle, true);