// ==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');
})();