Skip to content

Instantly share code, notes, and snippets.

@Sg4Dylan
Last active September 15, 2021 14:35
Show Gist options
  • Save Sg4Dylan/7eca02e43d585da15c508edc06a79920 to your computer and use it in GitHub Desktop.
Save Sg4Dylan/7eca02e43d585da15c508edc06a79920 to your computer and use it in GitHub Desktop.
配合 phuslu 的 autoindex,实现 nginx 自动列目录导出到 aria2
// ==UserScript==
// @name NginxAutoindexExporter
// @namespace http://tampermonkey.net/
// @version 20180915(0.2)
// @description Export link from nginx autoindex to aria2
// @author SgDylan
// @match https://example.com/*
// @grant none
// ==/UserScript==
let downloadFileUrl = [];
let downloadFolder = [];
let iterationDeepth = 3;
const basic_auth = "BASIC AUTH BASE64 CODE";
const aria2_rpc = "http://127.0.0.1:6800/jsonrpc";
addCallerLink();
// 绑定界面
function addCallerLink() {
// 添加提示区域
var tip = document.createElement("th");
tip.innerHTML = "下载状态: 准备就绪";
tip.id = "ariaTip";
document.getElementsByTagName('th')[0].parentNode.appendChild(tip);
// 添加按钮
var link = document.createElement("th");
link.innerHTML = "<button id=\"ariaLink\">Download via Aria2</button>";
document.getElementsByTagName('th')[0].parentNode.appendChild(link);
document.getElementById('ariaLink').addEventListener('click', callAria2, false);
// 添加单独链接
let pre_line_body = document.getElementsByTagName('a');
for (var index=0; index<pre_line_body.length; index++) {
let pre_link = document.createElement("td");
let pre_insert_parent = pre_line_body[index].parentNode.parentNode;
if(pre_line_body[index].href.endsWith("/")) {
pre_insert_parent.insertBefore(pre_link, pre_insert_parent.childNodes[1]);
continue;
}
// 忽略指向 deluge 的链接
if(pre_line_body[index].href.endsWith("/deluge")) {
continue;
}
pre_link.innerHTML = "<button id=\"precall" + index.toString() + "\">Download</button>";
pre_insert_parent.insertBefore(pre_link, pre_insert_parent.childNodes[1]);
document.getElementById('precall'+index.toString()).addEventListener('click', callAria2Once, false);
}
}
// 更新界面
function updateTip(content) {
console.log("下载状态: " + content);
document.getElementById('ariaTip').innerHTML = "下载状态: " + content;
}
// 调用 Aria2 模块
function callAria2() {
updateTip("开始解析页面");
parseAll();
updateTip("开始召唤Aria2");
var aria2 = new ARIA2(aria2_rpc);
for (var index=0; index<downloadFileUrl.length; index++) {
//console.log("FilePath: "+downloadFileUrl[index].path+" FileURL: "+downloadFileUrl[index].url);
aria2.addUri(downloadFileUrl[index].url, {out: downloadFileUrl[index].path, header: 'Authorization: Basic '+basic_auth});
}
updateTip("召唤Aria2完成");
}
function callAria2Once(evt) {
let pre_index = evt.target.id.substring(7);
let pre_link = document.getElementsByTagName('a')[pre_index].href;
let pre_path = safeName(document.getElementsByTagName('a')[pre_index].getAttribute("href").replace(/\\+\*?/g,"/"));
updateTip("开始召唤Aria2");
console.log("Link:"+pre_link+" Path:"+pre_path);
var aria2 = new ARIA2(aria2_rpc);
aria2.addUri(pre_link, {out: pre_path, header: 'Authorization: Basic '+basic_auth});
updateTip("召唤Aria2完成");
}
// 解析调用
function parseAll() {
downloadFileUrl = [];
downloadFolder = [];
iterationDeepth = 3;
updateTip("全页面第一次解析开始");
parseLinkOnce(window.location.href, document.getElementsByTagName('a'));
while(downloadFolder.length>0 && iterationDeepth>0) {
unpackFolder();
iterationDeepth--;
}
console.log(downloadFileUrl);
}
// 解析标签列表
function parseLinkOnce(baseUrl, rawTag) {
for (var index=1; index<rawTag.length; index++) {
updateTip("解析进度("+index.toString()+"/"+(rawTag.length-1).toString()+")");
if(typeof(rawTag[index].href) === 'undefined') {
console.log("Undef ERROR");
continue;
}
console.log(rawTag[index].href);
// 忽略指向根路径的链接
if(rawTag[index].href==window.location.origin+"/") {
continue;
}
// 忽略指向上一层的链接
if(rawTag[index].getAttribute("href")=="../") {
continue;
}
// 忽略指向 deluge 的链接
if(rawTag[index].href.endsWith("/deluge")) {
continue;
}
// 忽略浏览器插件带来的链接
if(rawTag[index].href.startsWith("chrome-extension://")) {
continue;
}
// 忽略 paypal 链接
if(rawTag[index].href.startsWith("https://www.paypal.com/")) {
continue;
}
// 过滤出文件夹
if(rawTag[index].href.endsWith("/")) {
downloadFolder.push(baseUrl + rawTag[index].getAttribute("href"));
// console.log("DIR: " + baseUrl + rawTag[index].getAttribute("href"));
continue;
}
// 待下载文件
let temp_item = {};
temp_item.url = baseUrl + rawTag[index].getAttribute("href");
temp_item.path = getFullPath(baseUrl) + "/" + safeName(rawTag[index].getAttribute("href").replace(/\\+\*?/g,"/"));
downloadFileUrl.push(temp_item);
}
}
// 过滤不合规的字符
function safeName(nameDesu) {
return decodeURIComponent(nameDesu).replace(/[\\\|\:\*\"\?\<\>]/g,"_");
}
// 处理文件夹路径
function getFullPath(baseUrl) {
// 找到任务目录
let basePathName = safeName(window.location.href.substring(document.getElementsByTagName('a')[0].href.length,window.location.href.length-1));
// 如果就在任务目录
if (window.location.href == baseUrl) {
return basePathName;
}
// 如果再更深的目录
let extra_path = baseUrl.substring(window.location.href.length).split('/');
for (var index=0; index<extra_path.length; index++) {
extra_path[index] = safeName(extra_path[index]);
}
let final_path = extra_path.join('/');
final_path = basePathName + "/" + final_path;
if (final_path.endsWith('/')) {
final_path = final_path.substring(0,final_path.length-1);
}
return final_path;
}
// 展开文件夹
function unpackFolder() {
for (var index=downloadFolder.length-1; index>=0; index--) {
updateTip("文件夹展开进度("+(downloadFolder.length-1-index).toString()+"/"+(downloadFolder.length-1).toString()+")");
let xhr = new XMLHttpRequest();
let target_url = downloadFolder[index];
downloadFolder.splice(index, 1);
// 响应本体
// console.log("UnpackFoler URL: " + target_url);
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4 && xhr.status == 200) {
let tempDiv = document.createElement('div');
tempDiv.innerHTML = xhr.responseText;
parseLinkOnce(target_url, tempDiv.getElementsByTagName('a'));
}
};
xhr.open("GET", target_url, false);
xhr.send();
}
}
var ARIA2 = (function() {
const jsonrpc_version = '2.0';
function get_auth(url) {
return url.match(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(?:\/\/)?(?:([^:@]*(?::[^:@]*)?)?@)?/)[1];
}
function request(jsonrpc_path, method, params) {
let xhr = new XMLHttpRequest();
let auth = get_auth(jsonrpc_path);
jsonrpc_path = jsonrpc_path.replace(/^((?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(\/\/)?(?:(?:[^:@]*(?::[^:@]*)?)?@)?(.*)/, '$1$2$3'); // auth string not allowed in url for firefox
let request_obj = {
jsonrpc: jsonrpc_version,
method: method,
id: (new Date()).getTime().toString(),
};
if (params) request_obj.params = params;
if (auth && auth.indexOf('token:') === 0) params.unshift(auth);
xhr.open("POST", jsonrpc_path+"?tm="+(new Date()).getTime().toString(), true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
if (auth && auth.indexOf('token:') !== 0) {
xhr.setRequestHeader("Authorization", "Basic "+btoa(auth));
}
xhr.send(JSON.stringify(request_obj));
}
return function(jsonrpc_path) {
this.jsonrpc_path = jsonrpc_path;
this.addUri = function (uri, options) {
request(this.jsonrpc_path, 'aria2.addUri', [[uri, ], options]);
};
return this;
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment