// ==UserScript==
// @name Stripchat 黑名单
// @namespace https://greasyfork.org/fr/users/1468290-payamarre
// @version 1.1
// @license MIT
// @description 增强Stripchat体验:查找主播信息和隐藏不感兴趣的主播
// @author NoOne
// @match https://stripchat.com/*
// @match https://*.stripchat.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @icon https://stripchat.com/favicon.ico
// @run-at document-end
// ==/UserScript==
(function () {
'use strict';
// ================ 公共功能 ================
const common = {
getModelName() {
const path = window.location.pathname.split('/');
const model = path[1];
if (model && !['female', 'male', 'trans', 'new', 'tags', 'login', 'signup'].includes(model)) {
return model;
}
return null;
},
createButton(id, svg, onClick, className = '') {
const a = document.createElement('a');
a.href = '#';
a.className = className;
a.innerHTML = svg;
a.id = id;
a.addEventListener('click', e => {
e.preventDefault();
onClick();
});
return a;
}
};
// ================ 查找主播信息功能 ================
function initFindMore() {
let buttonsInserted = false;
function insertButtons() {
if (buttonsInserted) return true;
const modelName = common.getModelName();
if (!modelName) return false;
const targetWrapper = document.querySelector('.view-cam-buttons-wrapper');
if (!targetWrapper || !targetWrapper.parentNode) return false;
['scfinder-button', 'recume-button', 'dodao-button', 'search-button'].forEach(id => {
const oldBtn = document.getElementById(id);
if (oldBtn) oldBtn.remove();
});
const scfinderBtn = common.createButton(
'scfinder-button',
`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="24" height="24">
<path stroke-linecap="round" stroke-linejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>`,
() => window.open(`https://camgirlfinder.net/models/sc/${modelName}`, '_blank'),
'enhanced-button'
);
const recumeBtn = common.createButton(
'recume-button',
`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="24" height="24">
<path stroke-linecap="round" stroke-linejoin="round" d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z" />
</svg>`,
() => window.open(`https://recu.me/performer/${modelName}`, '_blank'),
'enhanced-button'
);
const dodaoBtn = common.createButton(
'dodao-button',
`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="24" height="24">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21v-8.25M15.75 21v-8.25M8.25 21v-8.25M3 9l9-6 9 6m-1.5 12V10.332A48.36 48.36 0 0 0 12 9.75c-2.551 0-5.056.2-7.5.582V21M3 21h18M12 6.75h.008v.008H12V6.75Z" />
</svg>`,
() => window.open(`https://dodao.xyz/?cat=&s=${modelName}`, '_blank'),
'enhanced-button'
);
const searchBtn = common.createButton(
'search-button',
`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="24" height="24">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418" />
</svg>`,
() => {
const urls = [
`https://www.google.com/search?q=%22${modelName}%22&num=10&uact=5`,
`https://yandex.com/search/?text=%22${modelName}%22`,
`https://recu.me/performer/${modelName}`,
`https://camgirlfinder.net/models/sc/${modelName}`,
`https://btdig.com/search?order=0&q="${modelName}"`,
`https://dodao.xyz/?cat=&s=${modelName}`
];
urls.forEach((url, index) => {
setTimeout(() => window.open(url, '_blank'), index * 200);
});
},
'enhanced-button'
);
const buttonGroup = document.createElement('div');
buttonGroup.style.display = 'flex';
buttonGroup.style.gap = '18px';
buttonGroup.style.alignItems = 'center';
buttonGroup.appendChild(dodaoBtn);
buttonGroup.appendChild(scfinderBtn);
buttonGroup.appendChild(recumeBtn);
buttonGroup.appendChild(searchBtn);
targetWrapper.parentNode.insertBefore(buttonGroup, targetWrapper);
buttonsInserted = true;
return true;
}
const observer = new MutationObserver(() => insertButtons());
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(insertButtons, 1000);
}
// ================ 隐藏不感兴趣主播功能 ================
function initHideModels() {
// 存储不感兴趣的主播列表
let blockedModels = GM_getValue('blockedModels', {});
// 创建管理面板按钮
function createToggleButton() {
const toggleBtn = document.createElement('button');
toggleBtn.className = 'blocked-models-toggle';
toggleBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="20" height="20">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" />
</svg>`;
toggleBtn.title = '管理已隐藏主播';
toggleBtn.addEventListener('click', toggleBlockedModelsPanel);
document.body.appendChild(toggleBtn);
}
// 创建管理面板
function createBlockedModelsPanel() {
const panel = document.createElement('div');
panel.className = 'blocked-models-panel';
panel.id = 'blocked-models-panel';
const header = document.createElement('div');
header.className = 'blocked-models-header';
const title = document.createElement('h3');
title.textContent = '已隐藏的主播';
const closeBtn = document.createElement('button');
closeBtn.className = 'unblock-btn';
closeBtn.textContent = '关闭';
closeBtn.addEventListener('click', () => {
document.getElementById('blocked-models-panel').style.display = 'none';
});
header.appendChild(title);
header.appendChild(closeBtn);
const content = document.createElement('div');
content.className = 'blocked-models-content';
panel.appendChild(header);
panel.appendChild(content);
document.body.appendChild(panel);
updateBlockedModelsList();
}
// 切换管理面板显示
function toggleBlockedModelsPanel() {
const panel = document.getElementById('blocked-models-panel');
if (panel.style.display === 'block') {
panel.style.display = 'none';
} else {
updateBlockedModelsList();
panel.style.display = 'block';
}
}
// 更新已隐藏主播列表
function updateBlockedModelsList() {
const content = document.querySelector('.blocked-models-content');
content.innerHTML = '';
const modelCount = Object.keys(blockedModels).length;
if (modelCount === 0) {
const emptyMsg = document.createElement('p');
emptyMsg.textContent = '您还没有隐藏任何主播';
emptyMsg.style.color = '#aaa';
emptyMsg.style.textAlign = 'center';
content.appendChild(emptyMsg);
return;
}
for (const modelId in blockedModels) {
const modelItem = document.createElement('div');
modelItem.className = 'blocked-model-item';
const modelName = document.createElement('span');
modelName.className = 'blocked-model-name';
modelName.textContent = blockedModels[modelId].name;
const unblockBtn = document.createElement('button');
unblockBtn.className = 'unblock-btn';
unblockBtn.textContent = '取消隐藏';
unblockBtn.dataset.modelId = modelId;
unblockBtn.addEventListener('click', function() {
unblockModel(this.dataset.modelId);
});
modelItem.appendChild(modelName);
modelItem.appendChild(unblockBtn);
content.appendChild(modelItem);
}
}
// 添加隐藏按钮到主播缩略图
function addHideButtons() {
const modelItems = document.querySelectorAll('.model-list-item:not(.processed-for-hiding)');
modelItems.forEach(item => {
// 标记为已处理
item.classList.add('processed-for-hiding');
// 获取主播ID和名称
const linkEl = item.querySelector('a[href*="/"]');
if (!linkEl) return;
const href = linkEl.getAttribute('href');
const modelId = href.split('/').pop();
// 如果已经在屏蔽列表中,隐藏
if (blockedModels[modelId]) {
item.style.display = 'none';
return;
}
// 创建隐藏按钮
const hideBtn = document.createElement('button');
hideBtn.className = 'hide-model-btn';
hideBtn.innerHTML = '×';
hideBtn.title = '隐藏此主播';
hideBtn.dataset.modelId = modelId;
// 获取主播名称
const nameEl = item.querySelector('.model-name') || item.querySelector('a[href*="/"]');
const modelName = nameEl ? nameEl.textContent.trim() : modelId;
hideBtn.dataset.modelName = modelName;
hideBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
blockModel(this.dataset.modelId, this.dataset.modelName);
});
item.style.position = 'relative';
item.appendChild(hideBtn);
});
}
// 隐藏主播
function blockModel(modelId, modelName) {
blockedModels[modelId] = {
name: modelName,
blockedAt: new Date().toISOString()
};
GM_setValue('blockedModels', blockedModels);
// 隐藏所有匹配的主播元素
const modelItems = document.querySelectorAll(`.model-list-item`);
modelItems.forEach(item => {
const link = item.querySelector('a[href*="/"]');
if (link && link.getAttribute('href').endsWith(`/${modelId}`)) {
item.style.display = 'none';
}
});
// 如果面板打开,更新列表
if (document.getElementById('blocked-models-panel').style.display === 'block') {
updateBlockedModelsList();
}
}
// 取消隐藏主播
function unblockModel(modelId) {
delete blockedModels[modelId];
GM_setValue('blockedModels', blockedModels);
// 重新显示匹配的主播元素
const modelItems = document.querySelectorAll(`.model-list-item`);
modelItems.forEach(item => {
const link = item.querySelector('a[href*="/"]');
if (link && link.getAttribute('href').endsWith(`/${modelId}`)) {
item.style.display = '';
}
});
updateBlockedModelsList();
}
// 初始化隐藏主播功能
function initHideFeature() {
createToggleButton();
createBlockedModelsPanel();
// 初始隐藏已屏蔽主播
addHideButtons();
// 监听DOM变化,为新加载的主播添加隐藏按钮
const observer = new MutationObserver(mutations => {
let needToAddButtons = false;
mutations.forEach(mutation => {
if (mutation.addedNodes.length) {
needToAddButtons = true;
}
});
if (needToAddButtons) {
addHideButtons();
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// 初始化隐藏主播功能
initHideFeature();
}
// ================ 样式 ================
function addStyles() {
const styles = `
/* 查找更多信息按钮样式 */
.enhanced-button {
display: inline-flex !important;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid #feb601;
background-color: inherit;
color: inherit;
transition: background-color 0.2s, color 0.2s, stroke 0.2s;
cursor: pointer;
}
.enhanced-button:hover {
background-color: #feb601;
border: 2px solid #feb601;
}
.enhanced-button:hover svg {
stroke: black;
}
.enhanced-button svg {
width: 24px;
height: 24px;
stroke: currentColor;
}
/* 隐藏主播按钮样式 */
.hide-model-btn {
position: absolute;
top: 35px;
right: 8px;
z-index: 100;
background-color: #f03e3e;
color: white;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 1;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.model-list-item:hover .hide-model-btn {
opacity: 0.8;
}
.hide-model-btn:hover {
opacity: 1 !important;
background-color: #e03131;
}
/* 管理面板样式 */
.blocked-models-panel {
position: fixed;
top: 70px;
right: 20px;
width: 300px;
max-height: 400px;
background-color: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
z-index: 10000;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
display: none;
}
.blocked-models-header {
padding: 10px 15px;
background-color: #2a2a2a;
border-bottom: 1px solid #333;
display: flex;
justify-content: space-between;
align-items: center;
}
.blocked-models-header h3 {
margin: 0;
color: #feb601;
font-size: 16px;
}
.blocked-models-content {
padding: 10px 15px;
max-height: 300px;
overflow-y: auto;
}
.blocked-model-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #333;
}
.blocked-model-item:last-child {
border-bottom: none;
}
.blocked-model-name {
color: #fff;
font-size: 14px;
}
.unblock-btn {
background-color: #feb601;
color: #000;
border: none;
border-radius: 4px;
padding: 3px 8px;
font-size: 12px;
cursor: pointer;
}
.unblock-btn:hover {
background-color: #ffcc33;
}
.blocked-models-toggle {
position: fixed;
top: 7px;
right: 350px;
background-color: #a2252d;
color: #fff;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 9999;
}
.blocked-models-toggle svg {
stroke: #fff;
}
.blocked-models-toggle:hover {
background-color: #c42a35;
}
`;
const styleEl = document.createElement('style');
styleEl.textContent = styles;
document.head.appendChild(styleEl);
}
// ================ 初始化 ================
function init() {
// 添加样式
addStyles();
// 初始化查找主播信息功能
initFindMore();
// 初始化隐藏主播功能
initHideModels();
}
// 等待页面加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();