<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/rss/stylesheet/" type="text/xsl"?>
<rss xmlns:content='http://purl.org/rss/1.0/modules/content/' xmlns:taxo='http://purl.org/rss/1.0/modules/taxonomy/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:itunes='http://www.itunes.com/dtds/podcast-1.0.dtd' xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0" xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:podbridge='http://www.podbridge.com/podbridge-ad.dtd' version='2.0'>
<channel>
  <title>DBD-博客</title>
  <language>zh-cn</language>
  <generator>microfeed.org</generator>
  <itunes:type>episodic</itunes:type>
  <itunes:explicit>false</itunes:explicit>
  <atom:link rel="self" href="https://my-microfeed.z2326173351-8c6.workers.dev/rss/" type="application/rss+xml"/>
  <link>https://my-microfeed.z2326173351-8c6.workers.dev</link>
  <description>
    <![CDATA[<style>
        #api-text-container {
            font-size: 20px;
            max-width: 100%;
            text-align: center;
            line-height: 1.6;
            padding: 20px;
            border-left: 4px solid #4CAF50;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
@media (max-width: 768px) {
            #api-text-container {
                font-size: 19px; /* 移动端减小到18px */
                max-width: 100%; /* 移动端宽度占比更大（减少留白） */
                padding: 15px; /* 移动端内边距减小 */
            }
    </style>
<p id="api-text-container"></p>
<script>
  // 调用文字API（以「一言」为例，返回随机句子）
  fetch("https://v1.hitokoto.cn/?c=d") // API地址（返回JSON）
    .then(response => response.json())
    .then(data => {
      // 将API返回的文字填入容器（不添加任何样式，使用网站默认文本样式）
      document.getElementById("api-text-container").textContent = data.hitokoto;
    })
    .catch(error => {
      // 加载失败时显示提示（同样使用默认样式）
      document.getElementById("api-text-container").textContent = "加载失败，请稍后刷新";
    });
</script>
<p>这是一款轻量级的内容管理系统（CMS），可自行托管于Cloudflare平台。通过microfeed，您能够便捷地发布多种形式的内容——包括音频、视频、照片、文档、博客文章及外部链接，并以网页、RSS订阅和JSON格式输出信息流。</p>]]>
  </description>
  <itunes:author>DBD制作组</itunes:author>
  <itunes:image href="https://my-microfeed.z2326173351-8c6.workers.dev/assets/default/channel-image.png"/>
  <image>
    <title>DBD-博客</title>
    <url>https://my-microfeed.z2326173351-8c6.workers.dev/assets/default/channel-image.png</url>
    <link>https://my-microfeed.z2326173351-8c6.workers.dev</link>
  </image>
  <copyright>©2026</copyright>
  <item>
    <title>随机小姐姐 - JSON版</title>
    <guid>tWOeugxry5W</guid>
    <pubDate>Sun, 06 Sep 2026 20:08:21 GMT</pubDate>
    <itunes:explicit>false</itunes:explicit>
    <description>
      <![CDATA[<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>随机小姐姐</title>
    <style>
        //body {
            font-family: 'Arial', sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 15px;
            background-color: #f5f5f5;
        }
        
        #player-container {
            background: #000;
            border-radius: 8px;
            margin-bottom: 15px;
            overflow: hidden;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        
        #player {
            width: 100%;
            height: auto;
            min-height: 545px;
            max-height: 550px;
            display: block;
        }
        
        .control-panel {
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 15px;
        }
        
        .button-group {
            display: flex;
            gap: 8px;
            margin-bottom: 12px;
            flex-wrap: wrap;
        }
        
        button {
            background: #7F9CCC;
            color: #fff;
            border: none;
            padding: 10px 12px;
            border-radius: 6px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            flex-grow: 1;
            font-size: 14px;
            min-width: 80px;
        }
        
        button:hover {
            background: #6A8BBC;
            transform: translateY(-1px);
        }
        
        button#toggleAuto {
            flex-grow: 2;
        }
        
        .source-management {
            margin-top: 15px;
        }
        
        .source-list {
            margin-top: 10px;
            max-height: 30vh;
            overflow-y: auto;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 8px;
        }
        
        .source-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px;
            border-bottom: 1px solid #eee;
        }
        
        .source-item:last-child {
            border-bottom: none;
        }
        
        .source-url {
            flex-grow: 1;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            margin-right: 8px;
            font-size: 14px;
        }
        
        .source-actions {
            display: flex;
            gap: 5px;
        }
        
        .source-actions button {
            padding: 5px 8px;
            font-size: 12px;
            background: #ff6b6b;
            min-width: 50px;
            flex-grow: 0;
        }
        
        .source-actions button:first-child {
            background: #4CAF50;
        }
        
        .add-source-form {
            display: flex;
            gap: 8px;
            margin-top: 12px;
        }
        
        .add-source-form input {
            flex-grow: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
        }
        
        .add-source-form button {
            width: 90px;
            flex-grow: 0;
        }
        
        .status {
            margin-top: 10px;
            font-size: 14px;
            color: #666;
            text-align: center;
        }
        
        .current-source {
            font-weight: bold;
            color: #7F9CCC;
            word-break: break-all;
        }
        
        .default-source-indicator {
            color: #888;
            font-style: italic;
            margin-top: 5px;
        }
        
        @media (max-width: 600px) {
            body {
                padding: 10px;
            }
            #player {
                min-height: 540px;
            }
            .control-panel {
                padding: 12px;
            }
            button {
                padding: 8px 10px;
                font-size: 13px;
            }
            .source-item {
                flex-direction: column;
                align-items: flex-start;
            }
            .source-actions {
                margin-top: 5px;
                width: 100%;
                justify-content: flex-end;
            }
            .add-source-form {
                flex-direction: column;
            }
            .add-source-form button {
                width: 100%;
            }
        }
    </style>
