- // ==UserScript==
- // @name LegalPorno Enhancer
- // @namespace https://www.legalporno.com/forum/viewtopic.php?f=96&t=24238
- // @description Adds extra functionality to LegalPorno and Pornbox. Easily filter out unwanted categories. Also adds tags on top of every scene.
- // @match http*://*.legalporno.com/*
- // @match http*://legalporno.com/*
- // @exclude http*://*legalporno.com/forum/*
- // @exclude http*://account.legalporno.com/*
- // @match https://*pornbox.com/*
- // @version 1.2.8
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_addStyle
- // @run-at document-start
- // ==/UserScript==
-
- const is_lp = !!window.location.href.match(/legalporno/);
-
- let glo_filters = {
- studios: {
- 'Gonzo.com': true,
- 'Giorgio Grandi': true,
- 'Interracial Vision': true,
- 'American Anal': true,
- "Giorgio's Lab": true,
- Focus: true,
- Assablanca: true,
- 'Mr Anal': true,
- 'Porn World': true,
- 'Girls Gone Wild': true,
- 'Kinky Sex': true,
- Private: true,
- 'Mixed studios': true,
- 'Outside the Studio': true,
- },
- categories: {
- Piss: true,
- 'Piss Drink': true,
- Fisting: true,
- Prolapse: true,
- Shemale: true,
- },
- };
-
- const studio_colors = {
- 'Gonzo.com': { bg: '#cd0000', text: '#fff' },
- 'Giorgio Grandi': { bg: '#693180', text: '#fff' },
- 'Interracial Vision': { bg: '#242424', text: '#e6e6e6' },
- 'American Anal': { bg: '#b45219', text: '#fffa78' },
- "Giorgio's Lab": { bg: '#206d04', text: '#fff' },
- 'Kinky Sex': { bg: '#000', text: '#fff' },
- };
-
- // Uncomment the following line to reset global filters
- // GM_setValue('user_filters', JSON.stringify(glo_filters));
-
- validateUserFilters = (filters) => {
- if (!filters.studios || !filters.categories) return false;
- if (
- Object.keys(filters.studios).length !==
- Object.keys(glo_filters.studios).length
- )
- return false;
- if (
- Object.keys(filters.categories).length !==
- Object.keys(glo_filters.categories).length
- )
- return false;
- if (
- Object.keys(filters.categories)
- .sort()
- .some(
- (val, idx) => val !== Object.keys(glo_filters.categories).sort()[idx]
- )
- )
- return false;
- if (
- Object.keys(filters.studios)
- .sort()
- .some((val, idx) => val !== Object.keys(glo_filters.studios).sort()[idx])
- )
- return false;
- return true;
- };
-
- try {
- const user_config = GM_getValue('user_filters');
- if (!user_config)
- throw new Error('No user filters found. Using default ones.');
- user_filters = JSON.parse(user_config);
- if (!validateUserFilters(user_filters))
- throw new Error('Invalid user settings.');
- glo_filters = user_filters;
- } catch (e) {}
-
- const studios = {
- Interracial: 'Interracial Vision',
- 'Hard Porn World': 'Porn World',
- };
-
- const icon_categories = {
- interracial: 'IR',
- 'double anal (DAP)': 'DAP',
- fisting: 'Fisting',
- prolapse: 'Prolapse',
- transsexual: 'Shemale',
- trans: 'Shemale',
- 'triple anal (TAP)': 'TAP',
- piss: 'Piss',
- squirting: 'Squirt',
- '3+ on 1': '3+on1',
- 'double vaginal (DPP)': 'DPP',
- 'first time': '1st',
- 'triple penetration': 'TP',
- '0% pussy': '0% Pussy',
- 'cum swallowing': 'Cum Swallow',
- 'piss drinking': 'Piss Drink',
- 'anal creampies': 'Anal Creampie',
- '1 on 1': '1on1',
- milf: 'Milf',
- 'facial cumshot': 'Facial',
- };
-
- GM_addStyle(`
- .hiddenScene {
- display: none !important;
- }
-
- .hide_element {
- display: none !important;
- }
-
- .thumbnail-duration {
- top: 0 !important;
- right: 0 !important;
- left: unset !important;
- bottom: unset !important;
- margin: 5px !important;
- }
-
- .enhanced_categories_container {
- width: 100%;
- display: flex;
- flex-wrap: wrap-reverse;
- position: absolute;
- bottom:0; left: 0;
- z-index: 3;
- padding: 3px 5px;
- }
-
- .enchanced_icon {
- border-radius: 3px;
- background-color: #616161;
- color: #eee;
- opacity: 0.9;
- padding: 2px 7px;
- margin-right: 2px;
- margin-top: 2px;
- font-size: 13px;
- }
-
- .enhanced--studio {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 3;
- display: flex;
- margin: 4px 6px;
- }
-
- .enhanced--studio {
- background-color: #a76523c9;
- border-radius: 3px;
- padding: 2px 7px;
- color: white;
- text-shadow: 1px 1px #00000080;
- font-size: 12px;
- margin-right: 4px;
- }
-
- .enhanced_views_label {
- position: absolute;
- top: 28px;
- right: 5px;
- font-size: 11px;
- display: flex;
- }
-
- .enhanced--views {
- background-color: rgba(102,102,102,0.6);
- padding: 2px 6px;
- border-radius: 3px;
- color: #fff;
- display: flex;
- height: 100%;
- align-items: center;
- justify-content: center;
- }
-
- .enhanced--views > i {
- margin-right: 5px;
- }
-
- .item__img:hover > div {
- display: none;
- }
-
- .item__img-labels-bottom {
- top: 3px;
- right: 3px;
- left: unset;
- bottom: unset;
- display: flex
- }
-
- .img-label {
- margin-top: unset;
- margin-left: 2px;
- }
-
- .item__img-labels {
- display: flex;
- flex-direction: row-reverse;
- left: unset;
- right: 3px;
- top: 23px;
- }
-
- /* Filter Css Begin */
- .filters_container_lp {
- margin-left: -15px;
- margin-right: -15px;
- }
-
- .filters_container--main {
- width: 100%;
- display: flex;
- justify-content: center;
- background: linear-gradient(
- 0deg,
- #babcbc 0%,
- #dfe1e1 2%,
- #dfe1e1 98%,
- #babcbc 100%
- );
- }
-
- .filters_card {
- margin: 0 25px;
- padding-bottom: 15px;
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- }
-
- .filters_selections {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- }
-
- .filters--divider {
- width: 1px;
- background-color: rgb(0, 0, 0, 0.25);
- height: 50px;
- margin-top: 15px;
- align-self: center;
- }
-
- .filters--selection {
- padding: 1px 10px 0 0;
- min-width: 140px;
- display: flex;
- align-items: center;
- }
-
- .filters--selection > label,
- .filters--selection > input[type="checkbox"] {
- margin: 0 2px 0 0;
- font-weight: bold;
- }
-
- .fitlers--header {
- padding: 5px 0 5px 0;
- align-self: center;
- font-weight: bold;
- }
-
- .enhanced_toggle {
- background: -webkit-linear-gradient(
- top,
- #a9a9a9 0%,
- #d97575 5%,
- #563434 100%
- ) !important;
- // height: 100%;
- border: 1px solid #722424 !important;
- color: white;
- padding: 7px 11px;
- font-weight: 700;
- border: none !important;
- }
-
- .enhanced_toggle_pb {
- height: 100%;
- padding: 7px 11px;
- border-radius: 300px;
- position: absolute;
- margin-left: 4px;
- }
-
- .enhanced_toggle_lp {
- border-radius: 200px;
- margin-left: 4px;
- }
-
- .enhanced_toggle:hover {
- cursor: pointer;
- }
-
- .enhanced_toggle > i {
- font-size: 12px;
- }
- /* Filter Css End */
-
- .enhanced--sort {
- display: grid;
- grid-template-columns: 1fr 1fr;
- justify-items: center;
- grid-gap: 2px;
- position: absolute;
-
- top: -4px;
- right: 210px;
- }
-
- .enhanced--sort--navbar {
- right: 25px;
- top: 6px;
- }
-
- .enhanced--sort > span {
- grid-column-end: span 2;
- color: #fff;
-
- }
-
- .enhanced--sort > button {
- width: 70px;
- height: 23px;
- justify-content: center;
- align-items: center;
- text-align: center;
- padding: 0;
- margin: 0;
- }
-
- .page-section {
- position: relative !important;
- }
- `);
-
- const getSceneInfo = (scene) => {
- const info = {
- studio: null,
- categories: null,
- date: null,
- views: null,
- };
-
- info.studio = scene.querySelector('.rating-studio-name, a[href^="#studio/"]');
- info.studio = info.studio ? info.studio.innerText : null;
- if (studios[info.studio]) {
- info.studio = studios[info.studio];
- }
- info.categories = [...scene.querySelectorAll('a[href*="niche/"]')]
- .filter((cat) => cat.innerText && icon_categories[cat.innerText])
- .map((cat) => icon_categories[cat.innerText])
- .sort();
- // info.categories = info.categories.filter(
- // cat => !(cat === 'Piss' && info.categories.includes('Piss Drink'))
- // );
- info.categories = Array.from(new Set(info.categories));
-
- const views = scene.querySelector('.rating-views');
- const date = scene.querySelector('.glyphicon-calendar');
-
- if (views) {
- info.views = parseInt(views.innerText.replace('VIEWS:', '').trim(), 10);
- }
- if (date) {
- try {
- info.date = new Date(
- date.parentElement.innerText.replace('RELEASE:', '').trim()
- );
- } catch (e) {}
- }
-
- return info;
- };
-
- const formatViews = (n) => {
- if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(0) + 'k';
- if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(0) + 'm';
- if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(0) + 'b';
- // if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T";
- return n;
- };
-
- const enhanceScene = (scene) => {
- // Remove icons from thumnail. ("4k" and "new")
- const icons = scene.querySelectorAll('.icon, .thumbnail-price');
- for (const icon of icons) {
- icon.classList.add('hide_element');
- }
-
- const { studio, categories, views, date } = getSceneInfo(scene);
-
- if (studio) {
- const studioLabel = document.createElement('div');
- studioLabel.classList.add('enhanced--studio');
- studioLabel.innerHTML = studio;
-
- if (studio_colors[studio]) {
- studioLabel.style = `
- background-color: ${studio_colors[studio]['bg']}; color: ${studio_colors[studio]['text']};
- `;
- }
-
- if (views) {
- const viewsLabel = document.createElement('div');
- viewsLabel.innerHTML = `
- <div class='enhanced--views'><i class='fa fa-eye'></i>${formatViews(
- views
- )}</div>`;
- viewsLabel.classList.add('enhanced_views_label');
- if (scene.querySelector('.thumbnail-image')) {
- scene.querySelector('.thumbnail-image').appendChild(viewsLabel);
- }
- }
-
- // studioLabel.classList.add('enhanced_title_tags');
- scene
- .querySelector('.thumbnail-image, .item__img')
- .appendChild(studioLabel);
- }
- if (categories.length) {
- const cat_div = document.createElement('div');
- cat_div.classList.add('enhanced_categories_container');
- for (const cat of categories) {
- const icon = document.createElement('div');
- icon.classList.add('enchanced_icon');
- icon.innerHTML = cat;
- cat_div.appendChild(icon);
- }
-
- if (scene.querySelector('.thumbnail-image, .item__img')) {
- scene.querySelector('.thumbnail-image, .item__img').appendChild(cat_div);
- }
- }
- };
-
- const isSceneFiltered = (scene) => {
- const { studio, categories, views, date } = getSceneInfo(scene);
-
- for (const key of Object.keys(glo_filters.studios)) {
- if (studio && studio.includes(key) && !glo_filters.studios[key])
- return true;
- }
-
- for (const key of Object.keys(glo_filters.categories)) {
- if (categories && categories.includes(key) && !glo_filters.categories[key])
- return true;
- }
-
- return false;
- };
-
- const filterScene = (scene) => {
- if (isSceneFiltered(scene)) {
- scene.classList.add('hiddenScene');
- }
- };
-
- const updateFilters = () => {
- GM_setValue('user_filters', JSON.stringify(glo_filters));
- const scenes = document.querySelectorAll('.thumbnail, .block-item');
- for (const scene of scenes) {
- if (scene.classList.contains('hiddenScene'))
- scene.classList.remove('hiddenScene');
- filterScene(scene);
- }
- };
-
- const createFilterElement = () => {
- const { studios, categories } = glo_filters;
-
- const studioHtml = Object.keys(studios).reduce(
- (acc, studio) =>
- (acc += `<div class="filters--selection">
- <input type="checkbox" name="studios" id="${studio}"
- ${studios[studio] ? 'checked="checked"' : ''}
- />
- <label for="${studio}">${studio}</label>
- </div>`),
- ''
- );
-
- const categoriesHtml = Object.keys(categories).reduce(
- (acc, cat) =>
- (acc += `<div class="filters--selection">
- <input type="checkbox" name="categories" id="${cat}"
- ${categories[cat] ? 'checked="checked"' : ''}
- />
- <label for="${cat}">${cat}</label>
- </div>`),
- ''
- );
-
- const form = document.createElement('form');
- form.classList.add('filters_container', 'hide_element');
- if (is_lp) form.classList.add('filters_container_lp');
- form.innerHTML = `<div class="filters_container--main">
- <div class="filters_card">
- <div class="fitlers--header">Studios:</div>
- <div class="filters_selections">
- ${studioHtml}
- </div>
- </div>
- <!-- -->
- <div class="filters--divider"></div>
- <!-- -->
- <div class="filters_card">
- <div class="fitlers--header">Categories:</div>
- <div class="filters_selections">
- ${categoriesHtml}
- </div>
- </div>
- </div>`;
-
- form.addEventListener('change', (e) => {
- glo_filters[e.target.name][e.target.id] = e.target.checked;
- updateFilters();
- });
-
- const lp_header = document.querySelector('.header');
- const pb_header = document.querySelector('#wrap-container');
-
- if (lp_header) lp_header.insertBefore(form, lp_header.childNodes[2]);
- if (pb_header) pb_header.insertBefore(form, pb_header.childNodes[0]);
- createFilterToggle();
- };
-
- const createFilterToggle = () => {
- const toggleFilterBtn = document.createElement('button');
- toggleFilterBtn.classList.add('enhanced_toggle');
- toggleFilterBtn.classList.add(`enhanced_toggle_${is_lp ? 'lp' : 'pb'}`);
-
- toggleFilterBtn.innerHTML = `<i class="fa fa-filter"></i>`;
-
- toggleFilterBtn.addEventListener('click', () => {
- const filters_container = document.querySelector('.filters_container');
- if (filters_container) {
- filters_container.classList.toggle('hide_element');
- }
- });
-
- const search_container = document.querySelector(
- '.nav-search-container, .header-block:nth-of-type(3)'
- );
- is_lp ? (search_container.style = 'display: flex;') : null;
- search_container.appendChild(toggleFilterBtn);
- };
-
- const callback = (mutationsList) => {
- for (let mutation of mutationsList) {
- for (const node of mutation.addedNodes) {
- if (node.nodeType === 1) {
- if (node.nodeName === 'DIV') {
- if (
- node.classList.contains('block-item') ||
- node.classList.contains('thumbnail')
- ) {
- enhanceScene(node);
- filterScene(node);
- }
- }
- }
- }
- }
- };
-
- const config = { childList: true, subtree: true, attributes: true };
- const observer = new MutationObserver(callback);
- observer.observe(window.document, config);
-
- const sortScenes = ({ date = false, views = false, asc = true } = {}) => {
- const node = document.querySelector('.thumbnails');
- [...node.children]
- .sort((a, b) => {
- const infoA = getSceneInfo(a);
- const infoB = getSceneInfo(b);
-
- let order = -1;
-
- if (date) {
- order = infoA.date > infoB.date ? -1 : 1;
- } else if (views) {
- order = infoA.views > infoB.views ? -1 : 1;
- } else {
- order = 0;
- }
-
- if (a.classList.contains('button--load-more')) return 0;
- if (b.classList.contains('button--load-more')) return 0;
-
- return !asc ? order : order * -1;
- })
- .map((scene) => {
- node.appendChild(scene);
- node.appendChild(document.createTextNode(' '));
- });
- };
-
- const sortBtns = () => {
- const sortDiv = document.createElement('div');
- sortDiv.classList.add('enhanced--sort');
- sortDiv.innerHTML = `
- <span>Sort By:</span>
- <button asc="false">Date</button>
- <button asc="false">Views</button>
- `;
-
- sortDiv.addEventListener('click', (e) => {
- if (e.target.tagName === 'BUTTON') {
- const asc = e.target.getAttribute('asc') === 'true';
- e.target.setAttribute('asc', !asc);
- const sortObj = { asc };
- sortObj[e.target.innerText.toLowerCase()] = true;
- sortScenes(sortObj);
- }
- });
-
- const navbar = document.querySelectorAll('.navbar > .container-fluid');
- if (navbar.length) {
- navbar[navbar.length - 1].appendChild(sortDiv);
- sortDiv.classList.add('enhanced--sort--navbar');
- return;
- }
-
- const cont = document.querySelector('.page-section');
- if (cont) {
- sortDiv.children[0].style = 'color: #000;';
- cont.appendChild(sortDiv);
- }
- };
-
- document.addEventListener('DOMContentLoaded', () => {
- if (!is_lp && !document.querySelector('.nav-search-container')) return;
- createFilterElement();
- sortBtns();
-
- const nodes = document.querySelectorAll('.block-item, .thumbnail');
- [...nodes].map((node) => {
- enhanceScene(node);
- filterScene(node);
- });
- });