ExploitedX Sites - Release Codes

Episode numbers for ExploitedX sites.

Verzia zo dňa 17.06.2024. Pozri najnovšiu verziu.

  1. // ==UserScript==
  2. // @name ExploitedX Sites - Release Codes
  3. // @author peolic
  4. // @version 1.6
  5. // @description Episode numbers for ExploitedX sites.
  6. // @namespace https://github.com/peolic
  7. // ===== Exploited College Girls
  8. // @match http*://*.exploitedcollegegirls.com/
  9. // @match http*://*.exploitedcollegegirls.com/models/*
  10. // @match http*://*.exploitedcollegegirls.com/categories/movies_*
  11. // @match http*://*.exploitedcollegegirls.com/updates/page_*
  12. // ===== Backroom Casting Couch
  13. // @match http*://*.backroomcastingcouch.com/
  14. // @match http*://*.backroomcastingcouch.com/models/*
  15. // @match http*://*.backroomcastingcouch.com/categories/movies_*
  16. // @match http*://*.backroomcastingcouch.com/updates/page_*
  17. // ===== Black Ambush
  18. // @match http*://*.blackambush.com/
  19. // @match http*://*.blackambush.com/models/*
  20. // @match http*://*.blackambush.com/categories/movies_*
  21. // @match http*://*.blackambush.com/updates/page_*
  22. // ===== BBC Surprise
  23. // @match http*://*.bbcsurprise.com/
  24. // @match http*://*.bbcsurprise.com/models/*
  25. // @match http*://*.bbcsurprise.com/categories/movies_*
  26. // @match http*://*.bbcsurprise.com/updates/page_*
  27. // ===== Hot MILFs Fuck
  28. // @match http*://*.hotmilfsfuck.com/
  29. // @match http*://*.hotmilfsfuck.com/models/*
  30. // @match http*://*.hotmilfsfuck.com/categories/movies_*
  31. // @match http*://*.hotmilfsfuck.com/updates/page_*
  32. // ===== ExCoGi Girls
  33. // @match http*://*.excogigirls.com/
  34. // @match http*://*.excogigirls.com/models/*
  35. // @match http*://*.excogigirls.com/categories/movies_*
  36. // @match http*://*.excogigirls.com/updates/page_*
  37. // =====
  38. // @grant none
  39. // @homepageURL https://github.com/peolic/userscripts
  40. // ==/UserScript==
  41.  
  42. //@ts-check
  43. (() => {
  44. /**
  45. * @param {HTMLDivElement} item video item element
  46. * @param {HTMLDivElement} [infoDiv] release info element
  47. * @returns {void}
  48. * @throws no target error
  49. */
  50. function injectDefault(item, infoDiv) {
  51. if (!infoDiv)
  52. throw new Error('no element to inject');
  53. let target = item.querySelector('.rating-div') || item.querySelector('.content-div .text-right');
  54. if (target)
  55. return target.prepend(infoDiv);
  56. target = item.querySelector('.content-div');
  57. if (target)
  58. return target.append(infoDiv);
  59. throw new Error('no target');
  60. }
  61.  
  62. /**
  63. * @typedef SiteType
  64. * @property {RegExp} pattern
  65. * @property {(item: HTMLDivElement, infoDiv?: HTMLDivElement) => void} inject
  66. * @property {string} [textColor]
  67. * @property {Partial<CSSStyleDeclaration>} [style]
  68. */
  69.  
  70. // https://regex101.com/r/hPTK77/2
  71. const hostnamePattern = /^(?:www\.)?([a-z.]+)$/i;
  72.  
  73. /** @type {{ [hostname: string]: Partial<SiteType> }} */
  74. const SITES = {
  75. 'exploitedcollegegirls.com': {
  76. textColor: '#000000',
  77. // inject: injectDefault,
  78. },
  79. 'backroomcastingcouch.com': {
  80. textColor: '#dd0066',
  81. style: {
  82. position: 'absolute',
  83. right: '0',
  84. },
  85. inject: (item, infoDiv) => {
  86. let target = item.querySelector('.content-div');
  87. if (!target)
  88. throw new Error('no target');
  89.  
  90. if (window.location.pathname.startsWith('/models/')) {
  91. // Make video cards larger, like on the other network sites
  92. /** @type {HTMLDivElement} */ (item.parentElement).classList.add('col-lg-9');
  93. const row = /** @type {HTMLDivElement} */ (target.querySelector('div'));
  94. row.children[0].classList.add('col-lg-8');
  95. row.children[1].classList.add('col-lg-4');
  96. if (!infoDiv)
  97. return;
  98. }
  99.  
  100. if (!infoDiv)
  101. throw new Error('no element to inject');
  102.  
  103. target.prepend(infoDiv);
  104. },
  105. },
  106. 'blackambush.com': {
  107. textColor: '#ffa901',
  108. // inject: injectDefault,
  109. },
  110. 'bbcsurprise.com': {
  111. textColor: '#ffa901',
  112. // inject: injectDefault,
  113. },
  114. 'hotmilfsfuck.com': {
  115. textColor: '#d52023',
  116. // inject: injectDefault,
  117. },
  118. 'excogigirls.com': {
  119. textColor: '#000000',
  120. // inject: injectDefault,
  121. },
  122. };
  123.  
  124. // https://regex101.com/r/BtryUh/6
  125. const globalPattern = /(?<site>ecgg?|brcc|ba|blackambush|bbcs?|hmf).*?(?<release>\d{4})/;
  126.  
  127. /** @type {SiteType} */
  128. const defaultSite = {
  129. pattern: globalPattern,
  130. inject: injectDefault,
  131. };
  132.  
  133. /** @type {NodeListOf<HTMLDivElement>} */
  134. (document.querySelectorAll('.item-video')).forEach((item) => {
  135. const baseHostname = window.location.hostname.match(hostnamePattern)?.[1] ?? window.location.hostname;
  136. const options = { ...defaultSite, ...SITES[baseHostname] };
  137. const { pattern, textColor, inject, style } = options;
  138.  
  139. const videoSrc = item.querySelector('video > source')?.getAttribute('src');
  140. if (!videoSrc) {
  141. inject(item);
  142. return;
  143. }
  144.  
  145. const filename = videoSrc.split(/\//g).slice(-1)[0];
  146. const result = filename.match(pattern);
  147. const { site, release } = result?.groups ?? {};
  148.  
  149. const infoDiv = document.createElement('div');
  150. Object.assign(infoDiv.style, { position: 'relative' });
  151. const info = document.createElement('span');
  152. Object.assign(info.style, {
  153. color: textColor,
  154. fontWeight: 600,
  155. ...(style ?? {
  156. position: 'absolute',
  157. right: '0',
  158. top: '-22px',
  159. }),
  160. });
  161. info.innerText = release !== undefined ? `#${release}` : filename;
  162. info.title = `${site}-${release}\n${filename}`;
  163. infoDiv.appendChild(info);
  164.  
  165. inject(item, infoDiv);
  166. });
  167.  
  168. })();