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.1.2
  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. // debugger;
  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. loadAttackLog();
  39.  
  40.  
  41. if(site.indexOf('profiles.php') > 0) profileView();
  42.  
  43. })();
  44.  
  45. function loadAttackLog(){
  46. var selections = 'attacks';
  47. if('attackLogLoad' in data)
  48. //if(data.attackLogLoad > new Date().getTime() + (60*60*6))
  49. logAttacks(false);
  50. else
  51. logAttacks(true);
  52. }
  53.  
  54. function logAttacks(full){
  55. var selections = 'attacks' + (full ? 'full' : '');
  56. var url = 'https://api.torn.com/user/'+data.me.id+'?selections='+selections+'&key='+data.apikey;
  57. var now = new Date().getTime();
  58. if(!('attackLogLoad' in data) || data.attackLogLoad < now - (60*60*1000)){ // every one hour
  59. data.attackLogLoad = now;
  60.  
  61. apiCall(url, function(d) {
  62. if(d.error) getApiKey();
  63. else{
  64. for(var p in d.attacks){
  65. if (d.attacks.hasOwnProperty(p)) {
  66. var attack = d.attacks[p];
  67. var defender_id = attack.defender_id;
  68. if(!(defender_id in data)) data[defender_id] = {};
  69.  
  70. if(attack.attacker_id == data.me.id){
  71. // My attack
  72. if(!('attacks' in data[defender_id])) {console.log('Test'); data[defender_id].attacks = {};}
  73. data[defender_id].attacks[p] = attack;
  74. }else{
  75. // I'm being attacked
  76. }
  77. }
  78.  
  79. }
  80.  
  81. save();
  82. }
  83. });
  84. }
  85. }
  86.  
  87. function profileView(){
  88. var userid = getParameterByName('XID');
  89. var userData = data[userid];
  90. var content = '';
  91. // content += profileViewSelectionPopUp()+ // TODO: Figoure out how to call tampermonkey function from the injected code.
  92. content += '<div id="compareStats">';
  93. content += 'Loading...';
  94. content += '<br />';
  95. content += '</div>';
  96. // content += '<hr />';
  97. // content += '<b>Notes</b><br />';
  98. // content += getUserValue(userid, 'notes');
  99. // content += '<br />';
  100.  
  101. var block = $(
  102. '<div class="profile-wrapper medals-wrapper m-top10">' +
  103. '<div class="menu-header">Torn Helper</div>' +
  104. '<div class="profile-container"> ' +
  105. '<div class="profile-container-description">'+content+'</div>' +
  106. '</div>' +
  107. '<div class="clear"></div></div>');
  108.  
  109. $(block).insertAfter('.tutorial-cont + .profile-wrapper');
  110.  
  111. var compareFunc = function(){
  112. $('#compareStats').replaceWith(compareTemplate(userid, data.me.userid));
  113. };
  114. apiUserStats(userid, compareFunc);
  115. apiUserStats(data.me.userid, compareFunc);
  116. }
  117.  
  118. function profileViewSelectionPopUp(){
  119. var possibilities = possibleStats();
  120. var popupHtml = '<div><fieldset><legend>Select:</legend>';
  121. for(var p in possibilities){
  122. var o = possibilities[p];
  123. var checked = inArray(p, data.profileview.display) ? 'checked' : '';
  124.  
  125. popupHtml += '<label for="checkbox'+p+'">'+o.display+'</label>: '+
  126. '<input type="checkbox" name="checkbox'+p+'" id="view'+p+'" '+checked+'> ';
  127. }
  128. popupHtml += '</fieldset></div>';
  129. var popup = popupWindow(
  130. {
  131. element: '#editProfileView',
  132. title: 'Edit Profile view'
  133. },
  134. popupHtml,
  135. [
  136. {
  137. 'display': 'Save',
  138. 'close': false, // default: true // TODO: Not working!
  139. 'callback': function(){
  140. for(var p in possibleStats()){
  141. alert(p);
  142. }
  143. $(this).dialog("close");
  144. }
  145. }
  146. ]
  147. );
  148.  
  149. var button = '<div style="float:right">' +
  150. '<button id="editProfileView">Edit</button></div>';
  151.  
  152. return button+popup;
  153. }
  154.  
  155. /**
  156. * Example usage:
  157. * popupWindow(
  158. * { 'element': '#myDialogButton', 'title': 'Hello World' },
  159. * '<h3>Something</h3><input type="text" id="myfield" />',
  160. * [{'display': 'Save',
  161. * 'close': false, // default: true
  162. * callback: function(){var something = $("#myfield").val();}
  163. * }]);
  164. */
  165. function popupWindow(e, content, buttons){
  166. var script = '<script>$("'+e.element+'").click(function(){$("#dialog-message").dialog({'+
  167. 'modal: true,'+
  168. 'draggable: true,'+
  169. 'resizable: true,'+
  170. 'position: [\'center\'],'+
  171. 'show: \'blind\','+
  172. 'hide: \'blind\','+
  173. 'width: 400,'+
  174. 'buttons: [';
  175. var test = '';
  176. for(var i = 0; i < buttons.length; i++){
  177. var a = buttons[i].callback;
  178. script += '{';
  179. script += 'text: \''+buttons[i].display+'\',';
  180. script += 'id: \'dialogButton'+i+'\',';
  181. script += 'click: '+a;
  182. /*
  183. if('close' in buttons[i] || buttons[i].close)
  184. script += '$(this).dialog("close");';*/
  185. script += '}';
  186.  
  187. // TODO: Support multiple buttons!
  188. }
  189. // todo: remove last char
  190. script += ']}';
  191. script += ');});'+test;
  192.  
  193. script += '</script>';
  194.  
  195. var html = '<div id="dialog-message" title="'+e.title+'" style="display: none;">';
  196. html += content;
  197. html += '</div>';
  198.  
  199. return script+html;
  200. }
  201.  
  202. function inArray(c, a){
  203. // Somehow $.inArray is not working? ?
  204. for(var i = 0; i < a.length; i++){
  205. if(c == a[i]) return true;
  206. }
  207. return false;
  208. }
  209.  
  210. function getUserValue(userid, property){
  211. var user = data[userid];
  212. if(user){
  213. if($.isArray(property)){
  214. for(var i = 0; i < property.length; i++){
  215. user = user[property[i]];
  216. }
  217. return user;
  218. }else{
  219. var userData = user[property];
  220. if(userData){
  221. return userData;
  222. }
  223. }
  224. }
  225. return -1;
  226. }
  227.  
  228. function setUserValue(userid, property, value){
  229. if(data[userid] === undefined) data[userid] = {};
  230. data[userid][property] = value;
  231. }
  232.  
  233. function save(){
  234. localStorage.setItem('jebster.torn', JSON.stringify(data));
  235. }
  236.  
  237. function saveOwnData(){
  238. if(!('me' in data) || !('id' in data.me) || data.me.id < 1){
  239. var url = 'https://api.torn.com/user/'+data.me.id+'?selections=basic&key='+data.apikey;
  240. apiCall(url, function(d) {
  241. id = d.player_id;
  242. data.me = {'id': id};
  243. save();
  244. });
  245. }
  246. }
  247.  
  248. function loadData(){
  249. data = localStorage.getItem('jebster.torn');
  250. if(data === undefined || data === null){
  251. // Default settings
  252. data = {
  253. profileview:{
  254. display: ['xanax','logins','refills','timeplayed']
  255. }
  256. };
  257. }else{
  258. data = JSON.parse(data);
  259. }
  260.  
  261. if(data.apikey === undefined || data.apikey === ''){
  262. getApiKey();
  263. }
  264. }
  265.  
  266. var asked = false;
  267. function getApiKey(){
  268. // Add some beautiful input/popup on the page itself
  269. if(asked) return; asked = true;
  270. var key = prompt('You API Key', 'key');
  271. if(!('me' in data)) data.me = {};
  272. data.apikey = key;
  273. save();
  274. }
  275.  
  276. function apiUserStats(userid, cb){
  277. var lastRequest = getUserValue(userid, 'lastRequest');
  278. var now = new Date();
  279. if(lastRequest === 0 || lastRequest < now.getTime() - (60*60*5*1000)){ // TODO:
  280. var selections = 'personalstats,basic';
  281. var url = 'https://api.torn.com/user/'+userid+'?selections='+selections+'&key='+data.apikey;
  282. apiCall(url, function(data) {
  283. if(data.error) getApiKey();
  284. else{
  285. setUserValue(userid, 'stats', data.personalstats);
  286. setUserValue(userid, 'lastRequest', now.getTime());
  287. setUserValue(userid, 'username', data.name);
  288. save();
  289. cb(data);
  290. }
  291. });
  292. }else{
  293. cb(data[userid].stats);
  294. }
  295. }
  296.  
  297. function compareTemplate(user1Id, user2Id){
  298.  
  299. var css = '<style>'+
  300. '.tornHelper{' +
  301. 'min-width:200px;' +
  302. '}' +
  303. '</style>';
  304.  
  305. var html = css+'<div class="profile-container basic-info"><ul class="basic-list">' +
  306. '<li>' +
  307. '<div class="user-information-section left"><span class="bold"></span></div>' +
  308. '<div class="user-information-section left tornHelper"><span class="bold">'+getUserValue(user1Id, 'username')+'</span></div>' +
  309. '<div class="tornHelper"><span class="bold">'+getUserValue(user2Id, 'username')+' (You)</span></div>' +
  310. '</li>';
  311.  
  312. var stats = possibleStats();
  313. for(var i = 0; i < data.profileview.display.length; i++){
  314. var display = stats[data.profileview.display[i]];
  315. if(stats[data.profileview.display[i]]){
  316. var user1Value = getUserValue(user1Id, display.apiname);
  317. var user2Value = getUserValue(user2Id, display.apiname);
  318.  
  319. user1Value = user1Value ? user1Value : 0;
  320. user2Value = user2Value ? user2Value : 0;
  321.  
  322. if(display.format){
  323. user1Value = display.format(user1Value);
  324. user2Value = display.format(user2Value);
  325. }
  326.  
  327. html += '<li>' +
  328. '<div class="user-information-section left"><span class="bold">' +
  329. display.display +
  330. '</span></div>' +
  331. '<div class="user-information-section left tornHelper">' +
  332. user1Value +'</div>' +
  333. '<div class="tornHelper">'+user2Value+'</div>' +
  334. '</li>';
  335. }
  336. }
  337. html += '</ul><hr />';
  338. var attacks = {hosp: {display: 'Hosped', times: 0}, mug: {display: 'Mugged', times: 0}, left: {display: 'Left', times: 0}, lost: {display: 'Lost', times: 0}};
  339. if('attacks' in data[user1Id]){
  340. for(var p in data[user1Id].attacks){
  341. var attack = data[user1Id].attacks[p];
  342.  
  343. switch(attack.result){
  344. case 'Mug':
  345. attacks.mug.times++;
  346. break;
  347. case 'Hospitalize':
  348. attacks.hosp.times++;
  349. break;
  350. case 'Leave':
  351. attacks.left.times++;
  352. break;
  353. case 'Lose':
  354. attacks.lost.times++;
  355. break;
  356. }
  357. }
  358. }
  359. html += 'Attacks you made against \''+getUserValue(user1Id, 'username')+'\'';
  360. html += '<ul class="basic-list">';
  361. for(var type in attacks){
  362. html += '<li>';
  363. html += '<div class="user-information-section left width112"><span class="bold">'+attacks[type].display+'</span></div>';
  364. html += attacks[type].times;
  365. html += '</li>';
  366. }
  367. html += '</ul></div>';
  368.  
  369. return html;
  370. }
  371.  
  372. function possibleStats(){
  373. return {
  374. xanax:{apiname:['stats','xantaken'], display: 'Xanax taken'},
  375. refills:{apiname:['stats','refills'], display: 'Refills'},
  376. logins:{apiname:['stats','logins'], display: 'Logins'},
  377. timeplayed:{apiname:['stats','useractivity'], display: 'Time played', format: formatSeconds}
  378. };
  379. }
  380.  
  381. function apiCall(url, cb){
  382. console.log(url);
  383. $.ajax({
  384. url: url,
  385. type: 'GET',
  386. success: function(data) {
  387. cb(data);
  388. },
  389. //async: false
  390. });
  391. }
  392.  
  393. function removeFirstAndLastLine(text){
  394. var lines = text.split('\n');
  395. lines.splice(0,1);
  396. lines.splice(-1,1);
  397. var newtext = lines.join('\n');
  398. }
  399.  
  400. function formatSeconds(s){
  401. var minutes = Math.floor(s/60)%60;
  402. var hours = Math.floor(s/(60*60))%24;
  403. var days = Math.floor(s/(60*60*24));
  404. var seconds = s%60;
  405.  
  406. return '{0}d {1}h {2}m {3}s'.format(days, hours, minutes, seconds);
  407. }
  408.  
  409. // Taken from: http://stackoverflow.com/a/15724300/1832471
  410. function getCookieValue(name) {
  411. var nameEQ = name + "=";
  412. var ca = document.cookie.split(';');
  413. for(var i=0;i < ca.length;i++) {
  414. var c = ca[i];
  415. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  416. if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
  417. }
  418. return null;
  419. }
  420.  
  421. // Taken from: http://stackoverflow.com/a/901144/1832471
  422. function getParameterByName(name, url) {
  423. if (!url) {
  424. url = window.location.href;
  425. }
  426. name = name.replace(/[\[\]]/g, "\\$&");
  427. var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
  428. results = regex.exec(url);
  429. if (!results) return null;
  430. if (!results[2]) return '';
  431. return decodeURIComponent(results[2].replace(/\+/g, " "));
  432. }