Greasy Fork

来自缓存

Greasy Fork is available in English.

北交大iCalender课表生成

导出ics/csv/json格式的日程文件! 💻支持多端同步! 📝支持Excel编辑! 📆支持导入各系统原生日历!

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         北交大iCalender课表生成
// @namespace    https://github.com/ZiuChen/userscript
// @version      1.5.1
// @description  导出ics/csv/json格式的日程文件! 💻支持多端同步! 📝支持Excel编辑! 📆支持导入各系统原生日历!
// @author       ZiuChen
// @match        https://aa.bjtu.edu.cn/course_selection/courseselect/stuschedule/*
// @match        https://aa.bjtu.edu.cn/course_selection/courseselecttask/schedule/
// @require      https://fastly.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require      https://fastly.jsdelivr.net/gh/nwcell/ics.js@dfec67f37a3c267b3f97dd229c9b6a3521222794/demo/ics.deps.min.js
// @icon         https://fastly.jsdelivr.net/gh/ZiuChen/ZiuChen@main/avatar.jpg
// @grant        none
// @license      MIT
// ==/UserScript==

"use strict"

const defaultStartMonday = "2022-08-29" // 第一个教学周的第一个周一

if (localStorage.getItem("defaultStartMonday") === null) {
  localStorage.setItem("defaultStartMonday", defaultStartMonday)
}

function buttonGenerate() {
  $(".widget-title").append(/* html */ `
        <button id="scheduleIcsGenerate" class="btn btn-white btn-xs">导出为ics文件</button>
        <button id="csvGenerate" class="btn btn-white btn-xs">导出为csv文件</button>
        <button id="jsonGenerate" class="btn btn-white btn-xs">导出为json文件</button>
        <button id="scheduleRedirect" title="点击跳转校历" class="btn btn-white btn-xs">校历</button>
        <input id="startMonday" class="form-control" type="text" placeholder="第一个教学周的第一个周一" title="第一个教学周的第一个周一" style="height: 26px;width: 200px;display: inline;vertical-align: middle;"></input>
        <button id="restoreSetting" title="点击重置设置" class="btn btn-white btn-xs">重置</button>
        `)
  bindEvents()
}

function bindEvents() {
  $("#scheduleRedirect").click(() => {
    window.open("https://bksy.bjtu.edu.cn/Semester.html")
  })
  let pageFlag = 0
  if (window.location.href.search("/courseselect/stuschedule/") != -1) {
    // 本学期课表
  } else if (window.location.href.search("/courseselecttask/schedule/") != -1) {
    // 选课课表
    pageFlag = 1
  }
  $("#scheduleIcsGenerate").click(() => {
    icsmain(pageFlag)
  })
  $("#csvGenerate").click(() => {
    csvmain(pageFlag)
  })
  $("#jsonGenerate").click(() => {
    jsonmain(pageFlag)
  })
  $("#restoreSetting").click(() => {
    localStorage.clear()
    location.reload()
  })
  $("#startMonday")
    .change((e) => {
      localStorage.setItem("defaultStartMonday", e.target.value)
    })
    .val(localStorage.getItem("defaultStartMonday"))
}

// generateWeekTable() @github ygowill
function generateWeekTable() {
  let startMondayString = $("#startMonday").val()
  if (validCheck(startMondayString) === false) return
  const startMonday = new Date(startMondayString)
  let weekDateTable = []
  for (let i = 0; i < 30; i++) {
    // 生成到30周
    let weekArr = []
    for (let j = 0; j < 7; j++) {
      let tmpDate = new Date(startMonday)
      tmpDate.setDate(tmpDate.getDate() + 7 * i + j)
      weekArr.push(tmpDate)
    }
    weekDateTable.push(weekArr)
  }
  return weekDateTable
}

function validCheck(startMondayString) {
  const re = new RegExp(/^\d{4}-\d{1,2}-\d{1,2}/)
  if (re.test(startMondayString) === false) {
    alert("输入日期值非法,请重新输入。")
    throw Error("输入日期值非法")
  } else {
    return true
  }
}

function tableTransfer(rowTable, isOrigin) {
  // 7*7行转列
  let tmpTable = []
  let columnTable = []
  for (let i = 0; i < 7; i++) {
    if (isOrigin) {
      for (let j = 0; j < 7; j++) {
        tmpTable.push(rowTable[j])
      }
    } else {
      for (let j = i; j < 49; j += 7) {
        tmpTable.push(rowTable[j])
      }
    }
    columnTable[i] = tmpTable
    tmpTable = []
  }
  return columnTable
}

function removeZero(iArr) {
  for (let i = 0; i < iArr.length; i++) {
    iArr[i] = parseInt(iArr[i], 10)
  }
  return iArr
}

function dateStr2Arr(dateStr) {
  let dateArr = []
  if (dateStr) {
    if (dateStr.indexOf("-") != -1) {
      // 第X-Y周
      let indexArr = dateStr.split("-")
      removeZero(indexArr)
      for (let i = indexArr[0]; i < indexArr[1] + 1; i++) {
        dateArr.push(i)
      }
    } else if (dateStr.indexOf(",") != -1) {
      // 单双周
      dateArr = dateStr.split(", ")
      removeZero(dateArr)
    } else dateArr.push(parseInt(dateStr, 10)) // 第X周
  }
  return dateArr
}

// courseList[x]示例:
// allInfo: "国际贸易实务模拟 第03-06周思源东楼 SD401卜伟"
// courseNum: 1
// date: (4) [3, 4, 5, 6]
// initInfo: "第03-06周"
// location: "思源东楼 SD401"
// name: "国际贸易实务模拟 "
// teacher: "卜伟"
// weekNum: 6

function stuScheduleGetTable(isOrigin) {
  let courseListTmp = tableTransfer($("tr>td[style!='height:80px;']"), isOrigin)
  let courseList = []
  let courseTmp = {}
  for (let i = 0; i < 7; i++) {
    for (let j = 0; j < 7; j++) {
      for (
        let k = 0;
        k < courseListTmp[i][j].querySelectorAll('span[style="color:#000"]').length;
        k++
      ) {
        courseTmp.weekNum = i + 1
        courseTmp.courseNum = j + 1
        if (courseListTmp[i][j].querySelectorAll('span[style="color:#000"]')[k]) {
          courseTmp.name = courseListTmp[i][j]
            .querySelectorAll('span[style="color:#000"]')
            [k].innerText.split("[本")[0]
          courseTmp.location = courseListTmp[i][j].querySelectorAll('span[class="text-muted"]')[
            k
          ].innerText
          let dateStr = courseListTmp[i][j].querySelectorAll('div[style="max-width:120px;"]')[k]
            .innerText
          dateStr = dateStr.substring(dateStr.indexOf("第") + 1, dateStr.indexOf("周")) // 预处理
          courseTmp.initInfo = "第" + dateStr + "周"
          courseTmp.date = dateStr2Arr(dateStr)
          courseTmp.teacher = courseListTmp[i][j].querySelectorAll("i")[k].innerText
          courseTmp.allInfo =
            courseTmp.name +
            " " +
            courseTmp.initInfo +
            " " +
            courseTmp.location +
            " " +
            courseTmp.teacher
          courseList.push(courseTmp)
          courseTmp = {}
        }
      }
    }
  }
  return courseList
}

