Torn Helper

Adds extra information to different pages all around Torn.

目前為 2017-01-05 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Torn Helper
  3. // @namespace Jebster.Torn
  4. // @author Jeggy
  5. // @description Adds extra information to different pages all around Torn.
  6. // @include *.torn.com/profiles.php?XID=*
  7. // @version 0.0.8
  8. // @require http://code.jquery.com/jquery-2.2.4.min.js
  9. // @require http://code.jquery.com/ui/1.12.1/jquery-ui.min.js
  10. // @resource jquery-ui http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/black-tie/jquery-ui.min.css
  11. // @resource jquery-base http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css
  12. // @grant GM_addStyle
  13. // @grant GM_getResourceText
  14. // ==/UserScript==
  15.  
  16. GM_addStyle(GM_getResourceText('jquery-base'));
  17. GM_addStyle(GM_getResourceText('jquery-ui'));
  18.  
  19. String.prototype.format = function() {
  20. var formatted = this;
  21. for (var i = 0; i < arguments.length; i++) {
  22. var regexp = new RegExp('\\{'+i+'\\}', 'gi');
  23. formatted = formatted.replace(regexp, arguments[i]);
  24. }
  25. return formatted;
  26. };
  27.  
  28. var data = {};
  29.  
  30. (function() {
  31. 'use strict';
  32.  
  33. var site = window.location.pathname;
  34.  
  35. loadData();
  36. saveOwnData();
  37.  
  38. if(site.indexOf('profiles.php') > 0) profileView();
  39.  
  40. loadAttackLog();
  41. })();
  42.  
  43. function loadAttackLog(){
  44. var selections = 'attacks';
  45. if('attackLogLoad' in data)
  46. //if(data.attackLogLoad > new Date().getTime() + (60*60*6))
  47. logAttacks(false);
  48. else
  49. logAttacks(true);
  50. }
  51.  
  52. function logAttacks(full){
  53. var selections = 'attacks' + (full ? 'full' : '');
  54. var url = 'https://api.torn.com/user/'+data.id+'?selections='+selections+'&key='+data.apikey;
  55. /*$.ajax({
  56. url: url,
  57. type: 'GET',
  58. success: function(d) {
  59. if(d.error) getApiKey();
  60. else{
  61. save();
  62. }
  63. }
  64. });*/
  65. }
  66.  
  67. function profileView(){
  68. var userid = getParameterByName('XID');
  69. var userData = data[userid];
  70. var content =
  71. // profileViewSelectionPopUp()+ // TODO: Figoure out how to call tampermonkey function from the injected code.
  72. '<div id="compareStats">' +
  73. 'Loading...' +
  74. '<br />' +
  75. '</div>' +
  76. '<hr />' +
  77. '<b>Notes</b><br />' +
  78. getUserValue(userid, 'notes')+
  79. '<br />';
  80.  
  81. var compareFunc = function(){$('#compareStats').replaceWith(compareTemplate(userid, data.userid));};
  82. apiUserStats(userid, compareFunc);
  83. apiUserStats(data.userid, compareFunc);
  84.  
  85. var block = $(
  86. '<div class="profile-wrapper medals-wrapper m-top10">' +
  87. '<div class="menu-header">Torn Helper</div>' +
  88. '<div class="profile-container"> ' +
  89. '<div class="profile-container-description">'+content+'</div>' +
  90. '</div>' +
  91. '<div class="clear"></div></div>');
  92.  
  93. $(block).insertAfter('.tutorial-cont + .profile-wrapper');
  94. }
  95.  
  96. function profileViewSelectionPopUp(){
  97. var possibilities = possibleStats();
  98. var popupHtml = '<div><fieldset><legend>Select:</legend>';
  99. for(var p in possibilities){
  100. var o = possibilities[p];
  101. var checked = inArray(p, data.profileview.display) ? 'checked' : '';
  102.  
  103. popupHtml += '<label for="checkbox'+p+'">'+o.display+'</label>: '+
  104. '<input type="checkbox" name="checkbox'+p+'" id="view'+p+'" '+checked+'> ';
  105. }
  106. popupHtml += '</fieldset></div>';
  107. var popup = popupWindow(
  108. {
  109. element: '#editProfileView',
  110. title: 'Edit Profile view'
  111. },
  112. popupHtml,
  113. [
  114. {
  115. 'display': 'Save',
  116. 'close': false, // default: true // TODO: Not working!
  117. 'callback': function(){
  118. for(var p in possibleStats()){
  119. alert(p);
  120. }
  121. $(this).dialog("close");
  122. }
  123. }
  124. ]
  125. );
  126.  
  127. var button = '<div style="float:right">' +
  128. '<button id="editProfileView">Edit</button></div>';
  129.  
  130. return button+popup;
  131. }
  132.  
  133. /**
  134. * Example usage:
  135. * popupWindow(
  136. * { 'element': '#myDialogButton', 'title': 'Hello World' },
  137. * '<h3>Something</h3><input type="text" id="myfield" />',
  138. * [{'display': 'Save',
  139. * 'close': false, // default: true
  140. * callback: function(){var something = $("#myfield").val();}
  141. * }]);
  142. */
  143. function popupWindow(e, content, buttons){
  144. var script = '<script>$("'+e.element+'").click(function(){$("#dialog-message").dialog({'+
  145. 'modal: true,'+
  146. 'draggable: true,'+
  147. 'resizable: true,'+
  148. 'position: [\'center\'],'+
  149. 'show: \'blind\','+
  150. 'hide: \'blind\','+
  151. 'width: 400,'+
  152. 'buttons: [';
  153. var test = '';
  154. for(var i = 0; i < buttons.length; i++){
  155. var a = buttons[i].callback;
  156. script += '{';
  157. script += 'text: \''+buttons[i].display+'\',';
  158. script += 'id: \'dialogButton'+i+'\',';
  159. script += 'click: '+a;
  160. /*
  161. if('close' in buttons[i] || buttons[i].close)
  162. script += '$(this).dialog("close");';*/
  163. script += '}';
  164.  
  165. // TODO: Support multiple buttons!
  166. }
  167. // todo: remove last char
  168. script += ']}';
  169. script += ');});'+test;
  170.  
  171. script += '</script>';
  172.  
  173. var html = '<div id="dialog-message" title="'+e.title+'" style="display: none;">';
  174. html += content;
  175. html += '</div>';
  176.  
  177. return script+html;
  178. }
  179.  
  180. function inArray(c, a){
  181. // Somehow $.inArray is not working? ?
  182. for(var i = 0; i < a.length; i++){
  183. if(c == a[i]) return true;
  184. }
  185. return false;
  186. }
  187.  
  188. function getUserValue(userid, property){
  189. var user = data[userid];
  190. if(user){
  191. if($.isArray(property)){
  192. for(var i = 0; i < property.length; i++){
  193. user = user[property[i]];
  194. }
  195. return user;
  196. }else{
  197. var userData = user[property];
  198. if(userData){
  199. return userData;
  200. }
  201. }
  202. }
  203. return -1;
  204. }
  205.  
  206. function setUserValue(userid, property, value){
  207. if(data[userid] === undefined) data[userid] = {};
  208. data[userid][property] = value;
  209. }
  210.  
  211. function save(){
  212. localStorage.setItem('jebster.torn', JSON.stringify(data));
  213. }
  214.  
  215. function saveOwnData(){
  216. // TODO: Maybe only save when needed
  217. var profileLink = $("#t-blue#h").context.URL.toString();
  218. var start = profileLink.indexOf('XID')+4;
  219. var end = profileLink.indexOf('&') ? profileLink.indexOf('&') - start : start - profileLink.length;
  220. var id = profileLink.substr(start, end);
  221. data.me = {'id': id};
  222. save();
  223. }
  224.  
  225. function loadData(){
  226. data = localStorage.getItem('jebster.torn');
  227. if(data === undefined || data === null){
  228. // Default settings
  229. data = {
  230. profileview:{
  231. display: ['xanax','logins','refill','timeplayed']
  232. }
  233. };
  234. }else{
  235. data = JSON.parse(data);
  236. }
  237.  
  238. if(data.apikey === undefined || data.apikey === ''){
  239. getApiKey();
  240. }
  241. }
  242.  
  243. var asked = false;
  244. function getApiKey(){
  245. // Add some beautiful input/popup on the page itself
  246. if(asked) return; asked = true;
  247. var key = prompt('You API Key', 'key');
  248. if(!('me' in data)) data.me = {};
  249. data.pikey = key;
  250. console.log(data);
  251. save();
  252. }
  253.  
  254. function apiUserStats(userid, cb){
  255. var lastRequest = getUserValue(userid, 'lastRequest');
  256. var now = new Date();
  257. if(lastRequest === 0 || lastRequest < now.getTime() - (60*60*5)){ // TODO:
  258. var selections = 'personalstats,basic';
  259. var url = 'https://api.torn.com/user/'+userid+'?selections='+selections+'&key='+data.apikey;
  260. $.ajax({
  261. url: url,
  262. type: 'GET',
  263. success: function(data) {
  264. if(data.error) getApiKey();
  265. else{
  266. setUserValue(userid, 'stats', data.personalstats);
  267. setUserValue(userid, 'lastRequest', now.getTime());
  268. setUserValue(userid, 'username', data.name);
  269. save();
  270. cb(data);
  271. }
  272. }
  273. });
  274. }else{
  275. cb(data[userid].stats);
  276. }
  277. }
  278.  
  279. function compareTemplate(user1Id, user2Id){
  280. console.log(user1Id + ' : ' + user2Id);
  281. var css = '<style>'+
  282. '.tornHelper{' +
  283. 'min-width:200px;' +
  284. '}' +
  285. '</style>';
  286.  
  287. var html = css+'<ul class="basic-list">' +
  288. '<li>' +
  289. '<div class="user-information-section left"><span class="bold"></span></div>' +
  290. '<div class="user-information-section left tornHelper"><span class="bold">'+getUserValue(user1Id, 'username')+'</span></div>' +
  291. '<div class="tornHelper"><span class="bold">'+getUserValue(user2Id, 'username')+' (You)</span></div>' +
  292. '</li>';
  293.  
  294. var stats = possibleStats();
  295. for(var i = 0; i < data.profileview.display.length; i++){
  296. var display = stats[data.profileview.display[i]];
  297.  
  298. var user1Value = getUserValue(user1Id, display.apiname);
  299. var user2Value = getUserValue(user2Id, display.apiname);
  300.  
  301. if(display.extra){
  302. e1 = getUserValue(user1Id, display.extra.apiname);
  303. e2 = getUserValue(user2Id, display.extra.apiname);
  304. if(display.extra.format){
  305. e1 = '<span>{0}</span>'.format(display.extra.format(e1));
  306. e2 = '<span>{0}</span>'.format(display.extra.format(e2));
  307. }
  308.  
  309. user1Value += e1;
  310. user2Value += e2;
  311. }
  312.  
  313. html += '<li>' +
  314. '<div class="user-information-section left"><span class="bold">' +
  315. display.display +
  316. '</span></div>' +
  317. '<div class="user-information-section left tornHelper">' +
  318. user1Value +'</div>' +
  319. '<div class="tornHelper">'+user2Value+'</div>' +
  320. '</li>';
  321. }
  322. html += '</ul>';
  323. return html;
  324. }
  325.  
  326. function possibleStats(){
  327. return {
  328. xanax:{apiname:['stats','xantaken'], display: 'Xanax taken'},
  329. logins:{apiname:['stats','logins'], display: 'Logins'},
  330. timeplayed:{apiname:['stats','useractivity'], display: 'Time played'},
  331. refills:{apiname:['stats','refills'], display: 'Refills'}
  332. };
  333. }
  334.  
  335. function removeFirstAndLastLine(text){
  336. var lines = text.split('\n');
  337. lines.splice(0,1);
  338. lines.splice(-1,1);
  339. var newtext = lines.join('\n');
  340. }
  341.  
  342. function formatSeconds(s){
  343. var minutes = Math.floor(s/60)%60;
  344. var hours = Math.floor(s/(60*60))%24;
  345. var days = Math.floor(s/(60*60*24));
  346. var seconds = s%60;
  347.  
  348. return '{0}d {1}h {2}m {3}s'.format(days, hours, minutes, seconds);
  349. }
  350.  
  351. // Taken from: http://stackoverflow.com/a/15724300/1832471
  352. function getCookieValue(name) {
  353. var nameEQ = name + "=";
  354. var ca = document.cookie.split(';');
  355. for(var i=0;i < ca.length;i++) {
  356. var c = ca[i];
  357. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  358. if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
  359. }
  360. return null;
  361. }
  362.  
  363. // Taken from: http://stackoverflow.com/a/901144/1832471
  364. function getParameterByName(name, url) {
  365. if (!url) {
  366. url = window.location.href;
  367. }
  368. name = name.replace(/[\[\]]/g, "\\$&");
  369. var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
  370. results = regex.exec(url);
  371. if (!results) return null;
  372. if (!results[2]) return '';
  373. return decodeURIComponent(results[2].replace(/\+/g, " "));
  374. }