PornPics Enhancer

A framework to integrate various porn gallery sites - providing the ultimate porn gallery browsing experience.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         PornPics Enhancer
// @namespace    http://tampermonkey.net/
// @license      MIT
// @version      2.0.1
// @description  A framework to integrate various porn gallery sites - providing the ultimate porn gallery browsing experience.
// @match        https://www.pornpics.com/*
// @match        https://www.pichunter.com/*
// @match        https://yespornpics.com/*
// @match        https://babesource.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ncga.com
// @grant        GM_xmlhttpRequest
// @grant        GM.addStyle
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.3.7/umd/photoswipe.umd.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js
// @connect      pornpics.com
// @connect      pichunter.com
// @connect      yespornpics.com
// @connect      babesource.com
// ==/UserScript==

(function() {
    'use strict';

    const cornpics_url = 'https://www.pornpics.com/cornpics/';
    if (location != cornpics_url) {
        location = cornpics_url;
    }

    GM.addStyle(`
@import url('https://cdnjs.cloudflare.com/ajax/libs/photoswipe/5.3.7/photoswipe.min.css');

html {
  scroll-behavior: smooth;
}

.next-button#fb-button {
  display: block;
}

.pswp img {
  object-fit: contain;
}

.site-select {
  padding: 0 3px;
  text-align: center;
}

.grid {
  margin: 0 auto;
}

.grid-item {
  width: 300px;
  border: 1px solid #ccc;
  border-radius: 5px;
  margin: 3px;
}

.gallery-title {
  color: #5a5a5a;
  flex-grow: 0;
  font-size: 18px;
  font-weight: 700;
  line-height: 28px;
  padding: 0 10px;
}

.dark .gallery-title {
  color: #cfcfcf;
}

.grid-item img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 5px;
  cursor: pointer;
}

.gallery-title-container {
  display: flex;
  justify-content: center;
}

.gallery-title {
  white-space: nowrap;
  overflow-x: auto;
}

.gallery-title::-webkit-scrollbar {
  display: none;
}

.info-row {
  display: flex;
  align-items: center;
  margin: 2px 0;
}

.info-title {
  white-space: nowrap;
  color: #5a5a5a;
  font-size: 20px;
  margin: 0 3px 0 5px;
}

.dark .info-title {
  color: #cfcfcf;
}

.info-button-container {
  display: flex;
  overflow-x: auto;
}

.info-button-container::-webkit-scrollbar {
  display: none;
}

.info-button {
  white-space: nowrap;
  background-color: #676767;
  border-radius: 3px;
  color: #fff;
  margin: 0 1px;
  padding: 3px;
  transition: background-color 0.3s ease;
}

.info-button:hover {
  background-color: #4d4d4d;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
`);

    class BaseSite {
        constructor() {
            $('base').remove();
            $('.site-var-container').remove();
        }
        get_inputs() {}
        get_url() {}
        parse_galleries(data, callback) {}
        get_thumb_info(element) {}
        get_title_str(data) {}
        get_info_dict(data) {}
        get_image_list(data) {}
        set_vars(element) {}
        set_first_page() {}
        set_next_page() {}
    };

    class PornPics extends BaseSite {
        constructor() {
            super();
            this.key = '';
            this.key_elem = $('<input>').addClass('search__text inpt-default');
            this.latest = false;
            this.limit = 20;
            this.offset = 0;
        }
        get_inputs() {
            return $('<div>').addClass('site-var-container').append(this.key_elem);
        }
        get_url() {
            this.key = this.key_elem.val();
            return `https://www.pornpics.com/search/srch.php` +
                `?q=${encodeURIComponent(this.key)}` +
                `${this.latest ? '&date=latest' : ''}` +
                `&limit=${this.limit}` +
                `&offset=${this.offset}`;
        }
        parse_galleries(data, callback) {
            const json_array = $.parseJSON(data);
            json_array.forEach(callback);
        }
        get_thumb_info(element) {
            return [element.g_url, element.t_url_460, element.desc];
        }
        get_title_str(data) {
            return $(data).find('.title-section h1').text();
        }
        get_info_dict(data) {
            return {
                '📺': $(data).find(".gallery-info__item").eq(0).find("a"),
                '👠': $(data).find(".gallery-info__item").eq(1).find("a"),
                '📚': $(data).find(".gallery-info__item.tags").eq(0).find("a"),
                '🏷️': $(data).find(".gallery-info__item.tags").eq(1).find("a")
            };
        }
        get_image_list(data) {
            const image_elements = $(data).find('#main ul li a');
            const image_list = [];
            image_elements.each(function() {
                const src = $(this).attr('href');
                const [width, height] = $(this).attr('data-size').split('x');
                image_list.push({src: src,
                                 width: width,
                                 height: height});
            });
            return image_list;
        }
        set_vars(element) {
            this.key_elem.val($(element).text());
        }
        set_first_page() {
            this.offset = 0;
        }
        set_next_page() {
            this.offset += this.limit;
        }
    };

    class PicHunter extends BaseSite {
        constructor() {
            super();
            this.base_url = 'http://pichunter.com';
            $('head').append($('<base>').attr('href', this.base_url));
            this.type = '';
            this.type_elem = $('<select>').addClass('search__submit btn-light')
                .append($('<option>').text('models'))
                .append($('<option>').text('sites'))
                .append($('<option>').text('tags'))
                .css('border-radius', '3px 0 0 3px')
                .css('text-align', 'center');
            this.key = '';
            this.key_elem = $('<input>').addClass('search__text inpt-default')
                .css('width', 'calc(100% - 140px)')
                .css('border-radius', '0')
                .css('border-left', 'none');
            this.page = 1;
        }
        get_inputs() {
            return $('<div>').addClass('site-var-container').append(this.type_elem).append(this.key_elem);
        }
        get_url() {
            // TODO: add support for 'search' type, add support for sorting
            this.type = this.type_elem.val();
            this.key = this.key_elem.val();
            return `https://www.pichunter.com/` +
                `${this.type}/` +
                `${this.type == 'models' ? '' : 'all/'}` +
                `${encodeURIComponent(this.key)}/` +
                `${this.type == 'models' ? 'photos/' : ''}` +
                `${this.page}/format/json`;
        }
        parse_galleries(data, callback) {
            const json_array = $.parseJSON(data).thumbs;
            json_array.forEach(callback);
        }
        get_thumb_info(element) {
            return [this.base_url + element.galUrl, element.src, element.title2];
        }
        get_title_str(data) {
            return $(data).find('h1').text();
        }
        get_info_dict(data) {
            const tags = $(data).find('.tagCloud');
            return {
                '📺': tags.find('li.g_site a'),
                '👠': tags.find('li.g_star a'),
                '📚': tags.find("li:not([class]) a"),
            };
        }
        get_image_elements(data) {
            return $(data).find('.flex-images figure a');
        }
        get_image_list(data) {
            const image_elements = $(data).find('.flex-images figure a');
            const image_list = [];
            image_elements.each(function() {
                image_list.push({src: $(this).attr('href'),
                                 width: $(this).find('img').attr('xow'),
                                 height: $(this).find('img').attr('xoh')});
            });
            return image_list;
        }
        set_vars(element) {
            const [type, key] = $(element).attr('href').substr(1).split('/');
            this.type_elem.val(type);
            this.key_elem.val(key.replaceAll('_', ' '));
        }
        set_first_page() {
            this.page = 1;
        }
        set_next_page() {
            ++this.page;
        }
    }

    class YesPornPics extends BaseSite {
        constructor() {
            super();
            this.base_url = 'https://yespornpics.com';
            $('head').append($('<base>').attr('href', this.base_url));
            this.key = '';
            this.key_elem = $('<input>').addClass('search__text inpt-default');
            this.page = 1;
        }
        get_inputs() {
            return $('<div>').addClass('site-var-container').append(this.key_elem);
        }
        get_url() {
            this.key = this.key_elem.val();
            return `https://yespornpics.com/sex/` +
                `${encodeURIComponent(this.key)}/` +
                `${this.page}`;
        }
        parse_galleries(data, callback) {
            const galleries = $(data).find('.gallery a');
            galleries.each(function () {
                callback(this);
            });
        }
        get_thumb_info(element) {
            return [this.base_url + $(element).attr('href'), $(element).find('img').attr('src'), $(element).find('img').attr('alt')];
        }
        get_title_str(data) {
            return $(data).find('.jpeg a img').attr('alt').slice(0, -5);
        }
        get_info_dict(data) {
            const tags = $(data).find('.gallerytags');
            return {
                '📺': tags.find('h4 a'),
                '👠': tags.find('h5 a'),
                '📚': tags.find('h6 a'),
            };
        }
        get_image_list(data) {
            const image_elements = $(data).find('.jpeg a');
            const image_list = [];
            image_elements.each(function() {
                image_list.push({src: $(this).attr('href')});
            });
            return image_list;
        }
        set_vars(element) {
            const key = $(element).attr('href').split('/')[2];
            this.key_elem.val(key);
        }
        set_first_page() {
            this.page = 1;
        }
        set_next_page() {
            ++this.page;
        }
    }

    class BabeSource extends BaseSite {
        constructor() {
            super();
            this.key = '';
            this.key_elem = $('<input>').addClass('search__text inpt-default');
            $('.input-container').append(this.key_elem);
            this.page = 1;
            this.search_mode = true;
            this.jump_url = '';
        }
        get_inputs() {
            return $('<div>').addClass('site-var-container').append(this.key_elem);
        }
        get_url() {
            // TODO: sort by views
            var res;
            if (this.search_mode) {
                this.key = this.key_elem.val();
                res = `https://babesource.com/search/photos/` +
                    `${encodeURIComponent(this.key)}/`;
            } else {
                this.search_mode = true;
                res = this.jump_url;
            }
            res += `page${this.page}.html`;
            return res;
        }
        parse_galleries(data, callback) {
            const galleries = $(data).find('.main-content__card-link');
            galleries.each(function () {
                callback(this);
            });
        }
        /*async get_thumb_info(element) {
            const thumbnail_url = $(element).find('picture img').attr('data-src');
            return [$(element).attr('href'),
                    await get_base64_image(thumbnail_url),
                    $(element).find('picture img').attr('alt')];
        }*/
        get_thumb_info(element) {
            return [$(element).attr('href'),
                    $(element).find('picture img').attr('data-src'),
                    $(element).find('picture img').attr('alt')];
        }
        get_title_str(data) {
            return '';
        }
        get_info_dict(data) {
            return {
                '📺': $(data).find('div.aside-setting__chapter:has(h4:contains("Paysite")) a'),
                '👠': $(data).find('div.aside-setting__chapter:has(h4:contains("Models")) a'),
                '📚': $(data).find('div.aside-setting__chapter:has(h4:contains("Categories")) a'),
                '🏷️': $(data).find('.aside-setting__category-link'),
            };
        }
        get_image_elements(data) {
            return $(data).find('.slideshowGalleryImage');
        }
        /*async get_image_list(data) {
            const image_elements = $(data).find('.slideshowGalleryImage');
            const image_list = [];
            const promises = [];
            image_elements.each(async function() {
                promises.push(get_base64_image($(this).attr('href')).then((encoded_src) => {
                    image_list.push({src: encoded_src});
                }));
            });
            await Promise.all(promises);
            return image_list;
        }*/
        get_image_list(data) {
            const image_elements = $(data).find('.slideshowGalleryImage');
            const image_list = [];
            image_elements.each(function() {
                image_list.push({src: $(this).attr('href')});
            });
            return image_list;
        }
        set_vars(element) {
            this.key_elem.val('');
            this.jump_url = $(element).attr('href');
            this.search_mode = false;
        }
        set_first_page() {
            this.page = 1;
        }
        set_next_page() {
            ++this.page;
        }
    }

    function get_responce(url, type) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url: url,
                responseType: type,
                onload: function(response) {
                    resolve(response.response);
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    /*async function get_base64_image(url) {
        const blob = await get_responce(url, 'blob');
        return new Promise((resolve, _) => {
            const reader = new FileReader();
            reader.onloadend = () => resolve(reader.result);
            reader.readAsDataURL(blob);
        });
    }*/

    async function get_galleries(url) {
        const data = await get_responce(url, 'text');
        site.parse_galleries(data, async (element) => {
            const [gallery_url, thumbnail_src, thumbnail_alt] = site.get_thumb_info(element);
            const gallery_data = await get_responce(gallery_url, 'text');
            const title_str = site.get_title_str(gallery_data);
            const info_dict = site.get_info_dict(gallery_data);
            const title = $('<div>')
            .addClass('gallery-title-container')
            .append(
                $('<div>').addClass('gallery-title')
                .text(title_str)
            );
            const img = $('<img>')
            .attr('src', thumbnail_src)
            .attr('alt', thumbnail_alt)
            .on('click', function() {
                const image_list = site.get_image_list(gallery_data);
                const pswp = new PhotoSwipe({dataSource: image_list});
                pswp.init();
            })
            .on('load', () => {
                grid.masonry('layout');
            });
            const info = get_info(info_dict);
            const grid_item = $('<div>')
            .addClass('grid-item')
            .append(title)
            .append(img)
            .append(info);
            grid.append(grid_item).masonry('appended', grid_item);
        });
    }

    function get_info(info_dict) {
        const info = $('<div>').addClass('info');
        for (const [key, elements] of Object.entries(info_dict)) {
            if (elements.length === 0) {
                continue;
            }
            const info_title = $('<div>').addClass('info-title').text(key);
            const info_buttons = $('<div>').addClass('info-button-container');
            elements.each(function () {
                info_buttons.append(
                    $('<button>').addClass('info-button').text($(this).text().trim()).on('click', () => {
                        site.set_vars(this);
                        update_page();
                    })
                );
            });
            const info_row = $('<div>').addClass('info-row').append(info_title).append(info_buttons);
            info.append(info_row);
        }
        return info;
    }

    // next-button
    $('#fb-button').remove();
    const next_button = $('<span>').addClass('next-button').attr('id', 'fb-button').text('Next Page').on('click', function() {
        site.set_next_page();
        update_page();
    });
    next_button.insertBefore('footer').hide();

    // nav-section
    $('.nav-button-menu').remove();
    $('.left-side').remove();
    const url_display = $('<a>');
    $('.nav-section').prepend($('<div>').addClass('left-nav-menu').append($('<ul>').append($('<li>').append(url_display))));
    $('.right-side .item:not(.site-theme)').remove();

    // head
    $('head title').text('Corn Pics');
    $('head meta[name="referrer"]').attr('content', 'no-referrer');

    // footer
    $('footer').remove();

    function clear_galleries() {
        grid.masonry('remove', grid.find('.grid-item'));
        grid.empty();
        next_button.hide();
        url_display.text('');
    }

    function update_url() {
        const url = site.get_url();
        url_display.text(url);
        return url;
    }

    function update_page() {
        clear_galleries();
        get_galleries(update_url());
        window.scrollTo(0, 0);
        next_button.show();
    }

    $(window).on('resize', function() {
        grid.masonry('layout');
    });

    let site = new PornPics();
    const grid = $('<div>').addClass('grid').addClass('clearfix').masonry({
        itemSelector: '.grid-item',
        fitWidth: true
    });

    // header-section
    const go_button = $('<button>').addClass('search__submit btn-light').text('Go').on('click', function() {
        site.set_first_page();
        update_page();
    });
    const control_section = $('<div>').addClass('search-section').append(site.get_inputs()).append(go_button);
    const site_select = $('<select>').addClass('site-select btn-fill')
    .append($('<option>').text('PornPics'))
    .append($('<option>').text('PicHunter'))
    .append($('<option>').text('YesPornPics'))
    .append($('<option>').text('BabeSource'))
    .on('change', function() {
        switch ($(this).val()) {
            default:
            case 'PornPics':
                site = new PornPics();
                break;
            case 'PicHunter':
                site = new PicHunter();
                break;
            case 'YesPornPics':
                site = new YesPornPics();
                break;
            case 'BabeSource':
                site = new BabeSource();
                break;
        }
        clear_galleries();
        control_section.prepend(site.get_inputs());
    });
    $('.nav-button-search').remove();
    $('.search-section').remove();
    $('.user-section').remove();
    $('.login-section').remove();
    $('.header-section').append(control_section).append(
        $('<div>').addClass('login-section active').append(site_select)
    );

    $('#content').remove();
    grid.insertAfter('#wrapper nav');



})();