您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sort search so cards with public definition stays on top and marked with a star
当前为
- // ==UserScript==
- // @name c.AI Search Sort
- // @namespace http://tampermonkey.net/
- // @version 1.0.0
- // @description Sort search so cards with public definition stays on top and marked with a star
- // @author EnergoStalin
- // @license GPL-3.0-or-later
- // @match https://character.ai/search*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=character.ai
- // @grant none
- // ==/UserScript==
- (async function() {
- 'use strict';
- async function waitNotNull(func, timeout = 10000, interval = 1000) {
- return new Promise((res, rej) => {
- let time = timeout
- const i = setInterval(async () => {
- const c = await func()
- time -= interval
- if (time <= 0) {
- clearInterval(i)
- rej()
- }
- if (!c) return
- clearInterval(i)
- res(c)
- }, interval)
- })
- }
- const [pageProps, cardsContainer] = await Promise.all([
- waitNotNull(() => document.querySelector('#__NEXT_DATA__')).then(e => JSON.parse(e.textContent).props.pageProps),
- waitNotNull(() => document.evaluate('/html/body/div[1]/div/main/div/div/div/main/div/div[2]', document).iterateNext())
- ]);
- const token = pageProps.token
- async function isDefinitionPublic(id) {
- const character = await fetch(`https://plus.character.ai/chat/character/info/`, {
- headers: {
- 'Authorization': `Token ${token}`,
- 'Origin': 'https://character.ai/',
- 'Referer': 'https://character.ai/',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'
- },
- method: 'POST',
- body: JSON.stringify({ external_id: id })
- })
- .then(e => e.json())
- .then(e => e.character)
- return !!character.definition
- }
- function clearStatus(card) { card.removeChild(card.querySelector('div[data-status]')) }
- function isStarred(card) { return !!card.querySelector('div[data-status="starred"]') }
- function setStarredStatus(card) {
- card.innerHTML += `
- <div data-status="starred" class="relative" style="min-height: 90px;">
- <svg style="margin-top: 10px; margin-right: 10px;" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#75FB4C"><path d="M371.01-324 480-390.22 589-324l-29-124 97-84-127-11-50-117-50 117-127 11 96.89 83.95L371.01-324ZM480-72 360-192H192v-168L72-480l120-120v-168h168l120-120 120 120h168v168l120 120-120 120v168H600L480-72Zm0-102 90-90h126v-126l90-90-90-90v-126H570l-90-90-90 90H264v126l-90 90 90 90v126h126l90 90Zm0-306Z"/></svg>
- </div>
- `
- }
- function setPendingStatus(card) {
- card.innerHTML += `
- <div data-status="pending" class="relative" style="min-height: 90px;">
- <svg style="margin-top: 10px; margin-right: 10px;" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#5985E1"><path d="M288-420q25 0 42.5-17.5T348-480q0-25-17.5-42.5T288-540q-25 0-42.5 17.5T228-480q0 25 17.5 42.5T288-420Zm192 0q25 0 42.5-17.5T540-480q0-25-17.5-42.5T480-540q-25 0-42.5 17.5T420-480q0 25 17.5 42.5T480-420Zm192 0q25 0 42.5-17.5T732-480q0-25-17.5-42.5T672-540q-25 0-42.5 17.5T612-480q0 25 17.5 42.5T672-420ZM480.28-96Q401-96 331-126t-122.5-82.5Q156-261 126-330.96t-30-149.5Q96-560 126-629.5q30-69.5 82.5-122T330.96-834q69.96-30 149.5-30t149.04 30q69.5 30 122 82.5T834-629.28q30 69.73 30 149Q864-401 834-331t-82.5 122.5Q699-156 629.28-126q-69.73 30-149 30Zm-.28-72q130 0 221-91t91-221q0-130-91-221t-221-91q-130 0-221 91t-91 221q0 130 91 221t221 91Zm0-312Z"/></svg>
- </div>
- `
- }
- const cardsObserver = new MutationObserver(sortSearches)
- function sortSearches() {
- cardsObserver.disconnect()
- const nodes = Array.from(cardsContainer.childNodes)
- Promise.all(nodes.map(async card => {
- if(isStarred(card)) return
- setPendingStatus(card)
- const isPublic = await isDefinitionPublic(card.href.split('/').pop())
- clearStatus(card)
- if(isPublic) {
- setStarredStatus(card)
- } else {
- cardsContainer.appendChild(card)
- }
- })).then(() => cardsObserver.observe(cardsContainer, { attributes: false, childList: true, subtree: false }))
- }
- sortSearches()
- })();