Xhamster Improved

Infinite scroll [optional], Filter by Title and Duration

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Xhamster Improved
// @namespace    pervertmonkey
// @version      5.0.1
// @author       violent-orangutan
// @description  Infinite scroll [optional], Filter by Title and Duration
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=xhamster.com
// @homepage     https://github.com/smartacephale/sleazy-fork
// @homepageURL  https://github.com/smartacephale/sleazy-fork
// @source       github: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
// @require      data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
// @grant        GM_addStyle
// @grant        unsafeWindow
// @run-at       document-idle
// ==/UserScript==

(function (core, utils) {
  'use strict';

  var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : undefined)();

  const IS_VIDEO_PAGE = /^\/videos|moments\//.test(location.pathname);
  const IS_PLAYLIST = /^\/my\/favorites\/videos\/\w+/.test(location.pathname);
  function createThumb(data) {
    const attrsToReplace = {
      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
    };
    const text = {
      ".video-thumb-views": data.views,
      "[title]": data.title,
      '[data-role="video-duration"] div': data.duration
    };
    return utils.instantiateTemplate(".video-thumb", attrsToReplace, text);
  }
  const getPaginationData = !IS_PLAYLIST ? void 0 : async (url) => {
    const data = await utils.fetchJson(url);
    const thumbsHtml = data.list.map((e) => createThumb(e)).join("\n");
    return utils.parseHtml(`<div>${thumbsHtml}</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;
    const playlistPaginationStrategy = {
      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}`;
      }
    };
    return playlistPaginationStrategy;
  }
  const paginationStrategyOptionsDefault = {
    paginationSelector: ".prev-next-list, .test-pager"
  };
  const paginationStrategyOptions = IS_PLAYLIST ? createPlaylistPaginationStrategy() : paginationStrategyOptionsDefault;
  const rules = new core.RulesGlobal({
    paginationStrategyOptions,
    getPaginationData,
    containerSelectorLast: ".thumb-list",
    thumbsSelector: ".video-thumb",
    titleSelector: ".video-thumb-info__name,.video-thumb-info>a",
    durationSelector: ".thumb-image-container__duration",
    gropeStrategy: "all-in-all",
    getThumbImgDataStrategy: "auto",
    getThumbImgDataAttrDelete: "[loading]",
    customThumbDataSelectors: {
      watched: {
        type: "boolean",
        selector: '[data-role="video-watched'
      }
    },
    customDataSelectorFns: [
      "filterInclude",
      "filterExclude",
      "filterDuration",
      {
        filterWatched: (el, state) => !!(state.filterWatched && el.watched)
      },
      {
        filterUnwatched: (el, state) => !!(state.filterUnwatched && !el.watched)
      }
    ],
    schemeOptions: [
      "Text Filter",
      "Badge",
      {
        title: "Filter Watched",
        content: [
          { filterWatched: false, label: "watched" },
          { filterUnwatched: false, label: "unwatched" }
        ]
      },
      "Duration Filter",
      "Advanced"
    ],
    animatePreview
  });
  function animatePreview() {
    function createPreviewVideoElement(src, mount) {
      const video = document.createElement("video");
      video.playsInline = true;
      video.autoplay = true;
      video.loop = true;
      video.classList.add("thumb-image-container__video");
      video.src = src;
      video.addEventListener(
        "loadeddata",
        () => {
          mount.before(video);
        },
        false
      );
      return () => utils.exterminateVideo(video);
    }
    utils.OnHover.create(
      document.body,
      (e) => e.classList.contains("thumb-image-container__image"),
      (e) => {
        const videoSrc = e.parentElement?.getAttribute("data-previewvideo");
        const onOverCallback = createPreviewVideoElement(videoSrc, e);
        const leaveTarget = e.parentElement?.parentElement;
        return { leaveTarget, onOverCallback };
      }
    );
  }
  function expandMoreVideoPage() {
    utils.watchElementChildrenCount(rules.container, () => setTimeout(parseThumbs, 1800));
    utils.waitForElementToAppear(document.body, 'button[data-role="show-more-next"]', (el) => {
      const observer = new utils.Observer((target) => {
        target.click();
      });
      observer.observe(el);
    });
  }
  function parseThumbs() {
    const containers = utils.getCommonParents(rules.getThumbs(document.body));
    containers.forEach((c) => {
      rules.dataManager.parseData(c, c);
    });
  }
  if (IS_VIDEO_PAGE) {
    expandMoreVideoPage();
  }

})(core, utils);