Quick Porn Search

Adds a dropdown on many porn sites to search various sites found in the html.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Quick Porn Search
// @namespace    https://github.com/goawaylovestrike
// @description  Adds a dropdown on many porn sites to search various sites found in the html.
// @author       GoAwayLoveStrike
// @version      5.3
// @icon         https://raw.githubusercontent.com/goawaylovestrike/Userscripts/refs/heads/main/quick-porn-search/quick-porn-search.png
// @include https://www.wifey.com/*
// @include https://tour.swallowed.com/*
// @include https://myfamilypies.com/*
// @include https://cum4k.com/*
// @include https://www.brazzers.com/*
// @include https://*.dirtyauditions.com/*
// @include https://fansdb.cc/*
// @include https://www.lethalhardcore.com/*
// @include https://realitysis.com/*
// @include https://nubileset.com/*
// @include https://www.milfed.com/*
// @include https://bangbros.com/*
// @include https://www.bangadventures.com/*
// @include https://MomsTight.com/*
// @include https://store.fapnado.com/*
// @include https://brattysis.com/*
// @include https://www.tushyraw.com/*
// @include https://deeplush.com/*
// @include https://*.iafd.com/*
// @include https://*.data18.com/*
// @include https://www.mylf.com/*
// @include https://nubilesunscripted.com/*
// @include https://www.myfreecams.com/*
// @include https://*.teamskeet.com/*
// @include https://tour.allanal.com/*
// @include https://momlover.com/*
// @include https://www.lookathernow.com/*
// @include https://petitehdporn.com/*
// @include https://*.stephousexxx.com/*
// @include https://girlsonlyporn.com/*
// @include https://MomSwapped.com/*
// @include https://petiteballerinasfucked.com/*
// @include https://*.jonathanjordanxxx.com/*
// @include https://nympho.com/*
// @include https://www.bang.com/*
// @include https://*.westcoastproductions.com/*
// @include https://pervcity.com/*
// @include https://www.propertysex.com/*
// @include https://hotcrazymess.com/*
// @include https://www.empirestores.co/*
// @include https://brattymilf.com/*
// @include https://www.blackedraw.com/*
// @include https://*.allanal.com/*
// @include https://imnotyourmommy.com/*
// @include https://www.deeper.com/*
// @include https://www.bangpremium.com/*
// @include https://tour.trueanal.com/*
// @include https://*.manyvids.com/Video/*
// @include https://nubiles-casting.com/*
// @include https://lubed.com/*
// @include https://www.pervmom.com/*
// @include https://caughtmycoach.com/*
// @include https://exotic4k.com/*
// @include https://youngermommy.com/*
// @include https://www.dadcrush.com/*
// @include https://theporndb.net/*
// @include https://tour.nympho.com/*
// @include https://www.vixen.com/*
// @include https://*.18lust.com/*
// @include https://www.pornstarempire.com/*
// @include https://www.mypervyfamily.com/*
// @include https://*.lewood.com/*
// @include https://momsfamilysecrets.com/*
// @include https://MomsFamilySecrets.com/*
// @include https://momsteachsex.com/*
// @include https://nubiles-porn.com/*
// @include https://momswapped.com/*
// @include https://driverxxx.com/*
// @include https://pornpros.com/*
// @include https://bountyhunterporn.com/*
// @include https://princesscum.com/*
// @include https://*.joannaangel.com/*
// @include https://momwantscreampie.com/*
// @include https://ImNotYourMommy.com/*
// @include https://trueanal.com/*
// @include https://www.sislovesme.com/*
// @include https://www.adultdvdempire.com/*
// @include https://*.concoxxxion.com/*
// @include https://www.mrluckypov.com/*
// @include https://www.mofos.com/*
// @include https://anilos.com/*
// @include https://*.inserted.com/*
// @include https://girlcum.com/*
// @include https://familyswap.xxx/*
// @include https://vrbangers.com/*
// @include https://MomsBoyToy.com/*
// @include https://www.daughterswap.com/*
// @include https://*.adameveplus.com/*
// @include https://*.analonly.com/*
// @include https://momsboytoy.com/*
// @include https://badteenspunished.com/*
// @include https://www.wankzvr.com/*
// @include https://smashed.xxx/*
// @include https://teacherfucksteens.com/*
// @include https://stashdb.org/*
// @include https://www.naughtyamerica.com/*
// @include https://*.bruthasinc.com/*
// @include https://*.gloryholeswallow.com/*
// @include https://cumswappingsis.com/*
// @include https://MomWantsCreampie.com/*
// @include https://www.gloryholesecrets.com/*
// @include https://holed.com/*
// @include https://www.realitykings.com/*
// @include https://chaturbate.com/*
// @include https://anal4k.com/*
// @include https://nubiles.net/*
// @include https://MomWantsToBreed.com/*
// @include https://cheatingsis.com/*
// @include https://detentiongirls.com/*
// @include https://nfbusty.com/*
// @include https://thepovgod.com/*
// @include https://thatsitcomshow.com/*
// @include https://nubilefilms.com/*
// @include https://www.tushy.com/*
// @include https://www.mormongirlz.com/*
// @include https://*.fetishmovies.com/*
// @include https://*.kaiiaeve.com/*
// @include https://www.lethalhardcorevr.com/*
// @include https://thePOVGod.com/*
// @include https://baeb.com/*
// @include https://momwantstobreed.com/*
// @include https://fansly.com/*
// @include https://daddyslilangel.com/*
// @include https://tiny4k.com/*
// @include https://*.spankmonster.com/*
// @include https://tour.analonly.com/*
// @include https://www.blacked.com/*
// @include https://stepsiblingscaught.com/*
// @include https://momstight.com/*
// @include https://xhamsterlive.com/*
// @include https://povd.com/*
// @include https://www.slayed.com/*
// @include https://swallowed.com/*
// @include https://*.jayspov.net/*
// @license      MIT
// ==/UserScript==

