您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds filters to the discover feature
// ==UserScript== // @name OkCupid better filtering // @namespace http://tampermonkey.net/ // @version 20241108.3 // @description Adds filters to the discover feature // @author You // @match https://www.okcupid.com/home // @match https://www.okcupid.com/discover // @icon https://www.google.com/s2/favicons?sz=64&domain=okcupid.com // @grant none // @license MIT // ==/UserScript== const dynamicStylePrefix = `css-${window.crypto.randomUUID()}`; const locationIcon = `<svg width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39" /></svg>`; const basicsIcon = `<svg width="24" height="24" viewBox="0 0 24 24"><path d="M17.75 12.843a5.454 5.454 0 1 1-.001 10.907 5.454 5.454 0 0 1 0-10.907zm0 1.5a3.953 3.953 0 1 0-.001 7.907 3.953 3.953 0 0 0 0-7.907zM10.431 8.55a.75.75 0 0 1 .75.75v8.885a.75.75 0 0 1-.75.75H1.547a.75.75 0 0 1-.75-.75V9.3a.75.75 0 0 1 .75-.75h8.885zm-.75 1.5H2.297v7.385h7.385V10.05zM11.42.275l9.91 2.656a.75.75 0 0 1 .336 1.255l-7.254 7.254a.75.75 0 0 1-1.255-.337l-2.655-9.91a.75.75 0 0 1 .918-.918zm.867 1.785l1.983 7.4 5.417-5.417-7.4-1.983z" fill="#1A1A1A" fill-rule="nonzero"></path></svg>`; const looksIcon = `<svg width="24" height="24" viewBox="0 0 24 24"><path d="M12.03 7.104a3.552 3.552 0 1 1 3.552-3.543 3.543 3.543 0 0 1-3.552 3.543zm0-5.704a2.16 2.16 0 1 0 2.16 2.161 2.15 2.15 0 0 0-2.16-2.16z" fill="#191919"></path><path d="M14.376 24.01a2.059 2.059 0 0 1-1.984-1.743l-.334-2.57-.38 2.57a2.077 2.077 0 0 1-2.069 1.743 2.225 2.225 0 0 1-1.641-.705 2.207 2.207 0 0 1-.621-1.669l.62-6.946-.416.686a1.957 1.957 0 0 1-2.152.928 1.854 1.854 0 0 1-1.215-1.02 1.8 1.8 0 0 1 0-1.586l2.745-5.25a3.617 3.617 0 0 1 2.68-1.947l1.725-.25a4.48 4.48 0 0 1 1.317 0l1.734.25a3.617 3.617 0 0 1 2.7 1.948l2.726 5.212a1.855 1.855 0 0 1-1.178 2.606 1.957 1.957 0 0 1-2.152-.928l-.417-.686.621 6.918a2.27 2.27 0 0 1-2.262 2.402l-.047.037zm-2.365-9.162a.871.871 0 0 1 .872.77l.835 6.426a.668.668 0 0 0 .658.557.873.873 0 0 0 .64-.27.844.844 0 0 0 .232-.648l-.844-9.47a.788.788 0 0 1 1.465-.481l1.762 2.912a.566.566 0 0 0 .622.25.428.428 0 0 0 .278-.612L15.84 9.07a2.215 2.215 0 0 0-1.65-1.187l-1.725-.232a3.051 3.051 0 0 0-.928 0l-1.725.25A2.216 2.216 0 0 0 8.172 9.09L5.482 14.3a.427.427 0 0 0 .279.613.556.556 0 0 0 .621-.26l1.762-2.903a.788.788 0 0 1 1.465.482l-.853 9.497a.862.862 0 0 0 .533.822c.11.046.229.07.348.068a.668.668 0 0 0 .659-.566l.834-6.417a.927.927 0 0 1 .881-.788z" fill="#191919"></path></svg>`; const backgroundIcon = `<svg width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M12.155.016L12 .015C18.627.015 24 5.38 24 12c0 6.566-5.287 11.899-11.841 11.984a.769.769 0 0 1-.317-.001l.158.002C5.373 23.985 0 18.619 0 12 0 5.433 5.289.1 11.844.016a.764.764 0 0 1 .311 0zM6.773 12.748l-5.247.001c.344 4.855 3.996 8.797 8.718 9.592a17.025 17.025 0 0 1-3.47-9.593zm15.7.001h-5.246a17.025 17.025 0 0 1-3.47 9.591c4.721-.794 8.373-4.736 8.717-9.591zm-6.748 0h-7.45A15.543 15.543 0 0 0 12 22.13a15.54 15.54 0 0 0 3.725-9.383zm-5.481-11.09l-.191.034c-4.63.867-8.188 4.768-8.527 9.557h5.247a17.027 17.027 0 0 1 3.47-9.591zm1.756.21l-.253.303a15.537 15.537 0 0 0-3.472 9.078h7.45a15.535 15.535 0 0 0-3.472-9.078L12 1.869zm1.755-.21l.137.18a17.022 17.022 0 0 1 3.335 9.411h5.247c-.344-4.855-3.996-8.798-8.719-9.591z" id="Icon/Background/24" fill="#1A1A1A" fill-rule="nonzero"></path></g></svg>`; const lifestyleIcon = `<svg width="17" height="24" viewBox="0 0 17 24"><g fill="none" fill-rule="evenodd"><path d="M18.617.153c.305.232.383.65.196.973l-.053.078-.568.743h2.054a.75.75 0 0 1 .655 1.12l-.06.09-7.589 9.762V22.5h2.326c.416 0 .753.336.753.75 0 .385-.29.702-.665.745l-.088.005H9.422a.752.752 0 0 1-.753-.75c0-.385.29-.702.665-.745l.088-.005h2.324v-9.582L4.159 3.157a.75.75 0 0 1 .488-1.202l.107-.007L16.3 1.947 17.562.296a.755.755 0 0 1 1.055-.143zm.093 3.294h-1.664l-3.947 5.167a.755.755 0 0 1-1.055.143.748.748 0 0 1-.196-.973l.052-.078 3.253-4.259H6.289l6.21 7.99 6.211-7.99z" transform="translate(-4)" id="Icon/Lifestyle/24" fill="#1A1A1A" fill-rule="nonzero"></path></g></svg>`; const familyIcon = `<svg width="24" height="20" viewBox="0 0 24 20"><g fill="none" fill-rule="evenodd"><path d="M17.976 2c.229 0 .445.107.587.29l5.274 6.802a.77.77 0 0 1 .164.455L24 9.57v11.66c0 .389-.282.71-.648.761L23.25 22H.75a.757.757 0 0 1-.743-.664L0 21.23V9.571l.001-.041a.79.79 0 0 1 .004-.044L0 9.571c0-.18.06-.344.16-.475l.003-.003 5.268-6.795a.737.737 0 0 1 .35-.258c.003 0 .007 0 .01-.002A.699.699 0 0 1 6.024 2l-.062.003A.736.736 0 0 1 6.014 2h.01zM6.024 4.005L1.5 9.84v10.62h2.063v-6.921c0-.39.282-.712.648-.763l.102-.007h3.375a.76.76 0 0 1 .75.77v6.921h2.111V9.838L6.024 4.005zM22.5 10.34H12.049v10.12H22.5V10.34zM6.938 14.308H5.063v6.152h1.875v-6.152zM20.3 12.769a.76.76 0 0 1 .75.77V17a.76.76 0 0 1-.75.77h-6a.76.76 0 0 1-.75-.77V13.54a.76.76 0 0 1 .75-.77zm-3.776 1.538H15.05v1.924l1.474-.001v-1.923zm3.026 0h-1.526v1.923h1.526v-1.922zm-1.937-10.77H7.578l4.083 5.264h10.033l-4.081-5.263z" transform="translate(0 -2)" id="Icon/Family/24" fill="#1A1A1A" fill-rule="nonzero"></path></g></svg>`; const lookingIcon = `<svg width="24" height="22" viewBox="0 0 24 22"><g fill="none" fill-rule="evenodd"><path d="M11.994 6.415l.412.007c1.898.059 3.727.552 5.499 1.51.977.524 1.95 1.221 2.932 2.098.5.467.89.858 1.255 1.27l.428.496c.41.492.814 1.052 1.213 1.68a.75.75 0 0 1 0 .804 16.127 16.127 0 0 1-1.207 1.673l-.427.495c-.247.279-.502.545-.798.834l-.476.455c-.97.866-1.943 1.562-2.919 2.086-1.9 1.027-3.864 1.52-5.912 1.517-2.053-.015-4.012-.51-5.899-1.535-.976-.525-1.948-1.22-2.93-2.095a17.247 17.247 0 0 1-1.438-1.473 15.582 15.582 0 0 1-1.459-1.955.75.75 0 0 1 0-.808 15.51 15.51 0 0 1 1.45-1.945c.432-.505.873-.952 1.458-1.494.971-.864 1.943-1.56 2.917-2.083C7.982 6.927 9.94 6.43 11.994 6.415zm.01 1.5l-.387.01c-1.668.069-3.258.504-4.811 1.347-.868.466-1.746 1.094-2.621 1.874-.446.413-.8.765-1.137 1.14l-.41.473c-.28.335-.561.708-.84 1.119.35.514.701.97 1.06 1.373.388.454.788.86 1.315 1.35.887.788 1.765 1.416 2.635 1.884 1.671.907 3.388 1.342 5.193 1.355 1.794.002 3.513-.429 5.194-1.337.868-.467 1.745-1.095 2.618-1.873.47-.44.827-.797 1.168-1.182l.381-.441c.281-.338.562-.714.842-1.13-.28-.415-.562-.793-.848-1.135l-.41-.473a17.134 17.134 0 0 0-1.12-1.131c-.885-.79-1.763-1.419-2.633-1.886-1.559-.843-3.151-1.275-4.807-1.33l-.383-.007zM12 9.162a4.5 4.5 0 1 1 0 9 4.5 4.5 0 0 1 0-9zm0 1.5a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm10.088-7.307a.75.75 0 0 1 1.06 1.06L20.975 6.59a.75.75 0 0 1-1.06-1.06zm-21.236 0a.75.75 0 0 1 1.06 0l2.174 2.173a.75.75 0 0 1-1.061 1.06L.852 4.416a.75.75 0 0 1 0-1.06zM12 0a.75.75 0 0 1 .75.75v3.074a.75.75 0 1 1-1.5 0V.75A.75.75 0 0 1 12 0z" id="lookingfor-eye-Icon/Looking-For/24" fill="#1A1A1A" fill-rule="nonzero"></path></g></svg>`; const profileIDTest = /profile\/(.+)\/questions/; const skippedIds = []; const currentProfile = { id: null, username: null, exclusions: [], }; let debugMode = false; let filters = { filterLocation: [], filterBasics: [], filterLooks: [], filterBackground: [], filterLifetsyle: [], filterFamily: [], filterLooking: [], }; if (localStorage.getItem('filterList') !== null && localStorage.getItem('filterList') !== '') { filters = JSON.parse(localStorage.getItem('filterList')); } function updateStorage() { // Remove empty strings. Object.keys(filters).forEach((storageKey) => { filters[storageKey] = filters[storageKey].filter((term) => term !== ''); }); localStorage.setItem('filterList', JSON.stringify(filters)); } const filtersSkeleton = [ { icon: locationIcon, storageKey: 'filterLocation', title: 'Location', selector: 'div.card-content-header__location', }, { icon: basicsIcon, storageKey: 'filterBasics', title: 'Basics', selector: 'div.matchprofile-details-section--basics div.matchprofile-details-text', }, { icon: looksIcon, storageKey: 'filterLooks', title: 'Looks', selector: 'div.matchprofile-details-section--looks div.matchprofile-details-text', }, { icon: backgroundIcon, storageKey: 'filterBackground', title: 'Background', selector: 'div.matchprofile-details-section--background div.matchprofile-details-text', }, { icon: lifestyleIcon, storageKey: 'filterLifetsyle', title: 'Lifestyle', selector: 'div.matchprofile-details-section--lifestyle div.matchprofile-details-text', }, { icon: familyIcon, storageKey: 'filterFamily', title: 'Family', selector: 'div.matchprofile-details-section--family div.matchprofile-details-text', }, { icon: lookingIcon, storageKey: 'filterLooking', title: 'Loooking for', selector: 'div.matchprofile-details-section--wiw div.matchprofile-details-text', }, ]; function buildFilterHTML() { const htmlArray = filtersSkeleton.map((filter) => { const listElements = filters[filter.storageKey].map((el) => { return `<li class="${dynamicStylePrefix}exclusion" data-key="${filter.storageKey}" data-value="${el}">${el}</li>`; }).join(`\n`); return ` <div class="${dynamicStylePrefix}filter-item"> <div class="${dynamicStylePrefix}filter-addition"> <div title="${filter.title}">${filter.icon}</div> <div><input type="text" id="${dynamicStylePrefix}${filter.storageKey}" data-key="${filter.storageKey}" /></div> </div> <ul class="${dynamicStylePrefix}exclusion-list"> ${listElements} </ul> </div>\n`; }); return htmlArray.join(`\n`); } function toggleFeature() { const toggleElement = document.getElementById(`${dynamicStylePrefix}button-base-root`); const toggleTrack = document.getElementById(`${dynamicStylePrefix}track`); // Local storage saves only strings. const filtersEnabled = localStorage.getItem('filtersEnabled') === 'true'; if (filtersEnabled) { // Turn off the filter. toggleElement.classList.remove('checked'); toggleTrack.classList.remove('checked'); } else { // Turn on the filter. toggleElement.classList.add('checked'); toggleTrack.classList.add('checked'); } console.debug(`[user script] Setting the filtersEnabled value to ${!filtersEnabled}.`); localStorage.setItem('filtersEnabled', !filtersEnabled); } function bindFilterListItem(el) { el.addEventListener('click', () => { const value = el.innerText; const storageKey = el.getAttribute('data-key'); console.debug(`[user script] The user wants to remove this value. ${value}`); filters[storageKey] = filters[storageKey].filter((item) => item !== value); updateStorage(); el.remove(); }); } function bindFilterItem(el) { const inputField = el.querySelector('input'); const listElement = el.querySelector('ul'); const storageKey = inputField.getAttribute('data-key'); inputField.addEventListener('keyup', ({ target, key, keyCode }) => { const searchTerm = target.value.trim().toLowerCase(); if (searchTerm !== '' && (key === 'Enter' || keyCode === 13) && !filters[storageKey].includes(searchTerm)) { const newListItem = document.createElement('li'); newListItem.innerHTML = searchTerm; newListItem.setAttribute('data-key', storageKey); newListItem.setAttribute('data-value', searchTerm); bindFilterListItem(newListItem); listElement.insertAdjacentElement('beforeend', newListItem); inputField.value = null; filters[storageKey].push(searchTerm); updateStorage(); } }); } let profileLoop = null; function getProfileID() { let matchButton = document.querySelector('[data-cy="discover.userCardMatchPercentage"]'); if (matchButton) { const { href } = matchButton; const matches = href.match(profileIDTest); if (matches !== null) { return matches[1]; } } return 'unknown'; }; function getProfileUsername() { const headerElement = document.querySelector('div.card-content-header__name-container h2'); if (headerElement) { return headerElement.innerHTML; } return 'unknown'; } function compileExclusions() { // Reset the found exclusions list. currentProfile.exclusions = []; filtersSkeleton.forEach((filter) => { // Are there any exlusions set for this category? if (filters[filter.storageKey].length === 0) { return false; } const detailElement = document.querySelector(filter.selector); if (!detailElement) { return false; } detailElement.innerText.split('|').forEach((detail) => { const profileDetail = detail.trim().toLowerCase(); filters[filter.storageKey].forEach((filterTerm) => { const exclusionListItem = document.querySelector(`li[data-value="${filterTerm}"]`); exclusionListItem.classList.remove('found'); if (filterTerm !== '' && (profileDetail.includes(filterTerm) || profileDetail === filterTerm)) { exclusionListItem.classList.add('found'); currentProfile.exclusions.push(profileDetail); } }); }); }); } let passing = false; function pass() { const clickEvent = new Event('click'); const blockButton = document.getElementById('user-script-block'); const passButton = document.querySelector('button.dt-action-buttons-button.pass'); const notificationElement = document.getElementById(`${dynamicStylePrefix}notification`); // The page has not yet loaded enough to have rendered the elements we need. if (!passButton || !notificationElement) { console.debug(`[user script] [${currentProfile.id}] Waiting for elements.`); setTimeout(() => pass, 100); } const { id } = currentProfile; if (blockButton) { console.debug(`[user script] [${currentProfile.id}] Blocking profile.`); blockButton.dispatchEvent(clickEvent); } else { console.debug(`[user script] [${currentProfile.id}] Passing on profile.`); passButton.dispatchEvent(clickEvent); } skippedIds.push(id); setTimeout(() => { // The profile still hasn't changed. if (id === currentProfile.id) { pass(); } }, 2000); } function checkProfileLoop() { clearInterval(profileLoop); const notificationElement = document.getElementById(`${dynamicStylePrefix}notification`); const debugSpanID = document.getElementById(`${dynamicStylePrefix}debug-id`); const debugSpanUsername = document.getElementById(`${dynamicStylePrefix}debug-username`); const debugSpanExclusions = document.getElementById(`${dynamicStylePrefix}debug-exclusions`); profileLoop = setInterval(() => { const profileId = getProfileID(); const username = getProfileUsername(); compileExclusions(); const hasExclusion = currentProfile.exclusions.length > 0; // The profile has changed. if (profileId !== currentProfile.id) { console.debug(`[user script] [${profileId}] Found a new profile.`); passing = false; if (hasExclusion) { console.debug(`[user script] [${profileId}] This profile contains ${currentProfile.exclusions.length} exclusions.`); } } // Update the current profile. currentProfile.id = profileId; currentProfile.username = username; debugSpanUsername.innerHTML = username; debugSpanID.innerHTML = profileId; debugSpanExclusions.innerHTML = !hasExclusion ? '' : currentProfile.exclusions.join('<br />'); notificationElement.style.display = hasExclusion ? 'flex' : 'none'; if (!skippedIds.includes(profileId) && hasExclusion) { if (localStorage.getItem('filtersEnabled') === 'true') { console.debug(`[user script] [${currentProfile.id}] Setting this profile to be passed.`); passing = true; pass(); } } }, 500); } function initialize(detailsTopElement) { console.debug('[user script] Initializing the detail filter.'); const debugContainer = document.createElement('div'); debugContainer.classList.add(`${dynamicStylePrefix}hidden`); debugContainer.classList.add(`${dynamicStylePrefix}debug-container`); debugContainer.innerHTML = `<h3 class="dt-section-title">Debug</h3> <div class="dt-section-content"> <div> <span>id</span> <span id="${dynamicStylePrefix}debug-id"></span> </div> <div> <span>username</span> <span id="${dynamicStylePrefix}debug-username"></span> </div> <div style="margin-top: 1em;"> <span>exclusions</span> <br> <span id="${dynamicStylePrefix}debug-exclusions"></span> <div> </div>`; document.querySelector('body').insertAdjacentElement('beforeend', debugContainer); const enabled = localStorage.getItem('filtersEnabled') === 'true'; const filterContainer = document.createElement('div'); filterContainer.classList.add('dt-section'); filterContainer.innerHTML = ` <h3 class="dt-section-title">Filters</h3> <div class="dt-section-content"> <div class="${dynamicStylePrefix}control-container"> <div style="flex-grow: 1;"> <span class="${dynamicStylePrefix}switch-root" id="${dynamicStylePrefix}switch-root"> <span class="${dynamicStylePrefix}button-base-root ${enabled ? 'checked' : ''}" id="${dynamicStylePrefix}button-base-root"> <input class="${dynamicStylePrefix}input-toggle" /> <span class="${dynamicStylePrefix}thumb"></span> <span class="${dynamicStylePrefix}ripple"></span> </span> <span class="${dynamicStylePrefix}track ${enabled ? 'checked' : ''}" id="${dynamicStylePrefix}track"></span> </span> <span id="${dynamicStylePrefix}toggle-label">Automatically pass</span> </div> <div id="${dynamicStylePrefix}notification">This profile contains an exclusion.</div> <div class="${dynamicStylePrefix}icon-button" id="${dynamicStylePrefix}icon-button"> <svg><path d="M10 18h4v-2h-4zM3 6v2h18V6zm3 7h12v-2H6z" /></svg> </div> <div class="${dynamicStylePrefix}icon-button" id="${dynamicStylePrefix}icon-button-debug"> <svg viewBox="0 0 24 24"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5s-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20zm-6 8h-4v-2h4zm0-4h-4v-2h4z"></path></svg> </div> </div> <div class="${dynamicStylePrefix}filter-container" id="${dynamicStylePrefix}filter-container"> <p> Profiles containing any of these exclusions will be passed. All exclusions are case-insensitive. If you are also using the <a href="https://greasyfork.org/en/scripts/504158-okcupid-more-effective-pass">more effective pass</a> script then the profiles will instead be blocked. </p> <div class="${dynamicStylePrefix}filter-list"> ${buildFilterHTML()} </div> </div> </div> `; detailsTopElement.insertAdjacentElement('afterend', filterContainer); const toggleElement = document.getElementById(`${dynamicStylePrefix}switch-root`); toggleElement.addEventListener('click', toggleFeature); const showFiltersButton = document.getElementById(`${dynamicStylePrefix}icon-button`); const showDebugButton = document.getElementById(`${dynamicStylePrefix}icon-button-debug`); const filterContainerElement = document.getElementById(`${dynamicStylePrefix}filter-container`); showFiltersButton.addEventListener('click', () => { const display = filterContainerElement.style.display === 'none' || filterContainerElement.style.display === '' ? 'flex' : 'none'; filterContainerElement.style.display = display; }); showDebugButton.addEventListener('click', () => { debugContainer.classList.toggle(`${dynamicStylePrefix}hidden`); }); [...document.querySelectorAll(`div.${dynamicStylePrefix}filter-item`)].forEach(bindFilterItem); // Bind the existing list items that were loaded from local storage. [...document.querySelectorAll(`ul.${dynamicStylePrefix}exclusion-list li`)].forEach(bindFilterListItem); checkProfileLoop(); } const styleString = ` div.${dynamicStylePrefix}control-container { display: flex; alignItems: center; } span.${dynamicStylePrefix}switch-root { display: inline-flex; width: 58px; height: 38px; overflow: hidden; padding: 12px; box-sizing: border-box; position: relative; flex-shrink: 0; z-index: 0; vertical-align: middle; } span.${dynamicStylePrefix}button-base-root { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; background-color: transparent; outline: 0px; border: 0px; margin: 0px; cursor: pointer; user-select: none; vertical-align: middle; appearance: none; text-decoration: none; padding: 9px; border-radius: 50%; position: absolute; top: 0px; left: 0px; z-index: 1; color: rgb(255, 255, 255); transition: left 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1); } span.${dynamicStylePrefix}button-base-root.checked { color: rgb(25, 118, 210); transform: translateX(20px); } span.${dynamicStylePrefix}button-base-root:hover { background-color: rgba(0, 0, 0, 0.04); } input.${dynamicStylePrefix}input-toggle { left: -100%; width: 300%; cursor: inherit; position: absolute; opacity: 0; width: 100%; height: 100%; top: 0; left: 0; margin: 0; padding: 0; z-index: 1; } span.${dynamicStylePrefix}thumb { box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px; background-color: currentcolor; width: 20px; height: 20px; border-radius: 50%; } span.${dynamicStylePrefix}ripple { overflow: hidden; pointer-events: none; position: absolute; z-index: 0; inset: 0px; border-radius: inherit; } span.${dynamicStylePrefix}track { height: 100%; width: 100%; border-radius: 7px; z-index: -1; transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), background-color 150ms cubic-bezier(0.4, 0, 0.2, 1); background-color: rgb(0, 0, 0); opacity: 0.38; } span.${dynamicStylePrefix}track.checked { background-color: rgb(25, 118, 210); } div.${dynamicStylePrefix}icon-button { width: 32px; height: 32px; border: 1px solid silver; cursor: pointer; border-radius: 4px; display: flex; align-items: center; justify-content: center; } div.${dynamicStylePrefix}icon-button:hover { background-color: rgb(246 246 246); } div.${dynamicStylePrefix}icon-button:hover svg { fill: rgb(25, 118, 210); } div.${dynamicStylePrefix}icon-button svg { width: 24px; height: 24px; } div.${dynamicStylePrefix}filter-container { display: none; flex-direction: column; gap: 1em; border-top: 1px solid black; padding: 1em; margin-top: 1em; } div.${dynamicStylePrefix}filter-list { display: flex; flex-basis: auto; justify-content: center; gap: 1em; flex-wrap: wrap; } div.${dynamicStylePrefix}filter-item { display: flex; flex-direction: column; gap: 0.5em; border: 1px solid grey; border-radius: 4px; width: 260px; height: 200px; padding: 3px; } div.${dynamicStylePrefix}filter-addition { display: flex; gap: 2px; align-items: center; border-bottom: 1px dashed black; } div.${dynamicStylePrefix}filter-addition svg { width: 32px; height: 32px; } div.${dynamicStylePrefix}filter-addition input { width: 100%; } ul.${dynamicStylePrefix}exclusion-list { list-style: none; overflow: scroll; } ul.${dynamicStylePrefix}exclusion-list li { cursor: pointer; } ul.${dynamicStylePrefix}exclusion-list li:hover { text-decoration: line-through; background-color: rgb(246 246 246); } div#${dynamicStylePrefix}notification { display: none; flex-grow: 1; font-style: italic; color: red; } li.${dynamicStylePrefix}exclusion.found { color: red; } .${dynamicStylePrefix}hidden { display: none !important; } div.${dynamicStylePrefix}debug-container { display: flex; flex-direction: column; position: fixed; bottom: 1em; left: 1em; width: 300px; } div.${dynamicStylePrefix}debug-container .dt-section-content { background-color: rgb(255 255 255 / 70%); display: flex; flex-direction: column; } div#${dynamicStylePrefix}icon-button-debug { margin-left: 1em; } `; (function() { 'use strict'; const sheet = new CSSStyleSheet(); sheet.replaceSync(styleString); console.debug(`[user scripts] Adding ${sheet.rules.length} new CSS rules.`); document.adoptedStyleSheets.push(sheet); let detailsTopElement = null; setInterval(() => { if (detailsTopElement === null || !document.body.contains(detailsTopElement)) { detailsTopElement = document.querySelector('div.desktop-dt-top'); // The details container now exists. Create our custom elements. if (detailsTopElement !== null) { initialize(detailsTopElement); } } }, 100); })();