FanPass Btn

Adds button to redirect OnlyFans,Fansly,Candfans to Coomer with enhancement

  1. // ==UserScript==
  2. // @name FanPass Btn
  3. // @version 1.3
  4. // @description Adds button to redirect OnlyFans,Fansly,Candfans to Coomer with enhancement
  5. // @namespace https://greasyfork.org/en/users/1333430
  6. // @match https://onlyfans.com/*
  7. // @match https://coomer.su/*
  8. // @match https://fansly.com/*
  9. // @match https://candfans.jp/*
  10. // @grant GM_openInTab
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. "use strict";
  15.  
  16. // Function to handle redirection
  17. function redirect(username, service) {
  18. const coomerUrl = `https://coomer.su/${service}/user/${username}`;
  19. GM_openInTab(coomerUrl, { active: true });
  20. }
  21.  
  22. function createRedirectButton(username, service) {
  23. const button = document.createElement("button");
  24. button.innerHTML = `<img src="https://coomer.su/favicon.ico" style="width: 24px; height: 24px; display: block; margin: auto;">`;
  25. button.className = "redirect-button";
  26. button.addEventListener("click", () => redirect(username, service));
  27. document.body.appendChild(button);
  28. }
  29.  
  30. // Add styles for the button and main content adjustment
  31. const style = document.createElement("style");
  32. style.textContent = `
  33. .redirect-button {
  34. position: fixed;
  35. top: 20px;
  36. right: 20px;
  37. z-index: 9999;
  38. border: none;
  39. border-radius: 50%;
  40. background-color: rgba(105, 105, 105, 0.7);
  41. width: 50px;
  42. height: 50px;
  43. padding: 10px;
  44. box-sizing: border-box;
  45. cursor: pointer;
  46. }
  47. .shifted.content-wrapper.full-width {
  48. width: 100% !important;
  49. margin-left: 0 !important;
  50. }
  51. .post-card {
  52. border-radius: 10px !important;
  53. overflow: hidden;
  54. }
  55. .post-card__image-container {
  56. overflow: visible;
  57. }
  58. .post-card__image {
  59. transition: transform 0.3s ease, box-shadow 0.3s ease;
  60. }
  61. .post-card__image-container:hover .post-card__image {
  62. transform: scale(1.1);
  63. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  64. }
  65. .post-card.post-card--preview {
  66. transform: scale(1.2);
  67. margin: 20px;
  68. transition: transform 0.3s ease, box-shadow 0.3s ease;
  69. backface-visibility: hidden;
  70. perspective: 1000px;
  71. }
  72. .post-card.post-card--preview:hover {
  73. transform: scale(1.3);
  74. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  75. }
  76. .ad-banner, .ad-container, .banner, .advertisement {
  77. display: none !important;
  78. }
  79. .post__nav-links {
  80. position: sticky;
  81. top: 50%;
  82. display: flex;
  83. justify-content: space-between;
  84. align-items: center;
  85. width: 100%;
  86. z-index: 1000;
  87. transform: translateY(-50%);
  88. }
  89. .post__nav-item {
  90. flex: 1;
  91. text-align: center;
  92. font-size: 130%;
  93. }
  94. .post__nav-item.subtitle {
  95. font-size: 130%;
  96. position: absolute;
  97. left: 20%;
  98. }
  99. .post__nav-item a {
  100. text-decoration: none;
  101. color: inherit;
  102. font-size: 130%;
  103. }
  104. .post__nav-item.previous {
  105. position: absolute;
  106. left: 20%;
  107. }
  108. .post__nav-item.next {
  109. position: absolute;
  110. right: 20%;
  111. }
  112. .glow {
  113. animation: glow 1.5s infinite alternate;
  114. }
  115. @keyframes glow {
  116. 0% {
  117. text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #fff, 0 0 20px #ff00ff, 0 0 25px #ff00ff, 0 0 30px #ff00ff, 0 0 35px #ff00ff;
  118. }
  119. 50% {
  120. text-shadow: 0 0 10px #fff, 0 0 15px #fff, 0 0 20px #fff, 0 0 25px #ff00ff, 0 0 30px #ff00ff, 0 0 35px #ff00ff, 0 0 40px #ff00ff;
  121. }
  122. 100% {
  123. text-shadow: 0 0 15px #fff, 0 0 25px #fff, 0 0 35px #fff, 0 0 45px #ff00ff, 0 0 55px #ff00ff, 0 0 65px #ff00ff, 0 0 75px #ff00ff;
  124. }
  125. }
  126. `;
  127. document.head.appendChild(style);
  128.  
  129. function closeSidebar() {
  130. setTimeout(() => {
  131. const sidebar = document.querySelector(".global-sidebar");
  132. const closeButton = document.querySelector(
  133. ".global-sidebar .close-sidebar"
  134. );
  135.  
  136. if (sidebar && sidebar.classList.contains("expanded") && closeButton) {
  137. closeButton.click();
  138. }
  139.  
  140. setTimeout(() => {
  141. removeHeader();
  142. }, 100);
  143. }, 1000);
  144. }
  145.  
  146. function removeHeader() {
  147. const header = document.querySelector(".header.sidebar-retracted");
  148.  
  149. if (header) {
  150. header.remove();
  151. } else {
  152. const observer = new MutationObserver(() => {
  153. const header = document.querySelector(".header.sidebar-retracted");
  154. if (header) {
  155. header.remove();
  156. observer.disconnect();
  157. }
  158. });
  159.  
  160. observer.observe(document.body, { childList: true, subtree: true });
  161. }
  162. }
  163.  
  164. function removeMatrixBanner() {
  165. const matrixBanner = document.querySelector(
  166. 'a[href="https://coomer.su/matrix"]'
  167. );
  168. if (matrixBanner) {
  169. matrixBanner.remove();
  170. }
  171. }
  172.  
  173. function moveNavElement() {
  174. const navElements = document.querySelectorAll(".post__nav-links");
  175. const postBodyElement = document.querySelector(".post__body");
  176.  
  177. navElements.forEach((navElement) => {
  178. const previousItem =
  179. navElement.querySelector(".post__nav-link.prev") ||
  180. navElement.querySelector(".post__nav-item.subtitle");
  181. if (previousItem) {
  182. previousItem.innerHTML = "←";
  183. previousItem.parentElement.classList.add("previous", "glow");
  184. }
  185.  
  186. const nextItem = navElement.querySelector(".post__nav-link.next");
  187. if (nextItem) {
  188. nextItem.innerHTML = "→";
  189. nextItem.parentElement.classList.add("next", "glow");
  190. }
  191. });
  192. }
  193.  
  194. function runScript() {
  195. if (window.location.href.includes("onlyfans.com")) {
  196. const profileMatch = window.location.href.match(
  197. /https:\/\/onlyfans.com\/([^/]+)/
  198. );
  199. if (profileMatch) {
  200. const username = profileMatch[1];
  201. createRedirectButton(username, "onlyfans");
  202. }
  203. }
  204.  
  205. if (window.location.href.includes("fansly.com")) {
  206. (async () => {
  207. let userID = null;
  208. const profileMatch = window.location.href.match(
  209. /https:\/\/fansly.com\/([^/]+)/
  210. );
  211. if (profileMatch) {
  212. const userName = profileMatch[1];
  213. if (userName) {
  214. const res = await fetch(
  215. `https://apiv3.fansly.com/api/v1/account?usernames=${userName}&ngsw-bypass=true`
  216. );
  217. const data = await res.json();
  218. userID = data?.response?.[0]?.id ?? null;
  219. }
  220. if (userID) {
  221. createRedirectButton(userID, "fansly");
  222. }
  223. }
  224. })();
  225. }
  226.  
  227. if (window.location.href.includes("candfans.jp")) {
  228. const processedUserIds = new Set();
  229. const observer = new MutationObserver(() => {
  230. document.querySelectorAll("img[data-src]").forEach((imgElement) => {
  231. const userID = imgElement
  232. .getAttribute("data-src")
  233. ?.match(/user\/(\d+)\//)?.[1];
  234. if (userID && !processedUserIds.has(userID)) {
  235. createRedirectButton(userID, "candfans");
  236. processedUserIds.add(userID);
  237. }
  238. });
  239. });
  240. observer.observe(document.body, { childList: true, subtree: true });
  241. }
  242.  
  243. if (window.location.href.includes("coomer.su")) {
  244. removeMatrixBanner();
  245. if (
  246. window.location.href.includes("coomer.su/onlyfans/user") ||
  247. window.location.href.includes("coomer.su/fansly/user") ||
  248. window.location.href.includes("coomer.su/candfans/user")
  249. ) {
  250. closeSidebar();
  251. const mainContent = document.querySelector(".shifted.content-wrapper");
  252. if (mainContent) {
  253. mainContent.classList.add("full-width");
  254. }
  255. const imageContainers = document.querySelectorAll(
  256. ".post-card.post-card--preview"
  257. );
  258. imageContainers.forEach((container) => {
  259. container.style.transform = "scale(1.2)";
  260. container.style.margin = "20px";
  261. container.style.transition =
  262. "transform 0.3s ease, box-shadow 0.3s ease";
  263. container.style.backfaceVisibility = "hidden";
  264. container.style.perspective = "1000px";
  265. container.addEventListener("mouseover", () => {
  266. container.style.transform = "scale(1.3)";
  267. container.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.2)";
  268. });
  269. container.addEventListener("mouseout", () => {
  270. container.style.transform = "scale(1.2)";
  271. container.style.boxShadow = "none";
  272. });
  273. });
  274. }
  275. }
  276.  
  277. const links = document.querySelectorAll("a.image-link");
  278. links.forEach((link) => {
  279. link.addEventListener("click", (event) => {
  280. event.preventDefault();
  281. window.open(link.href, "_blank");
  282. });
  283. });
  284. moveNavElement();
  285. }
  286.  
  287. // Debounce function to limit the rate at which a function can fire.
  288. function debounce(func, wait) {
  289. let timeout;
  290. return function (...args) {
  291. clearTimeout(timeout);
  292. timeout = setTimeout(() => func.apply(this, args), wait);
  293. };
  294. }
  295.  
  296. // Initial script run
  297. document.addEventListener("DOMContentLoaded", runScript);
  298. window.addEventListener("load", runScript);
  299.  
  300. // Observe URL changes
  301. let lastUrl = location.href;
  302. const observer = new MutationObserver(
  303. debounce(() => {
  304. const currentUrl = location.href;
  305. if (currentUrl !== lastUrl) {
  306. lastUrl = currentUrl;
  307. runScript();
  308. }
  309. }, 500)
  310. );
  311. observer.observe(document, { subtree: true, childList: true });
  312. })();