// Search button configuration - Edit these to add/remove/modify search options
const searchButtons = [
	{
		name: "1337x",
		url: "https://1337x.to/sort-search/{query}/time/desc/1/",
	},
	{
		name: "PornoLabs",
		url: "https://pornolab.net/forum/tracker.php?max=1&nm={query}",
	},
	{
		name: "Yandex",
		url: "https://yandex.com/search/?text={query}",
	},
	{
		name: "Google",
		url: "https://www.google.com/search?q={query}",
	},
	{
		name: "Full Porn",
		url: "https://www.fullporn.xxx/search/{query}/",
		queryTransform: (query) => query.replace(/\s+/g, "-"), //This replaces all spaces with dashes in the url which is required for some sites.
	},
	{
		name: "WatchPorn.to",
		url: "https://watchporn.to/search/{query}/",
		queryTransform: (query) => query.replace(/\s+/g, "-"),
	},
	{
		name: "Hdporn92",
		url: "https://hdporn92.com/?s={query}",
	},
	{
		name: "Porndish",
		url: "https://www.porndish.com/?s={query}",
	},
	{
		name: "Sexuria",
		url: "https://sexuria.net/?do=search&subaction=search&search_start=0&full_search=0&story={query}",
	},
	{
		name: "Porn Horder",
		url: "https://w15.pornhoarder.tv/search/?search={query}&sort=0&date=0&servers%5B%5D=47&servers%5B%5D=21&servers%5B%5D=40&servers%5B%5D=45&servers%5B%5D=12&servers%5B%5D=35&servers%5B%5D=25&servers%5B%5D=41&servers%5B%5D=44&servers%5B%5D=42&servers%5B%5D=43&servers%5B%5D=29&author=0&page=1",
	},

];

function isMobileDevice() {
	return (
		/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
			navigator.userAgent
		) || window.innerWidth <= 768
	);
}

