您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically sort video results in a page on /videos, /images, /subscriptions, /users, and sidebars using customizable sort function.
当前为
// ==UserScript== // @name Iwara Custom Sort // @version 0.143 // @grant GM.setValue // @grant GM.getValue // @grant GM.deleteValue // @run-at document-start // @noframes // @match https://ecchi.iwara.tv/* // @match https://www.iwara.tv/* // @match http://ecchi.iwara.tv/* // @match http://www.iwara.tv/* // @description Automatically sort video results in a page on /videos, /images, /subscriptions, /users, and sidebars using customizable sort function. // @namespace https://greasyfork.org/users/245195 // ==/UserScript== /* jshint esversion: 6 */ /* global GM */ 'use strict'; const additionalPageCount = 0; const logDebug = (...args) => { const debugging = true; if (debugging) { console.log(...args); } }; const timeout = delay => new Promise(resolve => setTimeout(resolve, delay)); const parsePrefixed = str => Number.parseFloat(str) * (str.includes('k') ? 1000 : 1); const getNearbyNumber = element => (element ? parsePrefixed(element.parentElement.textContent) : 0); const evalSortValue = (item, valueExpression) => // eslint-disable-next-line no-new-func new Function('views', 'likes', 'ratio', 'image', 'private', `return (${valueExpression})`)( item.viewCount, item.likeCount, Math.min(item.likeCount / Math.max(1, item.viewCount), 1), item.imageFactor, item.privateFactor, ); const sortVideos = (container, valueExpression) => { const videoDivs = Array.from(container.querySelectorAll('.clearfix')); const videoItems = videoDivs .map(div => ({ div, viewCount: getNearbyNumber(div.querySelector('.glyphicon-eye-open')), likeCount: getNearbyNumber(div.querySelector('.glyphicon-heart')), imageFactor: div.querySelector('.glyphicon-th-large') ? 1 : 0, privateFactor: div.querySelector('.private-video') ? 1 : 0, })) .sort((itemA, itemB) => evalSortValue(itemB, valueExpression) - evalSortValue(itemA, valueExpression)); videoDivs .map((div) => { const anchor = document.createElement('div'); div.before(anchor); return anchor; }) .forEach((div, index) => div.replaceWith(videoItems[index].div)); }; const sortAllVideos = (valueExpression) => { const containers = Array.from(document.querySelectorAll('.views-responsive-grid')); GM.setValue('sortValue', valueExpression); let sortedCount = 0; try { containers.forEach((container) => { sortVideos(container, valueExpression); sortedCount += 1; }); } catch (message) { alert(message); } logDebug(`${sortedCount} containers sorted at ${window.location}`); }; const addPageEmbeds = (URL, pageCount) => { logDebug('page'); const params = URL.searchParams; let page = params.has('page') ? Number.parseInt(params.get('page')) : 0; for (let pageLeft = pageCount; pageLeft > 0; pageLeft -= 1) { page += 1; params.set('page', page); const nextPage = document.createElement('embed'); nextPage.src = URL; nextPage.style.display = 'none'; logDebug('page', nextPage.src, pageLeft); document.documentElement.append(nextPage); } }; const createUI = async () => { const sortValueInput = document.createElement('input'); sortValueInput.maxLength = 120; sortValueInput.size = 60; const defaultValue = '(ratio / (private * 2.5 + 1) + Math.sqrt(likes) / 3000) / (image + 3)'; sortValueInput.value = await GM.getValue('sortValue', defaultValue); const sortButton = document.createElement('button'); sortButton.innerHTML = 'Sort'; sortValueInput.addEventListener('keyup', (event) => { if (event.key !== 'Enter') { return; } sortButton.click(); event.preventDefault(); }); sortButton.addEventListener('click', () => sortAllVideos(sortValueInput.value)); const resetDefaultButton = document.createElement('button'); resetDefaultButton.innerHTML = 'Default'; resetDefaultButton.addEventListener('click', () => { sortValueInput.value = defaultValue; }); return { sortValueInput, sortButton, resetDefaultButton, }; }; const addUI = (UI) => { const UIDiv = document.createElement('div'); UIDiv.style.display = 'inline'; UIDiv.style.margin = '5px'; UIDiv.append(UI.resetDefaultButton, UI.sortValueInput, UI.sortButton); document.querySelector('#user-links') .prepend(UIDiv); }; const addVideosToParent = (videoContainers) => { const parentContainers = window.parent.document.querySelectorAll('.views-responsive-grid'); videoContainers.forEach((container, index) => { // eslint-disable-next-line no-param-reassign container.className = ''; if (parentContainers.length > index) { parentContainers[index].prepend(container); } }); window.parent.postMessage({ sender: 'iwara custom sort', message: 'videosAdded', }, window.location.origin); }; const init = async () => { const UI = await createUI(); const onMessageParent = (event) => { const originURL = new URL(event.origin); if ( originURL.hostname === window.location.hostname && event.data.sender === 'iwara custom sort' && event.data.message === 'videosAdded' ) { sortAllVideos(UI.sortValueInput.value); } }; const initParent = () => { addUI(UI); window.addEventListener('message', onMessageParent); sortAllVideos(UI.sortValueInput.value); if (/\/(videos|images|subscriptions)$/.test(window.location.pathname)) { addPageEmbeds(new URL(window.location), additionalPageCount); } }; const onDOMContentLoaded = async () => { const videoContainers = Array.from(document.querySelectorAll('.views-responsive-grid')); if (window === window.parent) { initParent(); } else if (videoContainers.length > 0) { await timeout(500); addVideosToParent(videoContainers); } }; document.addEventListener('DOMContentLoaded', onDOMContentLoaded); }; (() => { logDebug(`Parsed:${window.location}, ${document.readyState} Parent:`, window.parent); if (window !== window.parent) { logDebug('I am a child.'); } init(); })(); /* parsePrefixed = str => Number.parseFloat(str) * (str.includes('k') ? 1000 : 1); getNearbyNumber = element => (element ? parsePrefixed(element.parentElement.textContent) : 0); videoDivs = Array.from(document.querySelector('.views-responsive-grid').querySelectorAll('.clearfix')); accFunc = (items) => { console.log(items.reduce((acc, value) => acc + value)); const sums = []; for (let i = 0; i < items.length / 16; i += 1) { let sum = 0; for (let j = 0; j < 16; j += 1) { sum += items[i * 16 + j]; } sums.push(sum); } return sums; } videoItems = videoDivs .map(div => getNearbyNumber(div.querySelector('.glyphicon-eye-open'))); console.log(accFunc(videoItems)); videoItems = videoDivs .map(div => div.querySelector('.glyphicon-th-large') ? 1 : 0); console.log(accFunc(videoItems)); videoItems = videoDivs .map(div => div.querySelector('.private-video') ? 1 : 0); console.log(accFunc(videoItems)); videoItems = videoDivs .map(div => getNearbyNumber(div.querySelector('.glyphicon-heart')) / getNearbyNumber(div.querySelector('.glyphicon-eye-open'))); console.log(accFunc(videoItems)); */