imgur_show_user_stats_light

Show user statistics on imgur

目前為 2017-06-11 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name imgur_show_user_stats_light
  3. // @namespace someName
  4. // @include http://imgur.com/user/*
  5. // @include https://imgur.com/user/*
  6. // @version 0.3.4
  7. // @grant none
  8. // @description Show user statistics on imgur
  9. // ==/UserScript==
  10. // TODO: Catch errors and check result.success
  11. // TODO: Think about useable version numbers...
  12. // TODO: Add support for username.imgur.com style urls
  13. // TODO: Is there a way to request http://community.imgur.com/users/'+username+'.json without CORS problems ?
  14. // We could use greasemonkey ajax call, but that wouldn't work with bookmarklets and every other browser (i guess)
  15. // TODO: Show errors and handle no credits remaining ?
  16.  
  17. $(window).ready(function () {
  18. var CLIENT_ID = 'cd0695f1226536b';
  19. var MAX_SUB_PAGES = 15;
  20. var _submissions_left = -1;
  21. var _sub_site = 0;
  22. var _submissions = [];
  23. var _last_sub_id = -1;
  24. var _last_post = -1;
  25. function _update_limits_from_header(xhr) {
  26. xhr.getResponseHeader('Header')
  27. $('#stats_credits_user').html('User Credits: ' + xhr.getResponseHeader('X-RateLimit-UserRemaining') + ' / ' + xhr.getResponseHeader('X-RateLimit-UserLimit'));
  28. $('#stats_credits_script').html('Script Credits: : ' + xhr.getResponseHeader('X-RateLimit-ClientRemaining') + ' / ' + xhr.getResponseHeader('X-RateLimit-ClientLimit'));
  29. }
  30.  
  31. function request_user_info(endpoint, success_cb, error_cb) {
  32. $.ajax({
  33. url: 'https://api.imgur.com/3/account/' + username + '/' + endpoint,
  34. method: 'GET',
  35. headers: {
  36. Authorization: 'Client-ID ' + CLIENT_ID,
  37. Accept: 'application/json'
  38. },
  39. success: function (a, b, c) {
  40. _update_limits_from_header(c);
  41. success_cb(a, b, c);
  42. },
  43. error: error_cb
  44. });
  45. }
  46. if (window.location.pathname.indexOf('/user/') === 0 && $('.button').filter('.comments').length > 0) {
  47. // Set up UI
  48. var username = window.location.pathname.split('/', 3) [2]; // TODO: look for a more stable way (is there an imgur js var maybe ?)
  49. var newBox = $('<div id="statsBox" class="textbox"></div>');
  50. var tble = $('<table id="_stats_table" width="100%">' +
  51. '<tr><td colspan="2"><hr></td></tr>'+
  52. '<tr><td>Account creation</td><td align="right"><span id="stats_created"> - </span></td></tr>' +
  53. '<tr><td>Comments</td><td align="right"><a href="http://imgur.com/user/' + username + '/" id="stats_comments"> - </a></td></tr>' +
  54. '<tr><td>Submissions</td><td align="right"><a href="http://imgur.com/user/' + username + '/submitted" id="stats_submissions"> - </a></td></tr>' +
  55. '<tr><td>Albums</td><td align="right"><a href="http://' + username + '.imgur.com" id="stats_albums"> - </a></td></tr>' +
  56. '<tr><td>Images</td><td align="right"><a href="http://' + username + '.imgur.com/all" id="stats_images"> - </a></td></tr>' +
  57. '<tr><td>Favorites</td><td align="right"><a href="http://imgur.com/user/' + username + '/favorites" id="stats_favorites"> - </a></td></tr>' +
  58. '<tr><td colspan="2"><hr></td></tr>'+
  59. '<tr><td colspan="2" align="center"><button id="_btn_extend">Extended statistics</button></td></tr>' +
  60. '<tr class="_extended"><td colspan="2"><hr></td></tr>'+
  61. '<tr class="_extended"><td>Last activity</td><td align="right" id="stats_last_active"></td></tr>' +
  62. '<tr class="_extended"><td>AVG post points</td><td align="right" id="stats_score"></td></tr>' +
  63. '<tr class="_extended"><td>AVG post views</td><td align="right" id="stats_views"></td></tr>' +
  64. '<tr class="_extended"><td>Most viral posts </td><td align="right" id="stats_most_viral"></td></tr>' +
  65. '<tr class="_extended"><td>NSFW posts </td><td align="right" id="stats_nsfw"></td></tr>' +
  66. '<tr class="_extended"><td>Top tags</td><td align="right" id="stats_toptags"></td></tr>' +
  67. '<tr><td colspan="2"><hr></td></tr>'+
  68. '<tr><td colspan="2" align="center"><a href="http://community.imgur.com/users/' + username + '">IC profile</a></td></tr>' +
  69. '<tr><td style="color: #2B2B2B; font-size: 0.7em;" colspan="2" align="center" id="stats_credits_user"> - </td></tr>' +
  70. '<tr><td style="color: #2B2B2B; font-size: 0.7em;" colspan="2" align="center" id="stats_credits_script"> - </td></tr>' +
  71. '</table>');
  72. newBox.append(tble);
  73. newBox.insertBefore($('.notoriety-container'));
  74. tble.find('._extended').hide();
  75. // Add loading icon to all rows
  76. var tmp = $('#_stats_table tr td:nth-child(2)'); tmp.children().hide();
  77. tmp.append('<img style="height:1em" src="https://i.imgur.com/LR2v0rh.gif" />');
  78. $('#_btn_extend').click(function(){
  79. if(_submissions_left == 0) return;
  80. tble.find('._extended').show();
  81. get_submissions();
  82. });
  83. // get coments / submission stats
  84. request_user_info('gallery_profile', function (result, status, request) {
  85. $('#stats_comments').html(result.data.total_gallery_comments.toLocaleString()).closest('td').children().show().filter('img').remove();
  86. $('#stats_submissions').html(result.data.total_gallery_submissions.toLocaleString()).closest('td').children().show().filter('img').remove();
  87. $('#stats_favorites').html(result.data.total_gallery_favorites.toLocaleString()).closest('td').children().show().filter('img').remove();
  88. _submissions_left = result.data.total_gallery_submissions;
  89. if(_submissions_left == 0) $('#_btn_extend, #_stats_table hr:nth(1)').hide()
  90. }, function (a, b, c) {
  91. console.log('Failed to load', a, b, c);
  92. $('#stats_comments, #stats_submissions, #stats_favorites').text('Failed to load').closest('td').children().show().filter('img').remove();
  93. }
  94. );
  95. // get the exact (*) join date. TODO: I bet i messed up the time(zones) here.
  96. request_user_info('', function (result, status, request) {
  97. $('#stats_created').html(new Date(result.data.created * 1000).toLocaleDateString()).closest('td').children().show().filter('img').remove();
  98. }, function (a, b, c) {
  99. console.log('Failed to load', a, b, c);
  100. $('#stats_created').text('Failed to load').closest('td').children().show().filter('img').remove();
  101. }
  102. );
  103. // album count (inklusive not submitted to gallery), if album settings are set to public.
  104. request_user_info('albums/count', function (result, status, request) {
  105. $('#stats_albums').html(result.data.toLocaleString()).closest('td').children().show().filter('img').remove();
  106. }, function (a, b, c) {
  107. console.log('Failed to load', a, b, c);
  108. $('#stats_albums').html('private').closest('td').children().show().filter('img').remove();
  109. }
  110. );
  111. // image count (inklusive not submitted to gallery), if image settings are set to public.
  112. request_user_info('images/count', function (result, status, request) {
  113. $('#stats_images').html(result.data.toLocaleString()).closest('td').children().show().filter('img').remove();
  114. }, function (a, b, c) {
  115. console.log('Failed to load', a, b, c);
  116. $('#stats_images').html('private').closest('td').children().show().filter('img').remove();
  117. }
  118. );
  119. function get_submissions() {
  120. if(_submissions_left <= 0){
  121. return;
  122. }
  123. console.log("Requesting submission page #" + _sub_site);
  124. request_user_info('submissions/' + _sub_site, function (result, status, request) {
  125. _submissions.push.apply(_submissions, result.data);
  126. _submissions_left -= result.data.length;
  127. var done = true;
  128. if(result.data.length > 0 && _submissions_left > 0 && _last_sub_id != result.data[0].id){
  129. if(_sub_site+1 == MAX_SUB_PAGES){
  130. var a = $('<span style="color:yellow; font-weight: bold; padding: 0 5px 0 5px;">!</span>');
  131. a.attr('title', 'Only the last '+ _submissions.length +' submissions are considered.');
  132. $('#stats_score, #stats_views, #stats_toptags, #stats_nsfw, #stats_most_viral').parent().children('td:nth-child(1)').append(a);
  133. }else{
  134. _last_sub_id = result.data[0].id;
  135. _sub_site += 1;
  136. get_submissions();
  137. done = false;
  138. }
  139. }
  140. if(done){
  141. if(_submissions.length > 0){
  142. // TODO: are they always returned newest first ?
  143. _last_post = _submissions[0].datetime;
  144. }
  145. calc_views();
  146. calc_score();
  147. collect_tags();
  148. get_last_comment();
  149. calc_most_viral();
  150. calc_nsfw();
  151. }
  152. }, function (a, b, c) {
  153. console.log('Failed to load', a, b, c);
  154. }
  155. );
  156. }
  157. function _get_field(array, field){
  158. var ret = Array();
  159. for(var i=0; i < array.length; ++i){
  160. ret.push(array[i][field])
  161. }
  162. return ret;
  163. }
  164. // some array funcs for convinience
  165. Array.prototype.sum = function() {
  166. return this.reduce(function(a, b) { return a + b; }, 0);
  167. };
  168. Array.prototype.max = function() {
  169. return Math.max.apply(null, this);
  170. };
  171. Array.prototype.min = function() {
  172. return Math.min.apply(null, this);
  173. };
  174. var round = Math.round;
  175. function calc_views(){
  176. var views = _get_field(_submissions ,'views');
  177. var view_sum = views.sum();
  178. var a = $('<span></span>');
  179. a.text(round(view_sum / views.length).toLocaleString());
  180. a.attr('title', 'All: ' + round(view_sum).toLocaleString() + ". Max: " + views.max().toLocaleString() + ". Min: " + views.min().toLocaleString() + ".");
  181. $('#stats_views').append(a).closest('td').children().show().filter('img').remove();
  182. }
  183. function calc_score(){
  184. var points = _get_field(_submissions ,'points');
  185. var ups = _get_field(_submissions ,'ups').sum() / points.length;
  186. var downs = _get_field(_submissions ,'downs').sum() / points.length;
  187. var point_sum = points.sum();
  188. var a = $('<span></span>');
  189. a.text( round(point_sum / points.length).toLocaleString());
  190. a.attr('title', 'Upvotes avg: ' + round(ups).toLocaleString() + ". Downvotes avg: " + round(downs).toLocaleString() + ".");
  191. $('#stats_score').append(a).closest('td').children().show().filter('img').remove();
  192. }
  193. function calc_most_viral(){
  194. var virals = _get_field(_submissions ,'in_most_viral');
  195. var _sum = virals.sum();
  196. if(virals.length > 0){
  197. val = Math.round((100.0 / virals.length) * _sum);
  198. }
  199. var a = $('<span></span>');
  200. a.text( val + "%" );
  201. a.attr('title', _sum + " / " + virals.length + " posts");
  202. $('#stats_most_viral').append(a).closest('td').children().show().filter('img').remove();
  203. }
  204. function calc_nsfw(){
  205. var nsfws = _get_field(_submissions ,'nsfw');
  206. var _sum = nsfws.sum();
  207. var val = 0;
  208. if(nsfws.length > 0){
  209. val = Math.round((100.0 / nsfws.length) * _sum);
  210. }
  211. var a = $('<span></span>');
  212. a.text( val + "%" );
  213. a.attr('title', _sum + " / " + nsfws.length + " posts");
  214. $('#stats_nsfw').append(a).closest('td').children().show().filter('img').remove();
  215. }
  216. function collect_tags(){
  217. console.log('collect_tags');
  218. var counter = {};
  219. for(var i=0; i < _submissions.length; ++i){
  220. var tags = _submissions[i].tags;
  221. for(var j=0; j < tags.length; ++j){
  222. var count = 1; var k = tags[j].display_name;
  223. if( k in counter ){
  224. count += counter[k][0];
  225. }
  226. counter[k] = [count, tags[j]];
  227. }
  228. }
  229. var vals = Object.values(counter);
  230. vals.sort(function(a, b) {
  231. return b[0] - a[0];
  232. });
  233. $('#stats_toptags').children().show().filter('img').remove();
  234. for(var i=0; i < 5 && i < vals.length; ++i){
  235. var node = $('<a>-</a><br>');
  236. node.filter('a').text(vals[i][1].display_name).attr('title', "Used "+vals[i][0]+" times").attr('href', 'https://imgur.com/t/'+vals[i][1].name);
  237. $('#stats_toptags').append(node);
  238. }
  239. }
  240. }
  241. function get_last_comment(){
  242. request_user_info('comments/newest', function (result, status, request) {
  243. if(result.data.length == 0 && _last_post == -1){
  244. $('#stats_last_active').text('-');
  245. return;
  246. }
  247. if(result.data.length == 0) return;
  248. var d = result.data[0].datetime;
  249. var link = result.data[0].datetime;
  250. if(d > _last_post){
  251. link = 'https://imgur.com/gallery/' +result.data[0].image_id+ '/comment/' + result.data[0].id;
  252. }else{
  253. link = 'https://imgur.com/gallery/' + _submissions[0].id;
  254. d = _last_post;
  255. }
  256. var delta = (new Date().getTime()/1000) - d;
  257. function pluralize(val, word){
  258. val = Math.floor(val);
  259. return val + " " + Imgur.Util.pluralize(val, word);
  260. }
  261. // thats propably somewhere already
  262. if(delta >= 356*24*60*60) delta = pluralize(delta / (356*24*60*60), " year");
  263. else if(delta >= 24*60*60) delta = pluralize(delta / (24*60*60), " day");
  264. else if(delta >= 60*60) delta = pluralize(delta / (60*60), " hour");
  265. else if(delta >= 60) delta = pluralize(delta / 60, " minute");
  266. else delta = pluralize(delta, " second");
  267. d = new Date(d * 1000);
  268. var a = $('<a></a>').attr('href', link).text(delta + " ago").attr('title', d.toLocaleDateString() + " " + d.toLocaleTimeString());
  269. $('#stats_last_active').append(a).children().show().filter('img').remove();
  270. }, function (a, b, c) {
  271. console.log('Failed to load', a, b, c);
  272. $('#stats_last_active').text('Failed to load comment').closest('td').children().show().filter('img').remove();
  273. }
  274. );
  275. }
  276. });