Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save loonaticx/84d971fc85d54e0ab909e348bfdaf367 to your computer and use it in GitHub Desktop.
Save loonaticx/84d971fc85d54e0ab909e348bfdaf367 to your computer and use it in GitHub Desktop.
Schoology userscript - Quickly download files off folder browsers (press raw to install) - Be sure to allow popups!
// ==UserScript==
// @name Schoology quick-download files helper
// @namespace http://nicholastay.github.io/
// @version 0.3.0
// @author Nicholas Tay <nexerq@gmail.com>
// @license MIT
// @icon https://i.imgur.com/QmmYqzZ.png
// @match *://app.schoology.com/*
// @match *://*.schoology.com/*
// @match *://schoology.cgs.vic.edu.au/*
// @grant none
// @homepage https://gist.github.com/nicholastay/e6c108cc49bc297f50a1c417624e6601
// @downloadURL https://gist.github.com/nicholastay/e6c108cc49bc297f50a1c417624e6601/raw/schoology-quickdl.user.js
// @noframes
// @require https://unpkg.com/bottleneck@2.13.0/es5.js
// ==/UserScript==
;(function() {
// lets try not to kill schoology: 10 per 5s
var limiter = new Bottleneck({
reservoir: 10,
reservoirRefreshAmount: 100,
reservoirRefreshInterval: 5 * 1000
});
injectCSS();
if (injectLabels())
injectDownloadAll();
injectLabelEventHandler();
injectSubfolderHandler();
injectGroupResources();
console.log("[nexerq/quickDL] Initialized.");
function noop() {}
function injectCSS() {
$("head").append("<style type=\"text/css\">.nexerq-quickdl-style:hover { text-decoration: underline; cursor: pointer; }</style>");
console.log("[nexerq/quickDL] CSS injected");
}
function injectLabels(subfolder) {
var $contentFiles = $("#folder-contents-table");
if (!$contentFiles || ($contentFiles.length < 1))
return console.log("[nexerq/quickDL] Not a folder listing page, not injecting that.");
console.log("[nexerq/quickDL] Found folder listings.");
var $documents = $contentFiles.find(".type-document:not(.nexerq-quickdl-processed)");
if (!$documents || ($documents.length < 1)) {
console.log("[nexerq/quickDL] No download documents found.");
return false;
}
console.log("[nexerq/quickDL] Found " + $documents.length + " documents to process");
$documents.each(function() {
var $this = $(this);
var $attachment = $this.find(".attachments-file-name");
var $link = $attachment.find("a");
// mark as processed
$this.addClass("nexerq-quickdl-processed");
// create dl btn
var $newBtn = $attachment.find(".attachments-file-size").clone().appendTo($attachment);
$newBtn.addClass("nexerq-quickdl-style");
$newBtn.addClass("nexerq-quickdl-link");
$newBtn.text("Download");
$newBtn.attr("orig-link", $link.attr("href"));
// weird subfolder bullshit
var $subContent = $link.find(".infotip-content");
$newBtn.attr("orig-name", ($subContent.length > 0 ? $subContent.text() : $link.text()));
if (subfolder) // detection for quickdl all - do not include these!
$newBtn.addClass("nexerq-quickdl-subfolder");
});
console.log("[nexerq/quickDL] Labels injected");
return true;
}
function injectLabelEventHandler() {
$(document).on("click", ".nexerq-quickdl-link", function() {
var $this = $(this);
var origName = $this.attr("orig-name");
var origLink = $this.attr("orig-link");
// kinda hacky: ajax http get the other page
var req = function() {
console.log("[nexerq/quickDL] Attempting to ajax get the target page (" + origName + ").");
limiter.submit($.ajax, origLink, {
success: function(data) {
var $dl = $(data).find(".attachments-file a:first");
if (!$dl || ($dl.length < 1)) {
console.log("[nexerq/quickDL] File could not be found in success: " + origName);
return alert("[nexerq/quickDL] Sorry, this file (" + origName + ") cannot be quick-downloaded at this time. You may have to just open the page and download manually.");
}
// dl
invokeDownload(origName, $dl.attr("href"));
},
error: function(jqXHR, textStatus, err) {
if (jqXHR.status === 429) {// 429 rate limited
console.log("[nexerq/quickDL] Rate limited 429 on " + origName + ". Retry in 10s");
setTimeout(req, 30000);
}
}
}, noop); // noop cb
};
req();
});
console.log("[nexerq/quickDL] Event handler registered");
}
function invokeDownload(fileName, url) {
console.log("[nexerq/quickDL] Downloading " + fileName + ".");
// ugh - https://stackoverflow.com/questions/18451856/how-can-i-let-a-user-download-multiple-files-when-a-button-is-clicked
//var tmpLink = document.createElement("a");
//tmpLink.style.display = "none";
//document.body.appendChild(tmpLink);
//tmpLink.setAttribute("href", url);
//tmpLink.setAttribute("download", fileName);
//tmpLink.click();
//document.body.removeChild(tmpLink);
window.open(url, fileName + " - nexerq/quickDL");
}
function injectDownloadAll() {
$(".materials-top").append(`<span class="attachments-file-size gray nexerq-quickdl-all nexerq-quickdl-style">Quick-download all (non-recursive)</span>`);
$(".nexerq-quickdl-all").click(function() {
console.log("[nexerq/quickDL] Downloading all available files...");
// oh dear... recursion
var $links = $(".nexerq-quickdl-link:not(.nexerq-quickdl-subfolder)");
$links.each(function() {
$(this).click();
});
});
console.log("[nexerq/quickDL] Download all injected");
}
function injectSubfolderHandler() {
// attach to document
$(document).on("click", ".folder-contents-cell .folder-expander", function() {
var $this = $(this);
console.log("[nexerq/quickDL] Subfolder open detected");
// wait for ajax to complete...
var waitCount = 0;
var $parentTd = $this.closest("td");
var wait = setInterval(function() {
var $subtree = $parentTd.children(".folder-subtree");
if ($subtree && $subtree.length > 0) {
clearInterval(wait);
if (injectLabels(true)) {
// inject dl all
$parentTd.find(".folder-title").first().append(`<span class="attachments-file-size gray nexerq-quickdl-all-subfolder nexerq-quickdl-style">Quick-download all</span>`);
$parentTd.find(".nexerq-quickdl-all-subfolder").click(function() {
$parentTd.find(".nexerq-quickdl-link").each(function() {
$(this).click();
});
});
console.log("[nexerq/quickDL] Injected subfolder event and dl all");
}
}
if (++waitCount > 5) {
console.log("[nexerq/quickDL] Subfolder open - something went wrong while waiting.");
clearInterval(wait);
}
}, 750);
});
console.log("[nexerq/quickDL] Event handler for subfolder handling injected");
}
// probably the worst implemented one
function injectGroupResources() {
if (!window.location.pathname.includes("/group") || !window.location.pathname.includes("/materials"))
return console.log("[nexerq/quickDL] Not a group resource page, not injecting that.");
// wait. AJAX PLS
var i = 0;
console.log("[nexerq/quickDL] Waiting for group page...");
var wait = setInterval(function() {
var $groupResources = $("#collection-view");
if (!$groupResources || ($groupResources.length < 1)) {
if (++i > 5) {
console.log("[nexerq/quickDL] Failed to find resources.");
clearInterval(wait);
}
return;
}
clearInterval(wait);
_injectGroupResources();
}, 750);
}
function _injectGroupResources() {
var $groupResources = $("#collection-view");
// event handler
$(document).on("click", ".nexerq-quickdl-group-link", function() {
var $resource = $(this).closest(".template-s-content-generic-post-docviewer");
var resId = $resource.attr("id").replace("t-", "");
var origName = $resource.find(".item-title").text();
// ajax get template, then the ID docviewer and parse its config
// ... ughhhhhhhhhh
console.log("[nexerq/quickDL] Trying group resource: " + origName);
limiter.submit($.get, window.location.origin + "/template/" + resId, function(templateData) {
console.log("[nexerq/quickDL] Got template data: " + origName);
// time to docviewer
limiter.submit($.get, window.location.origin + $(templateData).find(".docviewer-iframe").attr("src"), function(docData) {
var $configFunc = $(docData).find("script:contains('pdfPath')");
if (!$configFunc || ($configFunc.length < 1))
return console.log("[nexerq/quickDL] Could not find pdfPath config: " + origName);
var _docConfig = $configFunc.text().match(/PdfTronWebViewer, ({.*"}"}})/);
if (!_docConfig)
return console.log("[nexerq/quickDL] Could not parse pdfConfig: " + origName);
var docConfig = JSON.parse(_docConfig[1]);
var customConfig = JSON.parse(docConfig.options.custom);
invokeDownload(origName, customConfig.downloadLink);
});
});
});
var $resources = $groupResources.find(".template-s-content-generic-post-docviewer:not(.nexerq-quickdl-processed)");
if (!$resources || ($resources.length < 1))
return console.log("[nexerq/quickDL] No download-docviewers found.");
console.log("[nexerq/quickDL] Found " + $resources.length + " group resources to process");
$resources.each(function() {
var $resource = $(this);
$resource.addClass("nexerq-quickdl-processed");
$resource.find(".resource-details").append(`<span class="nexerq-quickdl-style nexerq-quickdl-group-link"> · Download</span>`);
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment