Advertisement
Guest User

Untitled

a guest
Dec 14th, 2018
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.71 KB | None | 0 0
  1. // ==UserScript==
  2. // @name PoE Multilive
  3. // @namespace orlp
  4. // @version 0.9
  5. // @description Combine multiple PoE live searches
  6. // @author orlp
  7. // @match *://poe.trade/
  8. // @require https://code.jquery.com/jquery-3.1.1.min.js
  9. // @require https://cdn.jsdelivr.net/clipboard.js/1.5.13/clipboard.min.js
  10. // @require https://raw.githubusercontent.com/joewalnes/reconnecting-websocket/master/reconnecting-websocket.min.js
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @grant unsafeWindow
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. var Tinycon = unsafeWindow.Tinycon;
  20. var live_load_settings = unsafeWindow.live_load_settings;
  21. var live_notify = unsafeWindow.live_notify;
  22. var update_timers = unsafeWindow.update_timers;
  23.  
  24. var multilive_active = false;
  25.  
  26. var strip_ws_separators = function(str) {
  27. return str.replace(/[ \t\n:;|\/\\=@#$%^&*-]*$/,"")
  28. .replace(/^[ \t\n:;|\/\\=@#$%^&*-]*/,"");
  29. };
  30.  
  31. $(".form-choose-action .button-group").append('<li><a href="#" id="multilive-btn" class="button tiny secondary" onclick="return false;">Multilive</a></li>');
  32. $('<div class="custom" id="multilive" style="display: none;"><p>Place poe.trade search URLs in the box below, <b>one per line</b>. Any new items will be tracked here. It\'s suggested you write a short description on the same line, as this will be displayed on a match. For example:</p><p><pre>4mod essence drain jewel: http://poe.trade/search/abcdefghijklmnop</pre></p><p>Any line not containing <code>http://poe.trade</code> will be ignored, so you are free to put comments explaining what the URLs are wherever. You can use this also to temporarily disable an URL, by replacing <tt>http://</tt> with <tt>nope://</tt> or similar.</p><textarea style="height: 20em;" id="multilive-urls"></textarea><p>Account name blacklist, separated by commas:<input type="text" id="multilive-blacklist"></input></p></div>').insertAfter("#search");
  33. $("#multilive").append('<div class=\"alert-box\" id=\"live-notification-settings\">\r\nNotification settings: <label for=\"live-notify-sound\">Notify with sound<\/label> <input onclick=\"live_update_settings()\" type=\"checkbox\" id=\"live-notify-sound\"> | <label for=\"live-notify-browser\">Notify with a browser notification<\/label> <input onclick=\"live_update_settings()\" type=\"checkbox\" id=\"live-notify-browser\"> <span style="padding-left: 2em;">Searches connected: <span id="multilive-connected">0/0</span></span>\r\n<a href=\"#\" class=\"right\" onclick=\"live_notify(); return false;\">test notification<\/a>\r\n<audio id=\"live-audio\">\r\n<source src=\"\/static\/notification.mp3\" type=\"audio\/mpeg\">\r\n<\/audio>\r\n<\/div>\r\n<div id="items" style="min-height: 1000px;"><h2 id="multilive-init-msg"><br>Results will be shown here.<br><br>This page intentionally left blank.</h2></div>');
  34.  
  35. var url_autosave = GM_getValue("urls", '""');
  36. var blacklist_autosave = GM_getValue("blacklist", '""');
  37. $("#multilive-urls").val(JSON.parse(url_autosave));
  38. $("#multilive-blacklist").val(JSON.parse(blacklist_autosave));
  39.  
  40. var searches, search_lines, blacklist_accounts, last_known_id, last_found_id, currently_searching;
  41. var init_multilive = function() {
  42. searches = [];
  43. search_lines = {};
  44. last_known_id = {};
  45. last_found_id = {};
  46. currently_searching = {};
  47. blacklist_accounts = [];
  48. update_searched();
  49. update_blacklist();
  50. };
  51.  
  52. // Item count favicon.
  53. var displayed_item_count = 0;
  54. var is_focused = true;
  55. $(window).blur(function() { is_focused = false; });
  56. $(window).focus(function() {
  57. is_focused = true;
  58. displayed_item_count = 0;
  59. Tinycon.setBubble(0);
  60. });
  61.  
  62. var dispatch_search = function(search) {
  63. if (currently_searching[search]) return;
  64.  
  65. currently_searching[search] = true;
  66. $.post("http://poe.trade/search/" + search + "/live", { "id": last_found_id[search] }, function(data) {
  67. if (!multilive_active) return;
  68.  
  69. if (data.data) {
  70. console.log("found", last_found_id[search], "with data", search, "newid", data.newid);
  71. } else {
  72. console.log("found", last_found_id[search], "without data", search, "newid", data.newid);
  73. }
  74.  
  75. last_found_id[search] = data.newid;
  76.  
  77. if (data.uniqs && sockets[search].readyState == 1) {
  78. var uniqs = data.uniqs;
  79. for (var i = 0; i < uniqs.length; ++i) {
  80. sockets[search].send(JSON.stringify({
  81. type: "subscribe",
  82. value: uniqs[i]
  83. }));
  84. }
  85. }
  86.  
  87. if (data.data) {
  88. var not_ignored_count = data.count;
  89. var new_html = $.parseHTML(data.data);
  90. $(new_html).find('tbody.item').each(function(_, item) {
  91. item = $(item);
  92. var seller = item.attr('data-seller');
  93. var description = search_lines[search].replace(/https?:\/\/poe.trade\/search\/([a-z]+)(\/live)?\/?/, "");
  94. var profile = $('<a href="https://www.pathofexile.com/account/view-profile/'+seller+'" style="color: #aaa; font-size: 0.8em;" target="_blank"></a>').text(seller);
  95. item.find('.bottom-row .first-cell:empty').append(profile);
  96. var link = $('<a href="http://poe.trade/search/'+search+'" style="color: #aaa;" target="_blank"></a>').text(strip_ws_separators(description));
  97. item.find('.bottom-row .third-cell:empty').append(link);
  98.  
  99. if (blacklist_accounts.indexOf($.trim(seller)) > -1) {
  100. console.log("blacklisted", item, seller);
  101. item.hide().remove();
  102. not_ignored_count -= 1;
  103. }
  104. });
  105.  
  106. if (not_ignored_count > 0) {
  107. $("#multilive-init-msg").hide();
  108. $("#items").prepend(new_html);
  109. $("#items > div").filter(":gt(100)").hide().remove(); // Remove old woops.
  110. live_notify();
  111. }
  112.  
  113. if (!is_focused) {
  114. displayed_item_count += not_ignored_count;
  115. Tinycon.setBubble(displayed_item_count);
  116. }
  117. }
  118.  
  119. currently_searching[search] = false;
  120. //if (last_found_id[search] < last_known_id[search]) dispatch_search(search);
  121. }).fail(function() {
  122. console.log("error while retrieving data", search);
  123. currently_searching[search] = false;
  124. //setTimeout(function() {
  125. // if (last_found_id[search] < last_known_id[search]) dispatch_search(search);
  126. //}, 1000);
  127. });
  128. };
  129.  
  130. setInterval(function() {
  131. for (var search in last_found_id) {
  132. if (last_found_id[search] < last_known_id[search]) dispatch_search(search);
  133. }
  134. }, 1000);
  135.  
  136. var update_searched = function() {
  137. var text = $("#multilive-urls").val();
  138. searches = [];
  139. search_lines = {};
  140. var lines = text.split(/\r?\n/).forEach(function(line) {
  141. var search = line.match(/https?:\/\/poe.trade\/search\/([a-z]+)/);
  142. if (search) {
  143. searches.push(search[1]);
  144. search_lines[search[1]] = line;
  145.  
  146. if (!(search[1] in last_known_id)) {
  147. last_known_id[search[1]] = -1;
  148. last_found_id[search[1]] = -1;
  149. }
  150. }
  151. });
  152.  
  153. GM_setValue("urls", JSON.stringify(text));
  154.  
  155. update_sockets();
  156. };
  157.  
  158. var sockets = {};
  159.  
  160. var update_connected = function() {
  161. var num_connected = 0;
  162. for (var search in sockets) {
  163. if (sockets[search].readyState == 1) num_connected += 1;
  164. }
  165.  
  166. $("#multilive-connected").text(num_connected.toString() + "/" + searches.length.toString());
  167. };
  168.  
  169. var socket_heartbeat = function() {
  170. for (var search in sockets) {
  171. if (sockets[search].readyState == 1) sockets[search].send("ping");
  172. }
  173. };
  174. setInterval(socket_heartbeat, 30 * 1000);
  175.  
  176. var socket_onopen = function(event) {
  177. update_connected();
  178. this.send('{"type": "version", "value": 3}');
  179. };
  180.  
  181. var socket_onmessage = function(event) {
  182. var msg = $.parseJSON(event.data);
  183. if (typeof msg == "number") {
  184. console.log("notify", this.search, last_known_id[this.search], "->", msg);
  185. last_known_id[this.search] = Math.max(last_known_id[this.search], msg);
  186. dispatch_search(this.search);
  187. return;
  188. }
  189. switch (msg.type) {
  190. case "notify":
  191. console.log("notify", this.search, last_known_id[this.search], "->", msg.value);
  192. last_known_id[this.search] = Math.max(last_known_id[this.search], msg.value);
  193. dispatch_search(this.search);
  194. break;
  195. case "del":
  196. $(".item-live-" + msg.value).addClass("item-gone");
  197. break;
  198. }
  199. };
  200.  
  201. var socket_onclose = function(event) {
  202. update_connected();
  203. var search = this.search;
  204. setTimeout(function() {
  205. if (!multilive_active) return;
  206. create_socket(search);
  207. }, 1000);
  208. };
  209.  
  210. var create_socket = function(search) {
  211. var socket = new WebSocket("ws://live.poe.trade/" + search);
  212. sockets[search] = socket;
  213. socket.search = search;
  214. socket.onopen = socket_onopen;
  215. socket.onmessage = socket_onmessage;
  216. socket.onclose = socket_onclose;
  217. socket.onerror = socket_onclose;
  218. };
  219.  
  220. var delete_socket = function(socket) {
  221. delete sockets[socket.search];
  222. socket.onclose = function() { }; // Disable handler first.
  223. socket.onerror = function() { };
  224. socket.close();
  225. };
  226.  
  227. var update_sockets = function() {
  228. for (var i = 0; i < searches.length; ++i) {
  229. if (!(searches[i] in sockets)) {
  230. create_socket(searches[i]);
  231. dispatch_search(searches[i]);
  232. }
  233. }
  234.  
  235. for (var search in sockets) {
  236. if (searches.indexOf(search) == -1) delete_socket(sockets[search]);
  237. }
  238.  
  239. update_connected();
  240. };
  241.  
  242. var update_blacklist = function() {
  243. var blacklist = $("#multilive-blacklist").val();
  244. blacklist_accounts = [];
  245. var accounts = blacklist.split(/,/).forEach(function(account) {
  246. blacklist_accounts.push($.trim(account));
  247. });
  248. GM_setValue("blacklist", JSON.stringify(blacklist));
  249. };
  250.  
  251. $("#multilive-urls").on("change keyup paste", update_searched);
  252. $("#multilive-blacklist").on("change keyup paste", update_blacklist);
  253.  
  254. var show_multilive = function() {
  255. $("#search").hide();
  256. $("#import").hide();
  257. $("#multilive").show();
  258. $("#search-btn").removeClass("active");
  259. $("#import-btn").removeClass("active");
  260. $(this).addClass("active");
  261. multilive_active = true;
  262. init_multilive();
  263. };
  264.  
  265. var hide_multilive = function() {
  266. $("#multilive").hide();
  267. $("#multilive-btn").removeClass("active");
  268. multilive_active = false;
  269. for (var search in sockets) delete_socket(sockets[search]);
  270. };
  271.  
  272. $("#multilive-btn").click(show_multilive);
  273. $("#search-btn").click(hide_multilive);
  274. $("#import-btn").click(hide_multilive);
  275.  
  276. live_load_settings();
  277.  
  278. var info_heartbeat = function() {
  279. setTimeout(info_heartbeat, 1000);
  280. if (!multilive_active) return;
  281.  
  282. update_timers();
  283. };
  284. info_heartbeat();
  285.  
  286. // Fix whisper button and make big.
  287. var whisperClipboard = new Clipboard(".whisper-btn", {
  288. text: function(trigger) { return whisperMessage(trigger); }
  289. });
  290. whisperClipboard.on("success", function(e) {
  291. $(e.trigger).text("Copied to clipboard");
  292. });
  293. whisperClipboard.on("error", function(e) {
  294. sendWhisper(e.trigger);
  295. });
  296.  
  297. $("<style>.icon-td { cursor: pointer; }</style>").appendTo("head");
  298. var big_whisper = new Clipboard(".icon-td", {
  299. text: function(trigger) { return whisperMessage(trigger); }
  300. });
  301. big_whisper.on("success", function(e) {
  302. $(e.trigger).parents(".item").find(".whisper-btn").text("Copied to clipboard");
  303. });
  304. big_whisper.on("error", function(e) {
  305. sendWhisper(e.trigger);
  306. });
  307. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement