Skip to content

Instantly share code, notes, and snippets.

@GrzegorzManiak
Created January 1, 2024 17:34
Show Gist options
  • Save GrzegorzManiak/a0ed71a00733994245855f51721af55f to your computer and use it in GitHub Desktop.
Save GrzegorzManiak/a0ed71a00733994245855f51721af55f to your computer and use it in GitHub Desktop.
// ==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/jszip@3.10.1/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