// ==UserScript==
// @name         富学宝典刷课
// @namespace    fxbd-ultimate-real-progress
// @version      12.7
// @description  首次进入多时机自动播+Video.js+真实进度+防暂停+关弹窗+考试；无静音
// @match        https://iedu.foxconn.com/*
// @match        https://viedu.foxconn.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(async function () {
  'use strict';

  if (window !== window.top) return;

  if (window.fxbdFinalLoaded) return;

  const fxbdBoot = () => {
    if (window.fxbdFinalLoaded) return;
    window.fxbdFinalLoaded = true;

  // 仅吞掉 play() 的 Promise 拒绝，避免控制台 Uncaught NotAllowedError（不改音量、不静音）
  (function installPlayRejectionGuard() {
    try {
      const proto = HTMLMediaElement.prototype;
      if (proto.fxbdPlayGuard) return;
      proto.fxbdPlayGuard = true;
      const orig = proto.play;
      proto.play = function () {
        try {
          const ret = orig.apply(this, arguments);
          if (ret && typeof ret.catch === 'function') {
            return ret.catch(() => undefined);
          }
          return ret;
        } catch (e) {
          return Promise.resolve(undefined);
        }
      };
    } catch (e) {}
  })();

  // ================== 全局配置 ==================
  let keepPlay = true;
  let autoNext = true;
  let pdfScrollSpeed = 200;
  let PAGE_INIT_PLAYED = false;

  let videoQuality = 'sd';
  let qualityLock = false;

  let EXAM_LOCK = {
    triggered: false,
    clicked: false,
    polling: false
  };

  const CONFIG = {
    delayMin: 200,
    delayMax: 400,
    passScore: 100
  };

  let isPaused = false;
  let isRunning = false;
  let lastReportedTime = 0;
  let fakeActivityTimer = null;

  // ---------- 自动播放增强（无静音逻辑）----------
  function installPlaybackUnlockListeners() {
    if (window.fxbdUnlockListeners) return;
    window.fxbdUnlockListeners = true;
    const onGesture = (ev) => {
      if (ev && ev.isTrusted === false) return;
      tryStartAllVideosPlay(true);
    };
    document.addEventListener('pointerdown', onGesture, { capture: true, passive: true });
    document.addEventListener('click', onGesture, { capture: true, passive: true });
  }

  function tryVideoJsPlay(video) {
    try {
      if (typeof videojs === 'function' && video && video.closest) {
        const root = video.closest('.video-js');
        if (root) {
          let pl = null;
          if (root.id && videojs.getPlayer) {
            try { pl = videojs.getPlayer(root.id); } catch (e) {}
          }
          if (!pl && videojs.players) {
            for (const k of Object.keys(videojs.players)) {
              const cand = videojs.players[k];
              try {
                if (cand && cand.el && typeof cand.el === 'function') {
                  const el = cand.el();
                  if (el && el.contains && (el === video || el.contains(video))) {
                    pl = cand;
                    break;
                  }
                }
              } catch (e) {}
            }
          }
          if (pl && typeof pl.play === 'function') {
            const r = pl.play();
            if (r && typeof r.catch === 'function') r.catch(() => {});
            return true;
          }
        }
      }
    } catch (e) {}
    try {
      if (window.player && typeof window.player.play === 'function') {
        const r = window.player.play();
        if (r && typeof r.catch === 'function') r.catch(() => {});
        return true;
      }
    } catch (e) {}
    return false;
  }

  function tryStartAllVideosPlay(fromGesture) {
    if (!keepPlay) return;
    document.querySelectorAll('video').forEach(v => {
      if (v.ended) return;
      tryVideoJsPlay(v);
      safePlay(v).catch(() => {});
    });
    if (fromGesture && !window.fxbdLoggedGesturePlay) {
      window.fxbdLoggedGesturePlay = true;
      try {
        addLog('检测到页面操作，已尝试播放（浏览器限制时请先点一次页面）');
      } catch (e) {}
    }
  }

  function startVideoDiscoveryObserver() {
    if (window.fxbdVideoObserver) return;
    const obs = new MutationObserver(() => {
      document.querySelectorAll('video').forEach(v => hookVideo(v));
    });
    obs.observe(document.documentElement, { childList: true, subtree: true });
    window.fxbdVideoObserver = obs;
  }

  // ================== 【在这里编辑注意事项】==================
  // 换行用 <br> ，直接增删改文字即可
  const noticeText = `
1. 脚本只在富学宝典对应域名生效，且模拟人工防检测<br>
2. 脚本功能包括，自动刷视频、pdf、以及自动考试答题，可多开刷课<br>
3. 本脚本可多开，打开后缩小放后台即可，不必个人操作<br>
4. 自动答题会本地缓存题库，首次随机作答，后续稳定满分<br>
5. 网络缓慢、休息弹窗、违规提示均会自动关闭<br>
6. 挂机期间无需人工干预，学完自动进考试、自动重考<br>
7. 次数限制的考试建议先用软件刷，如果失败就重修，题库会继承<br>
  `;
  // ==========================================================

  // ==============================================
  // 读取平台真实已播放时间
  // ==============================================
  function getRealPlayedSeconds() {
    try {
      const progressText = document.querySelector('.study-progress, .progress, .time')?.textContent || '';
      const timeMatch = progressText.match(/(\d+):(\d+)/);
      if (timeMatch) {
        const min = parseInt(timeMatch[1]) || 0;
        const sec = parseInt(timeMatch[2]) || 0;
        return min * 60 + sec;
      }

      const bar = document.querySelector('.progress-bar');
      const outer = bar?.parentElement;
      if (bar && outer) {
        const percent = bar.offsetWidth / outer.offsetWidth;
        const video = document.querySelector('video');
        if (video && video.duration) {
          return Math.floor(video.duration * percent);
        }
      }

      if (typeof studyLengthSecond === 'number') return studyLengthSecond;
      if (typeof watchedLength === 'number') return watchedLength;
      if (typeof playerPosition === 'number') return playerPosition;
    } catch (e) {}
    return 0;
  }

  // ==============================================
  // 自动关闭【网络缓慢】弹窗 ×
  // ==============================================
  function autoCloseSlowNetworkModal() {
    try {
      const closeBtn = document.querySelector('button.close[data-dismiss="modal"][aria-hidden="true"]');
      if (closeBtn && closeBtn.textContent.includes('×')) {
        closeBtn.click();
        console.log('✅ 已自动关闭网络缓慢弹窗');
      }
    } catch (e) {}
  }

  // ==============================================
  // 模拟真人活跃防检测
  // ==============================================
  function startHumanActivity() {
    clearInterval(fakeActivityTimer);
    fakeActivityTimer = setInterval(() => {
      try {
        document.dispatchEvent(new MouseEvent('mousemove', {
          clientX: Math.random() * 50 + 50,
          clientY: Math.random() * 50 + 50,
          bubbles: true
        }));
        window.dispatchEvent(new Event('focus'));
        document.dispatchEvent(new Event('scroll'));
      } catch (e) {}
    }, 3000);
  }

  // ==============================================
  // 阻止后台冻结
  // ==============================================
  function blockPageSuspend() {
    if (document.addEventListener) {
      document.addEventListener('visibilitychange', e => {
        if (document.hidden) e.stopImmediatePropagation();
      }, true);
      window.addEventListener('blur', e => e.stopImmediatePropagation(), true);
      document.addEventListener('blur', e => e.stopImmediatePropagation(), true);
      document.addEventListener('webkitvisibilitychange', e => e.stopImmediatePropagation(), true);
    }
  }

  // ==============================================
  // 按真实进度智能跳播
  // ==============================================
  function enableBackgroundVideoKeepAlive() {
    setInterval(() => {
      try {
        let video = document.querySelector('video');
        if (!video || !video.duration) return;

        video.disableRemotePlayback = true;
        video.playsInline = true;

        if (video.paused && !video.ended && keepPlay) {
          tryVideoJsPlay(video);
          safePlay(video).catch(() => {});
        }

        const realPlayed = getRealPlayedSeconds();
        if (realPlayed > 5 && video.currentTime < realPlayed - 2) {
          video.currentTime = realPlayed + 3;
        }
        if (video.currentTime < 3 && realPlayed > 30) {
          video.currentTime = realPlayed + 3;
        }
      } catch (e) {}
    }, 1000);
  }

  // ==============================================
  // 进度上报
  // ==============================================
  function reportPlayProgress() {
    try {
      const video = document.querySelector('video');
      if (!video || video.paused || video.ended) return;
      let now = Date.now() / 1000;
      if (now - lastReportedTime < 2.8) return;
      lastReportedTime = now;

      video.dispatchEvent(new Event('timeupdate'));
      video.dispatchEvent(new Event('playing'));
      if (typeof saveStudyRecord === 'function') saveStudyRecord();
    } catch (e) {}
  }

  // ================== 主循环 ==================
  function watchAll() {
    autoCloseSlowNetworkModal();
    document.querySelectorAll('video').forEach(v => hookVideo(v));
    autoClosePopup();

    const frames = document.querySelectorAll('iframe');
    frames.forEach(f => {
      try {
        const d = f.contentDocument;
        if (!d) return;
        const pdfRoot =
          d.getElementById('viewerContainer') ||
          d.getElementById('outerContainer') ||
          d.querySelector('.pdfViewer');
        if (pdfRoot) {
          autoOpenPdf(d);
          injectPdfScrollLogic(d);
        }
      } catch (e) {}
    });

    if (autoNext) {
      const cur = document.querySelector('.chapter dd.active');
      if (cur?.querySelector('.right')?.textContent.trim() === '已完成') {
        playNextChapter();
      }
    }
    autoStartExam();
  }

function applyVideoQuality() {
  if (qualityLock) return;
  try {
    const select = document.querySelector('.vjs-control select, select.vjs-resolution-selector');
    if (select) {
      select.value = videoQuality;
      if (window.resolutionChange) resolutionChange(videoQuality);
      else select.dispatchEvent(new Event('change'));
      qualityLock = true;
      setTimeout(()=>qualityLock=false, 2000);
    }
  } catch(e){}
}

function setVideoQuality(q){
  videoQuality=q; applyVideoQuality(); updatePanelUI();
}

/** 等 play() 的 Promise 结束后再切画质，避免 resolutionChange 换源打断 play 导致 AbortError */
function applyQualityWhenPlaySettled(playResult) {
  const run = () => {
    try { applyVideoQuality(); } catch (e) {}
  };
  if (playResult !== undefined && playResult !== null && typeof playResult.finally === 'function') {
    playResult.catch(() => {}).finally(() => setTimeout(run, 200));
  } else {
    setTimeout(run, 450);
  }
}

function safePlay(video){
  if(!video)return Promise.resolve();
  if(video.readyState<2){
    return new Promise(resolve => {
      let settled = false;
      const finish = (p) => {
        if (settled) return;
        settled = true;
        clearTimeout(tid);
        video.removeEventListener('canplay', onReady);
        video.removeEventListener('loadeddata', onReady);
        resolve(p);
      };
      const onReady = () => {
        let p;
        try { p = video.play(); } catch (e) { finish(undefined); return; }
        if (p && typeof p.catch === 'function') p.catch(() => {});
        finish(p);
      };
      const tid = setTimeout(() => finish(undefined), 12000);
      video.addEventListener('canplay', onReady);
      video.addEventListener('loadeddata', onReady);
    });
  }
  let p;
  try { p = video.play(); } catch (e) { return Promise.resolve(undefined); }
  if (p && typeof p.catch === 'function') p.catch(() => {});
  return Promise.resolve(p);
}

function hookVideo(video){
  if(video.dataset.hooked)return; video.dataset.hooked=1;
  video.addEventListener('loadedmetadata',()=>{
    setTimeout(applyVideoQuality, 1500);
  });
  const tryAutoplayOnce = () => {
    if (!keepPlay || video.ended) return;
    tryVideoJsPlay(video);
    safePlay(video).catch(() => {});
  };
  video.addEventListener('loadeddata', tryAutoplayOnce, { once: true });
  video.addEventListener('canplay', tryAutoplayOnce, { once: true });
  video.addEventListener('pause',()=>{
    if(keepPlay && !video.ended) safePlay(video).catch(()=>{});
  });
  video.addEventListener('ended',()=>{
    if(autoNext) setTimeout(playNextChapter,800);
  });
}

/** 首次进入课程页：播放器常晚于脚本，多段延时再 try play（无程序化点击、无刷新逻辑） */
function autoPlayOnPageLoad(){
  if(PAGE_INIT_PLAYED)return; PAGE_INIT_PLAYED=true;
  const delays = [600, 1800, 4000, 7000];
  delays.forEach((ms, idx) => {
    setTimeout(() => {
      const cur=document.querySelector('.chapter dd.active');
      if(!cur)return;
      if(cur.textContent.includes('已完成'))return;
      const video=document.querySelector('video');
      if(!video||!keepPlay)return;
      tryVideoJsPlay(video);
      safePlay(video).then(p => {
        if (idx === 0) applyQualityWhenPlaySettled(p);
      });
    }, ms);
  });
}

function playNextChapter(){
  try{
    const list=Array.from(document.querySelectorAll('.chapter dd'));
    const t=list.find(d=>!d.textContent.includes('已完成'));
    if(t){t.click(); setTimeout(()=>{
      const v=document.querySelector('video');
      if(v){
        tryVideoJsPlay(v);
        safePlay(v).then(p => applyQualityWhenPlaySettled(p));
      } else {
        applyQualityWhenPlaySettled(undefined);
      }
    },600);}
  }catch(e){}
}

function autoClosePopup(){
  document.querySelectorAll('div').forEach(el=>{
    const t=el.textContent||'';
    if(t.includes('禁止快进')||t.includes('操作频繁')||t.includes('休息')){
      const b=el.querySelector('.layui-layer-btn0');
      if(b)b.click();
    }
  });
}

function injectPdfScrollLogic(d){
  if(d.pdfScroll)return; d.pdfScroll=1;
  let dir=1;
  setInterval(()=>{
    const e=d.getElementById('viewerContainer');
    if(!e)return;
    const m=e.scrollHeight-e.clientHeight;
    const n=e.scrollTop;
    if(n>=m-30)dir=-1; if(n<=30)dir=1;
    e.scrollTop+=dir*pdfScrollSpeed;
  },50);
}

function autoOpenPdf(d){
  try{
    const w = d.defaultView;
    if (typeof d.palyfirstpdf === 'function') { d.palyfirstpdf(); return; }
    if (typeof d.playfirstpdf === 'function') { d.playfirstpdf(); return; }
    if (w) {
      if (typeof w.palyfirstpdf === 'function') { w.palyfirstpdf(); return; }
      if (typeof w.playfirstpdf === 'function') { w.playfirstpdf(); return; }
      if (typeof w.playFirstPdf === 'function') { w.playFirstPdf(); return; }
    }
  }catch(e){}
}

function safeClickExamButton(el){
  if(!el||EXAM_LOCK.clicked)return; EXAM_LOCK.clicked=1;
  if(typeof el.onclick=='function')el.onclick(); else el.click();
}

function autoStartExam(){
  if(EXAM_LOCK.triggered)return;
  const all=Array.from(document.querySelectorAll('.chapter dd'));
  if(all.every(d=>d.textContent.includes('已完成'))){
    EXAM_LOCK.triggered=1;
    setTimeout(()=>{
      const tab=document.querySelector('a[href="#exam"]');
      if(tab)tab.click();
      let c=0;
      const it=setInterval(()=>{
        c++; const b=document.querySelector('a.exam_link');
        if(b){clearInterval(it); safeClickExamButton(b);}
        if(c>30)clearInterval(it);
      },600);
    },1800);
  }
}

  // ================== 稳定自动答题逻辑 ==================
  function getBank() {
    return JSON.parse(localStorage.getItem('fxbdAnswers') || '{}');
  }
  function saveBank(bank) {
    localStorage.setItem('fxbdAnswers', JSON.stringify(bank));
  }
  function clearBank() {
    localStorage.removeItem('fxbdAnswers');
    addLog('🗑️ 答案库已清空');
  }

  function autoClickLayerConfirm() {
    setTimeout(() => {
      const btn = document.querySelector('.layui-layer-btn0');
      if (btn && /确定|确认|关闭/.test(btn.innerText)) {
        btn.click();
        addLog('✅ 自动点击确定');
      }
    }, 700);
  }

  function collectAnswers() {
    const questions = document.querySelectorAll('.question_warp');
    if (!questions.length) return;
    const bank = getBank();
    let count = 0;
    questions.forEach(q => {
      const titleEl = q.querySelector('h3');
      const ansEl = q.querySelector('.answer strong');
      if (!titleEl || !ansEl) return;
      const title = titleEl.innerText.trim().replace(/^\d+\./, '').trim();
      const ans = ansEl.innerText.trim();
      bank[title] = ans;
      count++;
    });
    saveBank(bank);
    if (count > 0) addLog(`✅ 已收集 ${count} 题正确答案`);
  }

  function randomAnswer(question) {
    const radios = question.querySelectorAll("input[type='radio']");
    if (radios.length > 0) {
      const i = Math.floor(Math.random() * radios.length);
      radios[i].click();
      return;
    }
    const cbs = question.querySelectorAll("input[type='checkbox']");
    if (cbs.length > 0) {
      const n = Math.floor(Math.random() * cbs.length) + 1;
      const arr = Array.from(cbs.keys()).sort(() => Math.random() - 0.5);
      for (let i = 0; i < n; i++) cbs[arr[i]].click();
    }
  }

  async function autoAnswer() {
    if (isRunning) return;
    isRunning = true;
    addLog(`📚 开始自动答题（及格线≥${CONFIG.passScore}分）`);

    const bank = getBank();
    const questions = document.querySelectorAll('.question_warp');
    let hasRandom = false;

    for (const q of questions) {
      if (isPaused) await new Promise(r => {
        const t = setInterval(() => { if (!isPaused) { clearInterval(t); r(); } }, 200);
      });
      await new Promise(r => setTimeout(r, Math.floor(Math.random() * (CONFIG.delayMax - CONFIG.delayMin + 1)) + CONFIG.delayMin));

      const titleEl = q.querySelector('h3');
      if (!titleEl) continue;
      const title = titleEl.innerText.trim().replace(/^\d+\./, '').trim();
      const ans = bank[title];
      let ok = false;

      if (ans) {
        const radios = q.querySelectorAll("input[type='radio']");
        for (const r of radios) {
          const t = r.parentElement?.innerText.trim() || '';
          if (t.includes(ans)) { r.click(); ok = true; break; }
        }
        const cbs = q.querySelectorAll("input[type='checkbox']");
        const arr = ans.split('');
        for (const cb of cbs) {
          const t = cb.parentElement?.innerText.trim() || '';
          for (const a of arr) {
            if (t.startsWith(a)) { cb.click(); ok = true; break; }
          }
        }
      }

      if (!ok) {
        randomAnswer(q);
        hasRandom = true;
      }
    }

    if (hasRandom) addLog('⚠️ 部分题目无答案，已随机填写');
    addLog('✅ 答题完毕，准备提交');
    isRunning = false;
    await new Promise(r => setTimeout(r, 1000));
    submitExam();
  }

  function submitExam() {
    const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('提交'));
    if (btn) {
      addLog('🚀 提交试卷');
      btn.click();
      autoClickLayerConfirm();
    }
  }

  function checkScoreAndRetry() {
    const resultEl = document.querySelector('.exam_result');
    if (!resultEl) return;
    const match = resultEl.innerText.match(/(\d+)分/);
    if (!match) return;
    const score = parseInt(match[1]);
    addLog(`📊 当前得分：${score} 分，要求≥${CONFIG.passScore}分`);

    if (score >= CONFIG.passScore) {
      addLog('🎉 及格，自动停止');
      return;
    }

    addLog('⚠️ 未及格，准备重考');
    setTimeout(() => {
      const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText.includes('再考一次'));
      if (btn) btn.click();
    }, 1500);
  }

  function autoDetectPassScore() {
    const info = document.querySelector('.info')?.textContent || '';
    const reg = /(\d+)\s*分\s*及格/;
    const m = info.match(reg);
    if (m) {
      CONFIG.passScore = parseInt(m[1]);
      addLog(`📄 自动识别及格线：${CONFIG.passScore} 分`);
      document.getElementById('passScoreInput').value = CONFIG.passScore;
    }
  }

  // 弹出帮助说明窗口