</head>
<body>
<h1 style="text-align: center; margin-bottom: 15px;">随机小姐姐</h1>
<div id="player-container"><video id="player" controls playsinline></video></div>
<div class="control-panel">
  <div class="button-group">
            <button id="toggleAuto">连续播放: 开</button>
            <button id="nextVideo">换一个 ▶</button>
            <button id="switchSource">切换源</button>
  </div>
  <div class="status" id="statusArea"></div>
  <div class="source-management">
    <h3 style="margin-bottom: 8px;">视频源管理</h3>
    <div class="source-list" id="sourceList"></div>
    <div class="add-source-form">
            <input type="text" id="newSourceInput" placeholder="输入视频API地址">
            <button id="addSource">添加源</button>
    </div>
  </div>
</div>
<p>注意：这是一个JSON版随机视频播放器，部分浏览器播放失败或无法操作属于正常现象，更换浏览器尝试即可！跨域问题任未解决，但大部分能播放，点击按钮需等待。</p>
<script>
    document.addEventListener('DOMContentLoaded', function() {
        // 默认视频源（已去重）
        const defaultSources = [
            'http://api.nonebot.top/api/v1/random/dance_video',
            'https://api.4qb.cn/api/suiji-sp?msg=%E7%83%AD%E8%88%9E&type=json'
        ];

        // 用户自定义源（本地持久化）
        let userSources = JSON.parse(localStorage.getItem('userVideoSources')) || [];

        // 合并全部源
        function getAllSources() {
            return [...userSources, ...defaultSources];
        }

        // 核心状态
        let currentSourceIndex = 0;
        let autoPlay = localStorage.getItem('autoPlay') !== 'false';
        let currentSourceRetries = 0;
        const maxRetriesPerSource = 2;
        let currentLoadToken = 0; // 任务编号，代替 isProcessing

        // DOM 元素
        const player = document.getElementById('player');
        const elements = {
            toggleAuto: document.getElementById('toggleAuto'),
            nextVideo: document.getElementById('nextVideo'),
            switchSource: document.getElementById('switchSource'),
            sourceList: document.getElementById('sourceList'),
            newSourceInput: document.getElementById('newSourceInput'),
            addSource: document.getElementById('addSource'),
            statusArea: document.getElementById('statusArea')
        };

        // 重置重试次数
        function resetSourceRetry() {
            currentSourceRetries = 0;
        }

        // 显示状态
        function showStatus(message, isError = false) {
            requestAnimationFrame(() => {
                elements.statusArea.innerHTML = `<div class="status-message" style="color: ${isError ? '#ff4444' : '#666'}">${message}</div>`;
            });
        }

        // 更新自动播放按钮
        function updateAutoPlayButton() {
            elements.toggleAuto.textContent = `连续播放: ${autoPlay ? '开' : '关'}`;
        }

        // 更新当前源显示
        function updateSourceDisplay() {
            const allSources = getAllSources();
            if (allSources.length === 0) {
                showStatus('无可用视频源，请添加视频源', true);
                return;
            }
            const currentSource = allSources[currentSourceIndex];
            const isDefaultSource = defaultSources.includes(currentSource);
            
            requestAnimationFrame(() => {
                if (isDefaultSource) {
                    elements.statusArea.innerHTML = `
                        <div class="status-message">正在使用系统默认视频源</div>
                        <div class="default-source-indicator">如需更好体验，请添加自定义视频源</div>
                    `;
                } else {
                    elements.statusArea.innerHTML = `
                        <div class="status-message">当前视频源:</div>
                        <div class="current-source">${currentSource}</div>
                    `;
                }
            });
        }

        // 从 API 返回内容中提取视频直链
        function extractVideoUrl(data) {
            if (typeof data === 'string') {
                const s = data.trim();
                if (/^https?:\/\/.+/i.test(s)) return s;
                try {
                    return extractVideoUrl(JSON.parse(s));
                } catch (e) {
                    return null;
                }
            }
            if (Array.isArray(data)) {
                for (const item of data) {
                    const url = extractVideoUrl(item);
                    if (url) return url;
                }
                return null;
            }
            if (data && typeof data === 'object') {
                const preferred = ['url', 'video', 'src', 'play_url', 'playUrl', 'dance_video', 'data', 'video_url', 'videourl'];
                for (const key of preferred) {
                    if (data[key] !== undefined && data[key] !== null) {
                        const url = extractVideoUrl(data[key]);
                        if (url) return url;
                    }
                }
                for (const key in data) {
                    if (Object.prototype.hasOwnProperty.call(data, key)) {
                        const url = extractVideoUrl(data[key]);
                        if (url) return url;
                    }
                }
            }
            return null;
        }

        // fetch 带超时控制
        async function fetchVideoUrl(apiUrl) {
            const timestamp = new Date().getTime();
            const randomParam = Math.random();
            let url = apiUrl;
            if (url.includes('?')) {
                url += `&_t=${timestamp}_${randomParam}`;
            } else {
                url += `?_t=${timestamp}_${randomParam}`;
            }

            const controller = new AbortController();
            const timeout = setTimeout(() => controller.abort(), 10000); // 10秒超时

            try {
                const response = await fetch(url, { cache: 'no-store', signal: controller.signal });
                if (!response.ok) throw new Error('HTTP ' + response.status);
                const type = response.headers.get('content-type') || '';
                if (type.startsWith('video/')) {
                    return response.url || apiUrl;
                }
                const text = await response.text();
                const videoUrl = extractVideoUrl(text);
                if (!videoUrl) throw new Error('未提取到视频地址');
                return videoUrl;
            } catch (err) {
                if (err.name === 'AbortError') {
                    throw new Error('请求超时(10s)');
                }
                throw err;
            } finally {
                clearTimeout(timeout);
            }
        }

        // 加载随机视频（使用任务编号，旧任务不会阻塞新任务）
        async function loadRandomVideo() {
            const myToken = ++currentLoadToken;

            const allSources = getAllSources();
            if (allSources.length === 0) {
                showStatus('无可用视频源，请添加视频源', true);
                return;
            }

            if (currentSourceIndex >= allSources.length) {
                currentSourceIndex = 0;
            }

            const currentSource = allSources[currentSourceIndex];
            
            try {
                const videoUrl = await fetchVideoUrl(currentSource);
                // 如果已经不是最新任务，则丢弃结果
                if (myToken !== currentLoadToken) return;

                player.src = videoUrl;
                updateSourceDisplay();

                try {
                    await player.play();
                    // 播放成功，重置重试
                    if (myToken !== currentLoadToken) return;
                    resetSourceRetry();
                } catch (playErr) {
                    if (myToken !== currentLoadToken) return;

                    if (playErr.name === 'NotAllowedError') {
                        showStatus('请点击【换一个】按钮开始（浏览器限制自动播放）', true);
                    } else {
                        handleLoadFailure(myToken, currentSource);
                    }
                }
            } catch (err) {
                if (myToken !== currentLoadToken) return;
                console.error('获取视频地址失败:', currentSource, err);
                handleLoadFailure(myToken, currentSource);
            }
        }

        // 加载失败处理（重试或切换源）
        function handleLoadFailure(myToken, currentSource) {
            const allSources = getAllSources();

            if (currentSourceRetries < maxRetriesPerSource) {
                currentSourceRetries++;
                showStatus(`当前源重试中(${currentSourceRetries}/${maxRetriesPerSource})...`, true);
                setTimeout(() => {
                    // 只有当前任务仍然是最新的，才继续重试
                    if (myToken === currentLoadToken) {
                        loadRandomVideo();
                    }
                }, 1000);
            } else {
                showStatus(`当前源已重试${maxRetriesPerSource}次失败，切换到下一个源...`, true);
                resetSourceRetry();
                currentSourceIndex = (currentSourceIndex + 1) % allSources.length;
                setTimeout(() => {
                    if (myToken === currentLoadToken) {
                        loadRandomVideo();
                    }
                }, 500);
            }
        }

        // 切换到下一个源
        function switchToNextSource() {
            const allSources = getAllSources();
            if (allSources.length === 0) return;
            currentSourceIndex = (currentSourceIndex + 1) % allSources.length;
            resetSourceRetry();
            loadRandomVideo();
        }

        // 使用指定用户源
        function useSource(index) {
            currentSourceIndex = index;
            resetSourceRetry();
            loadRandomVideo();
        }

        // 删除用户源
        function deleteSource(userSourceIndex) {
            const sourceToDelete = userSources[userSourceIndex];
            const allSources = getAllSources();

            userSources.splice(userSourceIndex, 1);
            saveUserSources();
            renderSourceList();
            updateSourceDisplay();

            // 如果删除的是当前正在播放的源，必须重新加载
            if (allSources[currentSourceIndex] === sourceToDelete) {
                currentSourceIndex = 0;
                resetSourceRetry();
                loadRandomVideo();
            }
        }

        // 添加新源
        function addNewSource() {
            const newSource = elements.newSourceInput.value.trim();

            if (!newSource) {
                showStatus('请输入有效的视频API地址', true);
                return;
            }

            if (!newSource.startsWith('http://') && !newSource.startsWith('https://')) {
                showStatus('URL必须以http://或https://开头', true);
                return;
            }

            if (getAllSources().includes(newSource)) {
                showStatus('该视频源已存在', true);
                return;
            }

            userSources.unshift(newSource);
            elements.newSourceInput.value = '';
            saveUserSources();

            currentSourceIndex = 0;
            resetSourceRetry();
            renderSourceList();
            showStatus('视频源添加成功', false);
            loadRandomVideo();
        }

        // 保存用户源到本地存储
        function saveUserSources() {
            localStorage.setItem('userVideoSources', JSON.stringify(userSources));
        }

        // 渲染用户源列表
        function renderSourceList() {
            requestAnimationFrame(() => {
                elements.sourceList.innerHTML = '';

                if (userSources.length === 0) {
                    elements.sourceList.innerHTML = '<div style="text-align: center; padding: 10px; color: #888;">暂无自定义视频源，请添加</div>';
                    return;
                }

                const fragment = document.createDocumentFragment();

                userSources.forEach((source, index) => {
                    const sourceItem = document.createElement('div');
                    sourceItem.className = 'source-item';

                    const sourceUrl = document.createElement('span');
                    sourceUrl.className = 'source-url';
                    sourceUrl.textContent = source;

                    const sourceActions = document.createElement('div');
                    sourceActions.className = 'source-actions';

                    const useBtn = document.createElement('button');
                    useBtn.textContent = '使用';
                    useBtn.addEventListener('click', () => useSource(index));

                    const deleteBtn = document.createElement('button');
                    deleteBtn.textContent = '删除';
                    deleteBtn.addEventListener('click', () => deleteSource(index));

                    sourceActions.appendChild(useBtn);
                    sourceActions.appendChild(deleteBtn);

                    sourceItem.appendChild(sourceUrl);
                    sourceItem.appendChild(sourceActions);

                    fragment.appendChild(sourceItem);
                });

                elements.sourceList.appendChild(fragment);
            });
        }

        // 事件监听
        elements.toggleAuto.addEventListener('click', function() {
            autoPlay = !autoPlay;
            localStorage.setItem('autoPlay', autoPlay);
            updateAutoPlayButton();
        });

        elements.nextVideo.addEventListener('click', function() {
            resetSourceRetry();
            loadRandomVideo();
        });

        elements.switchSource.addEventListener('click', function() {
            resetSourceRetry();
            switchToNextSource();
        });

        elements.addSource.addEventListener('click', addNewSource);

        elements.newSourceInput.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                addNewSource();
            }
        });

        // 视频结束事件
        player.addEventListener('ended', function() {
            if (autoPlay) {
                resetSourceRetry();
                loadRandomVideo();
            }
        });

        // 视频错误事件
        player.addEventListener('error', function() {
            console.error('视频播放错误');
            // 如果当前没有在执行加载任务，则尝试切源
            // 由于使用了任务编号，这里直接重新加载是安全的
            if (currentSourceRetries < maxRetriesPerSource) {
                currentSourceRetries++;
                showStatus(`播放错误，重试中(${currentSourceRetries}/${maxRetriesPerSource})...`, true);
                setTimeout(() => loadRandomVideo(), 1000);
            } else {
                showStatus('播放错误，切换到下一个源...', true);
                resetSourceRetry();
                currentSourceIndex = (currentSourceIndex + 1) % getAllSources().length;
                loadRandomVideo();
            }
        });

        // 初始化
        updateAutoPlayButton();
        renderSourceList();
        updateSourceDisplay();
        resetSourceRetry();
        loadRandomVideo();
    });
</script>
</body>]]>
    </description>
    <link>https://cms.4km.cc.cd/i/测试代码-tWOeugxry5W/</link>
    <itunes:episodeType>full</itunes:episodeType>
  </item>
</channel>
</rss>