isididiidid commited on
Commit
51746f2
·
verified ·
1 Parent(s): fab9ca7

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +62 -162
index.js CHANGED
@@ -5,39 +5,39 @@ const http = require('http');
5
  const cron = require('node-cron');
6
  const port = process.env.PORT || 7860;
7
 
8
- // URLs to keep alive (24-hour visit cycle)
9
  const webpages = [
10
  'https://huggingface.co/spaces/isididiidid/Cursor-To-OpenAI', // Cursor-To-OpenAI
11
  'https://huggingface.co/spaces/isididiidid/cursor-ai-proxy', // cursor-ai-proxy
12
- 'https://huggingface.co/spaces/isididiidid/keep-alive-24h', // keep-alive service
13
  'https://isididiidid-getni.hf.space', // Gemini Balance
14
- 'https://isididiidid-gemini-balancre.hf.space', // Gemini Balance (short URL)
15
  'https://isididiidid-hajimi.hf.space' // Hajimi
16
  ];
17
 
18
- // Access logs for displaying detailed information
19
  const accessLogs = {};
20
 
21
- // Create HTTP server
22
  const createServer = () => {
23
  const server = http.createServer((req, res) => {
24
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
25
  res.end(generateStatusPage());
26
  });
27
  server.listen(port, () => {
28
- console.log(`Server started on port: ${port}`);
29
  });
30
  };
31
 
32
- // Calculate next execution time
33
  function getNextExecutionTime() {
34
  const now = moment().tz('Asia/Hong_Kong');
35
- // Calculate the next 24-hour point
36
  const nextExecution = moment().tz('Asia/Hong_Kong').add(24, 'hours').startOf('hour');
37
  return nextExecution.format('YYYY-MM-DD HH:mm:ss');
38
  }
39
 
40
- // Get server uptime
41
  let startTime = new Date();
42
  function getUptime() {
43
  const now = new Date();
@@ -48,26 +48,26 @@ function getUptime() {
48
  const minutes = Math.floor((uptimeMs % (60 * 60 * 1000)) / (60 * 1000));
49
  const seconds = Math.floor((uptimeMs % (60 * 1000)) / 1000);
50
 
51
- return `${days}d ${hours}h ${minutes}m ${seconds}s`;
52
  }
53
 
54
- // Generate HTML status page
55
  function generateStatusPage() {
56
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
57
- let lastCheckTime = "Never checked";
58
  if (Object.keys(accessLogs).length > 0) {
59
  lastCheckTime = Object.values(accessLogs).sort((a, b) => b.timestamp - a.timestamp)[0].time;
60
  }
61
 
62
- // Generate access record cards
63
  let webpageCards = '';
64
  for (const url of webpages) {
65
  const log = accessLogs[url];
66
- const status = log ? (log.status === 200 ? 'Success' : 'Failed') : 'Waiting';
67
  const statusClass = log ? (log.status === 200 ? 'success' : 'error') : 'waiting';
68
- const time = log ? log.time : 'Not checked yet';
69
 
70
- // Extract space name from URL
71
  let spaceName;
72
  if (url.includes('huggingface.co/spaces/')) {
73
  const shortUrl = url.replace(/https?:\/\/(www\.)?huggingface\.co\/spaces\//, '');
@@ -92,7 +92,7 @@ function generateStatusPage() {
92
  <span class="status-dot ${statusClass}"></span>
93
  <span class="status-text">${status}</span>
94
  </div>
95
- <p class="time">Last access: ${time}</p>
96
  </div>
97
  </div>
98
  `;
@@ -100,9 +100,9 @@ function generateStatusPage() {
100
 
101
  return `
102
  <!DOCTYPE html>
103
- <html lang="en" data-theme="light">
104
  <head>
105
- <title>HuggingFace Spaces Keep-Alive Service</title>
106
  <meta charset="utf-8">
107
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
  <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -367,7 +367,7 @@ function generateStatusPage() {
367
  gap: 0.5rem;
368
  }
369
 
370
- .language-switch, .theme-switch {
371
  background: var(--card-bg);
372
  border: 1px solid var(--border-color);
373
  border-radius: 0.5rem;
@@ -416,7 +416,7 @@ function generateStatusPage() {
416
  width: 100%;
417
  }
418
 
419
- .language-switch, .theme-switch {
420
  width: 100%;
421
  justify-content: center;
422
  }
@@ -427,10 +427,6 @@ function generateStatusPage() {
427
  <div class="container">
428
  <header class="header">
429
  <div class="controls">
430
- <div class="language-switch">
431
- <button class="control-btn" onclick="setLanguage('en')">EN</button>
432
- <button class="control-btn active" onclick="setLanguage('zh')">��文</button>
433
- </div>
434
  <div class="theme-switch">
435
  <button class="control-btn active" id="light-mode" onclick="setTheme('light')">
436
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -452,31 +448,31 @@ function generateStatusPage() {
452
  </button>
453
  </div>
454
  </div>
455
- <h1 id="title">HuggingFace Spaces Keep-Alive Service</h1>
456
- <p id="subtitle">Keep your HuggingFace Spaces applications online 24/7</p>
457
  <div class="status-badge">
458
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
459
  <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
460
  <polyline points="22 4 12 14.01 9 11.01"></polyline>
461
  </svg>
462
- <span id="status-text">Service Running</span>
463
  </div>
464
  </header>
465
  <div class="info-grid">
466
  <div class="info-card">
467
- <h3 id="current-time-label">Current Time</h3>
468
  <p id="current-time">${currentTime}</p>
469
  </div>
470
  <div class="info-card">
471
- <h3 id="last-check-label">Last Check</h3>
472
- <p id="last-check-value">${lastCheckTime}</p>
473
  </div>
474
  <div class="info-card">
475
- <h3 id="next-check-label">Next Check</h3>
476
- <p id="next-check-value">${getNextExecutionTime()}</p>
477
  </div>
478
  <div class="info-card">
479
- <h3 id="uptime-label">Uptime</h3>
480
  <p id="uptime">${getUptime()}</p>
481
  </div>
482
  </div>
@@ -484,109 +480,22 @@ function generateStatusPage() {
484
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
485
  <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
486
  </svg>
487
- <span id="monitoring-status">Monitoring Status</span>
488
  </h2>
489
  <div class="cards-grid">
490
  ${webpageCards}
491
  </div>
492
  </div>
493
  <footer class="footer">
494
- <p id="footer-text">HuggingFace Spaces Keep-Alive Service · Provided by isididiidid</p>
495
- <p>© ${new Date().getFullYear()} · Powered by Hugging Face Spaces</p>
496
  </footer>
497
  <script>
498
- // Language translations
499
- const translations = {
500
- en: {
501
- title: "HuggingFace Spaces Keep-Alive Service",
502
- subtitle: "Keep your HuggingFace Spaces applications online 24/7",
503
- statusText: "Service Running",
504
- currentTimeLabel: "Current Time",
505
- lastCheckLabel: "Last Check",
506
- nextCheckLabel: "Next Check",
507
- uptimeLabel: "Uptime",
508
- monitoringStatus: "Monitoring Status",
509
- footerText: "HuggingFace Spaces Keep-Alive Service · Provided by isididiidid",
510
- success: "Success",
511
- failed: "Failed",
512
- waiting: "Waiting",
513
- lastAccess: "Last access:",
514
- neverChecked: "Never checked",
515
- notCheckedYet: "Not checked yet"
516
- },
517
- zh: {
518
- title: "HuggingFace 空间保活服务",
519
- subtitle: "保持你的 HuggingFace Spaces 应用 24 小时在线",
520
- statusText: "服务运行中",
521
- currentTimeLabel: "当前时间",
522
- lastCheckLabel: "上次检查",
523
- nextCheckLabel: "下次检查",
524
- uptimeLabel: "运行时间",
525
- monitoringStatus: "监控状态",
526
- footerText: "HuggingFace 空间保活服务 · 由 isididiidid 提供",
527
- success: "成功",
528
- failed: "失败",
529
- waiting: "等待检查",
530
- lastAccess: "上次访问:",
531
- neverChecked: "从未检查",
532
- notCheckedYet: "尚未检查"
533
- }
534
- };
535
-
536
- // Set language
537
- function setLanguage(lang) {
538
- const t = translations[lang];
539
-
540
- // Update UI text
541
- document.getElementById('title').textContent = t.title;
542
- document.getElementById('subtitle').textContent = t.subtitle;
543
- document.getElementById('status-text').textContent = t.statusText;
544
- document.getElementById('current-time-label').textContent = t.currentTimeLabel;
545
- document.getElementById('last-check-label').textContent = t.lastCheckLabel;
546
- document.getElementById('next-check-label').textContent = t.nextCheckLabel;
547
- document.getElementById('uptime-label').textContent = t.uptimeLabel;
548
- document.getElementById('monitoring-status').textContent = t.monitoringStatus;
549
- document.getElementById('footer-text').textContent = t.footerText;
550
-
551
- // Update status text in cards
552
- document.querySelectorAll('.status-text').forEach(el => {
553
- if (el.textContent === 'Success' || el.textContent === '成功') el.textContent = t.success;
554
- else if (el.textContent === 'Failed' || el.textContent === '失败') el.textContent = t.failed;
555
- else if (el.textContent === 'Waiting' || el.textContent === '等待检查') el.textContent = t.waiting;
556
- });
557
-
558
- // Update time labels
559
- document.querySelectorAll('.time').forEach(el => {
560
- el.textContent = el.textContent.replace(/Last access:|上次访问:/, t.lastAccess);
561
- });
562
-
563
- // Update last check value
564
- const lastCheckEl = document.getElementById('last-check-value');
565
- if (lastCheckEl.textContent === 'Never checked' || lastCheckEl.textContent === '从未检查') {
566
- lastCheckEl.textContent = t.neverChecked;
567
- }
568
-
569
- // Update language buttons
570
- document.querySelectorAll('.language-switch .control-btn').forEach(btn => {
571
- btn.classList.remove('active');
572
- if ((btn.textContent === 'EN' && lang === 'en') ||
573
- (btn.textContent === '中文' && lang === 'zh')) {
574
- btn.classList.add('active');
575
- }
576
- });
577
-
578
- // Update uptime format based on language
579
- updateTime();
580
-
581
- // Store preference
582
- localStorage.setItem('preferred-language', lang);
583
- }
584
-
585
- // Set theme
586
  function setTheme(theme) {
587
  document.documentElement.setAttribute('data-theme', theme);
588
 
589
- // Update theme buttons
590
  document.querySelectorAll('.theme-switch .control-btn').forEach(btn => {
591
  btn.classList.remove('active');
592
  });
@@ -597,14 +506,14 @@ function generateStatusPage() {
597
  document.getElementById('dark-mode').classList.add('active');
598
  }
599
 
600
- // Store preference
601
  localStorage.setItem('preferred-theme', theme);
602
  }
603
 
604
- // Dynamic time update
605
  function updateTime() {
606
  const now = new Date();
607
- // Convert to Hong Kong time
608
  const options = {
609
  timeZone: 'Asia/Hong_Kong',
610
  year: 'numeric',
@@ -618,45 +527,35 @@ function generateStatusPage() {
618
 
619
  const formatter = new Intl.DateTimeFormat('zh-CN', options);
620
  let timeString = formatter.format(now);
621
- // Format as YYYY-MM-DD HH:mm:ss
622
  timeString = timeString.replace(/(\d{4})\/(\d{2})\/(\d{2})/, '$1-$2-$3');
623
 
624
  document.getElementById('current-time').textContent = timeString;
625
 
626
- // Update uptime
627
  const uptimeMs = now - ${startTime.getTime()};
628
  const days = Math.floor(uptimeMs / (24 * 60 * 60 * 1000));
629
  const hours = Math.floor((uptimeMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
630
  const minutes = Math.floor((uptimeMs % (60 * 60 * 1000)) / (60 * 1000));
631
  const seconds = Math.floor((uptimeMs % (60 * 1000)) / 1000);
632
 
633
- // Use the current language for display
634
- const lang = localStorage.getItem('preferred-language') || 'zh';
635
- if (lang === 'zh') {
636
- document.getElementById('uptime').textContent = days + '天 ' + hours + '小时 ' + minutes + '分 ' + seconds + '秒';
637
- } else {
638
- document.getElementById('uptime').textContent = days + 'd ' + hours + 'h ' + minutes + 'm ' + seconds + 's';
639
- }
640
  }
641
 
642
- // Load saved preferences or use defaults
643
  function loadPreferences() {
644
- // Load language preference
645
- const savedLang = localStorage.getItem('preferred-language') || 'zh';
646
- setLanguage(savedLang);
647
-
648
- // Load theme preference
649
  const savedTheme = localStorage.getItem('preferred-theme') || 'light';
650
  setTheme(savedTheme);
651
 
652
- // Check if system prefers dark mode
653
  if (!localStorage.getItem('preferred-theme') &&
654
  window.matchMedia &&
655
  window.matchMedia('(prefers-color-scheme: dark)').matches) {
656
  setTheme('dark');
657
  }
658
 
659
- // Listen for system theme changes
660
  if (window.matchMedia) {
661
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
662
  if (!localStorage.getItem('preferred-theme')) {
@@ -666,58 +565,59 @@ function generateStatusPage() {
666
  }
667
  }
668
 
669
- // Update time every second
670
  setInterval(updateTime, 1000);
671
 
672
- // Initialize
673
  loadPreferences();
674
- updateTime(); // Run immediately
675
  </script>
676
  </body>
677
  </html>
678
  `;
679
  }
680
 
681
- // Access function
682
  async function access(url) {
683
  try {
684
  const response = await axios.get(url);
685
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
686
  accessLogs[url] = { status: response.status, time: currentTime, timestamp: Date.now() };
687
- console.log(`${currentTime} Successfully accessed: ${url} - Status: ${response.status}`);
688
  } catch (error) {
689
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
690
  accessLogs[url] = { status: error.response ? error.response.status : 0, time: currentTime, timestamp: Date.now() };
691
- console.error(`${currentTime} Failed to access ${url}, Error: ${error.message}`);
692
  }
693
  }
694
 
695
- // Batch visit all URLs
696
  async function batchVisit() {
697
- console.log(`${moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss')} Starting 24-hour visit cycle...`);
698
  for (let url of webpages) {
699
  await access(url);
700
  }
701
  }
702
 
703
- // Restart function
704
  const restart = () => {
705
- console.log(`${moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss')} Server restarting...`);
706
- process.exit(1); // Exit process, Docker will automatically restart
707
  };
708
 
709
- // Start server
710
  createServer();
711
 
712
- // Schedule task: every 24 hours
713
  cron.schedule('0 0 */24 * * *', async () => {
714
- await batchVisit(); // Visit all URLs first
715
- restart(); // Then restart the service
716
  });
717
 
718
- // Run immediately on startup
719
  batchVisit().catch(console.error);
720
 
721
 
722
 
723
 
 
 
5
  const cron = require('node-cron');
6
  const port = process.env.PORT || 7860;
7
 
8
+ // 保活网址列表(24小时访问周期)
9
  const webpages = [
10
  'https://huggingface.co/spaces/isididiidid/Cursor-To-OpenAI', // Cursor-To-OpenAI
11
  'https://huggingface.co/spaces/isididiidid/cursor-ai-proxy', // cursor-ai-proxy
12
+ 'https://huggingface.co/spaces/isididiidid/keep-alive-24h', // 保活服务
13
  'https://isididiidid-getni.hf.space', // Gemini Balance
14
+ 'https://isididiidid-gemini-balancre.hf.space', // Gemini Balance (短网址)
15
  'https://isididiidid-hajimi.hf.space' // Hajimi
16
  ];
17
 
18
+ // 访问日志,用于显示详细信息
19
  const accessLogs = {};
20
 
21
+ // 创建HTTP服务器
22
  const createServer = () => {
23
  const server = http.createServer((req, res) => {
24
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
25
  res.end(generateStatusPage());
26
  });
27
  server.listen(port, () => {
28
+ console.log(`服务器启动,端口: ${port}`);
29
  });
30
  };
31
 
32
+ // 计算下次执行时间
33
  function getNextExecutionTime() {
34
  const now = moment().tz('Asia/Hong_Kong');
35
+ // 计算下一个24小时时间点
36
  const nextExecution = moment().tz('Asia/Hong_Kong').add(24, 'hours').startOf('hour');
37
  return nextExecution.format('YYYY-MM-DD HH:mm:ss');
38
  }
39
 
40
+ // 获取服务器运行时间
41
  let startTime = new Date();
42
  function getUptime() {
43
  const now = new Date();
 
48
  const minutes = Math.floor((uptimeMs % (60 * 60 * 1000)) / (60 * 1000));
49
  const seconds = Math.floor((uptimeMs % (60 * 1000)) / 1000);
50
 
51
+ return `${days} ${hours}小时 ${minutes} ${seconds}秒`;
52
  }
53
 
54
+ // 生成HTML状态页面
55
  function generateStatusPage() {
56
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
57
+ let lastCheckTime = "从未检查";
58
  if (Object.keys(accessLogs).length > 0) {
59
  lastCheckTime = Object.values(accessLogs).sort((a, b) => b.timestamp - a.timestamp)[0].time;
60
  }
61
 
62
+ // 生成访问记录卡片
63
  let webpageCards = '';
64
  for (const url of webpages) {
65
  const log = accessLogs[url];
66
+ const status = log ? (log.status === 200 ? '成功' : '失败') : '等待检查';
67
  const statusClass = log ? (log.status === 200 ? 'success' : 'error') : 'waiting';
68
+ const time = log ? log.time : '尚未检查';
69
 
70
+ // URL中提取空间名称
71
  let spaceName;
72
  if (url.includes('huggingface.co/spaces/')) {
73
  const shortUrl = url.replace(/https?:\/\/(www\.)?huggingface\.co\/spaces\//, '');
 
92
  <span class="status-dot ${statusClass}"></span>
93
  <span class="status-text">${status}</span>
94
  </div>
95
+ <p class="time">上次访问: ${time}</p>
96
  </div>
97
  </div>
98
  `;
 
100
 
101
  return `
102
  <!DOCTYPE html>
103
+ <html lang="zh" data-theme="light">
104
  <head>
105
+ <title>HuggingFace 空间保活服务</title>
106
  <meta charset="utf-8">
107
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
  <link rel="preconnect" href="https://fonts.googleapis.com">
 
367
  gap: 0.5rem;
368
  }
369
 
370
+ .theme-switch {
371
  background: var(--card-bg);
372
  border: 1px solid var(--border-color);
373
  border-radius: 0.5rem;
 
416
  width: 100%;
417
  }
418
 
419
+ .theme-switch {
420
  width: 100%;
421
  justify-content: center;
422
  }
 
427
  <div class="container">
428
  <header class="header">
429
  <div class="controls">
 
 
 
 
430
  <div class="theme-switch">
431
  <button class="control-btn active" id="light-mode" onclick="setTheme('light')">
432
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
 
448
  </button>
449
  </div>
450
  </div>
451
+ <h1>HuggingFace 空间保活服务</h1>
452
+ <p>保持你的 HuggingFace Spaces 应用 24 小时在线</p>
453
  <div class="status-badge">
454
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
455
  <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
456
  <polyline points="22 4 12 14.01 9 11.01"></polyline>
457
  </svg>
458
+ <span>服务运行中</span>
459
  </div>
460
  </header>
461
  <div class="info-grid">
462
  <div class="info-card">
463
+ <h3>当前时间</h3>
464
  <p id="current-time">${currentTime}</p>
465
  </div>
466
  <div class="info-card">
467
+ <h3>上次检查</h3>
468
+ <p>${lastCheckTime}</p>
469
  </div>
470
  <div class="info-card">
471
+ <h3>下次检查</h3>
472
+ <p>${getNextExecutionTime()}</p>
473
  </div>
474
  <div class="info-card">
475
+ <h3>运行时间</h3>
476
  <p id="uptime">${getUptime()}</p>
477
  </div>
478
  </div>
 
480
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
481
  <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
482
  </svg>
483
+ <span>监控状态</span>
484
  </h2>
485
  <div class="cards-grid">
486
  ${webpageCards}
487
  </div>
488
  </div>
489
  <footer class="footer">
490
+ <p>HuggingFace 空间保活服务 · isididiidid 提供</p>
491
+ <p>© ${new Date().getFullYear()} · 基于 Hugging Face Spaces</p>
492
  </footer>
493
  <script>
494
+ // 设置主题
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  function setTheme(theme) {
496
  document.documentElement.setAttribute('data-theme', theme);
497
 
498
+ // 更新主题按钮
499
  document.querySelectorAll('.theme-switch .control-btn').forEach(btn => {
500
  btn.classList.remove('active');
501
  });
 
506
  document.getElementById('dark-mode').classList.add('active');
507
  }
508
 
509
+ // 存储偏好设置
510
  localStorage.setItem('preferred-theme', theme);
511
  }
512
 
513
+ // 动态时间更新
514
  function updateTime() {
515
  const now = new Date();
516
+ // 转换为香港时间
517
  const options = {
518
  timeZone: 'Asia/Hong_Kong',
519
  year: 'numeric',
 
527
 
528
  const formatter = new Intl.DateTimeFormat('zh-CN', options);
529
  let timeString = formatter.format(now);
530
+ // 格式化为 YYYY-MM-DD HH:mm:ss
531
  timeString = timeString.replace(/(\d{4})\/(\d{2})\/(\d{2})/, '$1-$2-$3');
532
 
533
  document.getElementById('current-time').textContent = timeString;
534
 
535
+ // 更新运行时间
536
  const uptimeMs = now - ${startTime.getTime()};
537
  const days = Math.floor(uptimeMs / (24 * 60 * 60 * 1000));
538
  const hours = Math.floor((uptimeMs % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
539
  const minutes = Math.floor((uptimeMs % (60 * 60 * 1000)) / (60 * 1000));
540
  const seconds = Math.floor((uptimeMs % (60 * 1000)) / 1000);
541
 
542
+ document.getElementById('uptime').textContent = days + '天 ' + hours + '小时 ' + minutes + '分 ' + seconds + '秒';
 
 
 
 
 
 
543
  }
544
 
545
+ // 加载保存的偏好设置或使用默认值
546
  function loadPreferences() {
547
+ // 加载主题偏好设置
 
 
 
 
548
  const savedTheme = localStorage.getItem('preferred-theme') || 'light';
549
  setTheme(savedTheme);
550
 
551
+ // 检查系统是否偏好深色模式
552
  if (!localStorage.getItem('preferred-theme') &&
553
  window.matchMedia &&
554
  window.matchMedia('(prefers-color-scheme: dark)').matches) {
555
  setTheme('dark');
556
  }
557
 
558
+ // 监听系统主题变化
559
  if (window.matchMedia) {
560
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
561
  if (!localStorage.getItem('preferred-theme')) {
 
565
  }
566
  }
567
 
568
+ // 每秒更新时间
569
  setInterval(updateTime, 1000);
570
 
571
+ // 初始化
572
  loadPreferences();
573
+ updateTime(); // 立即运行
574
  </script>
575
  </body>
576
  </html>
577
  `;
578
  }
579
 
580
+ // 访问函数
581
  async function access(url) {
582
  try {
583
  const response = await axios.get(url);
584
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
585
  accessLogs[url] = { status: response.status, time: currentTime, timestamp: Date.now() };
586
+ console.log(`${currentTime} 成功访问: ${url} - 状态: ${response.status}`);
587
  } catch (error) {
588
  const currentTime = moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss');
589
  accessLogs[url] = { status: error.response ? error.response.status : 0, time: currentTime, timestamp: Date.now() };
590
+ console.error(`${currentTime} 访问失败 ${url}, 错误: ${error.message}`);
591
  }
592
  }
593
 
594
+ // 批量访问所有网址
595
  async function batchVisit() {
596
+ console.log(`${moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss')} 开始24小时访问周期...`);
597
  for (let url of webpages) {
598
  await access(url);
599
  }
600
  }
601
 
602
+ // 重启函数
603
  const restart = () => {
604
+ console.log(`${moment().tz('Asia/Hong_Kong').format('YYYY-MM-DD HH:mm:ss')} 服务器重启中...`);
605
+ process.exit(1); // 退出进程,Docker会自动重启
606
  };
607
 
608
+ // 启动服务器
609
  createServer();
610
 
611
+ // 定时任务:每24小时执行一次
612
  cron.schedule('0 0 */24 * * *', async () => {
613
+ await batchVisit(); // 先访问所有网址
614
+ restart(); // 然后重启服务
615
  });
616
 
617
+ // 启动时立即运行一次
618
  batchVisit().catch(console.error);
619
 
620
 
621
 
622
 
623
+