// 弹出帮助说明窗口（已调整大小：更宽、更高）
function showNoticeModal(){
    let modal = document.getElementById('fxbdNoticeModal');
    if(modal) return;
    modal = document.createElement('div');
    modal.id = 'fxbdNoticeModal';
    modal.style=`position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:1000000;display:flex;align-items:center;justify-content:center;`;
    modal.innerHTML=`
    <div style="width:auto;min-width:300px;max-width:600px;max-height:70vh;background:#111;border:1px solid #444;border-radius:12px;padding:20px;color:#fff;font-size:14px;line-height:1.8;overflow-y:auto;">
      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;border-bottom:1px solid #333;padding-bottom:10px;">
        <span style="font-weight:bold;font-size:16px;">📖 脚本使用说明</span>
        <span id="closeNotice" style="cursor:pointer;font-size:20px;">×</span>
      </div>
      <div style="color:#ddd;text-align:left;white-space:pre-line;">${noticeText}</div>
    </div>
    `;
    document.body.appendChild(modal);
    document.getElementById('closeNotice').onclick = ()=>modal.remove();
    modal.onclick = (e)=>{if(e.target===modal) modal.remove();};
}

  // ================== 面板UI ==================
const panel=document.createElement('div');
panel.innerHTML=`<style>#fxbdPanel{position:fixed; top:80px;right:12px;z-index:999999;background:#111;color:#fff;width:260px;border-radius:12px;overflow:hidden;font-size:13px;font-family:system-ui,Microsoft YaHei;border:1px solid #444;box-shadow:0 8px 24px #0006;}
.fx-head{display:flex;justify-content:space-between;padding:10px 12px;background:#0066cc;font-weight:bold;border-bottom:1px solid #004d99;align-items:center;}
.fx-head-right{display:flex;gap:10px;align-items:center;}
.help-icon{cursor:pointer;font-size:14px;background:#fff;color:#0066cc;width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:bold;}
.minmax{cursor:pointer;}
.fx-body{padding:12px;}.fx-line{margin:6px 0;display:flex;gap:6px;align-items:center;justify-content:space-between;}
.fx-btn{flex:1;padding:6px;border-radius:6px;border:none;background:#009955;color:white;cursor:pointer;}.fx-btn.off{background:#cc6600;}
.fx-log{height:110px;overflow-y:auto;background:#000;border-radius:8px;padding:8px;font-size:12px;line-height:1.4;border:1px solid #333;}
.fx-input{width:50px;padding:4px;background:#222;color:white;border:1px solid #444;border-radius:6px;text-align:center;}
.fx-select{flex:1;padding:4px;background:#222;color:white;border:1px solid #444;border-radius:6px;}
</style>
<div id="fxbdPanel">
<div class="fx-head">
  <span>富学宝典刷课☀️  -》使用说明</span>
  <div class="fx-head-right">
    <span class="help-icon" id="helpBtn">?</span>
    <span class="minmax">−</span>
  </div>
</div>
<div class="fx-body">
<div class="fx-line"><span>防暂停</span><button id="toggleKeep" class="fx-btn">开启</button></div>
<div class="fx-line"><span>自动下一集</span><button id="toggleNext" class="fx-btn">开启</button></div>
<div class="fx-line"><span>画质</span><select id="qualitySelect" class="fx-select"><option value="sd">标清</option><option value="hd">高清</option></select></div>
<div class="fx-line"><span>PDF速度</span><input type="number" id="pdfSpeed" class="fx-input" value="${pdfScrollSpeed}" min="1" max="500"></div>
<div class="fx-line"><span>及格线</span><input type="number" id="passScoreInput" class="fx-input" value="${CONFIG.passScore}"><button id="setPass" class="fx-btn">设置</button></div>
<div class="fx-line"><button id="startAnswer" class="fx-btn">开始答题</button><button id="pauseAnswer" class="fx-btn off">暂停</button></div>
<div class="fx-line"><button id="clearBank" class="fx-btn" style="background:#cc3333;">清空题库</button></div>
<div class="fx-log" id="fxLog"></div>
</div></div>`;
document.body.appendChild(panel);

