Created
January 1, 2024 17:34
-
-
Save GrzegorzManiak/a0ed71a00733994245855f51721af55f to your computer and use it in GitHub Desktop.
Exam Papers Link Extractor for https://exampapers-ta-tudublin-ie.tudublin.idm.oclc.org/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Exam Papers Link Extractor | |
// @namespace http://tampermonkey.net/ | |
// @version 2024-01-01 | |
// @description Extracts links from the exam papers website and displays them in a popup window. | |
// @author https://git.grzegorz.ie/ | |
// @match *://exampapers-ta-tudublin-ie.tudublin.idm.oclc.org/* | |
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=oclc.org | |
// @grant none | |
// ==/UserScript== | |
(() => { | |
'use strict'; | |
console.log('Exam Papers Link Extractor loaded.'); | |
/** | |
* A button is added to each main entry in the treeview to extract links for that module. | |
* id="treeview-searchable" | |
*/ | |
let module = '', course = ''; | |
const departments = json4.map(e => e.text); | |
console.log(departments); | |
const course_dropdown = document.createElement('select'); | |
course_dropdown.style.marginLeft = '20px'; | |
course_dropdown.addEventListener('change', () => course = course_dropdown.value); | |
departments.forEach(e => { | |
const option = document.createElement('option'); | |
option.textContent = e; | |
course_dropdown.appendChild(option); | |
}); | |
const search_box = document.createElement('input'); | |
search_box.type = 'text'; | |
search_box.placeholder = 'Module title'; | |
search_box.style.marginLeft = '20px'; | |
search_box.addEventListener('input', () => module = search_box.value); | |
const button = document.createElement('button'); | |
button.textContent = 'Extract links'; | |
button.style.marginLeft = '20px'; | |
button.addEventListener('click', () => { | |
console.log('Extracting links for', course, module); | |
extract(course, module); | |
}); | |
// -- Create a download button | |
const download_button = document.createElement('button'); | |
download_button.textContent = 'Download links'; | |
download_button.style.marginTop = '20px'; | |
download_button.addEventListener('click', async() => { | |
console.log('Downloading links...'); | |
// -- Check if the course exists | |
const selected_nodes = json4.find(e => e.text.toLowerCase() === course.toLowerCase()); | |
if (!selected_nodes) return console.error('No course found.'); | |
// -- Get all the links for the module | |
const links = []; | |
selected_nodes.nodes.forEach((n1) => n1.nodes.forEach((n2) => n2.nodes.forEach((n3) => (n3?.nodes ?? []).forEach((n4) => { | |
if(n4.text.toLowerCase().includes(module.toLowerCase()) && links.indexOf(n4) === -1) links.push(n4); | |
})))); | |
// -- Create a zip file | |
const zip = new JSZip(); | |
let readmefile = `# ${course} - ${module}\n\n`; | |
// -- Donwload all the pdfs | |
const promises = []; | |
links.forEach(link => { | |
const filename = link.text.replace(/[^a-z0-9]/gi, '_').toLowerCase(), | |
download_promise = download(`https://exampapers-ta-tudublin-ie.tudublin.idm.oclc.org/${link.href}`, filename); | |
// -- Add the filename to the readme file | |
readmefile += `* [${filename}](./${filename}.pdf)\n`; | |
// -- Add the download promise to the array | |
promises.push(download_promise); | |
console.log(`Downloading (0/1) ${filename}`); | |
download_promise.then((pdf) => { | |
console.log(`Downloaded (1/1) ${filename}`); | |
// -- Add the pdf to the zip file | |
zip.file(`${filename}.pdf`, pdf); | |
}); | |
}); | |
// -- Wait for all the downloads to finish | |
await Promise.all(promises); | |
console.log('All downloads finished.'); | |
readmefile += `\n\n ${promises.length} files downloaded at ${new Date().toLocaleString()}`; | |
// -- Add the readme file to the zip file | |
zip.file('README.md', readmefile); | |
// -- Generate the zip file and download it | |
zip.generateAsync({type: 'blob'}).then(content => { | |
const a = document.createElement('a'); | |
a.href = URL.createObjectURL(content); | |
a.download = `pdf_${course}_${module}.zip`.replace(/[^a-z0-9]/gi, '_').toLowerCase(); | |
a.click(); | |
}); | |
}); | |
const tree = document.querySelector('.jumbotron'); | |
tree.appendChild(download_button, tree.firstChild); | |
tree.appendChild(button, tree.firstChild); | |
tree.appendChild(search_box, tree.firstChild); | |
tree.appendChild(course_dropdown, tree.firstChild); | |
/** | |
* Main part of the script that actually does the work. | |
*/ | |
const extract = ( | |
course, | |
module | |
) => { | |
// -- Check if the course exists | |
const selected_nodes = json4.find(e => e.text.toLowerCase() === course.toLowerCase()); | |
if (!selected_nodes) return console.error('No course found.'); | |
// -- Get all the links for the module | |
const links = []; | |
selected_nodes.nodes.forEach((n1) => n1.nodes.forEach((n2) => n2.nodes.forEach((n3) => (n3?.nodes ?? []).forEach((n4) => { | |
if(n4.text.toLowerCase().includes(module.toLowerCase()) && links.indexOf(n4) === -1) links.push(n4); | |
})))); | |
// -- Create a popup with the links | |
const popup = (links, style = ` | |
table{width:100%;border-collapse:collapse;margin-top:20px;} | |
th,td{border:1px solid#ddd;padding:8px;text-align:left;} | |
th{background-color: #f2f2f2;}` | |
) => { | |
// -- Create a style element and append it to the head | |
const style_element = document.createElement('style'); | |
style_element.textContent = style; | |
document.head.appendChild(style_element); | |
// -- Create a table element | |
const table = document.createElement('table'); | |
// -- Create table header | |
const thead = table.createTHead(), | |
header_row = thead.insertRow(), | |
header1 = header_row.insertCell(0), | |
header2 = header_row.insertCell(1); | |
header1.textContent = 'Text'; | |
header2.textContent = 'Link'; | |
// -- Create table body | |
const tbody = table.createTBody(); | |
// -- Populate the table with data from the links array | |
links.forEach(link => { | |
const row = tbody.insertRow(), | |
cell1 = row.insertCell(0), | |
cell2 = row.insertCell(1); | |
cell1.textContent = link.text; | |
cell2.innerHTML = `<a href="https://exampapers-ta-tudublin-ie.tudublin.idm.oclc.org/${link.href}" target="_blank">${link.href}</a>`; | |
}); | |
// -- Open a popup with the table | |
const popup = window.open('', 'Popup', 'width=600,height=400'); | |
popup.document.write('<html><head><title>Links Table</title>'); | |
popup.document.write(`<style>${style}</style>`); | |
popup.document.write('</head><body>'); | |
popup.document.write('<h2>Links Table</h2>'); | |
popup.document.write(table.outerHTML); | |
popup.document.write('</body></html>'); | |
}; | |
popup(links); | |
}; | |
const download = (url, filename) => { | |
// -- Downloads the pdf and returns a promise for that pdf | |
return new Promise((resolve, reject) => { | |
const xhr = new XMLHttpRequest(); | |
xhr.open('GET', url, true); | |
xhr.responseType = 'blob'; | |
xhr.onload = () => { | |
if (xhr.status === 200) { | |
const blob = xhr.response; | |
resolve(blob); | |
} else { | |
reject(xhr.statusText); | |
} | |
}; | |
xhr.onerror = () => reject(xhr.statusText); | |
xhr.send(); | |
}); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment