Yande.re 手动加载热门图 (日期选择版)

点击按钮加载指定日期范围内按分数排序的热门图,支持分级、自定义日期范围和翻页加载。

// ==UserScript==
// @name         Yande.re 手动加载热门图 (日期选择版)
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  点击按钮加载指定日期范围内按分数排序的热门图,支持分级、自定义日期范围和翻页加载。
// @author       银蓝色 & Gemini
// @match        https://yande.re/post*
// @grant        GM_xmlhttpRequest
// @connect      yande.re
// @license      MIT
// ==/UserScript==

(function () {
    'usestric'

    // ==== 配置 ====
    const DEFAULT_DAYS_RANGE = 30; // 默认选择的日期范围(天数)
    const DEFAULT_TAGS = "";       // 可附加固定标签,如 genshin_impact。多个标签用空格隔开。
    const POSTS_PER_PAGE = 50;     // 每次加载的图片数量(Yande.re API 上限为 100)
    // ==============

    let selectedRating = "safe"; // 默认分级
    let currentPage = 1;
    let isLoading = false;

    // --- [新增] 日期处理辅助函数 ---
    function formatDate(date) {
        return date.toISOString().split('T')[0];
    }

    const today = new Date();
    const defaultStartDate = new Date();
    defaultStartDate.setDate(today.getDate() - DEFAULT_DAYS_RANGE);

    // --- 1. 创建全新的操作界面 (包含日期选择) ---
    const uiBox = document.createElement("div");
    uiBox.style = "position:fixed; top:10px; right:10px; z-index:9999; background:#fff; padding:12px; border:1px solid #ccc; box-shadow: 0 2px 8px rgba(0,0,0,0.2); display: flex; flex-direction: column; gap: 10px;";

    // 日期选择区域
    const dateContainer = document.createElement('div');
    dateContainer.style = "display: flex; align-items: center; gap: 5px;";
    dateContainer.innerHTML = `
        <label for="start-date-picker" style="font-size: 12px;">从:</label>
        <input type="date" id="start-date-picker" style="padding: 4px; border: 1px solid #ccc;">
        <label for="end-date-picker" style="font-size: 12px; margin-left: 8px;">到:</label>
        <input type="date" id="end-date-picker" style="padding: 4px; border: 1px solid #ccc;">
    `;

    // 操作区域
    const actionContainer = document.createElement('div');
    actionContainer.style = "display: flex; align-items: center; gap: 8px;";
    const ratingSelect = document.createElement("select");
    ratingSelect.style = "padding: 5px; border: 1px solid #ccc; flex-grow: 1;";
    ratingSelect.innerHTML = `
        <option value="safe">🟢 Safe</option>
        <option value="questionable">🟡 Questionable</option>
        <option value="explicit">🔴 Explicit</option>
        <option value="all">⚪️ All</option>
    `;
    ratingSelect.addEventListener("change", () => selectedRating = ratingSelect.value);

    const loadBtn = document.createElement("button");
    loadBtn.textContent = "📥 加载热门图";
    loadBtn.style = "padding: 5px 12px; cursor: pointer; background: #3498db; color: white; border: none; border-radius: 3px;";
    loadBtn.addEventListener("click", startLoading);

    actionContainer.appendChild(ratingSelect);
    actionContainer.appendChild(loadBtn);

    uiBox.appendChild(dateContainer);
    uiBox.appendChild(actionContainer);
    document.body.appendChild(uiBox);

    // [新增] 获取日期输入框并设置默认值
    const startDateInput = document.getElementById('start-date-picker');
    const endDateInput = document.getElementById('end-date-picker');
    startDateInput.value = formatDate(defaultStartDate);
    endDateInput.value = formatDate(today);


    // --- 2. 初始化加载流程 ---
    let container, resultsContainer, loadMoreBtn;
    let selectedStartDate, selectedEndDate;

    function startLoading() {
        // [改动] 保存用户选择的日期
        selectedStartDate = startDateInput.value;
        selectedEndDate = endDateInput.value;
        if (!selectedStartDate || !selectedEndDate) {
            alert("请选择一个完整的日期范围!");
            return;
        }

        uiBox.remove();
        initUI();
        fetchAndRenderPage();
    }

    // --- 3. 创建结果显示区域 ---
    function initUI() {
        container = document.createElement('div');
        container.style = "margin:20px; padding:10px; background:#f5f5f5; border:1px solid #ddd;";

        // [改动] 标题现在显示选择的日期范围
        const ratingText = selectedRating === 'all' ? 'ALL' : selectedRating.toUpperCase();
        container.innerHTML = `<h2>🔥 热门图片 (${ratingText}) | <small>${selectedStartDate} ~ ${selectedEndDate}</small></h2>`;

        resultsContainer = document.createElement('div');
        resultsContainer.style = "display: flex; flex-wrap: wrap; justify-content: center;";
        container.appendChild(resultsContainer);

        loadMoreBtn = document.createElement('button');
        loadMoreBtn.textContent = '⏬ 加载更多...';
        loadMoreBtn.style = "display:block; width:80%; max-width:400px; margin: 20px auto; padding:12px 20px; font-size:16px; cursor: pointer; border: 1px solid #ccc;";
        loadMoreBtn.onclick = fetchAndRenderPage;

        container.appendChild(loadMoreBtn);
        const insertTarget = document.querySelector("#post-list-posts") || document.body;
        insertTarget.prepend(container);
    }

    // --- 4. 核心:获取并渲染单页数据 ---
    function fetchAndRenderPage() {
        if (isLoading) return;
        isLoading = true;
        loadMoreBtn.textContent = '正在加载中...';
        loadMoreBtn.disabled = true;

        // [改动] 使用选择的日期范围构造查询
        // Yande.re 支持 `date:YYYY-MM-DD..YYYY-MM-DD` 语法
        let tags = `date:${selectedStartDate}..${selectedEndDate} order:score`;
        if (selectedRating !== "all") {
            tags += ` rating:${selectedRating}`;
        }
        if (DEFAULT_TAGS) {
            tags += ` ${DEFAULT_TAGS}`;
        }

        GM_xmlhttpRequest({
            method: "GET",
            url: `https://yande.re/post.json?tags=${encodeURIComponent(tags)}&page=${currentPage}&limit=${POSTS_PER_PAGE}`,
            onload: function (response) {
                try {
                    const posts = JSON.parse(response.responseText);
                    if (posts.length > 0) {
                        renderPosts(posts);
                        currentPage++;
                        loadMoreBtn.textContent = '⏬ 加载更多...';
                        loadMoreBtn.disabled = false;
                    } else {
                        loadMoreBtn.textContent = '✅ 已加载范围内全部图片';
                        loadMoreBtn.disabled = true;
                    }
                } catch (e) {
                     loadMoreBtn.textContent = '❌ 解析返回数据失败';
                     console.error("JSON Parse Error:", e, "Response Text:", response.responseText);
                } finally {
                    isLoading = false;
                }
            },
            onerror: function(error) {
                console.error("Yande.re Script Error:", error);
                loadMoreBtn.textContent = '❌ 加载失败,请检查控制台';
                loadMoreBtn.disabled = false;
                isLoading = false;
            }
        });
    }

    // --- 5. 渲染图片到页面 (与之前版本相同) ---
    function renderPosts(posts) {
        const fragment = document.createDocumentFragment();
        posts.forEach(post => {
            const div = document.createElement('div');
            div.style = "display:inline-block; margin:8px; text-align:center; width:180px; vertical-align: top; background: #fff; padding: 5px; border: 1px solid #ddd;";
            div.innerHTML = `
                <a href="/post/show/${post.id}" target="_blank" title="Tags: ${post.tags}">
                    <img src="${post.preview_url}" style="max-width:170px; height: 170px; object-fit: cover; border:1px solid #ccc;">
                </a>
                <div style="font-size:12px; margin-top:5px;">⭐ ${post.score}</div>
            `;
            fragment.appendChild(div);
        });
        resultsContainer.appendChild(fragment);
    }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址