Xhamster PervertMonkey

Infinite scroll [optional], Filter by Title, Duration and Watched/Unwatched. Sort by Duration and Views

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Xhamster PervertMonkey
// @namespace    pervertmonkey
// @version      5.0.23
// @author       violent-orangutan
// @description  Infinite scroll [optional], Filter by Title, Duration and Watched/Unwatched. Sort by Duration and Views
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=xhamster.com
// @homepage     https://github.com/smartacephale/sleazy-fork#readme
// @homepageURL  https://sleazyfork.org/en/users/1253342-smartacephale
// @source       https://github.com/smartacephale/sleazy-fork
// @supportURL   https://github.com/smartacephale/sleazy-fork/issues
// @match        https://*.xhamster.com/*
// @match        https://*.xhamster.*/*
// @exclude      https://*.xhamster.com/embed*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/core/pervertmonkey.core.umd.js
// @grant        GM_addElement
// @grant        GM_addStyle
// @grant        unsafeWindow
// @run-at       document-idle
// ==/UserScript==

var ___core = window.pervertmonkey.core || pervertmonkey.core;
var ___utils = ___core;


(function(___core, ___utils) {
	"use strict";
	var _GM_addElement = (() => typeof GM_addElement != "undefined" ? GM_addElement : void 0)();
	var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
	var IS_VIDEO_PAGE = /^\/videos|moments\//.test(location.pathname);
	var IS_PLAYLIST = /^\/my\/favorites\/videos\/\w+/.test(location.pathname);
	function createThumb(data) {
		return (0, ___utils.instantiateTemplate)(".video-thumb", {
			href: data.pageURL,
			"data-previewvideo": data.trailerURL,
			"data-previewvideo-fallback": data.trailerFallbackUrl,
			"data-sprite": data.spriteURL,
			title: data.title,
			"data-video-id": data.id,
			srcset: data.thumbURL,
			src: data.imageURL
		}, {
			".video-thumb-views": data.views,
			"[title]": data.title,
			"[data-role=\"video-duration\"] div": data.duration
		});
	}
	var getPaginationData = !IS_PLAYLIST ? void 0 : async (url) => {
		return (0, ___utils.parseHtml)(`<div>${(await (0, ___utils.fetchJson)(url)).list.map((e) => createThumb(e)).join("\n")}</div>`);
	};
	function createPlaylistPaginationStrategy() {
		const collectionId = location.pathname.split("/my/favorites/videos/")[1].split("-")[0];
		const data = _unsafeWindow.initials;
		const paginationLast = data.favoritesVideoPaging.maxPages;
		const paginationOffset = data.favoritesVideoPaging.active;
		return {
			paginationSelector: "nav[class *= \"pagination\"]",
			getPaginationLast: () => paginationLast,
			getPaginationOffset: () => paginationOffset,
			getPaginationUrlGenerator: () => (offset) => {
				return `https://xhamster.com/api/front/favorite/get-playlist?id=${collectionId}&perPage=60&page=${offset}`;
			}
		};
	}
	var rules = new ___core.Rules({
		paginationStrategyOptions: IS_PLAYLIST ? createPlaylistPaginationStrategy() : { paginationSelector: ".prev-next-list, .test-pager" },
		getPaginationData,
		containerSelectorLast: ".thumb-list",
		thumbs: {
			selector: ".video-thumb",
			transform: (thumb) => {
				if (thumb.querySelector("[class*=placeholder]")) console.log("has placeholder", thumb);
				return thumb;
			}
		},
		thumb: { selectors: {
			title: ".video-thumb-info__name,.video-thumb-info>a",
			duration: ".thumb-image-container__duration",
			watched: {
				selector: "[data-role=\"video-watched",
				type: "boolean"
			},
			views: {
				selector: ".video-thumb-views",
				type: "float"
			}
		} },
		thumbImg: { strategy: "auto" },
		gropeStrategy: "all-in-all",
		customDataFilterFns: [{ filterWatched: (e, state) => !!(state.filterWatched && e.watched) }, { filterUnwatched: (e, state) => !!(state.filterUnwatched && !e.watched) }],
		schemeOptions: [
			"Title Filter",
			{
				title: "Filter Watched",
				content: [{
					filterWatched: false,
					label: "watched"
				}, {
					filterUnwatched: false,
					label: "unwatched"
				}]
			},
			"Sort By",
			"Duration Filter",
			"Badge",
			"Advanced"
		],
		animatePreview
	});
	function animatePreview() {
		function createPreviewVideoElement(src, mount) {
			const video = _GM_addElement("video", {
				playsInline: true,
				autoplay: true,
				loop: true,
				class: "thumb-image-container__video",
				src
			});
			video.addEventListener("loadeddata", () => {
				mount.before(video);
			}, false);
			return () => (0, ___utils.exterminateVideo)(video);
		}
		___utils.OnHover.create(document.body, ".video-thumb", (e) => {
			const container = e.querySelector(".thumb-image-container__image");
			const videoSrc = e.querySelector("[data-previewvideo]")?.getAttribute("data-previewvideo");
			return createPreviewVideoElement(videoSrc, container);
		});
	}
	function expandMoreVideoPage() {
		(0, ___utils.watchElementChildrenCount)(rules.container, () => setTimeout(rules.gropeInit, 1800));
		(0, ___utils.waitForElementToAppear)(document.body, "button[data-role=\"show-more-next\"]", (e) => {
			new ___utils.Observer((target) => {
				target.click();
			}).observe(e);
		});
	}
	if (IS_VIDEO_PAGE) expandMoreVideoPage();
})(___core, ___utils);