xREL Release Filter

Release filter for xREL. Also hides the "new comments" box upon clicking on its title. Special thanks to GarionCZ for his SteamGifts filter script.

  1. // ==UserScript==
  2. // @name xREL Release Filter
  3. // @namespace tag:https://github.com/0657code/greasemonkey-xrel-filter,2015-07-16
  4. // @description Release filter for xREL. Also hides the "new comments" box upon clicking on its title. Special thanks to GarionCZ for his SteamGifts filter script.
  5. // @author 0657_Code
  6. // @include http://www.xrel.to/movie/*/releases.html*
  7. // @include http://www.xrel.to/tv/*/releases.html*
  8. // @version 1.1
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // ==/UserScript==
  12.  
  13. // Constants
  14. {
  15. var ID_DIV_HEADER = "idDivHeader";
  16. var ID_DIV_CONTENT = "idDivContent";
  17.  
  18. var KEY_FILTER_MASTERSWITCH = "filterMasterSwitch";
  19. var KEY_FILTER_HIDE = "hideFilter";
  20. var KEY_HIDE_NEW_COMMENTS = "hideNewComments";
  21. var DEFAULT_FILTER_STATUS = false;
  22. }
  23.  
  24. // Variables, settings
  25. {
  26. var HIDE_FILTER_DEFAULT = true;
  27. var HIDE_NEW_COMMENTS_DEFAULT = true;
  28. var HIDE_BOTTOM_CLEARFIX = true; // autimatically deactivated if there more than one page
  29. var HIDE_BOTTOM_BANNER = false;
  30. var FILTER_US_RELEASE = false;
  31. var FILTER_SEASON_WHITELIST = [
  32. ]
  33. var FILTER_GROUP_WHITELIST = [
  34. ]
  35.  
  36. var filter_MasterSwitch = GM_getValue(KEY_FILTER_MASTERSWITCH, DEFAULT_FILTER_STATUS);
  37.  
  38. var contentDivStyleDisplay;
  39. var commentDivStyleDisplay;
  40.  
  41. var FILTERS = {
  42. CATEGORIES : {
  43. name : "Category",
  44. VALUE : {
  45. XVID : {name: 'XviD', key: "filterCatXvid", func: function(){onCheckboxClick(FILTERS.CATEGORIES.VALUE.XVID);}},
  46. X264 : {name: 'x264', key: "filterCatX264", func: function(){onCheckboxClick(FILTERS.CATEGORIES.VALUE.X264);}},
  47. DVD : {name: 'DVD-R', key: "filterCatDvd", func: function(){onCheckboxClick(FILTERS.CATEGORIES.VALUE.DVD);}},
  48. HDTV : {name: 'HDTV', key: "filterCatHdtv", func: function(){onCheckboxClick(FILTERS.CATEGORIES.VALUE.HDTV);}},
  49. COMPLETEHD : {name: 'Compl. HD', key: "filterCatCompleteHd", func: function(){onCheckboxClick(FILTERS.CATEGORIES.VALUE.COMPLETEHD);}}
  50. }
  51. },
  52. TYPES : {
  53. name : "Type",
  54. VALUE : {
  55. TELESYNC : {name: ' TeleSync', key: "filterTypeTeleSync", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.TELESYNC);}},
  56. WEBRIP : {name: ' Web-Rip', key: "filterTypeWebRip", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.WEBRIP);}},
  57. DVDRIP : {name: ' DVD-Rip', key: "filterTypeDvdRip", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.DVDRIP);}},
  58. DVDSCR : {name: ' DVD-Scr.', key: "filterTypeDvdScr", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.DVDSCR);}},
  59. DVD : {name: ' DVD-R', key: "filterTypeDvd", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.DVD);}},
  60. HDTV : {name: ' HDTV', key: "filterTypeHdtv", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.HDTV);}},
  61. BLURAY : {name: ' Blu-ray', key: "filterTypeBluray", func: function(){onCheckboxClick(FILTERS.TYPES.VALUE.BLURAY);}}
  62. }
  63. },
  64. RLSNAME : {
  65. name : "Rls.-Name",
  66. VALUE : {
  67. BDRIP : {name: ' BD-Rip', searchtext: /BDRip/i, key: "filterRlsnameBdRip", func: function(){onCheckboxClick(FILTERS.RLSNAME.VALUE.BDRIP);}},
  68. P720 : {name: ' 720p', searchtext: /720p/i, key: "filterRlsname720p", func: function(){onCheckboxClick(FILTERS.RLSNAME.VALUE.P720);}},
  69. P1080 : {name: ' 1080p', searchtext: /1080p/i, key: "filterRlsname1080p", func: function(){onCheckboxClick(FILTERS.RLSNAME.VALUE.P1080);}},
  70. COMPLETEBLURAY : {name: ' Compl. Blu-Ray', searchtext: /Complete.Bluray/i, key: "filterRlsnameCompleteBluRay", func: function(){onCheckboxClick(FILTERS.RLSNAME.VALUE.COMPLETEBLURAY);}}
  71. }
  72. }
  73. };
  74. }
  75.  
  76. drawUi();
  77. filterReleases();
  78. clickableNewComments();
  79.  
  80. // Filter function
  81. function filterReleases() {
  82. var releases = getReleases();
  83.  
  84. // Remove the filtering
  85. for (i = 0; i < releases.length; i++)
  86. removeFiltering(releases[i]);
  87. // Filter
  88. if(filter_MasterSwitch)
  89. {
  90. var releasesToRemove = [];
  91.  
  92. // Outside filter loop (releases)
  93. for (i = 0; i < releases.length; i++) {
  94. // Remove the filtering
  95. removeFiltering(releases[i]);
  96. // Inside filter loop (filtertypes, filters)
  97. for (var t in FILTERS){
  98. var filtertype = FILTERS[t];
  99. for (var f in filtertype.VALUE){
  100. var filter = filtertype.VALUE[f];
  101. if(filter.bool){
  102. if(isRelease(releases[i], filtertype.name, filter)){
  103. releasesToRemove.push(releases[i]);
  104. break;
  105. }
  106. }
  107. }
  108. // Break the (filtertypes) loop if the releases is already marked to remove
  109. var releasesToRemoveLength = releasesToRemove.length;
  110. if (releasesToRemoveLength > 0 && releasesToRemove[releasesToRemoveLength-1] == releases[i])
  111. break;
  112. }
  113.  
  114. // US-Release filter
  115. if (typeof FILTER_US_RELEASE !== 'undefined' && FILTER_US_RELEASE) {
  116. if (releases[i].className == "release_item release_us") {
  117. releasesToRemove.push(releases[i]);
  118. continue;
  119. }
  120. }
  121.  
  122. // Season filter
  123. if (typeof FILTER_SEASON_WHITELIST !== 'undefined' && FILTER_SEASON_WHITELIST.length > 0 && window.location.pathname.search(/\/tv\//i) != -1) {
  124. if (!isReleaseSeason(releases[i], FILTER_SEASON_WHITELIST)) {
  125. releasesToRemove.push(releases[i]);
  126. continue;
  127. }
  128. }
  129.  
  130. // Group filter
  131. if (typeof FILTER_GROUP_WHITELIST !== 'undefined' && FILTER_GROUP_WHITELIST.length > 0) {
  132. if (!isReleaseByGroup(releases[i], FILTER_GROUP_WHITELIST)) {
  133. releasesToRemove.push(releases[i]);
  134. continue;
  135. }
  136. }
  137. }
  138.  
  139. // Remove the releases in releasesToRemove[]
  140. for (i = 0; i < releasesToRemove.length; i++) {
  141. releasesToRemove[i].style.display = 'none';
  142. releasesToRemove[i].nextElementSibling.style.display = 'none';
  143. }
  144. }
  145. }
  146.  
  147. // Parses the release elements from the whole page
  148. function getReleases() {
  149. var releasesOdd = document.getElementsByClassName('release_item release_odd');
  150. var releasesEven = document.getElementsByClassName('release_item release_even');
  151. var releasesUS = document.getElementsByClassName('release_item release_us');
  152. var releasesHighlight = document.getElementsByClassName('release_item release_highlight');
  153. var allReleases = [];
  154. allReleases.push.apply(allReleases, releasesOdd);
  155. allReleases.push.apply(allReleases, releasesEven);
  156. allReleases.push.apply(allReleases, releasesUS);
  157. allReleases.push.apply(allReleases, releasesHighlight);
  158. return allReleases;
  159. }
  160.  
  161. function isRelease(release, filtertypename, filter){
  162. switch (filtertypename){
  163. case FILTERS.TYPES.name: {return isReleaseType(release, filter.name)};
  164. case FILTERS.CATEGORIES.name: {return isReleaseCat(release, filter.name)};
  165. case FILTERS.RLSNAME.name: {return isReleaseName(release, filter.searchtext)};
  166. }
  167. }
  168.  
  169. function isReleaseType(release, type) {
  170. var release_type = release.getElementsByClassName('release_type') [0];
  171. return release_type.firstChild.textContent == type;
  172. }
  173.  
  174. function isReleaseCat(release, cat) {
  175. var release_cat = release.getElementsByClassName('release_cat') [0];
  176. var sub_link = release_cat.getElementsByClassName('sub_link') [0];
  177. var span = sub_link.getElementsByTagName('span') [0];
  178. return span.textContent == cat;
  179. }
  180.  
  181. function isReleaseName(release, filter) {
  182. var release_title = release.getElementsByClassName('release_title') [0];
  183. var sub_link = release_title.getElementsByClassName('sub_link') [0];
  184. var span = sub_link.getElementsByTagName('span') [0];
  185. return span.textContent.search(filter) != -1;
  186. }
  187.  
  188. function isReleaseSeason(release, seasonArray) {
  189. var release_title = release.getElementsByClassName('release_title')[0];
  190. var sub = release_title.getElementsByClassName('sub') [0];
  191. for (j = 0; j < seasonArray.length; j++)
  192. if (sub.textContent.indexOf(seasonArray[j]) != - 1)
  193. return true;
  194. return false;
  195. }
  196.  
  197. function isReleaseByGroup(release, groupArray) {
  198. var release_grp = release.getElementsByClassName('release_grp')[0];
  199. for (j = 0; j < groupArray.length; j++)
  200. if (release_grp.textContent.indexOf(groupArray[j]) != - 1)
  201. return true;
  202. return false;
  203. }
  204.  
  205. // Removes filtering from a given release
  206. function removeFiltering(release) {
  207. release.style.display = '';
  208. }
  209.  
  210. // Draws the UI
  211. function drawUi() {
  212. // HeaderDiv
  213. {
  214. // HeaderTextSpan
  215. {
  216. var headerTextSpan = document.createElement("span");
  217. headerTextSpan.appendChild(document.createTextNode(" Filter "/*getFilterCaption()*/));
  218. headerTextSpan.onclick = function() {
  219. // Clicking on the header opens/closes the filter details UI
  220. var contentDiv = document.getElementById(ID_DIV_CONTENT);
  221. if (contentDiv.style.display !== "none"){
  222. GM_setValue(KEY_FILTER_HIDE, true);
  223. contentDivStyleDisplay = contentDiv.style.display;
  224. contentDiv.style.display = "none";
  225. }
  226. else{
  227. GM_setValue(KEY_FILTER_HIDE, false);
  228. contentDiv.style.display = contentDivStyleDisplay;
  229. }
  230. };
  231. unselectable(headerTextSpan);
  232. }
  233. // HeaderCheckbox
  234. {
  235. var headerCheckbox = document.createElement("input");
  236. headerCheckbox.setAttribute("type", "checkbox");
  237. //filter_MasterSwitch = GM_getValue(KEY_FILTER_MASTERSWITCH, DEFAULT_FILTER_STATUS);
  238. headerCheckbox.checked = filter_MasterSwitch;
  239. headerCheckbox.onclick = function() {
  240. GM_setValue(KEY_FILTER_MASTERSWITCH, headerCheckbox.checked);
  241. filter_MasterSwitch = headerCheckbox.checked;
  242. filterReleases();
  243. };
  244. }
  245. var headerDiv = document.createElement("div");
  246. headerDiv.id = ID_DIV_HEADER;
  247. headerDiv.style.fontWeight = "700";
  248. headerDiv.style.paddingTop = "5px";
  249. headerDiv.style.paddingBottom = "5px";
  250. headerDiv.style.paddingLeft = "10px";
  251. headerDiv.style.paddingRight = "10px";
  252. headerDiv.style.cursor = "pointer";
  253. headerDiv.style.font = '700 14px/22px "Open Sans",sans-serif';
  254. headerDiv.appendChild(headerTextSpan);
  255. headerDiv.appendChild(headerCheckbox);
  256. }
  257.  
  258. // ContentDiv
  259. {
  260. var contentDiv = document.createElement("div");
  261. contentDiv.id = ID_DIV_CONTENT;
  262. contentDiv.style.display = "flex";
  263. contentDiv.style.paddingTop = "5px";
  264. contentDiv.style.paddingBottom = "5px";
  265. for (var t in FILTERS){
  266. var filtertype = FILTERS[t];
  267. var typeDiv = document.createElement("div");
  268. typeDiv.style.paddingLeft = "15px";
  269. var typeSpan = document.createElement("span");
  270. typeSpan.appendChild(document.createTextNode(filtertype.name));
  271. unselectable(typeSpan);
  272. typeDiv.appendChild(typeSpan);
  273. for (var f in filtertype.VALUE){
  274. var filter = filtertype.VALUE[f];
  275. var span = document.createElement("span");
  276. span.appendChild(document.createTextNode(filter.name));
  277. unselectable(span);
  278. filter.checkbox = document.createElement("input");
  279. filter.checkbox.setAttribute("type", "checkbox");
  280. filter.bool = GM_getValue(filter.key, DEFAULT_FILTER_STATUS);
  281. filter.checkbox.checked = !filter.bool;
  282. filter.checkbox.onclick = filter.func;
  283. var div = document.createElement("div");
  284. div.appendChild(span);
  285. div.appendChild(filter.checkbox);
  286. typeDiv.appendChild(div);
  287. }
  288. contentDiv.appendChild(typeDiv);
  289. }
  290. }
  291. // Hide the filter
  292. if ( GM_getValue(KEY_FILTER_HIDE, (typeof HIDE_FILTER_DEFAULT !== 'undefined') ? HIDE_FILTER_DEFAULT : false) ){
  293. contentDivStyleDisplay = contentDiv.style.display;
  294. contentDiv.style.display = "none";
  295. }
  296.  
  297. // Add the filter UI to the correct place on the current page
  298. insertFilterUi(headerDiv);
  299. insertFilterUi(contentDiv);
  300. // Remove bottom banner
  301. if (typeof HIDE_BOTTOM_BANNER !== 'undefined' && HIDE_BOTTOM_BANNER)
  302. {
  303. document.getElementById('bottom').style.display = 'none';
  304. }
  305.  
  306. // Remove bottom clearfix (if only one page exists)
  307. if (typeof HIDE_BOTTOM_CLEARFIX !== 'undefined' && HIDE_BOTTOM_CLEARFIX)
  308. {
  309. var clearfix = document.getElementsByClassName('releases_bottom clearfix')[0];
  310. if(clearfix.childElementCount == 0)
  311. clearfix.style.display = 'none';
  312. }
  313.  
  314. }
  315.  
  316. function onCheckboxClick(filter){
  317. GM_setValue(filter.key, !filter.checkbox.checked);
  318. filter.bool = !filter.checkbox.checked;
  319. filterReleases();
  320. }
  321.  
  322. // Inserts a node into the rls_filter_selection div
  323. function insertFilterUi(filterUi) {
  324. var element = document.getElementById("rls_filter_selection");
  325. if (element !== 'undefined') {
  326. if(element.firstElementChild.className == "sub")
  327. element.replaceChild(filterUi, element.firstElementChild);
  328. else
  329. element.appendChild(filterUi);
  330. }
  331. }
  332.  
  333. // Makes the "new comments" header clickable (hide/unhide)
  334. function clickableNewComments(){
  335. var divs_titles = document.getElementsByClassName('box_title1');
  336. if (divs_titles.length > 1){
  337. commentTitleDiv = divs_titles[1];
  338. commentTitleDiv.style.cursor = "pointer";
  339. commentTitleDiv.onclick = function() {
  340. var commentDiv = commentTitleDiv.nextElementSibling;
  341. GM_setValue(KEY_HIDE_NEW_COMMENTS, commentDiv.style.display !== "none");
  342. if (commentDiv.style.display !== "none"){
  343. commentDivStyleDisplay = commentDiv.style.display;
  344. commentDiv.style.display = "none";
  345. }
  346. else
  347. commentDiv.style.display = commentDivStyleDisplay;
  348. };
  349. }
  350. if (GM_getValue(KEY_HIDE_NEW_COMMENTS, HIDE_NEW_COMMENTS_DEFAULT)){
  351. var commentDiv = commentTitleDiv.nextElementSibling;
  352. commentDivStyleDisplay = commentDiv.style.display;
  353. commentDiv.style.display = "none";
  354. }
  355. }
  356.  
  357. // Make span text unselectable
  358. function unselectable(span){
  359. if ('unselectable' in span) // Internet Explorer, Opera
  360. span.unselectable = !span.unselectable;
  361. else {
  362. if (window.getComputedStyle) {
  363. var style = window.getComputedStyle (span, null);
  364. if ('MozUserSelect' in style) { // Firefox
  365. span.style.MozUserSelect = (style.MozUserSelect == "none") ? "text" : "none";
  366. }
  367. else
  368. if ('webkitUserSelect' in style) // Google Chrome and Safari
  369. span.style.webkitUserSelect = (style.webkitUserSelect == "none") ? "text" : "none";
  370. }
  371. }
  372. }