function scheduleGetTable(isOrigin) {
  let courseListTmp = tableTransfer($("tr>td[style!='height:80px;']"), isOrigin)
  let courseList = []
  let courseTmp = {}
  for (let i = 0; i < 7; i++) {
    for (let j = 0; j < 7; j++) {
      for (
        let k = 0;
        k < courseListTmp[i][j].querySelectorAll('div[style="max-width:120px;"]').length;
        k++
      ) {
        courseTmp.weekNum = i + 1
        courseTmp.courseNum = j + 1
        if (courseListTmp[i][j].querySelectorAll("span")[k]) {
          courseTmp.name = courseListTmp[i][j]
            .getElementsByTagName("span")
            [k * 3].innerText.split("\n")[1]
          courseTmp.location = courseListTmp[i][j].querySelectorAll('span[class="text-muted"]')[
            k
          ].innerText
          let dateStr = courseListTmp[i][j].querySelectorAll('div[style="max-width:120px;"]')[k]
            .innerText
          dateStr = dateStr.substring(dateStr.indexOf("第") + 1, dateStr.indexOf("周")) // 预处理
          courseTmp.initInfo = "第" + dateStr + "周"
          courseTmp.date = dateStr2Arr(dateStr)
          courseTmp.teacher = courseListTmp[i][j].querySelectorAll("i")[k].innerText
          courseTmp.allInfo =
            courseTmp.name +
            " " +
            courseTmp.initInfo +
            " " +
            courseTmp.location +
            " " +
            courseTmp.teacher
          courseList.push(courseTmp)
          courseTmp = {}
        }
      }
    }
  }
  return courseList
}

function timeConstructor(weekTh, weekNum, courseNum, isStamp, isDelay) {
  let standardTimeTable = [
    ["08:00", "09:50"],
    ["10:10", "12:00"],
    ["12:10", "14:00"],
    ["14:10", "16:00"],
    ["16:20", "18:10"],
    ["19:00", "20:50"],
    ["21:00", "21:50"]
  ]
  let delayTimeTable = [
    ["08:00", "09:50"],
    ["10:30", "12:20"],
    ["12:10", "14:00"],
    ["14:10", "16:00"],
    ["16:20", "18:10"],
    ["19:00", "20:50"],
    ["21:00", "21:50"]
  ]

  let WeekTable = generateWeekTable()
  let DayTime = new Date(WeekTable[weekTh - 1][weekNum - 1])
  let rtnTime = []
  let startTimeStamp, endTimeStamp
  let delayClassroom = ["思源西楼", "逸夫"]

  for (let item of delayClassroom) {
    if (isDelay.search(item) != -1) {
      startTimeStamp = DayTime.setHours(
        delayTimeTable[courseNum - 1][0].split(":")[0],
        delayTimeTable[courseNum - 1][0].split(":")[1]
      )
      endTimeStamp = DayTime.setHours(
        delayTimeTable[courseNum - 1][1].split(":")[0],
        delayTimeTable[courseNum - 1][1].split(":")[1]
      )
    } else {
      startTimeStamp = DayTime.setHours(
        standardTimeTable[courseNum - 1][0].split(":")[0],
        standardTimeTable[courseNum - 1][0].split(":")[1]
      )
      endTimeStamp = DayTime.setHours(
        standardTimeTable[courseNum - 1][1].split(":")[0],
        standardTimeTable[courseNum - 1][1].split(":")[1]
      )
    }
  }

  if (isStamp === 1) {
    rtnTime.push(startTimeStamp)
    rtnTime.push(endTimeStamp)
    return rtnTime
  }

  let startTime = new Date(startTimeStamp)
  let endTime = new Date(endTimeStamp)
  startTime = startTime.toString()
  endTime = endTime.toString()
  rtnTime.push(startTime)
  rtnTime.push(endTime)
  return rtnTime
}

function icsConstructor(icsEventList) {
  let cal = ics()
  let today = new Date()
  today = today.toLocaleDateString()
  for (let i = 0; i < icsEventList.length; i++) {
    cal.addEvent(
      icsEventList[i].name,
      icsEventList[i].description,
      icsEventList[i].location,
      icsEventList[i].startTime,
      icsEventList[i].endTime
    )
  }
  cal.download("iCalender - 课表 - " + today)
}

function eventConstructor(courseList) {
  let icsEvent = {}
  let icsEventList = []
  for (let i = 0; i < courseList.length; i++) {
    for (let j = 0; j < courseList[i].date.length; j++) {
      let timeRst = timeConstructor(
        courseList[i].date[j],
        courseList[i].weekNum,
        courseList[i].courseNum,
        0,
        courseList[i].location
      )
      let timeRstStamp = timeConstructor(
        courseList[i].date[j],
        courseList[i].weekNum,
        courseList[i].courseNum,
        1,
        courseList[i].location
      )
      icsEvent.name = courseList[i].name
      icsEvent.description =
        courseList[i].location +
        " " +
        courseList[i].initInfo +
        " 任课教师:" +
        courseList[i].teacher
      icsEvent.location = courseList[i].location
      icsEvent.startTime = timeRst[0]
      icsEvent.endTime = timeRst[1]
      icsEvent.startTimeStamp = timeRstStamp[0]
      icsEvent.endTimeStamp = timeRstStamp[1]
      icsEventList.push(icsEvent)
      icsEvent = {}
    }
  }
  return icsEventList
}

function toExcelFormatter(courseList) {
  let standardTimeTable = [
    ["08:00", "09:50"],
    ["10:10", "12:00"],
    ["12:10", "14:00"],
    ["14:10", "16:00"],
    ["16:20", "18:10"],
    ["19:00", "20:50"],
    ["21:00", "21:50"]
  ]
  let jsonData = [
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    },
    {
      column1: "",
      column2: "",
      column3: "",
      column4: "",
      column5: "",
      column6: "",
      column7: ""
    }
  ]
  let charArr = ["第一节", "第二节", "第三节", "第四节", "第五节", "第六节", "第七节"]
  let objKeys = Object.keys(jsonData[0])

  for (let i = 0; i < 7; i++) {
    for (let j = 0; j < 7; j++) {
      let tmpKey = objKeys[j + 1]
      jsonData[i].column1 =
        charArr[i] + " [" + standardTimeTable[i][0] + " - " + standardTimeTable[i][0] + "]"
      for (let k = 0; k < courseList.length; k++) {
        if (courseList[k].courseNum == i + 1 && courseList[k].weekNum == j + 1) {
          jsonData[i][tmpKey] = jsonData[i][tmpKey] + "  " + courseList[k].allInfo
        }
      }
    }
  }
  return jsonData
}

// tableToExcel() @csdn hhzzcc_
function tableToExcel(jsonData) {
  let str = `课程|星期,星期一,星期二,星期三,星期四,星期五,星期六,星期日\n`
  for (let i = 0; i < jsonData.length; i++) {
    for (let key in jsonData[i]) {
      str += `${jsonData[i][key] + "\t"},`
    }
    str += "\n"
  }
  const uri = "data:text/csv;charset=utf-8,\ufeff" + encodeURIComponent(str)
  const link = document.createElement("a")
  link.href = uri
  link.download = "课程表.csv"
  link.click()
}

function icsmain(icase) {
  let icsEventList
  if (icase === 0) {
    icsEventList = eventConstructor(stuScheduleGetTable())
  } else if (icase === 1) {
    icsEventList = eventConstructor(scheduleGetTable())
  }
  icsConstructor(icsEventList)
}

function csvmain(icase) {
  let jsonData
  if (icase === 0) {
    jsonData = toExcelFormatter(stuScheduleGetTable())
  } else if (icase === 1) {
    jsonData = toExcelFormatter(scheduleGetTable())
  }
  tableToExcel(jsonData)
}

function jsonmain(icase) {
  let jsonData
  if (icase === 0) {
    jsonData = stuScheduleGetTable()
  } else if (icase === 1) {
    jsonData = scheduleGetTable()
  }
  const uri = "data:text/json;charset=utf-8,\ufeff" + encodeURIComponent(JSON.stringify(jsonData))
  const link = document.createElement("a")
  link.href = uri
  link.download = "课程表.json"
  link.click()
}

buttonGenerate()