f95zone tweaks

f95zone exclude tags and min like filter.

От 26.09.2021. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name        f95zone tweaks
// @namespace   f95zone tweaks
// @description f95zone exclude tags and min like filter.
// @match       https://f95zone.to/latest/
// @version     1.3.8
// @author      3xd_Tango
// @require     https://cdn.jsdelivr.net/combine/npm/@violentmonkey/dom@1,npm/@violentmonkey/[email protected]
// @require     https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// ==/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{width:127px;opacity:1;position:relative;left:0}.border-gradient{border:3px solid;border-image-slice:1}.flxgrow{flex-grow:1}";

const likes = GM_getValue('likes', [['incest', '#ff0000'], ['harem', '#0011ff'], ['futa/trans', '#EE82EE'], ['loli', '#00f5ffff'], ['futa/trans protagonist', '#EE82EE']]);
const dislikes = GM_getValue('dislikes', ['female protagonist', 'text based', 'mind control']);
const totalTags = GM_getValue('tags', []);

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][0])) {
        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;
    const elementName = 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 protagonist', 'male protagonist', 'futa/trans protagonist'];
  const tagProtNames = dislikes.filter(e => e.includes('protagonist'));
  const b = [];
  let c = 0;
  dataTags.forEach(e => {
    if (tagProtNames.length >= 1) {
      if (tagProtNames.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++) {
      console.debug(`datatags includes? = ${dataTags.includes(tagProt[i])} for ${tagProt[i]} `);

      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 !== 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 === 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 = event.target.value;
  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];
    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 = event.target.value;
  dislikes.push(tagName);
  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.innerHTML));
        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.style.getPropertyValue('display') === 'block';
      });

      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.createElement("div", {
    className: "filter-block accordion-block filter-block_prefix-group"
  }, VM.createElement("h4", {
    className: "filter-block_title accordion-toggle"
  }, "Like Tags"), VM.createElement("div", {
    className: "filter-block_content filter-block_v accordion-content"
  }, VM.createElement("div", {
    className: "selectize-input"
  }, VM.createElement("input", {
    autoComplete: "on",
    placeholder: "Enter a tag to filter...",
    className: "input-tag",
    onChange: likeHandler,
    list: "totalTagName"
  })), VM.createElement("datalist", {
    id: "totalTagName"
  }, totalTags.map(item => {
    return VM.createElement("option", {
      value: item
    });
  })), VM.createElement("div", {
    className: "selected-tags-wrap"
  }, likes.map(dl => VM.createElement("span", {
    onClick: e => tagRemoveHandler(e, true),
    style: {
      borderLeft: `${dl[1]} solid`
    }
  }, dl[0])))));
}

function DislikeTagFilter() {
  return VM.createElement("div", {
    className: "filter-block accordion-block filter-block_prefix-group"
  }, VM.createElement("h4", {
    className: "filter-block_title accordion-toggle"
  }, "Dislike Tags"), VM.createElement("div", {
    className: "filter-block_content filter-block_v accordion-content"
  }, VM.createElement("div", {
    className: "selectize-input"
  }, VM.createElement("input", {
    autoComplete: "off",
    placeholder: "Enter a tag to filter...",
    className: "input-tag",
    onChange: dislikeHandler,
    list: "totalTagName1"
  })), VM.createElement("datalist", {
    id: "totalTagName1"
  }, totalTags.map(item => {
    return VM.createElement("option", {
      value: item
    });
  })), VM.createElement("div", {
    className: "selected-tags-wrap"
  }, dislikes.map(dl => VM.createElement("span", {
    onClick: e => tagRemoveHandler(e, false)
  }, dl)))));
}

function LikeLimitDisplay() {
  return VM.createElement("div", {
    className: "filter-block"
  }, VM.createElement("h4", {
    className: "filter-block_title"
  }, "Tags Like Limits"), VM.createElement("div", {
    className: "selectize-input"
  }, VM.createElement("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.createElement(VM.Fragment, null, LikeLimitDisplay(), VM.createElement("div", {
    className: "filter-block"
  }, VM.createElement("div", {
    className: "filter-block_button-wrap",
    style: {
      display: 'flex'
    }
  }, VM.createElement("span", {
    className: "filter-block_title flxgrow"
  }, "Filter Fav likes:"), VM.createElement("input", {
    type: "checkbox",
    id: "filter-fav-likes",
    onChange: FilterFavLikeHandler,
    checked: GM_getValue('favLikeFilter', false)
  }))), VM.createElement("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);

}());