Flatmates Plus

Adds blacklist and whitelist filters to the FlatMates website, gets rid of early bird listings

  1. // ==UserScript==
  2. // @name Flatmates Plus
  3. // @namespace http://www.facebook.com/Tophness
  4. // @include https://flatmates.com.au/share-houses/*
  5. // @require https://gf.qytechs.cn/scripts/6217-gm-config/code/GM_config.js?version=23537
  6. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @grant GM_log
  10. // @grant GM_registerMenuCommand
  11. // @version 1.1
  12. // @noframes
  13. // @run-at document-idle
  14. // @description Adds blacklist and whitelist filters to the FlatMates website, gets rid of early bird listings
  15. // ==/UserScript==
  16. GM_config.init('Flatmates Plus Options', {
  17. 'filters':
  18. {
  19. 'label': 'Location Filters',
  20. 'type': 'text',
  21. 'default': 'blacktown'
  22. },
  23. 'blacklist':
  24. {
  25. 'label': 'Descriptions Blacklist',
  26. 'type': 'text',
  27. 'default': 'Not included in rent'
  28. },
  29. 'whitelist':
  30. {
  31. 'label': 'Descriprions Whitelist',
  32. 'type': 'text',
  33. 'default': 'unlimited-internet'
  34. },
  35. 'homeaddress':
  36. {
  37. 'label': 'Work Address (For distance calculating)',
  38. 'type': 'text',
  39. 'default': 'Central Station, Sydney, NSW'
  40. }
  41. });
  42. function opengmcf() {
  43. GM_config.open();
  44. }
  45. GM_registerMenuCommand('Flatmates Plus Options', opengmcf);
  46. var stream = document.querySelector('div[data-react-class^="ListingResults"]');
  47. var whitelist = GM_config.get('whitelist');
  48. var blacklist = GM_config.get('blacklist');
  49. if (whitelist.length != 0) {
  50. whitelist = whitelist.split(',');
  51. }
  52. if (blacklist.length != 0) {
  53. blacklist = blacklist.split(',');
  54. }
  55. function searchProp(id, listingel) {
  56. if (stream) {
  57. var arr = JSON.parse(stream.getAttribute('data-react-props')).listings;
  58. var findid = arr.indexOf('"id":' + id);
  59. if (findid != - 1) {
  60. var listing = arr.substring(findid);
  61. listing = listing.substring(0, arr.indexOf('},{'));
  62. return findProp(listing, listingel);
  63. }
  64. else {
  65. ajaxsubmit('https://flatmates.com.au/P' + id, id, listingel);
  66. }
  67. }
  68. }
  69. function ajaxsubmit(url, id, listingel)
  70. {
  71. var mygetrequest = new ajaxRequest();
  72. mygetrequest.onreadystatechange = function () {
  73. if (mygetrequest.readyState == 4) {
  74. if (mygetrequest.status == 200) {
  75. findPropAjax(mygetrequest.responseText, id, listingel);
  76. }
  77. }
  78. }
  79. mygetrequest.open('GET', url, true);
  80. mygetrequest.send(null);
  81. }
  82. function findPropAjax(arr, id, listingel) {
  83. var findid = arr.indexOf('PropertyListing');
  84. if (findid != - 1) {
  85. //var listing = arr.substring(findid);
  86. //listing = listing.substring(0, arr.indexOf('modal-placeholder'));
  87. //findProp(listing, prop);
  88. findProp(unescapeHtml(arr.substring(findid)), listingel);
  89. }
  90. }
  91. function findProp(listing, listingel) {
  92. if (whitelist.length > 0) {
  93. for (var i6 = 0; i6 < whitelist.length; i6++) {
  94. if (listing.indexOf(whitelist[i6]) == -1) {
  95. listingel.parentNode.removeChild(listingel);
  96. }
  97. }
  98. }
  99. if (blacklist.length > 0) {
  100. for (var i7 = 0; i7 < blacklist.length; i7++) {
  101. if (listing.indexOf(blacklist[i7]) != -1) {
  102. listingel.parentNode.removeChild(listingel);
  103. }
  104. }
  105. }
  106. }
  107. function ajaxRequest() {
  108. var activexmodes = [
  109. 'Msxml2.XMLHTTP',
  110. 'Microsoft.XMLHTTP'
  111. ];
  112. if (window.ActiveXObject) {
  113. for (var i = 0; i < activexmodes.length; i++) {
  114. try {
  115. return new ActiveXObject(activexmodes[i]);
  116. }
  117. catch (e) {
  118. }
  119. }
  120. }
  121. else if (window.XMLHttpRequest)
  122. return new XMLHttpRequest();
  123. else
  124. return false;
  125. }
  126. function unescapeHtml(safe) {
  127. return safe.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#039;/g, '\'');
  128. }
  129. //function unescapeHtml(safe) {
  130. // return $('<div />').html(safe).text();
  131. //}
  132. var i = 0;
  133. function filter(listingel) {
  134. i++;
  135. var id = listingel.getElementsByClassName('link');
  136. if (id.length != 0) {
  137. id = id[0].href.toString();
  138. id = id.substring(id.indexOf('/P') + 2);
  139. searchProp(id, listingel);
  140. }
  141. var earlybird = listingel.getElementsByClassName('home-listing-contact');
  142. if (earlybird.length != 0) {
  143. if (earlybird[0].innerText.indexOf('Free to Message') == -1) {
  144. listingel.parentNode.removeChild(listingel);
  145. }
  146. }
  147. var title = listingel.getElementsByClassName('listing-head');
  148. if (title.length != 0) {
  149. title = title[0].innerText.toString().toLowerCase();
  150. var filters = GM_config.get('filters');
  151. if (filters.length != 0) {
  152. filters = filters.split(',');
  153. for (var i2 = 0; i2 < filters.length; i2++) {
  154. if (title.indexOf(filters[i2].toLowerCase()) != -1) {
  155. listingel.parentNode.removeChild(listingel);
  156. }
  157. }
  158. }
  159. listingel.id = 'listing' + i;
  160. gdist(listingel.id, title);
  161. }
  162. }
  163. function gdist(listingel, title) {
  164. var etitle = document.createElement('div');
  165. etitle.innerHTML = title;
  166. etitle.id = 'etitle';
  167. etitle.style.visibility = 'hidden';
  168. var elistingel = document.createElement('div');
  169. elistingel.innerHTML = listingel;
  170. elistingel.id = 'elistingel';
  171. elistingel.style.visibility = 'hidden';
  172. var ehomeaddress = document.createElement('div');
  173. ehomeaddress.innerHTML = GM_config.get('homeaddress');
  174. ehomeaddress.id = 'ehomeaddress';
  175. ehomeaddress.style.visibility = 'hidden';
  176. document.body.appendChild(etitle);
  177. document.body.appendChild(elistingel);
  178. document.body.appendChild(ehomeaddress);
  179. exec(function () {
  180. var el = document.getElementById('elistingel').innerHTML.toString();
  181. var or = document.getElementById('ehomeaddress').innerHTML.toString();
  182. var des = document.getElementById('etitle').innerHTML.toString();
  183. var TransitOptions = {
  184. modes: [
  185. 'TRAIN',
  186. 'BUS'
  187. ]
  188. }
  189. var service = new google.maps.DistanceMatrixService;
  190. service.getDistanceMatrix({
  191. origins: [
  192. or
  193. ],
  194. destinations: [
  195. des
  196. ],
  197. travelMode: 'TRANSIT',
  198. transitOptions: TransitOptions,
  199. unitSystem: google.maps.UnitSystem.METRIC
  200. }, function (response, status) {
  201. if (status !== 'OK') {
  202. console.log('Error was: ' + status);
  203. } else {
  204. var originList = response.originAddresses;
  205. var destinationList = response.destinationAddresses;
  206. for (var i = 0; i < originList.length; i++) {
  207. var results = response.rows[i].elements;
  208. for (var j = 0; j < results.length; j++) {
  209. var newdiv = document.createElement('div');
  210. newdiv.innerHTML += results[j].duration.text + ' to ' + originList[i] + '<br>';
  211. document.getElementById(el).appendChild(newdiv);
  212. }
  213. }
  214. }
  215. });
  216. });
  217. document.body.removeChild(etitle);
  218. document.body.removeChild(elistingel);
  219. document.body.removeChild(ehomeaddress);
  220. }
  221. function exec(fn) {
  222. var script = document.createElement('script');
  223. script.setAttribute('type', 'application/javascript');
  224. script.textContent = '(' + fn + ')();';
  225. document.body.appendChild(script); // run the script
  226. document.body.removeChild(script); // clean up
  227. }
  228. function removeit(id) {
  229. if (document.getElementById(id)) {
  230. document.getElementById(id).parentNode.removeChild(document.getElementById(id));
  231. }
  232. }
  233. function timefilter(listingel) {
  234. setTimeout(function () {
  235. filter(listingel[0]);
  236. }, 200);
  237. }
  238. waitForKeyElements('div.content-column', timefilter);
  239. function waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
  240. var targetNodes,
  241. btargetsFound;
  242. if (typeof iframeSelector == 'undefined')
  243. targetNodes = $(selectorTxt);
  244. else
  245. targetNodes = $(iframeSelector).contents().find(selectorTxt);
  246. if (targetNodes && targetNodes.length > 0) {
  247. btargetsFound = true;
  248. /*--- Found target node(s). Go through each and act if they
  249. are new.
  250. */
  251. targetNodes.each(function () {
  252. var jThis = $(this);
  253. var alreadyFound = jThis.data('alreadyFound') || false;
  254. if (!alreadyFound) {
  255. //--- Call the payload function.
  256. var cancelFound = actionFunction(jThis);
  257. if (cancelFound)
  258. btargetsFound = false;
  259. else
  260. jThis.data('alreadyFound', true);
  261. }
  262. });
  263. }
  264. else {
  265. btargetsFound = false;
  266. } //--- Get the timer-control variable for this selector.
  267.  
  268. var controlObj = waitForKeyElements.controlObj || {
  269. };
  270. var controlKey = selectorTxt.replace(/[^\w]/g, '_');
  271. var timeControl = controlObj[controlKey];
  272. //--- Now set or clear the timer as appropriate.
  273. if (btargetsFound && bWaitOnce && timeControl) {
  274. //--- The only condition where we need to clear the timer.
  275. clearInterval(timeControl);
  276. delete controlObj[controlKey]
  277. }
  278. else {
  279. //--- Set a timer, if needed.
  280. if (!timeControl) {
  281. timeControl = setInterval(function () {
  282. waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector
  283. );
  284. }, 300
  285. );
  286. controlObj[controlKey] = timeControl;
  287. }
  288. }
  289. waitForKeyElements.controlObj = controlObj;
  290. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址