(function () {
	"use strict";

	var searchterm = null;
	let initAttempts = 0;
	const MAX_ATTEMPTS = 5;



	let includeTitle = true;
	let includePerformers = true;
	let includeSite = true;
	let excludeMalePerformers = true;

	// Initialize with retry mechanism
	console.log("DOM ready state:", document.readyState);
	console.log("Current URL:", window.location.href);
	console.log("Attempt number:", initAttempts + 1, "of", MAX_ATTEMPTS);

	function initialize() {
		if (initAttempts >= MAX_ATTEMPTS) {
			console.log("Failed to initialize after maximum attempts");
			return;
		}

		initAttempts++;

		// First detect the pattern
		const pattern = detectSitePattern();

		if (!pattern) {
			// Remove buttons
			document
				.querySelectorAll(".search-button-container")
				.forEach((el) => el.remove());

			// Retry after delay if we haven't hit max attempts
			if (initAttempts < MAX_ATTEMPTS) {
				setTimeout(initialize, 1000);
			}
			return;
		}

		// Set the current pattern for use by other functions
		window._currentPattern = pattern;

		updateSearchButtons();
	}

	function getHostnameSite() {
		const hostname = window.location.hostname;
		const parts = hostname.split(".");
		// Always take the part before the TLD (second-to-last part)
		let site = parts[parts.length - 2].toLowerCase();
		
		// Normalize site names for specific platforms
		if (site.includes("onlyfans")) {
			return "OnlyFans";
		}
		if (site.includes("manyvids")) {
			return "ManyVids";
		}
		
		return site;
	}

	function getsearchterm() {
		const hostname = window.location.hostname;
		const path = window.location.pathname;

		if (
			!path ||
			path === "/" ||
			path.includes("/categories") ||
			path.includes("/search") ||
			path.includes("/models") ||
			path.includes("/channels") ||
			path.includes("/tags")
		) {
			return;
		}

		let title = null;
		let performers = [];
		let site = null;
		searchterm = null;

		if (window._currentPattern) {
			const { selectors } = window._currentPattern;

			const titleElement = document.querySelector(selectors.title);
			if (titleElement) {
				title = window._currentPattern.titleTransform
					? window._currentPattern.titleTransform(titleElement)
					: titleElement.textContent.trim();
			}

			// Special handling for ThePornDB
			if (window._currentPattern.name === "THEPORNDB") {
				const performerElements = Array.from(
					document.querySelectorAll(selectors.performers)
				);
				if (performerElements.length > 0) {
					performers = performerElements
						.filter((el) => {
							// Skip male performers if excludeMalePerformers is enabled
							if (excludeMalePerformers) {
								// Check if this performer has the male icon
								const parentCard =
									el.closest(".relative.group");
								if (parentCard) {
									// Look for the male icon (SVG with Mars symbol)
									const maleIcon =
										parentCard.querySelector(
											"svg.text-blue-400"
										);
									if (maleIcon) {
										console.log(
											`Filtering out male performer: ${el.textContent.trim()}`
										);
										return false;
									}
								}
							}
							return true;
						})
						.map((el) => el.textContent.trim())
						.filter((name) => name && name !== "");
				}
			} else if (window._currentPattern.name === "STASHBOX") {
				const performerElements = Array.from(
					document.querySelectorAll(selectors.performers)
				);
				if (performerElements.length > 0) {
					performers = performerElements
						.filter((el) => {
							// Skip male performers if excludeMalePerformers is enabled
							if (excludeMalePerformers) {
								// Check if this performer has the male icon (Mars symbol SVG)
								const parentElement =
									el.closest(".scene-performer");
								if (parentElement) {
									// Look for the Mars symbol SVG with title "Male"
									const maleIcon =
										parentElement.querySelector(
											'svg[data-icon="mars"], svg.fa-mars'
										);
									if (maleIcon) {
										console.log(
											`Filtering out male performer: ${el.textContent.trim()}`
										);
										return false;
									}
								}
							}
							return true;
						})
						.map((el) => el.textContent.trim())
						.filter((name) => name && name !== "");
				}
			} else {
				// Original performer extraction for other sites
				const performerElements = Array.from(
					document.querySelectorAll(selectors.performers)
				);
				if (performerElements.length > 0) {
					if (
						window._currentPattern &&
						window._currentPattern.name === "GLORY"
					) {
						performers = performerElements
							.map((el) => {
								const text = el.textContent.trim();
								const match = text.match(/\((.*?)\)/);
								return match
									? match[1].trim().replace(/[@\s]/g, "")
									: "";
							})
							.filter((name) => name !== "");
					} else {
						performers = performerElements
							.map((el) => el.textContent.trim())
							.filter((name) => name && name !== "");
					}
				}
			}

			const siteElement = document.querySelector(selectors.site);
			if (siteElement) {
				site = window._currentPattern.siteTransform
					? window._currentPattern.siteTransform(siteElement)
					: siteElement.textContent.trim();
			}

			if (!site) {
				site = getHostnameSite();
			}
			
			// Normalize site names for specific platforms
			if (site && site.toLowerCase().includes("onlyfans")) {
				site = "OnlyFans";
			}
			if (site && site.toLowerCase().includes("manyvids")) {
				site = "ManyVids";
			}
		}

		// Build searchterm based on checkbox preferences
		const parts = [];

		if (includePerformers && performers.length > 0) {
			parts.push(performers.join(" "));
		}

		if (includeTitle && title) {
			parts.push(title);
		}

		if (includeSite && site) {
			parts.push(site.replace(/\((\w+)\)/g, "$1").replace(/[\s']+/g, "")); // Remove parentheses, spaces, and apostrophes
		}

		searchterm = parts
			.join(" ")
			.trim()
			.replace(/[^\w\s-.!&]/g, "") // Remove special characters without replacing with spaces
			.replace(/\s+/g, " "); // Normalize spaces
		console.log(`Final searchterm for ${hostname}:`, searchterm);
	}

	function updateSearchLinks() {
		// Get all existing links in the dropdown
		const links = document.querySelectorAll(".search-button-container a");

		// Update each link's href with the new searchterm
		links.forEach((link) => {
			const buttonName = link.textContent.trim();
			const button = searchButtons.find((b) => b.name === buttonName);
			if (button) {
				const query = button.queryTransform
					? button.queryTransform(searchterm)
					: encodeURIComponent(searchterm);
				link.href = button.url.replace("{query}", query);
			}
		});
	}

	function updateSearchButtons() {
		// Remove the pattern check since it's already done in initialize()
		getsearchterm();

		// Only create dropdown if we have a valid searchterm
		if (searchterm && searchterm.length > 0) {
			const dropdownContainer = document.createElement("div");
			dropdownContainer.className = "search-button-container";

			// Adjust container position based on device
			const isMobile = isMobileDevice();
			dropdownContainer.style.cssText = `
                position: fixed !important;
                ${
					isMobile
						? "left: 5px !important; top: 10px !important;"
						: "left: 15px !important; top: 80px !important;"
				}
                z-index: 2147483647 !important;
                pointer-events: auto !important;
                visibility: visible !important;
                opacity: 1 !important;
            `;

			// Create the dropdown button
			const dropdownButton = document.createElement("button");
			if (isMobile) {
				dropdownButton.textContent = "🔍";
				dropdownButton.style.cssText = `
                    background: #ffffff !important;
                    color: #000000 !important;
                    font-family: Arial, sans-serif !important;
                    font-weight: bold !important;
                    padding: 8px !important;
                    border: 2px solid #000000 !important;
                    border-radius: 50% !important;
                    font-size: 16px !important;
                    cursor: pointer !important;
                    width: 40px !important;
                    height: 40px !important;
                    display: flex !important;
                    align-items: center !important;
                    justify-content: center !important;
                    box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
                `;
			} else {
				dropdownButton.textContent = "🔍 Search";
				dropdownButton.style.cssText = `
                    background: #ffffff !important;
                    color: #000000 !important;
                    font-family: Arial, sans-serif !important;
                    font-weight: bold !important;
                    padding: 10px 15px !important;
                    border: 2px solid #000000 !important;
                    border-radius: 7px !important;
                    font-size: 18px !important;
                    cursor: pointer !important;
                    min-width: 140px !important;
                    box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
                `;
			}

			// Create the dropdown content
			const dropdownContent = document.createElement("div");
			dropdownContent.style.cssText = `
                display: none;
                position: absolute !important;
                background-color: #ffffff !important;
                min-width: ${isMobile ? "200px" : "140px"} !important;
                box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
                border-radius: 7px !important;
                margin-top: 5px !important;
                border: 2px solid #000000 !important;
                overflow: hidden !important;
                ${isMobile ? "left: 0 !important;" : ""}
            `;

			searchButtons.forEach((button) => {
				const link = document.createElement("a");
				link.id = button.name;

				// Create favicon image
				const favicon = document.createElement("img");
				const urlObj = new URL(button.url);
				const domain = urlObj.hostname.split(".").slice(-2).join(".");
				favicon.src = `${urlObj.protocol}//${domain}/favicon.ico`;
				favicon.style.cssText = `
                    width: 16px !important;
                    height: 16px !important;
                    margin-right: 8px !important;
                    vertical-align: middle !important;
                    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.2)) !important;
                `;

				const textSpan = document.createElement("span");
				textSpan.textContent = button.name;
				textSpan.style.cssText = `
                    vertical-align: middle !important;
                    font-weight: bold !important;
                    color: #000000 !important;
                    font-size: 14px !important;
                    font-family: Arial, sans-serif !important;
                    line-height: normal !important;
                `;

				const query = button.queryTransform
					? button.queryTransform(searchterm)
					: encodeURIComponent(searchterm);
				link.href = button.url.replace("{query}", query);
				link.target = "_blank";
				link.style.cssText = `
                    color: #000000 !important;
                    background: white !important;
                    padding: 10px 10px !important;
                    text-decoration: none !important;
                    display: flex !important;
                    align-items: center !important;
                    text-align: left !important;
                    font-size: 14px !important;
                    cursor: pointer !important;
                    border-bottom: 1px solid #eee !important;
                    font-family: Arial, sans-serif !important;
                    line-height: normal !important;
                    width: auto !important;
                    height: auto !important;
                `;

				textSpan.style.cssText = `
                    vertical-align: middle !important;
                    font-weight: bold !important;
                    color: #000000 !important;
                    font-size: 15px !important;
                    line-height: normal !important;
                `;

				const container = document.createElement("div");
				container.className = "search-button-container";
				container.style.cssText = `
                    position: fixed !important;
                    top: 10px !important;
                    right: 10px !important;
                    background: white !important;
                    border: 1px solid #ddd !important;
                    border-radius: 4px !important;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
                    z-index: 9999999 !important;
                    width: auto !important;
                    min-width: 200px !important;
                `;

				link.onmouseover = function () {
					this.style.backgroundColor = "#f1f1f1 !important";
				};
				link.onmouseout = function () {
					this.style.backgroundColor = "#ffffff !important";
				};

				link.appendChild(favicon);
				link.appendChild(textSpan);
				dropdownContent.appendChild(link);
			});

			const separator = document.createElement("div");
			separator.style.cssText = `
                border-top: 2px solid #eee !important;
                margin-top: 5px !important;
            `;
			dropdownContent.appendChild(separator);

			const controlsDiv = document.createElement("div");
			controlsDiv.style.borderBottom = "1px solid #ddd";
			controlsDiv.style.marginBottom = "10px";
			controlsDiv.style.paddingBottom = "10px";

			const options = [
				{
					id: "includePerformers",
					label: "Performers",
					ref: () => includePerformers,
				},
				{ id: "includeTitle", label: "Title", ref: () => includeTitle },
				{ id: "includeSite", label: "Site", ref: () => includeSite },
				{
					id: "excludeMalePerformers",
					label: "No Male Performers",
					ref: () => excludeMalePerformers,
				},
			];

			options.forEach((option) => {
				const div = document.createElement("div");
				div.style.marginBottom = "5px";

				const checkbox = document.createElement("input");
				checkbox.type = "checkbox";
				checkbox.id = option.id;
				checkbox.checked = option.ref();
				checkbox.style.cssText = `
                    margin-right: 5px !important;
                    cursor: pointer !important;
                `;

				// Single consolidated event listener
				checkbox.addEventListener("change", (e) => {
					e.stopPropagation();
					console.log(
						`Checkbox ${option.id} changed to ${checkbox.checked}`
					); // Debug log
					switch (option.id) {
						case "includePerformers":
							includePerformers = checkbox.checked;
							break;
						case "includeTitle":
							includeTitle = checkbox.checked;
							break;
						case "includeSite":
							includeSite = checkbox.checked;
							break;
						case "excludeMalePerformers":
							excludeMalePerformers = checkbox.checked;
							break;
					}
					getsearchterm();
					updateSearchLinks();
					console.log("Updated searchterm:", searchterm); // Debug log
				});

				const label = document.createElement("label");
				label.htmlFor = option.id;
				label.textContent = option.label;
				label.style.cssText = `
                    font-family: Arial, sans-serif !important;
                    font-size: 12px !important;
                    color: black !important;
                    cursor: pointer !important;
                `;

				div.appendChild(checkbox);
				div.appendChild(label);
				controlsDiv.appendChild(div);
			});

			dropdownContent.appendChild(controlsDiv);

			// Toggle dropdown on click
			dropdownButton.onclick = function (e) {
				e.stopPropagation();
				dropdownContent.style.display =
					dropdownContent.style.display === "none" ? "block" : "none";
			};

			dropdownContainer.appendChild(dropdownButton);
			dropdownContainer.appendChild(dropdownContent);

			if (document.body) {
				document.body.appendChild(dropdownContainer);
				console.log("Dropdown created with searchterm:", searchterm);
			}
		}
	}

	initialize();

	// Watch for URL changes
	let lastUrl = location.href;
	const observer = new MutationObserver(() => {
		const url = location.href;
		if (url !== lastUrl) {
			lastUrl = url;
			// Immediately remove the button
			document
				.querySelectorAll(".search-button-container")
				.forEach((el) => el.remove());
			// Reset attempts and try to initialize with new page
			initAttempts = 0;
			setTimeout(initialize, 1000);
		}
	});

	observer.observe(document.body || document, {
		subtree: true,
		childList: true,
	});

	function detectSitePattern() {
		const hostname = window.location.hostname;

		// Define common selectors to test
		const commonPatterns = [
			{
				name: "TEAMSKEET",
				selectors: {
					title: ".sceneTitle",
					performers: ".contentTitle .model-name-link",
					site: ".siteName",
				},
			},
			{
				name: "NAUGHTYAMERICA",
				selectors: {
					title: "h1.scene-title",
					performers: ".performer-list",
					site: ".site-title",
				},
			},
			{
				name: "ADULTEMPIRECASH",
				selectors: {
					title: ".video-title",
					performers: "span.video-performer-name span.overlay-inner",
					site: 'div.studio span:not(.font-weight-bold), meta[property="og:site_name"]',
				},
				siteTransform: (el) =>
					(el.tagName.toLowerCase() === "meta"
						? el.getAttribute("content")
						: el.textContent
					).replace(/\s+/g, ""),
			},
			{
				name: "STASHBOX",
				selectors: {
					title: ".card-header h3 span",
					performers: ".scene-performer span",
					site: 'a[href^="/studios/"]',
				},
			},
			{
				name: "AYLO",
				selectors: {
					title: "h2.sc-wxt7nk-4, h2.sc-1b6bgon-3, h1.sc-1b6bgon-3",
					performers:
						'a[href^="/pornstar/"][class^="sc-"], a[href^="/model/"][class^="sc-"]',
					site: ".sc-vdkjux-5",
				},
			},
			{
				name: "PORNPROS",
				selectors: {
					title: 'div[id="trailer_player"] .scene-info h1',
					performers: ".scene-info .link-list-with-commas a",
				},
			},
			{
				name: "BANG",
				selectors: {
					title: '[data-controller="video-entry"] div.flex.mb-6', // More specific selector targeting h1 within the flex container
					performers: 'div.w-full .leading-6 a[href^="/pornstar/"]',
				},
			},
			{
				name: "VIXEN",
				selectors: {
					title: '[data-test-component="VideoTitle"]', // More specific selector targeting h1 within the flex container
					performers:
						'[data-test-component="VideoModels"] a[href^="/performers/"]',
				},
			},
			{
				name: "NUBILES",
				selectors: {
					title: "div.row.content-pane-container .content-pane-title h2", // More specific selector targeting h1 within the flex container
					performers: ".content-pane-performer.model",
					site: ".row.content-pane-container .site-link",
				},
			},
			{
				name: "THEPORNDB",
				selectors: {
					title: ".justify-between h2.text-3xl", // More specific selector targeting h1 within the flex container
					performers: "div.px-3.py-1.text-center h2.text-xl a[title]",
					site: 'a[href^="/sites/"]',
				},
			},
			{
				name: "MANYVIDS",
				selectors: {
					title: ".VideoMetaInfo_title__mWRak", // More specific selector targeting h1 within the flex container
					performers: ".VideoProfileCard_actions__x_NEr",
					site: 'a[href^="/sites/"]',
				},
			},
			{
				name: "ADULTDVDEMPIRE",
				selectors: {
					title: ".movie-page__heading__title", // More specific selector targeting h1 within the flex container
					performers: '[label="Performer"]',
					site: '[label="Studio"]',
				},
			},
			{
				name: "GLORYHOLESWALLOW",
				selectors: {
					title: "div.memberVideoPics div.objectInfo h1",
					performers: "div.content p",
				},
			},
			{
				name: "STICKYDOLLARS",
				selectors: {
					title: "h1.title", // More specific selector targeting h1 within the flex container
					performers: 'h2.models a[href^="/models/"]',
				},
			},
			{
				name: "GLORYHOLESECRETS",
				selectors: {
					title: "h1.Title", // More specific selector targeting h1 within the flex container
					performers: ".ActorThumb-Name-Link",
				},
			},
			{
				name: "DATA18",
				selectors: {
					title: "#h1div h1 a",
					performers: "a.bold.gen",
					site: "p b a.bold",
				},
			},
			{
				name: "IAFD",
				selectors: {
					title: "h1",
					performers: "div.castbox a",
					site: 'p.bioheading a[href*="/studio.rme"], p.biodata a[href*="/studio.rme"]',
				},
				// Custom transform to remove the year in parentheses and apostrophes from the title
				titleTransform: (titleElement) => {
					const titleText = titleElement.textContent.trim();
					return titleText
						.replace(/\s*\(\d{4}\)$/, "") // Remove year in parentheses at the end
						.replace(/'/g, ""); // Remove all apostrophes without adding spaces
				},
				// Custom transform to remove the top-level domain from the site name
				siteTransform: (siteElement) => {
					const siteText = siteElement.textContent.trim();
					return siteText.replace(/\.[a-z]+$/, ""); // Remove the TLD (.com, .net, etc.)
				},
			},
		];

		console.log(
			`[Pattern Detector] ⚡ Starting pattern detection for: ${hostname}`
		);

		// Find matching patterns
		const matchingPattern = commonPatterns.find((pattern) => {
			const { selectors } = pattern;
			let matches = 0;

			for (const [key, selector] of Object.entries(selectors)) {
				const elements = document.querySelectorAll(selector);
				if (elements && elements.length > 0) {
					matches++;
					console.log(
						`[Pattern Detector] Found ${elements.length} matches for ${key} using selector: ${selector}`
					);

					// Log the actual site name if we're checking the site selector
					if (key === "site") {
						console.log(
							`[Pattern Detector] Site name found: "${elements[0].textContent.trim()}"`
						);
					}
				}
			}
			return matches >= 2;
		});

		if (matchingPattern) {
			console.log(
				`[Pattern Detector] Found matching pattern: ${matchingPattern.name}`,
				matchingPattern
			);
			window._currentPattern = matchingPattern;

			// Immediately try to extract data using the pattern
			const titleElement = document.querySelector(
				matchingPattern.selectors.title
			);
			const performerElements = document.querySelectorAll(
				matchingPattern.selectors.performers
			);
			const siteElement = document.querySelector(
				matchingPattern.selectors.site
			);

			console.log("[Pattern Detector] Extracted data:", {
				title: titleElement?.textContent.trim(),
				performers: Array.from(performerElements).map((el) =>
					el.textContent.trim()
				),
				site: siteElement?.textContent.trim(),
			});

			return matchingPattern;
		}

		console.log(
			`[Pattern Detector] No matching patterns found for ${hostname}`
		);
		return null;
	}
})();