您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
僅供PDF下載
当前为
// ==UserScript== // @name 下載北科i學員PDF // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 僅供PDF下載 // @author Umeow // @match https://istudy.ntut.edu.tw/learn/index.php // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant GM_registerMenuCommand // @license MIT // ==/UserScript== const parser = new DOMParser(); const ErrorFileChar = [ "/" , "|" ,'\\',"?",'"' ,'*' ,":" ,"<" ,">" , "/" , ":"]; async function GM_fetch(url, {method = "get", headers} = {}) { //source: https://github.com/AlttiRi/gm_fetch return new Promise((resolve, _reject) => { const blobPromise = new Promise((resolve, reject) => { GM_xmlhttpRequest({ url, method, headers, responseType: "blob", onload: response => resolve(response.response), onerror: reject, ontimeout: reject, onreadystatechange: onHeadersReceived }); }); blobPromise.catch(_reject); function onHeadersReceived(response) { const { readyState, responseHeaders, status, statusText } = response; if (readyState === 2) { // HEADERS_RECEIVED const headers = parseHeaders(responseHeaders); resolve({ headers, status, statusText, ok: status.toString().startsWith("2"), arrayBuffer: () => blobPromise.then(blob => blob.arrayBuffer()), blob: () => blobPromise, json: () => blobPromise.then(blob => blob.text()).then(text => JSON.parse(text)), text: () => blobPromise.then(blob => blob.text()), }); } } }); } function parseHeaders(headersString) { class Headers { get(key) { return this[key.toLowerCase()]; } } const headers = new Headers(); for (const line of headersString.trim().split("\n")) { const [key, ...valueParts] = line.split(":"); // last-modified: Fri, 21 May 2021 14:46:56 GMT headers[key.trim().toLowerCase()] = valueParts.join(":").trim(); } return headers; } const saveData = (function () { const a = document.createElement("a"); document.body.appendChild(a); a.style = "display: none"; return function (url, fileName) { a.href = url; a.download = fileName; a.click(); window.URL.revokeObjectURL(url); }; }()); const GET = (url) => { return new Promise((resolve, reject) => { $.ajax({ url, success: (data, status) => { resolve({data, status}); } }); }); } const fetchGET = async (url, headers = {}, args = {}) => { const res = await fetch(url, { ...args, headers: { ...headers, }, method: "GET" }); return res; } const fetchPOST = async (url, data, headers) => { const res = await fetch(url, { body: new URLSearchParams(data).toString(), headers: { ...headers, "Content-Type": "application/x-www-form-urlencoded", "Access-Control-Allow-Origin": "*" }, method: "POST", }); return res; } const get_cid = async () => { const cidURL = "https://istudy.ntut.edu.tw/learn/path/launch.php"; const cidResponse = await GET(cidURL); const cidHTML = parser.parseFromString(cidResponse['data'], 'text/html'); const cidScriptHTML = cidHTML.getElementsByTagName('script')[0].innerHTML; const cidLine = cidScriptHTML.split("\n").filter(str => str.includes('cid'))[0]; const cidStartIndex = cidLine.indexOf('/learn'); const cidResultURL = 'https://istudy.ntut.edu.tw' + cidLine.slice(cidStartIndex).slice(0, -3); const cidResultURLObj = new URL(cidResultURL); const cid = cidResultURLObj.searchParams.get('cid'); return cid; } const getDownloadArguments = async (cid) => { const URL = `https://istudy.ntut.edu.tw/learn/path/pathtree.php?cid=${cid}` const DownloadData = { 'is_player' : false, 'href' : '', 'prev_href' : '', 'prev_node_id' : '', 'prev_node_title' : '', 'is_download' : false, 'begin_time' : '', 'course_id' : '', 'read_key' : '' } const Response = await GET(URL); const HTML = parser.parseFromString(Response['data'], 'text/html'); const FormElement = HTML.getElementById('fetchResourceForm'); const InputList = [...FormElement.getElementsByTagName('input')]; InputList.forEach((InputElement) => { const key = InputElement.getAttribute('name'); if(key === "is_download" || key === "is_player") return; const value = InputElement.getAttribute('value') || ''; DownloadData[key] = value; }); return DownloadData } const getFileList = async () => { const FileList = []; const FileListURL = 'https://istudy.ntut.edu.tw/learn/path/SCORM_loadCA.php'; const FileListResponse = await GET(FileListURL); const FileListXML = FileListResponse['data']; const FileListItems = [...FileListXML.getElementsByTagName('item')].filter((ele) => ele.getAttribute('identifierref')); const FileListElements = [...FileListXML.getElementsByTagName('resource')].filter((ele) => ele.getAttribute('identifier')); FileListElements.forEach((element) => { const identifier = element.getAttribute('identifier'); const href = '@' + element.getAttribute('href'); const item = FileListItems.filter((ele) => ele.getAttribute('identifierref') === identifier)[0]; const name = item.getElementsByTagName('title')[0].innerHTML.split("\t")[0].replace("\n" , ""); const file = { href, name }; FileList.push(file); }); return FileList; } const DownloadFile = async (DownloadData, file, btn) => { btn.disabled = true; let filename = file['name']; while(ErrorFileChar.map( c => filename.includes(c) ).filter(bool => bool).length) ErrorFileChar.forEach( c => filename.replace(c, ' ')); DownloadData['href'] = file['href']; const URL = "https://istudy.ntut.edu.tw/learn/path/SCORM_fetchResource.php"; const Response = await fetchPOST(URL, DownloadData); const ResponseText = await Response.text(); const ResponseLocation = ResponseText.slice(26, -12); const ViewPDFURL = 'https://istudy.ntut.edu.tw/learn/path/' + ResponseLocation; const ViewPDF = await GET(ViewPDFURL); const getPDFLine = ViewPDF['data'].split('\n').filter(str => str.includes('getPDF.php'))[0]; const StartIndex = getPDFLine.indexOf('"'); const EndIndex = getPDFLine.lastIndexOf('"'); const getPDFURL = getPDFLine.slice(StartIndex + 1, EndIndex); const PDFResponse = await GM_fetch('https://istudy.ntut.edu.tw/learn/path/' + getPDFURL, { headers: { referer: ViewPDFURL } }); console.log(PDFResponse); const PDFBlob = await PDFResponse.blob(); const PDFLink = window.URL.createObjectURL(PDFBlob); saveData(PDFLink, filename); btn.disabled = false; } const main = async () => { const cid = await get_cid(); const DownloadData = await getDownloadArguments(cid); const FileList = await getFileList(); const doc = document.createElement("html"); const head = document.createElement("head"); const meta = document.createElement("meta"); meta["charset"] = "utf-8"; head.appendChild(meta); const body = document.createElement("body"); body.style = 'display: flex;flex-direction: column;' doc.appendChild(head); doc.appendChild(body); FileList.forEach(file => { const base = document.createElement("div"); const span = document.createElement("span"); span.innerHTML = file['name']; span.style = "margin-right: 10px;"; const btn = document.createElement("button"); btn.innerHTML = '下載'; btn.addEventListener("click", () => { DownloadFile(DownloadData, file, btn); }); base.innerHTML += "</br>"; base.appendChild(span); base.appendChild(btn); body.appendChild(base); }); const new_window = window.open('', 'i學員檔案列表', config='height=500,width=500'); new_window.document.body.appendChild(doc); } GM_registerMenuCommand('擷取目前頁面的檔案', main, 'r');