Last active
October 28, 2025 11:16
-
-
Save d1y/4d0551fc8105c9d57f85da8cbbdc8b2e to your computer and use it in GitHub Desktop.
小猫影视发布页
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>小猫影视</title> | |
| <!-- favicon --> | |
| <link rel="icon" href="https://raw.githubusercontent.com/waifu-project/movie/refs/heads/dev/logo.png"> | |
| </link> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| color: #333; | |
| position: relative; | |
| overflow-x: hidden; | |
| } | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: | |
| radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), | |
| radial-gradient(circle at 80% 80%, rgba(138, 43, 226, 0.3) 0%, transparent 50%); | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 40px 20px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 60px; | |
| animation: fadeInDown 0.8s ease-out; | |
| } | |
| @keyframes fadeInDown { | |
| from { | |
| opacity: 0; | |
| transform: translateY(-30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .logo { | |
| font-size: 3.5rem; | |
| font-weight: 800; | |
| color: #fff; | |
| margin-bottom: 20px; | |
| text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); | |
| letter-spacing: -1px; | |
| } | |
| .subtitle { | |
| font-size: 1.2rem; | |
| color: rgba(255, 255, 255, 0.95); | |
| margin-bottom: 40px; | |
| font-weight: 300; | |
| letter-spacing: 0.5px; | |
| } | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); | |
| gap: 30px; | |
| margin-bottom: 60px; | |
| } | |
| .card { | |
| background: rgba(255, 255, 255, 0.98); | |
| backdrop-filter: blur(20px); | |
| border-radius: 24px; | |
| padding: 32px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08); | |
| transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(135deg, rgba(102, 126, 234, 0.05) 0%, rgba(118, 75, 162, 0.05) 100%); | |
| opacity: 0; | |
| transition: opacity 0.4s ease; | |
| } | |
| .card:hover::before { | |
| opacity: 1; | |
| } | |
| .card:hover { | |
| transform: translateY(-12px) scale(1.02); | |
| box-shadow: 0 30px 60px rgba(0, 0, 0, 0.15); | |
| border-color: rgba(102, 126, 234, 0.3); | |
| } | |
| .card-header { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .card-icon { | |
| width: 56px; | |
| height: 56px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 16px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin-right: 16px; | |
| font-size: 1.6rem; | |
| color: white; | |
| box-shadow: 0 8px 16px rgba(102, 126, 234, 0.3); | |
| transition: all 0.3s ease; | |
| } | |
| .card:hover .card-icon { | |
| transform: rotate(5deg) scale(1.1); | |
| box-shadow: 0 12px 24px rgba(102, 126, 234, 0.4); | |
| } | |
| .card-title { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| color: #2d2d2d; | |
| letter-spacing: -0.5px; | |
| } | |
| .card-description { | |
| color: #666666; | |
| line-height: 1.7; | |
| margin-bottom: 28px; | |
| font-size: 0.95rem; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .source-list { | |
| list-style: none; | |
| } | |
| .source-item { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 12px 0; | |
| border-bottom: 1px solid #e2e8f0; | |
| } | |
| .source-item:last-child { | |
| border-bottom: none; | |
| } | |
| .source-name { | |
| font-weight: 500; | |
| color: #2d3748; | |
| } | |
| .copy-btn { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 12px; | |
| cursor: pointer; | |
| font-size: 0.95rem; | |
| font-weight: 600; | |
| transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .copy-btn::before { | |
| content: ''; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| width: 0; | |
| height: 0; | |
| border-radius: 50%; | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: translate(-50%, -50%); | |
| transition: width 0.6s, height 0.6s; | |
| } | |
| .copy-btn:hover::before { | |
| width: 300px; | |
| height: 300px; | |
| } | |
| .copy-btn:hover { | |
| transform: translateY(-2px) scale(1.05); | |
| box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); | |
| } | |
| .copy-btn:active { | |
| transform: translateY(0) scale(0.98); | |
| } | |
| .source-type-actions { | |
| text-align: center; | |
| margin-top: 24px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .source-type-actions .copy-btn { | |
| font-size: 1.05rem; | |
| padding: 14px 32px; | |
| border-radius: 14px; | |
| } | |
| .stats { | |
| background: rgba(255, 255, 255, 0.15); | |
| backdrop-filter: blur(20px); | |
| border-radius: 24px; | |
| padding: 40px; | |
| text-align: center; | |
| margin-bottom: 50px; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
| gap: 40px; | |
| } | |
| .stat-item { | |
| color: white; | |
| transition: transform 0.3s ease; | |
| } | |
| .stat-item:hover { | |
| transform: translateY(-5px); | |
| } | |
| .stat-number { | |
| font-size: 2.8rem; | |
| font-weight: 800; | |
| margin-bottom: 10px; | |
| text-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); | |
| background: linear-gradient(135deg, #fff 0%, rgba(255, 255, 255, 0.8) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .stat-number.mini { | |
| font-size: 1.6rem; | |
| margin-bottom: 1rem; | |
| margin-top: 1rem; | |
| } | |
| .stat-label { | |
| font-size: 1.05rem; | |
| opacity: 0.95; | |
| font-weight: 300; | |
| letter-spacing: 0.5px; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 20px 15px; | |
| } | |
| .logo { | |
| font-size: 2.5rem; | |
| } | |
| .subtitle { | |
| font-size: 1rem; | |
| } | |
| .grid { | |
| grid-template-columns: 1fr; | |
| gap: 20px; | |
| } | |
| .card { | |
| padding: 24px; | |
| } | |
| .stats { | |
| padding: 30px 20px; | |
| } | |
| .stats-grid { | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 25px; | |
| } | |
| .stat-number { | |
| font-size: 2.2rem; | |
| } | |
| .stat-number.mini { | |
| font-size: 1.3rem; | |
| } | |
| } | |
| .toast { | |
| position: fixed; | |
| top: 30px; | |
| right: 30px; | |
| background: linear-gradient(135deg, #48bb78 0%, #38a169 100%); | |
| color: white; | |
| padding: 16px 24px; | |
| border-radius: 12px; | |
| box-shadow: 0 8px 24px rgba(72, 187, 120, 0.3); | |
| transform: translateX(400px); | |
| transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| z-index: 1000; | |
| font-weight: 600; | |
| font-size: 0.95rem; | |
| } | |
| .toast.show { | |
| transform: translateX(0); | |
| } | |
| @media (max-width: 768px) { | |
| .toast { | |
| top: 20px; | |
| right: 20px; | |
| left: 20px; | |
| transform: translateY(-100px); | |
| } | |
| .toast.show { | |
| transform: translateY(0); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1 class="logo" id="site-logo"></h1> | |
| <p class="subtitle" id="site-subtitle"></p> | |
| </div> | |
| <div class="stats"> | |
| <div class="stats-grid" id="stats-grid"> | |
| <!-- 统计数据将由JS动态生成 --> | |
| </div> | |
| </div> | |
| <div class="grid" id="cards-grid"> | |
| <!-- 卡片内容将由JS动态生成 --> | |
| </div> | |
| <div id="toast" class="toast"> | |
| 链接已复制到剪贴板! | |
| </div> | |
| <script> | |
| // 站点配置对象 - 方便统一管理和调整所有文字内容 | |
| const siteConfig = { | |
| // 网站基本信息 | |
| site: { | |
| logo: 'd1y/kitty', | |
| subtitle: '请勿用于商业和非法用途' | |
| }, | |
| // 统计数据配置 | |
| stats: [ | |
| { number: '4', label: '源类型', animation: { end: 4, static: true, suffix: '' } }, | |
| { number: '$$sourceTotal', label: '订阅源数量', animation: { end: $$sourceTotal, static: true, suffix: '+' } }, | |
| { number: '$$update', label: '更新时间', animation: { static: true } } | |
| ], | |
| // 卡片配置 - 使用Map结构管理不同源类型 | |
| cards: [ | |
| { | |
| id: 'js', | |
| icon: '⚙️', | |
| title: 'JS 脚本源', | |
| description: 'JavaScript 脚本驱动的动态源,支持实时解析和更新,功能更加灵活。', | |
| buttonText: 'JS 订阅源', | |
| file: 'x.json' | |
| }, | |
| { | |
| id: 'vod', | |
| icon: '📺', | |
| title: 'VOD 影视源', | |
| description: '传统视频点播源,支持电影、电视剧、综艺节目等内容,高清画质,稳定播放。', | |
| buttonText: 'VOD 订阅源', | |
| file: 'vod.json' | |
| }, | |
| { | |
| id: 'xvod', | |
| icon: '🔞', | |
| title: 'XVOD 成人源', | |
| description: '成人内容专用源,提供丰富的成人影视资源,需要用户自行选择。', | |
| buttonText: 'XVOD 订阅源', | |
| file: 'xvod.json' | |
| }, | |
| { | |
| id: 't4', | |
| icon: '🚀', | |
| title: 'T4 快速源', | |
| description: '第四代快速订阅源,优化加载速度和缓存机制,提供更好的播放体验。', | |
| buttonText: 'T4 订阅源', | |
| file: 't4.json' | |
| }, | |
| { | |
| id: 'lives', | |
| icon: "🎬", | |
| title: '电视直播', | |
| description: '提供各大卫视、地方台、央视频道等电视直播源,实时观看精彩节目。', | |
| buttonText: '订阅源', | |
| file: 'lives.json' | |
| }, | |
| { | |
| id: 'all', | |
| icon: '🌐', | |
| title: '全部源', | |
| description: '聚合所有订阅源类型,一键获取最全面的影视资源。', | |
| buttonText: '聚合所有源', | |
| file: [] | |
| }, | |
| { | |
| id: 'sponsor', | |
| icon: '💖', | |
| title: '赞助', | |
| description: '如果您觉得这个项目对您有帮助,不妨请开发者喝杯咖啡 ☕️', | |
| buttonText: null, // 不显示按钮 | |
| file: null, | |
| customContent: ` | |
| <div style="color: #4a5568; line-height: 1.8; text-align: center;"> | |
| <img src="$$sponsorship" alt="赞助二维码" style="max-width: 200px; margin: 20px auto; display: block;"> | |
| <p style="font-size: 0.9rem; color: #718096; margin-top: 15px;">💝 每一份支持都是前进的动力</p> | |
| <p style="font-size: 0.9rem; color: #718096;">🚀 让更多优质资源与您相遇</p> | |
| </div> | |
| ` | |
| } | |
| ] | |
| }; | |
| // 使用Map结构管理源类型配置,提升代码的简洁性和可维护性 | |
| const sourceTypeMap = new Map(); | |
| // 初始化页面内容 | |
| function initializePage() { | |
| // 渲染网站基本信息 | |
| document.getElementById('site-logo').textContent = siteConfig.site.logo; | |
| document.getElementById('site-subtitle').textContent = siteConfig.site.subtitle; | |
| // 渲染统计数据 | |
| renderStats(); | |
| // 渲染卡片 | |
| renderCards(); | |
| // 初始化源类型映射 | |
| initSourceTypeMap(); | |
| } | |
| // 渲染统计数据 | |
| function renderStats() { | |
| const statsGrid = document.getElementById('stats-grid'); | |
| statsGrid.innerHTML = ''; | |
| siteConfig.stats.forEach(stat => { | |
| let _class = '' | |
| if (stat.label == "更新时间") { | |
| _class = 'mini' | |
| } | |
| const statItem = document.createElement('div'); | |
| statItem.className = 'stat-item'; | |
| statItem.innerHTML = ` | |
| <div class="stat-number ${_class}">${stat.number}</div> | |
| <div class="stat-label">${stat.label}</div> | |
| `; | |
| statsGrid.appendChild(statItem); | |
| }); | |
| } | |
| // 渲染卡片 | |
| function renderCards() { | |
| const cardsGrid = document.getElementById('cards-grid'); | |
| cardsGrid.innerHTML = ''; | |
| siteConfig.cards.forEach(cardConfig => { | |
| const card = document.createElement('div'); | |
| card.className = 'card'; | |
| let buttonHtml = ''; | |
| if (cardConfig.buttonText) { | |
| buttonHtml = ` | |
| <div class="source-type-actions"> | |
| <button class="copy-btn" onclick="copyToClipboard('${cardConfig.id}')">${cardConfig.buttonText}</button> | |
| </div> | |
| `; | |
| } | |
| card.innerHTML = ` | |
| <div class="card-header"> | |
| <div class="card-icon">${cardConfig.icon}</div> | |
| <h3 class="card-title">${cardConfig.title}</h3> | |
| </div> | |
| <p class="card-description">${cardConfig.description}</p> | |
| ${cardConfig.customContent || buttonHtml} | |
| `; | |
| cardsGrid.appendChild(card); | |
| }); | |
| } | |
| // 初始化源类型映射 | |
| function initSourceTypeMap() { | |
| sourceTypeMap.clear(); | |
| siteConfig.cards.forEach(card => { | |
| if (card.file) { | |
| sourceTypeMap.set(card.id, { | |
| file: card.file, | |
| name: card.title | |
| }); | |
| } | |
| }); | |
| } | |
| function copyToClipboard(sourceType) { | |
| const baseUrl = `$$baseUrl` | |
| const sourceConfig = sourceTypeMap.get(sourceType); | |
| if (!sourceConfig) { | |
| console.error('未知的源类型:', sourceType); | |
| return; | |
| } | |
| let sourceUrl = `${baseUrl}/${sourceConfig.file}`; | |
| if (Array.isArray(sourceConfig.file)) { | |
| sourceUrl = '' | |
| siteConfig.cards.forEach(item => { | |
| if (typeof item.file == 'string') { | |
| sourceUrl += `${baseUrl}/${item.file}\n` | |
| } | |
| }) | |
| } | |
| navigator.clipboard.writeText(sourceUrl).then(function () { | |
| showToast(`${sourceConfig.name}链接已复制!`); | |
| console.log('复制成功: ' + sourceUrl); | |
| }).catch(function (err) { | |
| // 如果现代API不可用,使用传统方法 | |
| const textArea = document.createElement('textarea'); | |
| textArea.value = sourceUrl; | |
| document.body.appendChild(textArea); | |
| textArea.select(); | |
| document.execCommand('copy'); | |
| document.body.removeChild(textArea); | |
| showToast(`${sourceConfig.name}链接已复制!`); | |
| console.log('复制成功 (fallback): ' + sourceUrl); | |
| }); | |
| } | |
| function showToast(message = '链接已复制到剪贴板!') { | |
| const toast = document.getElementById('toast'); | |
| toast.textContent = message; | |
| toast.classList.add('show'); | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // 添加一些动态效果 | |
| document.addEventListener('DOMContentLoaded', function () { | |
| // 初始化页面 | |
| initializePage(); | |
| // 为卡片添加进入动画 | |
| setTimeout(() => { | |
| const cards = document.querySelectorAll('.card'); | |
| cards.forEach((card, index) => { | |
| card.style.opacity = '0'; | |
| card.style.transform = 'translateY(30px)'; | |
| setTimeout(() => { | |
| card.style.transition = 'all 0.6s ease'; | |
| card.style.opacity = '1'; | |
| card.style.transform = 'translateY(0)'; | |
| }, index * 100); | |
| }); | |
| }, 100); | |
| // 数字动画效果 | |
| setTimeout(() => { | |
| const statNumbers = document.querySelectorAll('.stat-number'); | |
| statNumbers.forEach((stat, index) => { | |
| const statConfig = siteConfig.stats[index]; | |
| if (statConfig && statConfig.animation) { | |
| if (statConfig.animation.static) { | |
| stat.textContent = statConfig.number; | |
| } else { | |
| animateNumber(stat, 0, statConfig.animation.end, statConfig.animation.suffix); | |
| } | |
| } | |
| }); | |
| }, 200); | |
| }); | |
| function animateNumber(element, start, end, suffix) { | |
| const duration = 2000; | |
| const increment = (end - start) / (duration / 16); | |
| let current = start; | |
| const timer = setInterval(() => { | |
| current += increment; | |
| if (current >= end) { | |
| current = end; | |
| clearInterval(timer); | |
| } | |
| element.textContent = Math.floor(current) + suffix; | |
| }, 16); | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment