Sleazy Fork is available in English.

Danbooru Copy Tags Optimized

优化后的Danbooru标签复制脚本,支持角色名、艺术家名等功能,并移除重复逗号和多余空格

// ==UserScript==
// @name         Danbooru Copy Tags Optimized
// @namespace    http://tampermonkey.net/
// @version      1.31
// @description  优化后的Danbooru标签复制脚本,支持角色名、艺术家名等功能,并移除重复逗号和多余空格
// @match        https://danbooru.donmai.us/posts/*
// @match        https://aibooru.online/posts/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const BUTTON_STYLE = `
        position: absolute;
        right: 10px;
        z-index: 9999;
        padding: 10px;
        background-color: #28a745;
        color: #fff;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        margin-right: 5px;
    `;

    const BUTTON_COLORS = {
        general: '#28a745',
        nonCharacter: '#dc3545',
        characterFeatures: '#17a2b8',
        clothing: '#ffc107',
        characterNames: '#007bff',
        artistNames: '#6f42c1'
    };

    const TAG_LISTS = {
        general: '.general-tag-list a',
        characters: '.character-tag-list a',
        artists: '.artist-tag-list a'
    };

    const FILTERS = {
        all: () => true,
        nonCharacter: tag => !blacklist.some(b => tag.includes(b)) && characterFeatures.every(f => !tag.includes(f)) && clothingFeatures.every(f => !tag.includes(f)),
        characterFeatures: tag => characterFeatures.some(f => tag.includes(f)) && !blacklist.some(b => tag.includes(b)),
        clothing: tag => clothingFeatures.some(f => tag.includes(f)) && !blacklist.some(b => tag.includes(b))
    };

    const allTagsFilter = (tag) => !blacklist.some(blacklistedTag => tag.includes(blacklistedTag));

    const characterFeatures = [
    'hair', 'eyes', 'choker', 'medium hair', '1girl', 'large breasts', 'twintails', 'girl on top', 'multiple girls',
    'hair ornament', 'animal ears', 'hairband', 'symbol-shaped pupils', 'fake animal ears', 'heart-shaped pupils',
    'mouse ears', 'long hair', 'one eye closed', 'dark skin', 'pubic hair', 'upper teeth only', 'looking over eyewear',
    'red-tinted eyewear', 'eyeshadow', 'v-shaped eyebrows', 'wide-eyed', 'constricted pupils', 'bloodshot eyes', 'tail',
    'cat ears', 'cat tail', 'half-closed eyes', 'cat girl', 'eyepatch', 'empty eyes', 'medical eyepatch', 'very long hair',
    'hair bow', 'hairclip', 'green eyes', 'rabbit ears', 'streaked hair', 'hair tie', 'adjusting hair', 'hair tie in mouth',
    'earrings', 'ribbon', 'halo', 'braid', 'pointy ears', 'feathered wings', 'angel wings', 'single side bun', 'low twintails',
    'alternate costume', 'closed eyes', 'long bangs', 'absurdly long hair', 'blue halo', 'mechanical halo', 'facial hair', 'ahoge',
    'two-tone hair', 'gradient hair', 'eyelashes', 'straight hair', 'pale skin', 'black wings', 'detached wings', 'energy wings',
    'hair flowing over', 'broken halo', 'dark halo', 'ponytail', 'round eyewear', 'pearl earrings', 'glowing eyes', 'cowgirl position',
    'drill hair', 'horns', 'demon horns', 'shiny skin', 'crossed bangs', 'fox ears', 'necklace', 'wavy hair', 'wolf ears', 'wolf tail',
    'extra ears', 'bead necklace', 'scar across eye', 'colored eyelashes', 'butterfly hair ornament', 'dark-skinned female', 'covering face',
    'ringed eyes', 'frilled hair tubes', 'ear piercing', 'cow horns', 'draph', 'cow tail', 'monkey tail', 'forehead', 'red ribbon',
    'fox tail', 'skull hair ornament', 'eyes visible through hair', 'asymmetrical hair', 'official alternate hairstyle', 'mini wings',
    'multicolored wings', 'star halo', 'heart hair ornament', 'spiked choker', 'high ponytail', 'tentacle hair', 'choker', 'fangs',
    'pom pom hair ornament', 'floating hair', 'forked tail', 'ribbon-trimmed skirt', 'leaf hair ornament', 'short hair with long locks',
    'fake horns', 'blood in hair', 'diamond hair ornament', 'skin fang', 'braided ponytail', 'multicolored eyes', 'demon tail',
    'o-ring choker', 'playboy bunny', 'bob cut', 'button eyes', 'braided bangs', 'heart choker', 'tassel hair ornament', 'asymmetrical horns',
    'demon wings', 'butterfly wings', 'horse ears', 'horse tail', 'side ponytail', 'diamond-shaped pupils', 'dog ears', 'bandaid hair ornament',
    'neck ribbon', 'ribbon hair ornament', 'sharp teeth', 'messy hair', 'bright pupils', 'one side up', 'bags under eyes', 'hairband',
    'braid', 'blue wings', 'star hair ornament', 'side ponytail', 'twisted horns', 'swirling eyes', 'vampire teeth','animal ear fluff',
];


    const clothingFeatures = [
    'swimsuit', 'bikini', 'strap gap', 'skirt', 'gloves', 'thighhighs', 'jacket', 'fingerless gloves', 'open jacket',
    'sunglasses', 'leather jacket', 'long sleeves', 'bow', 'boots', 'detached sleeves', 'belt', 'wide sleeves', 'high heels',
    'side-tie bikini bottom', 'thigh boots', 'micro bikini', 'striped bikini', 'heart brooch', 'bikini bottom aside',
    'bikini top lift', 'black gloves', 'black footwear', 'turtleneck', 'cropped jacket', 'short sleeves', 'yellow gloves',
    'boxing gloves', 'shirt', 'collared shirt', 'shorts', 'shoes', 'socks', 'white jacket', 'white footwear', 'bow',
    'grey shorts', 'multicolored jacket', 'dress', 'asymmetrical legwear', 'single leg pantyhose', 'frills', 'bowtie', 'detached collar',
    'sandals', 'toenails', 'frilled bikini', 'jewelry', 'braid', 'bell', 'shirt', 'official alternate costume', 'short shorts',
    'shirt lift', 'track jacket', 'gym uniform', 'gym shirt', 'gym shorts', 'flowers', 'leotard', 'black leotard', 'cuffs',
    'handcuffs', 'torn leotard', 'school uniform', 'capelet', 'scrunchie', 'wrist scrunchie', 'blue skirt', 'sweater',
    'red shorts', 'underwear', 'panties', 'japanese clothes', 'kimono', 'pasties', 'open kimono', 'collar', 'black panties',
    'highleg', 'highleg panties', 'black sweater', 'tentacle hair', 'vest', 'uniform', 'white socks', 'wing collar',
    'long skirt', 'blue footwear', 'blue vest', 'serafuku', 'neckerchief', 'white skirt', 'cardigan', 'slippers',
    'frilled collar', 'bra', 'underwear only', 'china dress', 'print dress', 'striped coat', 'beret', 'school swimsuit',
    'one-piece swimsuit', 'shawl', 'collar', 'micro shorts', 'cow costume', 'casual one-piece swimsuit', 'green one-piece swimsuit',
    'hood', 'scarf', 'coat', 'fur trim', 'beanie', 'white scarf', 'black dress', 'sleeveless dress', 'arm strap', 'elbow gloves',
    'strappy heels', 'bodysuit', 'red bodysuit', 'wrist cuffs', 'no shoes', 'garter straps', 'grey thighhighs', 'thigh strap',
    'vibrator', 'jacket on shoulders', 'pants rolled up', 'red ribbon', 'pantyhose', 'sailor collar', 'white pantyhose',
    'thighband pantyhose', 'sun hat', 'high heel boots', 'fishnet thighhighs', 'fishnets', 'o-ring thigh strap', 'thigh belt',
    'strapless', 'chinese clothes', 'aqua dress', 'aqua gloves', 'puffy sleeves', 'apron', 'maid headdress', 'pleated skirt',
    'green skirt', 'black pantyhose', 'frilled dress', 'frilled apron', 'two-tone dress', 'necktie', 'sash', 'waist apron',
    'jingle bell', 'neck bell', 'purple bow', 'pink kimono', 'sleeveless kimono', 'pink sleeves', 'hatsune miku', 'miniskirt',
    'sleeveless shirt', 'grey shirt', 'yellow necktie', 'ascot', 'frilled bow', 'orange ascot', 'hoodie', 'bandages',
    'black hoodie', 'bandaged neck', 'white shorts', 'animal costume', 'one-piece swimsuit', 'shawl', 'collar', 'green one-piece swimsuit',
    'vest', 'uniform', 'highleg panties', 'tentacle hair', 'pants', 'jacket'
];


    const blacklist = [
    'lowres', 'jpeg artifacts', 'signature', 'watermark', 'text', 'artist name',
    'sample', 'resolution mismatch', 'bad anatomy', 'error', 'low quality', 'character name',
    'name', 'censored', 'censoring', 'censor',
];


    const createButton = (text, color, top, callback) => {
        const button = document.createElement('button');
        button.innerText = text;
        button.style.cssText = `${BUTTON_STYLE} top: ${top}px; background-color: ${color};`;
        document.querySelector('.image-container')?.appendChild(button);
        button.addEventListener('click', callback);
    };

    const sanitizeTags = tags =>
        tags.filter(Boolean) // 移除空字符串
            .join(', ') // 将数组转换为字符串,用逗号连接
            .replace(/, ,+/g, ',') // 移除多余的连续逗号
            .replace(/,\s+/g, ', ') // 确保每个逗号后只有一个空格
            .trim(); // 去除首尾多余空格

    const copyTags = (selector, filter) => {
        setTimeout(() => {
            const tags = Array.from(document.querySelectorAll(selector)).map(el => el.innerText.replace(/\?/g, '').trim());
            const filtered = filter ? tags.filter(filter) : tags;
            const result = sanitizeTags(filtered);
            if (!result) return alert('未找到符合条件的标签。');
            navigator.clipboard.writeText(result).then(() => alert(`已复制到剪贴板: ${result}`)).catch(err => alert(`复制失败: ${err}`));
        }, 1000); // 延迟确保加载完成
    };

    const copyNames = (selector, type) => {
        setTimeout(() => {
            const elements = document.querySelectorAll(selector);
            const names = Array.from(elements).map(el => el.innerText.replace(/\?/g, '').trim());
            const result = sanitizeTags(names);
            if (!result) return alert(`未找到${type}。`);
            navigator.clipboard.writeText(result).then(() => alert(`已复制${type}: ${result}`)).catch(err => alert(`复制失败: ${err}`));
        }, 1000);
    };

    // 创建各类按钮
    createButton('复制所有标签', BUTTON_COLORS.general, 10, () => copyTags(TAG_LISTS.general, FILTERS.all));
    createButton('复制非角色特征标签', BUTTON_COLORS.nonCharacter, 50, () => copyTags(TAG_LISTS.general, FILTERS.nonCharacter));
    createButton('复制角色特征标签', BUTTON_COLORS.characterFeatures, 90, () => copyTags(TAG_LISTS.general, FILTERS.characterFeatures));
    createButton('仅复制服装标签', BUTTON_COLORS.clothing, 130, () => copyTags(TAG_LISTS.general, FILTERS.clothing));
    createButton('复制角色名字', BUTTON_COLORS.characterNames, 170, () => copyNames(TAG_LISTS.characters, '角色名字'));
    createButton('复制艺术家名字', BUTTON_COLORS.artistNames, 210, () => copyNames(TAG_LISTS.artists, '艺术家名字'));
})();