您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically sort teaser images on /videos, /images, /subscriptions, /users, and sidebars using customizable sort function. Can load and sort multiple pages at once.
当前为
- // ==UserScript==
- // @name Iwara Custom Sort
- // @version 0.193
- // @grant GM.setValue
- // @grant GM.getValue
- // @grant GM.deleteValue
- // @run-at document-start
- // @match https://ecchi.iwara.tv/*
- // @match https://www.iwara.tv/*
- // @match http://ecchi.iwara.tv/*
- // @match http://www.iwara.tv/*
- // @description Automatically sort teaser images on /videos, /images, /subscriptions, /users, and sidebars using customizable sort function. Can load and sort multiple pages at once.
- // @license AGPL-3.0-or-later
- // @namespace https://gf.qytechs.cn/users/245195
- // ==/UserScript==
- /* jshint esversion: 6 */
- /* global GM */
- 'use strict';
- const logDebug = (...args) => {
- const debugging = true;
- if (debugging) {
- console.log(...args);
- }
- };
- const teaserDivSelector = '.node-teaser, .node-sidebar_teaser';
- const getTeaserGrids = (node) => {
- const teaserGridSelector = '.views-responsive-grid';
- return Array.from(node.querySelectorAll(teaserGridSelector))
- .filter(grid => grid.querySelector(teaserDivSelector));
- };
- const timeout = delay => new Promise(resolve => setTimeout(resolve, delay));
- const sortTeasers = (grid, valueExpression) => {
- const viewsIconSelector = '.glyphicon-eye-open';
- const likesIconSelector = '.glyphicon-heart';
- const imageFieldSelector = '.field-type-image';
- const galleryIconSelector = '.glyphicon-th-large';
- const privateDivSelector = '.private-video';
- const teaserDivs = Array.from(grid.querySelectorAll(teaserDivSelector));
- const getNearbyNumber = (element) => {
- const parsePrefixed = str => Number.parseFloat(str) * (str.includes('k') ? 1000 : 1);
- return element ? parsePrefixed(element.parentElement.textContent) : 0;
- };
- const teaserItems = teaserDivs.map(div => ({
- div,
- viewCount: getNearbyNumber(div.querySelector(viewsIconSelector)),
- likeCount: getNearbyNumber(div.querySelector(likesIconSelector)),
- imageFactor: div.querySelector(imageFieldSelector) ? 1 : 0,
- galleryFactor: div.querySelector(galleryIconSelector) ? 1 : 0,
- privateFactor: div.querySelector(privateDivSelector) ? 1 : 0,
- }));
- const evalSortValue = (item, expression) =>
- // eslint-disable-next-line no-new-func
- new Function(
- 'views',
- 'likes',
- 'ratio',
- 'image',
- 'gallery',
- 'private',
- `return (${expression})`,
- )(
- item.viewCount,
- item.likeCount,
- Math.min(item.likeCount / Math.max(1, item.viewCount), 1),
- item.imageFactor,
- item.galleryFactor,
- item.privateFactor,
- );
- teaserItems.forEach((item) => {
- // eslint-disable-next-line no-param-reassign
- item.sortValue = evalSortValue(item, valueExpression);
- });
- teaserItems.sort((itemA, itemB) => itemB.sortValue - itemA.sortValue);
- teaserDivs.map((div) => {
- const anchor = document.createElement('div');
- div.before(anchor);
- return anchor;
- }).forEach((div, index) => div.replaceWith(teaserItems[index].div));
- };
- const sortAllTeasers = (valueExpression) => {
- GM.setValue('sortValue', valueExpression);
- let sortedCount = 0;
- try {
- getTeaserGrids(document).forEach((grid) => {
- sortTeasers(grid, valueExpression);
- sortedCount += 1;
- });
- } catch (message) {
- alert(message);
- }
- logDebug(`${sortedCount} grids sorted`);
- };
- const getNumberParam = (URL, name) => {
- const params = URL.searchParams;
- return params.has(name) ? Number.parseInt(params.get(name)) : 0;
- };
- const getPageParam = URL => getNumberParam(URL, 'page');
- const currentPage = getPageParam(new URL(window.location));
- const createAdditionalPages = (URL, additionalPageCount) => {
- const params = URL.searchParams;
- let page = getPageParam(URL);
- const pages = [];
- for (let pageLeft = additionalPageCount; pageLeft > 0; pageLeft -= 1) {
- page += 1;
- params.set('page', page);
- const nextPage = (() =>
- (navigator.userAgent.indexOf('Firefox') > -1
- ? document.createElement('embed')
- : document.createElement('iframe'))
- )();
- nextPage.src = URL;
- nextPage.style.display = 'none';
- logDebug('Add page:', nextPage.src);
- pages.push(nextPage);
- }
- return pages;
- };
- const createTextInput = (text, maxLength, size) => {
- const input = document.createElement('input');
- input.value = text;
- input.maxLength = maxLength;
- input.size = size;
- return input;
- };
- const createButton = (text, clickHandler) => {
- const button = document.createElement('button');
- button.innerHTML = text;
- button.addEventListener('click', clickHandler);
- return button;
- };
- const createNumberInput = (value, min, max, step, width) => {
- const input = document.createElement('input');
- Object.assign(input, {
- type: 'number', value, min, max, step,
- });
- input.setAttribute('required', '');
- input.style.width = width;
- return input;
- };
- const createSpan = (text, color) => {
- const span = document.createElement('span');
- span.innerHTML = text;
- span.style.color = color;
- return span;
- };
- const createUI = async (pageCount) => {
- const lable1 = createSpan('1 of', 'white');
- const pageCountInput = createNumberInput(pageCount, 1, 15, 1, '3em');
- const lable2 = createSpan('pages loaded.', 'white');
- pageCountInput.addEventListener('change', (event) => {
- GM.setValue('pageCount', Number.parseInt(event.target.value));
- lable2.innerHTML = 'pages loaded. Refresh to apply the change';
- });
- const defaultValue = '(ratio / (private * 2.0 + 1) + Math.log(likes) / 250) / (image + 8.0)';
- const sortValueInput = createTextInput(await GM.getValue('sortValue', defaultValue), 120, 60);
- sortValueInput.classList.add('form-text');
- const sortButton = createButton('Sort', () => sortAllTeasers(sortValueInput.value));
- sortButton.classList.add('btn', 'btn-sm', 'btn-primary');
- sortValueInput.addEventListener('keyup', (event) => {
- if (event.key === 'Enter') {
- sortButton.click();
- }
- });
- const resetDefaultButton = createButton('Default', () => {
- sortValueInput.value = defaultValue;
- });
- resetDefaultButton.classList.add('btn', 'btn-sm', 'btn-info');
- return {
- lable1,
- pageCountInput,
- lable2,
- sortValueInput,
- sortButton,
- resetDefaultButton,
- };
- };
- const addUI = (UI) => {
- const UIDiv = document.createElement('div');
- UIDiv.style.display = 'inline-block';
- UIDiv.append(
- UI.sortValueInput,
- UI.resetDefaultButton,
- UI.sortButton,
- UI.lable1,
- UI.pageCountInput,
- UI.lable2,
- );
- UIDiv.childNodes.forEach((node) => {
- // eslint-disable-next-line no-param-reassign
- node.style.margin = '5px 2px';
- });
- document.querySelector('#user-links').after(UIDiv);
- };
- const addTeasersToParent = (teaserGrids) => {
- const parentGrids = getTeaserGrids(window.parent.document);
- for (let i = 0, j = 0; i < parentGrids.length; i += 1) {
- if (teaserGrids[j].className === parentGrids[i].className) {
- // eslint-disable-next-line no-param-reassign
- teaserGrids[j].className = '';
- teaserGrids[j].setAttribute('originPage', currentPage);
- parentGrids[i].prepend(teaserGrids[j]);
- j += 1;
- }
- }
- };
- const adjustPageAnchors = (container, pageCount) => {
- const changePageParam = (anchor, value) => {
- const anchorURL = new URL(anchor.href, window.location);
- anchorURL.searchParams.set('page', value);
- // eslint-disable-next-line no-param-reassign
- anchor.href = anchorURL.pathname + anchorURL.search;
- };
- if (currentPage > 0) {
- const previousPageAnchor = container.querySelector('.pager-previous a');
- changePageParam(previousPageAnchor, Math.max(0, currentPage - pageCount));
- }
- const nextPage = currentPage + pageCount;
- {
- const lastPageAnchor = container.querySelector('.pager-last a');
- const nextPageAnchor = container.querySelector('.pager-next a');
- if (nextPageAnchor) {
- changePageParam(nextPageAnchor, nextPage);
- }
- if (lastPageAnchor) {
- if (getPageParam(new URL(lastPageAnchor.href, window.location)) < nextPage) {
- nextPageAnchor.remove();
- lastPageAnchor.remove();
- }
- }
- }
- const loadedPageAnchors = Array.from(container.querySelectorAll('.pager-item a'))
- .filter((anchor) => {
- const page = getPageParam(new URL(anchor.href, window.location));
- return page >= currentPage && page < nextPage;
- });
- if (loadedPageAnchors.length > 0) {
- const parentItem = document.createElement('li');
- const groupList = document.createElement('ul');
- groupList.style.display = 'inline';
- groupList.style.backgroundColor = 'hsla(0, 0%, 75%, 50%)';
- loadedPageAnchors[0].parentElement.before(parentItem);
- const currentPageItem = container.querySelector('.pager-current');
- currentPageItem.style.marginLeft = '0';
- groupList.append(currentPageItem);
- loadedPageAnchors.forEach((anchor) => {
- anchor.parentNode.classList.remove('pager-item');
- anchor.parentNode.classList.add('pager-current');
- groupList.append(anchor.parentElement);
- });
- parentItem.append(groupList);
- }
- };
- const adjustAnchors = (pageCount) => {
- const pageAnchorList = document.querySelectorAll('.pager');
- pageAnchorList.forEach((list) => {
- adjustPageAnchors(list, pageCount);
- });
- };
- const initParent = async (teasersAddedMeesage) => {
- const pageCount = await GM.getValue('pageCount', 1);
- const UI = await createUI(pageCount);
- addUI(UI);
- const extraPageRegEx = /\/(videos|images|subscriptions)$/;
- let pages = [];
- if (extraPageRegEx.test(window.location.pathname)) {
- pages = createAdditionalPages(new URL(window.location), pageCount - 1);
- document.body.append(...pages);
- logDebug(pages);
- adjustAnchors(pageCount);
- }
- let loadedPageCount = 1;
- window.addEventListener('message', (event) => {
- if (
- new URL(event.origin).hostname === window.location.hostname
- && event.data === teasersAddedMeesage
- ) {
- sortAllTeasers(UI.sortValueInput.value);
- const loadedPage = pages[
- getPageParam(new URL(event.source.location)) - currentPage - 1
- ];
- loadedPage.src = '';
- loadedPage.remove();
- loadedPageCount += 1;
- UI.lable1.innerHTML = `${loadedPageCount} of `;
- }
- });
- UI.sortButton.click();
- };
- const init = async () => {
- try {
- const teaserGrids = getTeaserGrids(document);
- if (teaserGrids.length === 0) {
- return;
- }
- const teasersAddedMeesage = 'iwara custom sort: teasersAdded';
- if (window === window.parent) {
- logDebug('I am a Parent.');
- initParent(teasersAddedMeesage);
- } else {
- logDebug('I am a child.', window.location, window.parent.location);
- await timeout(500);
- addTeasersToParent(teaserGrids);
- window.parent.postMessage(teasersAddedMeesage, window.location.origin);
- }
- } catch (error) {
- logDebug(error);
- }
- };
- logDebug(`Parsed:${window.location}, ${document.readyState} Parent:`, window.parent);
- document.addEventListener('DOMContentLoaded', init);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址