// 绑定帮助图标点击
document.getElementById('helpBtn').onclick = showNoticeModal;

function addLog(text){
  const d=new Date(); const hh=d.getHours().toString().padStart(2,'0');
  const mm=d.getMinutes().toString().padStart(2,'0');
  const ss=d.getSeconds().toString().padStart(2,'0');
  const log=document.getElementById('fxLog');
  log.innerHTML=`[${hh}:${mm}:${ss}] ${text}<br/>`+log.innerHTML;
}

  installPlaybackUnlockListeners();
  startVideoDiscoveryObserver();
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden && keepPlay) tryStartAllVideosPlay(false);
  });

const minmax=panel.querySelector('.minmax');
const body=panel.querySelector('.fx-body');
minmax.onclick=()=>{
  body.style.display=body.style.display=='none'?'block':'none';
  minmax.textContent=body.style.display=='none'?'+':'−';
};

function updatePanelUI(){
  document.getElementById('toggleKeep').className='fx-btn '+(keepPlay?'':'off');
  document.getElementById('toggleKeep').textContent=keepPlay?'开启':'关闭';
  document.getElementById('toggleNext').className='fx-btn '+(autoNext?'':'off');
  document.getElementById('toggleNext').textContent=autoNext?'开启':'关闭';
  document.getElementById('qualitySelect').value=videoQuality;
}

