// 全局变量 let videos = [ { "id": 1, "title": "透明なパレット (self cover)", "channel": "Aqu3ra", "views": "576,197", "uploadDate": "1 months ago", "duration": "3:03", "thumbnail": "img/cover/music-01.jpg", "category": "music", "type": "video" }, { "id": 2, "title": "【歌ってみた】Duvet / covered by ヰ世界情緒", "channel": "ヰ世界情緒 -Isekaijoucho-", "views": "721,627", "uploadDate": "5 days ago", "duration": "3:32", "thumbnail": "img/cover/music-02.jpg", "category": "music", "type": "video" }, { "id": 3, "title": "ヨルシカ 『 晴る 』 -文化祭2025-", "channel": "countben", "views": "142,561", "uploadDate": "2 months ago", "duration": "4:46", "thumbnail": "img/cover/music-03.jpg", "category": "music", "type": "video" }, { "id": 4, "title": "【Silent Witch沈默魔女的秘密】OST 主題曲「沈黙の魔女」bgm|Kitkit Lu COVER", "channel": "KitKit Lu", "views": "1,856,264", "uploadDate": "5 months ago", "duration": "2:39", "thumbnail": "img/cover/music-04.jpg", "category": "music", "type": "video" }, { "id": 5, "title": "I Can't Wait feat. GUMI", "channel": "d0tc0mmie", "views": "315,293", "uploadDate": "1 month ago", "duration": "1:35", "thumbnail": "img/cover/music-05.jpg", "category": "music", "type": "video" }, { "id": 6, "title": "MiSiDE: ZERO Update – Full Gameplay + Ending (Showcase)", "channel": "RUSH PLAY", "views": "900,156", "uploadDate": "4 weeks ago", "duration": "24:39", "thumbnail": "img/cover/game-06.jpg", "category": "game", "type": "video" }, { "id": 7, "title": "Minecraftの効果音でサイエンス", "channel": "gmailアカウント", "views": "651,192", "uploadDate": "11 months ago", "duration": "1:05", "thumbnail": "img/cover/game-07.jpg", "category": "game", "type": "video" }, { "id": 8, "title": "osu! NEEDS to Take Notes... (00PARTS World's 1st Clear)", "channel": "bmc", "views": "892,163", "uploadDate": "1 month ago", "duration": "8:21", "thumbnail": "img/cover/game-08.jpg", "category": "game", "type": "video" }, { "id": 9, "title": "ヨルシカ - 春泥棒(OFFICIAL VIDEO)", "channel": "ヨルシカ / n-buna Official", "views": "123,456,789", "uploadDate": "5 years ago", "duration": "4:17", "thumbnail": "img/cover/music-09.jpg", "category": "music", "type": "video" }, { "id": 10, "title": "YOASOBI「アイドル」Official Music Video", "channel": "YOASOBI Official", "views": "456,789,123", "uploadDate": "2 years ago", "duration": "3:33", "thumbnail": "img/cover/music-10.jpg", "category": "music", "type": "video" }, { "id": 11, "title": "花譜 - 不可解", "channel": "花譜 -KAF-", "views": "12,345,678", "uploadDate": "3 years ago", "duration": "4:05", "thumbnail": "img/cover/music-11.jpg", "category": "music", "type": "video" }, { "id": 12, "title": "ZUTOMAYO - STUDY ME", "channel": "ZUTOMAYO", "views": "23,456,789", "uploadDate": "1 year ago", "duration": "3:45", "thumbnail": "img/cover/music-12.jpg", "category": "music", "type": "video" }, { "id": 13, "title": "Eve - 廻廻奇譚", "channel": "Eve", "views": "89,123,456", "uploadDate": "4 years ago", "duration": "3:55", "thumbnail": "img/cover/music-13.jpg", "category": "music", "type": "video" }, { "id": 14, "title": "ClariS - コネクト", "channel": "ClariS Official", "views": "45,678,901", "uploadDate": "10 years ago", "duration": "4:30", "thumbnail": "img/cover/music-14.jpg", "category": "music", "type": "video" }, { "id": 15, "title": "米津玄師 Kenshi Yonezu - Lemon", "channel": "Kenshi Yonezu 米津玄師", "views": "96,539,145", "uploadDate": "7 years ago", "duration": "4:35", "thumbnail": "img/cover/music-15.jpg", "category": "music", "type": "video" }, { "id": 16, "title": "【初音ミク】 夜明けと蛍 【オリジナル】", "channel": "ヨルシカ / n-buna Official", "views": "27,749,534", "uploadDate": "8 years ago", "duration": "5:10", "thumbnail": "img/cover/music-16.jpg", "category": "music", "type": "video" }, { "id": 17, "title": "Empty old City - Buffer", "channel": "Empty old city", "views": "838,946", "uploadDate": "1 year ago", "duration": "3:18", "thumbnail": "img/cover/music-17.jpg", "category": "music", "type": "video" }, { "id": 18, "title": "I built Git for Minecraft for a hackathon and won", "channel": "MathRayyan", "views": "288,346", "uploadDate": "12 days ago", "duration": "5:13", "thumbnail": "img/cover/game-18.jpg", "category": "game", "type": "video" }, { "id": 19, "title": "怎麼讓遊戲越來越真?PBR貼圖是怎麼做到的?", "channel": "孫拓海Taku", "views": "25,364", "uploadDate": "3 weeks ago", "duration": "13:14", "thumbnail": "img/cover/game-19.jpg", "category": "game", "type": "video" }, { "id": 20, "title": "「空あくあ!」當さくな說出這句台詞時 全場都淚崩了....【結城さくな】【Vtuber中文/翻譯/精華】", "channel": "Dar烤肉!", "views": "116,498", "uploadDate": "7 days ago", "duration": "8:35", "thumbnail": "img/cover/game-20.jpg", "category": "game", "type": "video" }, { "id": 21, "title": "「明日方舟:终末地性能分析:二游画质巅峰?榨干手机!", "channel": "极客湾Geekerwan", "views": "51,649", "uploadDate": "10 days ago", "duration": "22:13", "thumbnail": "img/cover/tech-21.jpg", "category": "tech", "type": "video" }, { "id": 22, "title": "What GPU is the BEST for Linux Gaming?", "channel": "Linus Tech Tips", "views": "96,751", "uploadDate": "7 days ago", "duration": "10:55", "thumbnail": "img/cover/tech-22.jpg", "category": "tech", "type": "video" }, { "id": 23, "title": "How Hard Is It to Build Your First PC?", "channel": "PLACITECH", "views": "4,351", "uploadDate": "2 months ago", "duration": "12:47", "thumbnail": "img/cover/tech-23.jpg", "category": "tech", "type": "video" }, { "id": 24, "title": "回顾我们最中意的 2025 年产品发布 - 谷歌开发者新闻(年终特辑)", "channel": "Google for Developers", "views": "3,475", "uploadDate": "1 month ago", "duration": "6:39", "thumbnail": "img/cover/tech-24.jpg", "category": "tech", "type": "video" }, { "id": 25, "title": "Commodore 128 Alternate Universe", "channel": "The 8-Bit Guy", "views": "17,498", "uploadDate": "4 months ago", "duration": "8:35", "thumbnail": "img/cover/tech-25.jpg", "category": "tech", "type": "video" }, { "id": 25, "title": "Commodore 128 Alternate Universe", "channel": "The 8-Bit Guy", "views": "17,498", "uploadDate": "4 months ago", "duration": "8:35", "thumbnail": "img/cover/tech-25.jpg", "category": "tech", "type": "video" }, { "id": 25, "title": "Commodore 128 Alternate Universe", "channel": "The 8-Bit Guy", "views": "17,498", "uploadDate": "4 months ago", "duration": "8:35", "thumbnail": "img/cover/tech-25.jpg", "category": "tech", "type": "video" }, { "id": 26, "title": "\"The Roller Coaster\" - Behind the Scenes - Time Lapse & Commentary", "channel": "AlanBeckerTutorials", "views": "193,762", "uploadDate": "7 years ago", "duration": "14:52", "thumbnail": "img/cover/art-26.jpg", "category": "art", "type": "video" }, { "id": 27, "title": "Animation vs. Game Design", "channel": "Alan Backer", "views": "694,264", "uploadDate": "2 months ago", "duration": "3:12", "thumbnail": "img/cover/art-27.jpg", "category": "art", "type": "video" }, { "id": 28, "title": "The Far Lands - Animation vs. Minecraft Shorts Ep 38", "channel": "Alan Backer", "views": "975,192", "uploadDate": "1 month ago", "duration": "9:10", "thumbnail": "img/cover/art-28.jpg", "category": "art", "type": "video" }, { "id": 29, "title": "【Official MV】ray 超かぐや姫!Version/かぐや (cv.夏吉ゆうこ) & 月見ヤチヨ (cv.早見沙織) from #超かぐや姫 !【新作アニメーション】", "channel": "", "views": "78,192", "uploadDate": "5 days ago", "duration": "", "thumbnail": "img/cover/music-29.jpg", "category": "music", "type": "short" }, { "id": 30, "title": "ドッペルゲンガー feat.初音ミク#vocaloid #初音ミク", "channel": "", "views": "2,359", "uploadDate": "3 days ago", "duration": "", "thumbnail": "img/cover/music-30.jpg", "category": "music", "type": "short" }, { "id": 31, "title": "Melt CPK! Remix — English Subtitled Version", "channel": "", "views": "2,264", "uploadDate": "3 days ago", "duration": "", "thumbnail": "img/cover/music-31.jpg", "category": "music", "type": "short" }, { "id": 32, "title": "【Suite History】花譜×#KTちゃん「ギミギミ逃避行feat. #KTちゃん(Prod. peko)」 #花譜 #KTちゃん #組曲 #shorts", "channel": "", "views": "5,430", "uploadDate": "2 days ago", "duration": "", "thumbnail": "img/cover/music-32.jpg", "category": "music", "type": "short" }, { "id": 33, "title": "ヨルシカ - プレイシック #ヨルシカ #プレイシック #二人称 #yorushika #playsick #secondperson", "channel": "", "views": "39,254", "uploadDate": "10 days ago", "duration": "", "thumbnail": "img/cover/music-33.jpg", "category": "music", "type": "short" }, { "id": 34, "title": "#ヨルシカ #live #前世 #yorushika", "channel": "", "views": "36,181", "uploadDate": "1 month ago", "duration": "", "thumbnail": "img/cover/music-34.jpg", "category": "music", "type": "short" }, { "id": 35, "title": "【歌ってみた】蜜月アン・ドゥ・トロワ covered by ヰ世界情緒 #shorts", "channel": "", "views": "2,163", "uploadDate": "6 days ago", "duration": "", "thumbnail": "img/cover/music-35.jpg", "category": "music", "type": "short" }, { "id": 36, "title": "Thank you 2025🩵Have a wonderful new year! #YOASOBI_2025", "channel": "", "views": "36,165", "uploadDate": "20 days ago", "duration": "", "thumbnail": "img/cover/music-36.jpg", "category": "music", "type": "short" }, { "id": 37, "title": "初めてラブソングを書きました。新曲「ハートマーク feat.川谷絵音」#礼衣 #ハートマーク", "channel": "", "views": "2,609", "uploadDate": "3 days ago", "duration": "", "thumbnail": "img/cover/music-37.jpg", "category": "music", "type": "short" }, { "id": 38, "title": "Would you play this at the school talent show for $500? #osu #osugame", "channel": "", "views": "133,658", "uploadDate": "2 months ago", "duration": "", "thumbnail": "img/cover/game-38.jpg", "category": "game", "type": "short" }, { "id": 39, "title": "May your holidays be filled with great vibes, full combos, and lots of epic tracks! 🎵", "channel": "", "views": "1,658", "uploadDate": "1 months ago", "duration": "", "thumbnail": "img/cover/game-39.jpg", "category": "game", "type": "short" }, { "id": 40, "title": "PANDORA PARADOXXX RE:MASTER alternative spin method #maimai #maimaiでらっくす #maimai_dx", "channel": "", "views": "25,365", "uploadDate": "12 days ago", "duration": "", "thumbnail": "img/cover/game-40.jpg", "category": "game", "type": "short" }, { "id": 41, "title": "Arch Linux VS Debian in 1 Min #linux #arch #debian", "channel": "", "views": "3,565", "uploadDate": "11 days ago", "duration": "", "thumbnail": "img/cover/tech-41.jpg", "category": "tech", "type": "short" }, { "id": 42, "title": "#linux #homelab #opensource #tech #debian", "channel": "", "views": "7,925", "uploadDate": "10 days ago", "duration": "", "thumbnail": "img/cover/tech-42.jpg", "category": "tech", "type": "short" }, { "id": 43, "title": "The one key keyboard #tech", "channel": "", "views": "4,571", "uploadDate": "1 month ago", "duration": "", "thumbnail": "img/cover/tech-43.jpg", "category": "tech", "type": "short" }, ]; let currentCategory = 'All'; // DOM 元素 const searchInput = document.querySelector('.search-input'); const searchBtn = document.querySelector('.search-btn'); const searchResults = document.querySelector('.search-results'); const searchResultsContent = document.querySelector('.search-results-content'); const videoGrid = document.querySelector('.video-grid'); const shortsGrid = document.querySelector('.shorts-grid'); const categoryBtns = document.querySelectorAll('.category-btn'); const subscriptionsList = document.querySelector('.subscriptions-list'); async function init() { await loadVideos(); renderVideos(); renderShorts(); renderSubscriptions(); bindEvents(); } async function loadVideos() { return Promise.resolve(); // Already defined in global scope } function renderVideos() { const filteredVideos = filterVideosByCategory(currentCategory); videoGrid.innerHTML = ''; filteredVideos.forEach(video => { if (video.type === 'video') { const videoCard = createVideoCard(video); videoGrid.appendChild(videoCard); } }); } function renderShorts() { const filteredVideos = filterVideosByCategory(currentCategory); shortsGrid.innerHTML = ''; filteredVideos.forEach(video => { if (video.type === 'short') { const shortsCard = createShortsCard(video); shortsGrid.appendChild(shortsCard); } }); } function filterVideosByCategory(category) { if (category === 'All') { return videos; } const categoryMap = { 'Music': ['music'], 'Game': ['game'], 'Technology': ['tech'], 'Art': ['art'], 'Recently': videos.filter(v => v.uploadDate.includes('days ago')), 'Watched': [] }; if (categoryMap[category]) { if (Array.isArray(categoryMap[category]) && categoryMap[category].length > 0 && typeof categoryMap[category][0] === 'string') { return videos.filter(v => categoryMap[category].includes(v.category)); } else if (Array.isArray(categoryMap[category])) { return categoryMap[category]; } } return videos; } function createVideoCard(video) { const card = document.createElement('div'); card.className = 'video-card'; card.innerHTML = `
No videos found related to your search.
'; searchResults.style.display = 'block'; return; } results.forEach(video => { const item = document.createElement('div'); item.className = 'search-result-item'; // Highlight the search keywords in the title and channel name const highlightedTitle = video.title.replace(new RegExp(`(${query})`, 'gi'), '$1'); const highlightedChannel = video.channel.replace(new RegExp(`(${query})`, 'gi'), '$1'); item.innerHTML = `