您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
f95zone exclude tags and min like filter.
当前为
// ==UserScript== // @name f95zone tweaks // @namespace f95zone tweaks // @description f95zone exclude tags and min like filter. // @match https://f95zone.to/sam/latest_alpha/ // @version 1.4.0 // @author 3xd_Tango // @require https://cdn.jsdelivr.net/combine/npm/@violentmonkey/dom@2,npm/@violentmonkey/[email protected] // @require https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @license GNU GPLv3 // ==/UserScript== (function () { 'use strict'; var css_248z = ".customTags{border-radius:2px;box-shadow:0 0 0 0 transparent,0 1px 1px 0 rgba(0,0,0,.15),0 1px 2px 0 rgba(0,0,0,.15);display:inline-block;font-size:.8em;line-height:1.8em;margin:4px 4px 0 0;padding:0 6px;text-shadow:1px 1px 2px rgba(0,0,0,.75)}.selected-tags-wrap span:hover{background-color:#ba4545}.selected-tags-wrap span{background-color:#181a1d;border-radius:3px;cursor:pointer;display:inline-block;font-size:.9em;line-height:24px;margin:4px 4px 0 0;padding:0 7px;transition:.2s}.input-tag{left:0;opacity:1;position:relative;width:127px}.border-gradient{border:3px solid;border-image-slice:1}.flxgrow{flex-grow:1}"; const likes = GM_getValue('likes', [['incest', '#ff0000', '30'], ['harem', '#0011ff', '254'], ['futa/trans', '#EE82EE', '191'], ['loli', '#00f5ffff', '639'], ['futa/trans protagonist', '#EE82EE', '2255']]); const dislikes = GM_getValue('dislikes', [['female protagonist', '392'], ['text based', '522'], ['mind control', '111']]); const totalTags = GM_getValue('tags', [['2d game', '2214'], ['2dcg', '1507'], ['3d game', '1434'], ['3dcg', '107'], ['adventure', '162'], ['ahegao', '916'], ['anal sex', '2241'], ['animated', '783'], ['bdsm', '264'], ['bestiality', '105'], ['big ass', '817'], ['big tits', '130'], ['blackmail', '339'], ['bukkake', '216'], ['censored', '2247'], ['character creation', '2246'], ['cheating', '924'], ['combat', '550'], ['corruption', '103'], ['cosplay', '606'], ['creampie', '278'], ['dating sim', '348'], ['dilf', '1407'], ['drugs', '2217'], ['dystopian setting', '2249'], ['exhibitionism', '384'], ['fantasy', '179'], ['female domination', '2252'], ['female protagonist', '392'], ['footjob', '553'], ['furry', '382'], ['futa/trans', '191'], ['futa/trans protagonist', '2255'], ['gay', '360'], ['graphic violence', '728'], ['groping', '535'], ['group sex', '498'], ['handjob', '259'], ['harem', '254'], ['horror', '708'], ['humiliation', '871'], ['humor', '361'], ['incest', '30'], ['internal view', '1483'], ['interracial', '894'], ['japanese game', '736'], ['kinetic novel', '1111'], ['lactation', '290'], ['lesbian', '181'], ['loli', '639'], ['male domination', '174'], ['male protagonist', '173'], ['management', '449'], ['masturbation', '176'], ['milf', '75'], ['mind control', '111'], ['mobile game', '2229'], ['monster', '182'], ['monster girl', '394'], ['multiple endings', '322'], ['multiple penetration', '1556'], ['multiple protagonist', '2242'], ['necrophilia', '1828'], ['no sexual content', '324'], ['ntr', '258'], ['oral sex', '237'], ['paranormal', '408'], ['parody', '505'], ['platformer', '1508'], ['point & click', '1525'], ['possession', '1476'], ['pov', '1766'], ['pregnancy', '225'], ['prostitution', '374'], ['puzzle', '1471'], ['rape', '417'], ['real porn', '1707'], ['religion', '2218'], ['romance', '330'], ['rpg', '45'], ['sandbox', '2257'], ['scat', '689'], ['school setting', '547'], ['sci-fi', '141'], ['sex toys', '2216'], ['sexual harassment', '670'], ['shooter', '1079'], ['shota', '749'], ['side-scroller', '776'], ['simulator', '448'], ['sissification', '2215'], ['slave', '44'], ['sleep sex', '1305'], ['spanking', '769'], ['strategy', '628'], ['stripping', '480'], ['superpowers', '354'], ['swinging', '2234'], ['teasing', '351'], ['tentacles', '215'], ['text based', '522'], ['titfuck', '411'], ['trainer', '199'], ['transformation', '875'], ['trap', '362'], ['turn based combat', '452'], ['twins', '327'], ['urination', '1254'], ['vaginal sex', '2209'], ['virgin', '833'], ['virtual reality', '895'], ['voiced', '1506'], ['vore', '757'], ['voyeurism', '485']]); function likeFilter() { const element = document.querySelectorAll('.resource-tile'); document.querySelectorAll('.customTags').forEach(e => e.parentNode.remove()); for (let i = 0; i < element.length; i += 1) { element[i].style = ''; element[i].classList.remove('border-gradient'); element[i].setAttribute('isDisplay', 'false'); const colors = []; const node = document.createElement('DIV'); const dataTags = element[i].dataset.tags.split(','); node.style.padding = '.5rem 0'; for (let j = likes.length - 1; j >= 0; j -= 1) { if (dataTags.includes(likes[j][2])) { console.debug(likes[j][0], likes[j][1]); if (!element[i].classList.contains('border-gradient')) { element[i].classList.add('border-gradient'); } const node1 = document.createElement('SPAN'); colors.push(likes[j][1]); node1.classList.add('customTags'); node1.style.borderLeft = `${likes[j][1]} solid`; node1.appendChild(document.createTextNode(likes[j][0])); node.appendChild(node1); element[i].setAttribute('isDisplay', 'true'); } else if (element[i].getAttribute('isDisplay') === null) { element[i].setAttribute('isDisplay', 'false'); } } if (colors.length > 1) { element[i].style.borderImageSource = `linear-gradient(to bottom right, ${colors.toString()})`; } else { element[i].style.color = colors[0]; } if (element[i].getAttribute('isDisplay') === 'true') { try { element[i].childNodes[0].childNodes[1].childNodes[1].appendChild(node); } catch (e) { console.error(e); setTimeout(likeFilter, 200); } } } } function likeLimit() { const element = document.querySelectorAll('.resource-tile_info'); // if (likesLimit === '') { // likesLimit = -1; // } for (let i = 0; i < element.length; i++) { const elementLikes = element[i].childNodes[1].childNodes[1].innerText; element[i].childNodes[0].childNodes[0].childNodes[0].innerText; const checkFilter = Number(elementLikes) <= Number(GM_getValue('like_limit', 200)); // console.debug(`we get Like limit of ${elementName} is ${elementLikes} with check ${checkFilter} with display attribute of ${(element[i].parentNode.parentNode.parentNode.getAttribute('isDisplay').toLowerCase() !== 'false')}`); if (checkFilter) { if (element[i].parentNode.parentNode.parentNode.getAttribute('isDisplay') === 'false') { element[i].parentNode.parentNode.parentNode.setAttribute('isLikeLimit', 'true'); continue; } if (GM_getValue('favLikeFilter', false)) { element[i].parentNode.parentNode.parentNode.setAttribute('isLikeLimit', 'true'); continue; } } element[i].parentNode.parentNode.parentNode.setAttribute('isLikeLimit', 'false'); } } function filterOut() { const element = document.querySelectorAll('.resource-tile'); for (let i = 0; i < element.length; i++) { if (element[i].getAttribute('isDislike') === 'true' || element[i].getAttribute('isLikeLimit') === 'true') { element[i].style.setProperty('display', 'none', 'important'); element[i].style.setProperty('height', '0px', 'important'); element[i].style.setProperty('margin', '0px', 'important'); } else { element[i].style.setProperty('display', 'block', 'important'); element[i].style.setProperty('height', 'unset', 'important'); element[i].style.setProperty('margin', 'unset', 'important'); } } } function checkTags(element, dataTags) { let tagProt = [['female domination', '2252'], ['male protagonist', '173'], ['futa/trans protagonist', '2255']]; const tagProtNames = dislikes.filter(e => e[0].includes('protagonist')); console.log(tagProtNames, 'tagProtNames'); const b = []; let c = 0; dataTags.forEach(e => { if (tagProtNames.length >= 1) { for (let i = 0; i < tagProtNames.length; i += 1) { if (tagProtNames[i][1].includes(e)) { return b.push(e); } } } if (dislikes.includes(e)) { c += 1; } }); // console.debug(`b = ${b}`, c, element); if (c > 0) { return true; } if (b.length > 0) { b.forEach(e => { tagProt = tagProt.filter(r => r !== e); }); for (let i = 0; i <= tagProt.length - 1; i += 1) { console.debug(`datatags includes? = ${dataTags.includes(tagProt[i][1])} for ${tagProt[i][0]} `); if (dataTags.includes(tagProt[i])) { return false; } if (i === tagProt.length - 1) { return true; } } } console.debug(`tagProt = ${tagProt}`); return false; } function dislikeFilter() { const element = document.querySelectorAll('.resource-tile'); for (let i = 0; i < element.length; i++) { const dataTags = element[i].dataset.tags.split(','); const isFP = checkTags(element[i], dataTags); if (isFP) { element[i].setAttribute('isDislike', 'true'); } else { element[i].setAttribute('isDislike', 'false'); } } } function tagRemoveHandler(event, isLikes) { let filtered = []; if (isLikes) { filtered = likes.filter(r => r[0] !== event.target.textContent); console.debug(`You have clicked the Like Tag to Remove it and the filtered is: ${filtered} within ${likes}`); const removed = _.remove(likes, n => { return n[0] === event.target.textContent; }); console.debug(`after filtred you got likes tags: ${likes} and you removed ${removed}`); likeFilter(); likeLimit(); } else { filtered = dislikes.filter(r => r[0] !== event.target.textContent); console.debug(`You have clicked the dislike Tag to Remove it and the filtered is: ${filtered} within ${dislikes}`); const removed = _.remove(dislikes, n => { return n[0] === event.target.textContent; }); console.debug(`after filtred you got dislike tags: ${dislikes} and you removed ${removed}`); dislikeFilter(); } event.target.remove(); GM_setValue(isLikes ? 'likes' : 'dislikes', filtered); filterOut(); } // function tagRemoveHandler1(event) { // likes = likes.filter(r => r[0] !== event.target.textContent); // event.target.remove(); // GM_setValue('likes', likes); // likeFilter(); // likeLimit(); // filterOut(); // } function likeHandler(event) { const [tagName, tagCode] = event.target.value.split(':'); event.target.value = ''; let x; do { x = prompt("Please Enter the Color in Hex like '#FFFFFF'"); } while (!x.includes('#') && x === '' && x.length <= 1); console.debug(`you have entered color in hex: ${x} with tagName: ${tagName} and the condition ${x !== null}`); if (x !== null) { const tag = [tagName, x, tagCode]; likes.push(tag); console.debug(`the likes after pushing the ${tag} is ${likes}`); GM_setValue('likes', _.sortBy(likes, item => item[0])); const node = document.createElement('SPAN'); node.onclick = e => tagRemoveHandler(e, true); node.style.borderLeft = `${x} solid`; node.appendChild(document.createTextNode(tagName)); event.target.parentNode.parentNode.childNodes[2].append(node); likeFilter(); likeLimit(); filterOut(); } } function dislikeHandler(event) { const [tagName, tagCode] = event.target.value.split(':'); dislikes.push([tagName, tagCode]); GM_setValue('dislikes', _.sortBy(dislikes)); event.target.value = ''; const node = document.createElement('SPAN'); node.onclick = e => tagRemoveHandler(e, false); node.appendChild(document.createTextNode(tagName)); event.target.parentNode.parentNode.childNodes[2].append(node); dislikeFilter(); filterOut(); } function limitHandler(event) { GM_setValue('like_limit', event.target.value); likeLimit(); filterOut(); } function clickTotalTags() { const y = document.querySelector('.selectize-control'); if (y !== null) { y.addEventListener('click', e => { const x = document.querySelectorAll('div.option'); console.log('clicked', x); if (x !== []) { const totalTags = []; x.forEach(e => totalTags.push([e.childNodes[0].innerHTML, e.dataset.value])); GM_setValue('tags', totalTags); } }); } } function init() { const element = document.querySelectorAll('.resource-tile'); const elementLength = element.length; if (element[0]) { likeFilter(); clickTotalTags(); for (let i = 0; i < 3; i++) { dislikeFilter(); likeLimit(); filterOut(); // if(document.querySelectorAll('.resource-tile')) const filtered = _.filter(document.querySelectorAll('.resource-tile'), e => { return e.getAttribute('isDisplay') === 'true'; }); console.debug('Filtered', filtered); if (filtered.length < elementLength) { break; } } } else { setTimeout(init, 100); } } function waitForElementToDisplayAndAppend(selector, callback, checkFrequencyInMs, timeoutInMs) { const startTimeInMs = Date.now(); (function loopSearch() { if (document.querySelector(selector).childNodes.length > 0) { document.querySelector(selector).appendChild(callback()); } else { setTimeout(() => { if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs) return; loopSearch(); }, checkFrequencyInMs); } })(); } function LikesTagFilter() { // filter-block accordion-block filter-block_prefix-group return VM.hm("div", { className: "filter-block accordion-block filter-block_prefix-group" }, VM.hm("h4", { className: "filter-block_title accordion-toggle" }, "Like Tags"), VM.hm("div", { className: "filter-block_content filter-block_v accordion-content" }, VM.hm("div", { className: "selectize-input" }, VM.hm("input", { autoComplete: "on", placeholder: "Enter a tag to filter...", className: "input-tag", onChange: likeHandler, list: "totalTagName" })), VM.hm("datalist", { id: "totalTagName" }, totalTags.map(item => { return VM.hm("option", { value: `${item[0]}:${item[1]}` }); })), VM.hm("div", { className: "selected-tags-wrap" }, likes.map(dl => { const node = document.createElement('SPAN'); node.onclick = e => tagRemoveHandler(e, true); node.style.borderLeft = `${dl[1]} solid`; node.appendChild(document.createTextNode(dl[0])); return node; // <span // style={{ borderLeft: `${dl[1]} solid` }} // onClick={(e) => tagRemoveHandler(e, true)} // > // {dl[0]} // </span>; })))); } function DislikeTagFilter() { return VM.hm("div", { className: "filter-block accordion-block filter-block_prefix-group" }, VM.hm("h4", { className: "filter-block_title accordion-toggle" }, "Dislike Tags"), VM.hm("div", { className: "filter-block_content filter-block_v accordion-content" }, VM.hm("div", { className: "selectize-input" }, VM.hm("input", { autoComplete: "off", placeholder: "Enter a tag to filter...", className: "input-tag", onChange: dislikeHandler, list: "totalTagName1" })), VM.hm("datalist", { id: "totalTagName1" }, totalTags.map(item => { return VM.hm("option", { value: `${item[0]}:${item[1]}` }); })), VM.hm("div", { className: "selected-tags-wrap" }, dislikes.map(dl => VM.hm("span", { onClick: e => tagRemoveHandler(e, false) }, dl[0]))))); } function LikeLimitDisplay() { return VM.hm("div", { className: "filter-block" }, VM.hm("h4", { className: "filter-block_title" }, "Tags Like Limits"), VM.hm("div", { className: "selectize-input" }, VM.hm("input", { value: GM_getValue('like_limit', 200), autoComplete: "off", style: "width: 127px;", onChange: limitHandler }))); } function FilterFavLikeHandler(event) { GM_setValue('favLikeFilter', event.target.checked); likeLimit(); filterOut(); } function mainFilter() { init(); return VM.hm(VM.Fragment, null, LikeLimitDisplay(), VM.hm("div", { className: "filter-block" }, VM.hm("div", { className: "filter-block_button-wrap", style: { display: 'flex' } }, VM.hm("span", { className: "filter-block_title flxgrow" }, "Filter Fav likes:"), VM.hm("input", { type: "checkbox", id: "filter-fav-likes", onChange: FilterFavLikeHandler, checked: GM_getValue('favLikeFilter', false) }))), VM.hm("style", null, css_248z)); } document.querySelector('.content-block_filter').appendChild(mainFilter()); waitForElementToDisplayAndAppend('#filter-block_prefixes', LikesTagFilter, 1000, 10000); waitForElementToDisplayAndAppend('#filter-block_prefixes', DislikeTagFilter, 1000, 10000); history.onpushstate = function (state) { setTimeout(init, 200); }; (function (history) { const pushState = history.pushState; history.pushState = function (state) { if (typeof history.onpushstate === 'function') { history.onpushstate({ state }); } return pushState.apply(history); }; })(window.history); })();