Greasy Fork is available in English.

学习通刷课助手-自动静音,防止鼠标移出暂停,章节结束自动跳转下一节

学习通课程自动挂机,当前脚本支持课程视频播放完成,自动跳转下一小节,章节测试自动跳过,后台播放防止视频暂停。

// ==UserScript==
// @name         学习通刷课助手-自动静音,防止鼠标移出暂停,章节结束自动跳转下一节
// @namespace    http://tampermonkey.net/
// @version      0.0.13
// @description  学习通课程自动挂机,当前脚本支持课程视频播放完成,自动跳转下一小节,章节测试自动跳过,后台播放防止视频暂停。
// @author       Sweek
// @match        *://*.chaoxing.com/*
// @license      GPLv3
// @icon         https://www.google.com/s2/favicons?sz=64&domain=csdn.net
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://code.jquery.com/jquery-2.1.4.min.js
// ==/UserScript==


// 定义全局变量
let currentTime = null // 当前视频当前播放节点
let duration = null // 当前视频总长度
let progress = null // 当前视频播放进度
let playbackRate = 1 // 当前视频播放倍速

// 课程章节相关数据
let courseName = null // 当前课程名称
let courseId = null // 当前课程id
let chapterInfo = [] // 当前课程所有章节数据
let currentChapterId = null // 当前所在章节id
let currentChapterName = null // 当前所在章节名称
let allChapterName = []  // 所有章节名称
let currentChapterTabArr = [] // 当前页面所有的分栏
let currentChapterTabName = '' // 当前页面激活的分栏名称
let videoProgressId = '' // 定时监听页面内容监听事件

// 获取当前页面的 URL
url = ''
chapterId = ''


// 页面模板部分
// 页面模板部分
// 页面模板部分

// 页面样式
var popCSs = `
#my-window {
    position: fixed;
    top: 5px;
    left: 20px;
    width: 300px;
    height: auto;
    background-color: rgba(247, 247, 247, 1);
    border: 1px solid #fff;
    border-radius: 5px;
    z-index: 9999;
    overflow: hidden;
  }
  
  #my-window .header {
    background-color: #4497fa;
    color: #fff;
    padding: 5px;
    font-size: 16px;
    font-family: 'fangsong';
    font-weight: bold;
    border-radius: 5px;
    cursor: move;
    height: 25px;
    width: 300px;
  }

  #my-window .content {
    width: 300px;
    height: 570px;
  }

  #my-window .content .content-title {
    height: 22px;
    width: 280px;
    background-color: #dadada;
    line-height: 22px;
    padding-left: 5px;
    font-size: 12px;
    font-family: 'fangsong';
    font-weight: 600;
    boder-radius: 5px;
    border-left: 4px solid #2196f3;
    border-right: 4px solid #dadada;
    margin-top: 5px;
  }

  #my-window .content .content-notice {
    height: 80px;
    width: 280px;
    overflow: auto;
    border: 1px solid gray;
    border-radius: 5px;
    padding: 5px;
    margin-top: 5px;
  }

  #my-window .content .content-process {
    height: 60px;
    width: 280px;
    overflow: auto;
    border: 1px solid gray;
    border-radius: 5px;
    padding: 5px;
    margin-top: 5px;
  }

  #my-window .content .content-log {
    height: 120px;
    width: 280px;
    overflow: auto;
    border: 1px solid gray;
    border-radius: 5px;
    padding: 5px;
    margin-top: 5px;
  }
  
  #my-window .content .content-set {
    height: 130px;
    width: 280px;
    overflow: auto;
    border: 1px solid gray;
    border-radius: 5px;
    padding: 5px;
    margin-top: 5px;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
  }

  #my-window .content .content-set .content-set-content {
    width: 280px;
    display: flex;
    justify-content: space-between;
  }

  #my-window .content .content-set .content-set-content #email-input {
    width: 200px;
    border-radius: 5px;
    border: 1px solid gray;
  }


  #my-window .content .content-set #save-btn {
    color: gray;
    width: 100%;
    margin-top: 10px;
    border-radius: 5px;
    border: 1px solid gray;
  }

  #save-btn:hover {
    background-color: #e3e3e3!important;
  }

  #my-window .resizer {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 20px;
    height: 20px;
    background-color: #2196f3;
    cursor: se-resize;
    border-radius: 0px;
    z-index: 1;
  }
  
  #hide-btn {
    height: 25px;
    width: auto;
    float: right;
    margin-right: 10px;
    background-color: #fff;
    border: 1px solid gray;
    border-radius: 5px;
    font-size: 12px;
    padding: 0 5px;
    font-family: 'fangsong';
  }

  #hide-btn:active {
    background-color: #4497fa;
  }
`

// 页面Html
var popHtml = `
<div class="header">学习通助手
  <button id="hide-btn">显示/隐藏</button>
</div>
<div class="content" id="my-window-content">
  <div class="resizer" style="display: none;"></div>
  <div class="row" style="border: 1px solid #ccc; padding: 5px;">
    <div class="content-title">公告</div>
    <div class="content-notice" id="content-notice">
    </div>
    <div class="content-title">播放进度</div>
    <div class="content-process" id="content-process"></div>
    <div class="content-title">执行日志</div>
    <div class="content-log" id="content-log"></div>
    <div class="content-title">配置</div>
    <div class="content-set" id="content-set">        
    <div>该邮箱地址用来登录app网站,该邮箱需要和网站注册邮箱保持一致,不可为空,填写完,点击保存,可在网站查看课程进度,二维码:
      <a style="color: dodgerblue;cursor: pointer;" id="Qcode">点击查看,微信扫码</a>
    </div>
      <div class="content-set-content">
        <label for="email-input">邮箱:</label>
        <input type="email" id="email-input" placeholder="请输入邮箱地址">
      </div>
      <button id="save-btn">保存</button>
    </div>
  </div>
</div>
`

// 执行方法部分
// 执行方法部分
// 执行方法部分
function takeEmail() {
  // 获取邮箱输入框和保存按钮
  const emailInput = document.getElementById("email-input");
  const saveBtn = document.getElementById("save-btn");

  // 当保存按钮被点击时
  saveBtn.addEventListener("click", function() {
    // 获取输入的邮箱地址
    const email = emailInput.value.trim();
    console.log('emailInput.value:::+ ', emailInput.value)
    // 检查邮箱地址是否有效
    if (!isValidEmail(email)) {
      notify('请输入有效的邮箱地址!', 2500)
      return;
    }
    
    const url = 'https://www.sweek.online/api/checkEmailExists';
    const data = { 
      email
    };
    if(email) {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON
        },
        body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体
      }).then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json(); // 解析 JSON 响应数据
      }).then(data => {
        // console.log('Response:', data);
        console.log('data:::+ ', data)
        if(data.exists){
          // 将邮箱地址存储到本地存储中
          GM_setValue("savedEmail", email);
          // 提示保存成功
          notify('保存成功!课程信息将同步到该邮箱账号', 2500)
        } else {
          notify('邮箱账号尚未注册,请扫码前往留言信箱网站注册', 2500)
        }
      }).catch(error => {
        console.error('Error:', error);
      });
    }

  });

  // 页面加载时,尝试从本地存储中获取已保存的邮箱地址并反显到输入框中
  const savedEmail = GM_getValue("savedEmail");
  if (savedEmail) {
    console.log('savedEmail:::+ ', savedEmail)
    emailInput.value = savedEmail;
  }
}

// 邮箱地址验证函数
function isValidEmail(email) {
  // 此处可以使用正则表达式等方式进行邮箱地址的验证
  // 这里简单地判断邮箱是否包含 '@' 符号
  return email.includes("@");
}

// 开始播放视频
function startVideo() {
  setTimeout(function() {
    if(location.pathname === '/ananas/modules/video/index.html') {
      var video = document.querySelector('video');
      if (video) {
        video.volume = 0; // 将声音调节至0
        addlog('已将视频声音调至0')
        addlog('当前视频倍速为' + video.playbackRate)
        if (video) {
          // video.play();
          const startBtn = document.querySelector('.vjs-big-play-button')
          // console.log('startBtn:::+ ', startBtn)
          startBtn.click()
          addlog('视频开始播放')
        }
      }
    }
  }, 2000);
}

// 获取视频播放进度-定时监听页面内容进行下一步处理
function getVideoProgress() {
  // 同步课程进度
  if(location.pathname == '/mycourse/studentstudy') {
    const emailInput = document.getElementById("email-input");
    const email = emailInput.value.trim();
    const url = 'https://www.sweek.online/api/checkEmailExists';
    const data = { 
      email
    };
    if(email) {
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON
        },
        body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体
      }).then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json(); // 解析 JSON 响应数据
      }).then(data => {
        // console.log('Response:', data);
        // console.log('data:::+ ', data)
        if(data.exists){  
          syncCourseData()
        } else {
          addlog('同步课程信息失败,该邮箱尚未注册')
        }
      }).catch(error => {
        console.error('Error:', error);
      });
    }

  }
  var video = null
  // console.log('location.pathname:::+ ', location.pathname)
  getSubChapter()
  // 学习目标模块显示时
  if(location.pathname === '/mycourse/studentstudy') {
    var studyModel = window.top.document.querySelector('#dct1')
    var ifStudyModel = studyModel.classList.contains('active') && studyModel.getAttribute('title') === '学习目标'
    if (ifStudyModel) {
      addlog('当前小节为学习目标,自动跳过')
      return toNextChapter()
    }
  }
  // 章节测试模块显示时
  if(location.pathname === '/ananas/modules/work/index.html') {
    addlog('当前小节为章节测试,自动跳过')
    return toNextChapter()
  } 
  // 章节小节模块显示时
  if(location.pathname === '/ananas/modules/questionnaire/index.html') {
    addlog('当前小节为章节小节,自动跳过')
    return toNextChapter()
  } 
  // 阅读模块显示时
  if (location.pathname === '/mooc-ans/coursedata/readjobv2/show') {
    addlog('当前小节为阅读,自动跳过')
    return toNextChapter()
  }
  // 调查问卷模块显示时
  if (location.pathname === '/ananas/modules/zt/vote/index-pc-new.html') {
    addlog('当前小节为调查问卷,课程已结束')
    // 清除定时器任务
    clearInterval(videoProgressId);
    addlog('脚本已终止')
    return toNextChapter()
  }  
  // 视频模块显示时
  if(location.pathname === '/ananas/modules/video/index.html') {
    video = document.querySelector('video');
    if (video) {
    }
  } else if (currentChapterTabName.length > 1 && currentChapterTabName.indexOf("视频") === -1) {
    if(location.pathname == '/mycourse/studentstudy') {
      // console.log('currentChapterTabName:::+ ', currentChapterTabName)
      addlog('当前小节为非视频内容:' + currentChapterTabName + ',自动跳过')
      return toNextChapter()
    }
  }
}

// 定时处理监听视频事件
function setIntervalStart() {
  if (location.pathname === '/ananas/modules/video/index.html') {
    let video = document.querySelector('video');
    let intervalId;

    function restartVideo() {
      if (video && video.paused && video.currentTime < video.duration) {
        // video.play(); // 重新开始播放
        const startBtn = document.querySelector('.vjs-big-play-button')
        // console.log('startBtn:::+ ', startBtn)
        startBtn.click()
      }
    }
    function goToNextChapter() {
      clearInterval(intervalId); // 清除定时器
      addlog('当前视频观看进度为100%,自动跳转到下一小节');
      toNextChapter();
    }
    function handleErrors() {
      clearInterval(intervalId); // 清除定时器
      addlog('遇到错误,页面将刷新');
      location.reload(); // 刷新页面
    }

    // 处理视频暂停
    video.addEventListener("pause", restartVideo);
    // 处理视频观看完成
    video.addEventListener("timeupdate", function() {
      let currentTime = video.currentTime; // 当前播放时间(以秒为单位)
      let duration = video.duration; // 视频总时长(以秒为单位)
      let progress = (currentTime / duration) * 100; // 计算播放进度百分比
      setVideoProcess(progress.toFixed(2) + '%', currentTime.toFixed(0), duration.toFixed(0)); // 设置视频播放进度显示
      // 如果播放进度大于等于100%,则跳转到下一章节
      if (progress >= 100) {
        goToNextChapter();
      }
    });
    // 定期检查视频是否出现错误
    intervalId = setInterval(function() {
      if (video.error) {
        handleErrors();
      }
    }, 10000); // 每秒检查一次
  }
}

// 跳转到下一章节 
function toNextChapter() {
  var nextButton = window.top.document.querySelector('#prevNextFocusNext');
  // console.log('nextButton:::+ ', nextButton)
  const nextChapter = window.top.document.querySelector('.nextChapter');
  if(nextChapter) {
      nextChapter.click()
      // console.log(nextChapter)
      return
  }
  if (nextButton) {
    nextButton.click();
  }
}

// 获取页面url
function getURLInfo() {
  if(location.pathname == '/mycourse/studentstudy') {
    url = location.href
    // console.log('url:::+ ', url)
    // 获取问号后面的部分
    var queryString = url.split('?')[1];
    // 将查询字符串拆分为参数对
    var queryParams = queryString.split('&');
    // 创建一个对象来存储参数
    var params = {};
    // 遍历参数对,将它们存储在对象中
    queryParams.forEach(function(queryParam) {
        var parts = queryParam.split('=');
        var key = decodeURIComponent(parts[0]);
        var value = decodeURIComponent(parts[1]);
        params[key] = value;
    });
    chapterId = params['chapterId']
    courseId = params['courseId']
    console.log('params:::+ ', params)
    GM_setValue("courseId", courseId);
  }
}

// 初始化添加页面弹窗以及悬浮球
function initPopup() {
  // 添加CSS样式
  GM_addStyle(popCSs);
  // 创建窗口元素
  const myWindow = document.createElement("div");
  myWindow.id = "my-window";
  myWindow.innerHTML = popHtml;
  // 获取页面body元素
  const body = document.getElementsByTagName("body")[0];
  // 添加窗口和悬浮球到页面
  body.appendChild(myWindow);
 // 绑定隐藏窗口按钮的click事件
 const hideBtn = document.querySelector("#hide-btn");
 hideBtn.addEventListener("click", hideWindow);
// 获取弹窗内容
var htmlContent = '<img src="https://www.sweek.online/api/preview/Qcode.png" alt="微信扫码">';

// 点击链接显示弹窗
document.getElementById('Qcode').addEventListener('click', function() {
  showCustomPopup(htmlContent, 500, 500);
});
 

// 获取头部元素
const header = myWindow.querySelector('.header');

// 处理移动事件
let isDragging = false;
let mouseX = 0;
let mouseY = 0;

header.addEventListener('mousedown', function (e) {
  e.preventDefault();
  isDragging = true;
  mouseX = e.clientX;
  mouseY = e.clientY;
});

document.addEventListener('mousemove', function (e) {
  if (isDragging) {
    const deltaX = e.clientX - mouseX;
    const deltaY = e.clientY - mouseY;
    const newLeft = Math.min(
      Math.max(0, myWindow.offsetLeft + deltaX),
      window.innerWidth - myWindow.offsetWidth
    );
    const newTop = Math.min(
      Math.max(0, myWindow.offsetTop + deltaY),
      window.innerHeight - myWindow.offsetHeight
    );
    myWindow.style.left = newLeft + 'px';
    myWindow.style.top = newTop + 'px';
    mouseX = e.clientX;
    mouseY = e.clientY;
  }
});

document.addEventListener('mouseup', function () {
  isDragging = false;
});

}

// 隐藏窗口函数
function hideWindow() {
  var myWindowContent = document.getElementById("my-window-content");
  var showPop = myWindowContent.style.display
  if (showPop == '' || showPop == 'block') {
    myWindowContent.style.display = "none";
  } else {
    myWindowContent.style.display = "block";
  }
}

// 获取当前页面章节小节的所有分栏
function getSubChapter() {
  try {
    if(location.pathname == '/mycourse/studentstudy') {
      var subChapter = window.top.document.querySelector('#prev_tab');
      if(subChapter) {
        currentChapterTabArr = subChapter.querySelectorAll('li');
        // console.log('currentChapterTabArr:::+ ', currentChapterTabArr)
        currentChapterTabArr.forEach(function(item) {
          if(item.className === 'active') {
            currentChapterTabName = item.innerText
          }
        })
      // console.log('currentChapterTabName:::+ ', currentChapterTabName)
      }
      
    }
  } catch (error) {
    console.error('An error occurred:', error);
    // location.reload(); // 刷新页面
  }
}

// 获取课程所有章节节点数据
function getChapterCodeInfo() {
  // console.log('location.pathname:::+ ', location.pathname)
  if(location.pathname === '/mooc-ans/knowledge/cards') {
    var chapter = window.top.document.querySelectorAll('.posCatalog_select')
    chapterInfo = chapter
    allChapterName=[]

    // console.log('chapterInfo:::+ ', chapterInfo)
    chapterInfo.forEach(function(item) {
      // console.log(item);
      allChapterName.push({
        id: item.id,
        title: item.innerText,
        active: item.classList.contains('posCatalog_active') ? 1 : 0,
        ifTitle: item.classList.contains('firstLayer') ? 1 : 0,
        status: item.childNodes[3]?.className == 'icon_Completed prevTips' ? 1 : 0
      })
      if (item.classList.contains('posCatalog_active')) {
        currentChapterId = item.id
        GM_setValue("currentChapterId", currentChapterId);
        currentChapterName = item.innerText
        GM_setValue("currentChapterName", currentChapterName);
      }
    });
    // console.log('allChapterName:::+ ', allChapterName)
    GM_setValue("chapterInfo", JSON.parse(JSON.stringify(allChapterName)));
    // console.log('currentChapterId:::+ ', currentChapterId)
    // console.log('currentChapterName:::+ ', currentChapterName)
    // console.log('allChapterName:::+ ', allChapterName)
    addlog('当前章节为' + currentChapterName, 'green')
  }
}

// 获取公告数据
function getBoard() {
  fetch('https://www.sweek.online/api/board')
  .then(response => response.json())
  .then(data => {
    // 在这里处理接收到的数据
    // console.log(data);
    var notice = document.querySelector('#content-notice');
    notice.innerHTML = data.text
  })
  .catch(error => {
    // 在这里处理错误
    console.error('Error:', error);
  });
}

// 同步课程数据至数据库
function syncCourseData() {
  const url = 'https://www.sweek.online/api/insertOrUpdateCourse';
  const email = GM_getValue("savedEmail")
  const course_name = GM_getValue("courseName")
  const current_chapter_id = GM_getValue("currentChapterId")
  const current_chapter_name = GM_getValue("currentChapterName")
  const course_id = GM_getValue("courseId")
  const process = document.querySelector('#content-process').innerHTML  
  const chapter_info = GM_getValue("chapterInfo")
  var chapter = window.top.document.querySelectorAll('.posCatalog_select')
  allChapterName = []
  chapter.forEach(function(item) {
    // console.log(item);
    allChapterName.push({
      id: item.id,
      title: item.innerText,
      active: item.classList.contains('posCatalog_active') ? 1 : 0,
      ifTitle: item.classList.contains('firstLayer') ? 1 : 0,
      status: item.childNodes[3]?.className == 'icon_Completed prevTips' ? 1 : 0
    })
    if (item.classList.contains('posCatalog_active')) {
      currentChapterId = item.id
      GM_setValue("currentChapterId", currentChapterId);
      currentChapterName = item.innerText
      GM_setValue("currentChapterName", currentChapterName);
    }
  });
  // console.log('chapter_info:::+ ', chapter_info)
  const data = { 
    email,
    course_id: course_id || '',
    course_name: course_name || '测试',
    chapter: JSON.stringify(allChapterName),
    current_chapter: current_chapter_id + ',' + current_chapter_name,
    process
  };
  if(process.includes("NaN")) {
    // console.log('视频播放异常,将发送邮件至邮箱' + email)
    console.log('视频播放异常,页面将刷新')
    location.reload(); // 刷新页面
    return
  }
  if(email && process) {
    fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON
      },
      body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体
    }).then(response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json(); // 解析 JSON 响应数据
    }).then(data => {
      // console.log('Response:', data);
      addlog('同步课程信息成功')
    }).catch(error => {
      console.error('Error:', error);
    });
  }
}

// 获取当前时间,年月日时分秒
function getCurrentDateTime() {
  var now = new Date();

  var year = now.getFullYear();
  var month = (now.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始,需要加1,并确保两位数格式
  var day = now.getDate().toString().padStart(2, '0'); // 确保两位数格式
  var hours = now.getHours().toString().padStart(2, '0'); // 确保两位数格式
  var minutes = now.getMinutes().toString().padStart(2, '0'); // 确保两位数格式
  var seconds = now.getSeconds().toString().padStart(2, '0'); // 确保两位数格式

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// 设置播放进度
function setVideoProcess(val1, val2, val3) {
  var _process = window.top.document.querySelector('#content-process');
  var _time = getCurrentDateTime()
  var newContent = '<p style="color: #000;">[' + _time + ']' + '</p><hr><p>' + '播放进度:' + val1 + '</p><hr><p>' + '视频长度:' + val2 + 's' + '/' +val3 + 's' + '</p>';
  _process.innerHTML = newContent;
}

// 页面弹窗显示
function showCustomPopup(htmlContent, width, height) {
  // 创建弹窗容器
  var popupContainer = document.createElement('div');
  popupContainer.className = 'custom-popup-container';
  // 设置弹窗容器样式
  popupContainer.style.position = 'fixed';
  popupContainer.style.top = '50px';
  popupContainer.style.left = '0';
  popupContainer.style.width = '100%';
  popupContainer.style.height = 'calc(100% - 50px)';
  popupContainer.style.display = 'flex';
  popupContainer.style.justifyContent = 'center';
  popupContainer.style.alignItems = 'center';
  popupContainer.style.zIndex = '999999';

  // 创建弹窗内容容器
  var popupContent = document.createElement('div');
  popupContent.className = 'custom-popup-content';
  // 设置弹窗内容样式
  popupContent.style.width = width + 'px';
  popupContent.style.height = height + 'px';
  popupContent.style.backgroundColor = '#fff';
  popupContent.style.border = '1px solid #ccc';
  popupContent.style.borderRadius = '5px';
  popupContent.style.position = 'relative';

  // 创建关闭按钮
  var closeButton = document.createElement('button');
  closeButton.innerHTML = '关闭';
  closeButton.style.position = 'absolute';
  closeButton.style.top = '5px';
  closeButton.style.right = '5px';
  closeButton.style.padding = '5px 10px';
  closeButton.style.backgroundColor = '#ccc';
  closeButton.style.border = 'none';
  closeButton.style.borderRadius = '3px';
  closeButton.style.cursor = 'pointer';
  closeButton.style.fontFamily = 'Arial, sans-serif';

  // 关闭按钮点击事件处理
  closeButton.addEventListener('click', function() {
    popupContainer.remove();
  });

  // 设置弹窗内容
  popupContent.innerHTML = htmlContent;

  // 将关闭按钮和弹窗内容添加到弹窗容器中
  popupContent.appendChild(closeButton);
  popupContainer.appendChild(popupContent);

  // 将弹窗容器添加到页面中
  document.body.appendChild(popupContainer);
}

// 页面通知提示
function notify(text, time) {
  // 创建通知元素
  var notification = document.createElement('div');
  notification.className = 'notification';
  // 设置通知内容
  notification.innerHTML = '<div class="notification-content"><h2 style="font-size: 16px;font-weight: bold;color: #307dff;font-family: fangsong;">' + '学习通助手提示' + '</h2><p style="font-family: fangsong;font-size: 13px;font-weight: bold;">' + text + '</p></div>';
  // 将通知添加到页面中
  document.body.appendChild(notification);
  // 设置通知样式
  notification.style.position = 'fixed';
  notification.style.top = '50px';
  notification.style.left = '-400px'; // 从左边弹出
  notification.style.transform = 'translateY(-50%)'; // 垂直居中
  notification.style.transition = 'left 0.5s ease-in-out'; // 添加过渡效果
  notification.style.zIndex = '999999';
  notification.style.backgroundColor = '#fff';
  notification.style.border = '1px solid #ccc';
  notification.style.padding = '10px';
  notification.style.borderRadius = '5px';
  notification.style.lineHeight = '25px';

  // 等待一小段时间后,移动通知到左边
  setTimeout(function() {
    notification.style.left = '20px'; // 移动到左边
  }, 100);

  // 设置定时器,在指定时间后移除通知
  setTimeout(function() {
    // 移动通知到左边以外
    notification.style.left = '-400px';
    // 等待过渡效果完成后,移除通知元素
    setTimeout(function() {
      notification.remove();
    }, 500);
  }, time);
}

// 添加执行日志
function addlog(str, color) {
  var _time = new Date().toLocaleTimeString()
  var contentLog = window.top.document.querySelector('.content-log');
  // console.log('contentLog:::+ ', contentLog)
  var newContent = '<p style="color: ' + color + ';">[' + _time + ']' + str + '</p><hr>';
  contentLog.innerHTML += newContent;
  // 将滚动条滚动到底部
  contentLog.scrollTop = contentLog.scrollHeight;
}

// 方法执行入口
(function () {
  // console.log('location.pathname:::+ ', location.pathname)
  // 进入学习通弹出提示
  if(location.pathname == '/base') {
    notify('已进入学习通首页,请进入课程,选择需要学习的课程', 5000)
  }
  // 进入课程弹出提示
  if(location.pathname == '/mooc2-ans/mycourse/stu') {   
    courseName = window.top.document.querySelector('.classDl .colorDeep').getAttribute('title')
    GM_setValue("courseName", courseName);
    notify('已进入课程:' + courseName + ',请选择需要学习的章节', 5000)
  }
  // 初始化显示页面弹窗
  if(location.pathname == '/mycourse/studentstudy') {
    initPopup()  
    // 获取公告数据
    getBoard()  
    // 邮箱操作
    takeEmail() 
  }
  // 获取页面章节节点数据
  getChapterCodeInfo()
  // 获取当前页面章节小节的所有分栏
  getSubChapter()
  // 获取页面url信息
  getURLInfo()
  // 开始播放视频
  startVideo()
  // 定时处理监听视频事件
  setTimeout(() => {
    setIntervalStart()
  }, 2000);
  // 定时打印视频播放进度-定时监听页面内容进行下一步处理
  videoProgressId = setInterval(() => {
    getVideoProgress()
  }, 10000);
})();