document.getElementById('toggleKeep').onclick=()=>{keepPlay=!keepPlay; updatePanelUI();};
document.getElementById('toggleNext').onclick=()=>{autoNext=!autoNext; updatePanelUI();};
document.getElementById('qualitySelect').onchange=e=>{setVideoQuality(e.target.value);};
document.getElementById('pdfSpeed').oninput=e=>{pdfScrollSpeed=parseInt(e.target.value)||100;};
document.getElementById('setPass').onclick=()=>{
  const v=parseInt(document.getElementById('passScoreInput').value);
  if(!isNaN(v)&&v>0&&v<=100){CONFIG.passScore=v; addLog(`及格线设为 ${v} 分`);}
};
document.getElementById('startAnswer').onclick=()=>autoAnswer();
document.getElementById('pauseAnswer').onclick=()=>{isPaused=!isPaused; addLog(isPaused?'已暂停':'继续');};
document.getElementById('clearBank').onclick=()=>clearBank();

updatePanelUI();
addLog('脚本已加载 · 自动关弹窗');

  // ================== 启动所有任务 ==================
  setInterval(watchAll, 800);
  setInterval(reportPlayProgress, 1000);
  blockPageSuspend();
  startHumanActivity();
  enableBackgroundVideoKeepAlive();
  autoPlayOnPageLoad();
  autoDetectPassScore();

  setTimeout(()=>{
    if(document.querySelector('.answer')){collectAnswers(); checkScoreAndRetry();}
    if(document.querySelector('#examForm')){addLog('进入考试'); autoAnswer();}
  },1500);

  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', fxbdBoot, { once: true });
  } else {
    fxbdBoot();
  }

})();