// ==UserScript==
// @name 腾讯文档助手(批量导出)
// @namespace http://tampermonkey.net/
// @version 2024-02-11
// @description 批量导出
// @author zhengqinqian
// @match https://doc.weixin.qq.com/home/recent
// @match https://doc.weixin.qq.com/home/mydoc
// @match http://doc.weixin.qq.com/home/recent
// @require https://cdn.jsdelivr.net/npm/toastr@2.1.4/toastr.min.js
// @resource toastrCss https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.css
// @icon https://www.google.com/s2/favicons?sz=64&domain=qq.com
// @grant GM_cookie
// @license MIT
// @grant GM_xmlhttpRequest
// ==/UserScript==
//本地vue存储的文档信息
let list_data;
//doc下载API
let doc_export_api="https://doc.weixin.qq.com/v1/export/export_office?sid="
//doc导出进度查询
let doc_export_query_api="https://doc.weixin.qq.com/v1/export/query_progress?"
var localHref = window.location.href;
var UA = navigator.userAgent;
//正在导出的作业
var exporting_operationId=[]
var docCookies = {
getItem: function (sKey) {
return (
decodeURIComponent(
document.cookie.replace(
new RegExp(
"(?:(?:^|.*;)\\s*" +
encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") +
"\\s*\\=\\s*([^;]*).*$)|^.*$",
),
"$1",
),
) || null
);
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
return false;
}
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires =
vEnd === Infinity
? "; expires=Fri, 31 Dec 9999 23:59:59 GMT"
: "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie =
encodeURIComponent(sKey) +
"=" +
encodeURIComponent(sValue) +
sExpires +
(sDomain ? "; domain=" + sDomain : "") +
(sPath ? "; path=" + sPath : "") +
(bSecure ? "; secure" : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) {
return false;
}
document.cookie =
encodeURIComponent(sKey) +
"=; expires=Thu, 01 Jan 1970 00:00:00 GMT" +
(sDomain ? "; domain=" + sDomain : "") +
(sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
return new RegExp(
"(?:^|;\\s*)" +
encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") +
"\\s*\\=",
).test(document.cookie);
},
keys: /* optional method: you can safely remove it! */ function () {
var aKeys = document.cookie
.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "")
.split(/\s*(?:\=[^;]*)?;\s*/);
for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
}
return aKeys;
},
};
//vue数据初始化
function setData(){
list_data=document.querySelector(".fileList_item_wrapper").__vue__.$attrs.list;
console.log(list_data.length)
}
//恢复console.log
function setConsole() {
// var iframe = document.createElement('iframe');
// iframe.style.display = 'none';
// document.body.appendChild(iframe);
// var console = iframe.contentWindow.console;
// window.console = console;
// window.__autoClearConsoleTimer && clearInterval(window.__autoClearConsoleTimer)
setInterval(()=>{window.__autoClearConsoleTimer && clearInterval(window.__autoClearConsoleTimer)},3000)
// window.__resetConsole()
// setTimeout(window.__resetConsole(),1000)
//清除定时器
// clearInterval(window.__autoClearConsoleTimer)
}
function JSON_to_URLEncoded(element,key,list){
var list = list || [];
if(typeof(element)=='object'){
for (var idx in element)
JSON_to_URLEncoded(element[idx],key?key+'['+idx+']':idx,list);
} else {
list.push(key+'='+encodeURIComponent(element));
}
return list.join('&');
}
function AjaxCall(href,type,data,callback) {
var encode_data="";
if(data){
encode_data=JSON_to_URLEncoded(data);
}
console.log("AjaxCall:"+href+","+type+","+encode_data+","+encode_data.length)
GM_xmlhttpRequest({
method: type,
url: href,
data: encode_data,
headers: {
"User-Agent": UA,
"Origin": "https://doc.weixin.qq.com/home",
"content-type":"application/x-www-form-urlencoded; charset=UTF-8",
// "cookie": document.cookie,
// "Content-Length":encode_data.length,
// "Host":"doc.weixin.qq.com"
},
onload: function(data,status) {
if(data.readyState==4 && data.status==200){
var htmlTxt = data.responseText;
callback(null,htmlTxt);
};
},
onerror: function (error) {
console.info("AjaxCall.onerror")
callback(error);
},
ontimeout: function (error) {
console.info("AjaxCall.ontimeout")
callback(error);
},
});
};
// 下载文档
function downLoadDoc(url,data){
return new Promise(function(reslove,reject){
AjaxCall(url,"POST",data,(error,reponse)=>{
if(error){
console.log("downLoadDoc error")
resolve([false]);
return;
}
var json = JSON.parse(reponse);
if(json.ret==0){
console.log("downLoadDoc return :"+reponse)
console.log(reponse)
reslove([true,json.operationId])
}else{
console.warn("downLoadDoc return :"+reponse)
console.warn(reponse)
reslove([false])
}
})
})
}
//查询进度
function queryProgress(url,itemId){
return new Promise(function(reslove,reject){
AjaxCall(url,"GET",null,(error,reponse)=>{
if(error){
console.log("queryProgress error")
resolve([false,itemId]);
return;
}
var json = JSON.parse(reponse);
if(json.ret==0&&json.progress==100){
console.log("queryProgress ret:"+json.ret)
console.log(reponse)
reslove([true,json.file_url])
}else{
console.warn("queryProgress ret "+json.ret)
console.warn(reponse)
reslove([false,itemId])
}
})
})
}
// selector is optional - defaults to all elements including window and document
// Do not pass window / document objects. Instead use pseudoselectors: 'window' or 'document'
// eTypeArray is optional - defaults to clearing all event types
function removeAllEventListeners(selector = '*', eTypeArray = ['*']) {
switch (selector.toLowerCase()) {
case 'window':
removeListenersFromElem(window);
break;
case 'document':
removeListenersFromElem(document);
break;
case '*':
removeListenersFromElem(window);
removeListenersFromElem(document);
default:
document.querySelectorAll(selector).forEach(removeListenersFromElem);
}
function removeListenersFromElem(elem) {
let eListeners = getEventListeners(elem);
let eTypes = Object.keys(eListeners);
for (let eType of inBoth(eTypes, eTypeArray)) {
eListeners[eType].forEach((eListener)=>{
let options = {};
inBoth(Object.keys(eListener), ['capture', 'once', 'passive', 'signal'])
.forEach((key)=>{ options[key] = eListener[key] });
elem.removeEventListener(eType, eListener.listener, eListener.useCapture);
elem.removeEventListener(eType, eListener.listener, options);
});
}
}
function inBoth(arrA, arrB) {
setB = new Set(arrB);
if (setB.has('*')) {
return arrA;
} else {
return arrA.filter(a => setB.has(a));
}
}
}
//阻止冒泡,去除框外取消勾选 todo
function cancelBubble(){
document.querySelector("body").addEventListener("click",(e)=>{e.stopPropagation();})
document.querySelector("body").addEventListener("mousedown",(e)=>{e.stopPropagation();})
var home_topfile=document.querySelector(".home_topfile");
// removeAllEventListeners(".home_topfile")
// home_topfile.replaceWith(home_topfile.cloneNode(true))
// getEventListeners(document.querySelector(".home_topfile"))
var placeToReplace;
if (window.EventTarget && EventTarget.prototype.addEventListener) {
placeToReplace = EventTarget;
} else {
placeToReplace = Element;
}
placeToReplace.prototype.oldaddEventListener = placeToReplace.prototype.addEventListener;
placeToReplace.prototype.addEventListener = function(event, handler, placeholder) {
// console.log("calling substitute");
if (arguments.length < 3) {
this.oldaddEventListener(event, handler, false);
} else {
this.oldaddEventListener(event, handler, placeholder);
}
}
document.querySelector(".home_topfile").addEventListener("mousedown", function() {
console.log("foo");
});
}
//onLoad
function pageOnload(){
// setData
setData();
// setConsole
setConsole();
// cancelBubble();
//recent页面显示在tab-container
if(localHref.includes("home/recent")){
//批量导出按钮
document.querySelector(".tab-container").insertAdjacentHTML('beforeend','<button id="batchExport" type="button" class="xd_btn fileToolbar_button xd_btn_Blue xd_btn_Supper" style="width: auto; ">批量导出</button>')
//全选按钮
document.querySelector(".tab-container").insertAdjacentHTML('beforeend','<button id="selectAllItem" type="button" class="xd_btn fileToolbar_button xd_btn_Supper" style="width: auto;color: white;background: seagreen;display:inline">全选</button>')
}else{
document.querySelector(".xd-web-header_toolbar").insertAdjacentHTML('beforeend','<button id="selectAllItem" type="button" class="xd_btn fileToolbar_button xd_btn_Supper" style="width: auto;color: white;background: seagreen;display:inline">全选</button>')
document.querySelector(".xd-web-header_toolbar").insertAdjacentHTML('beforeend','<button id="batchExport" type="button" class="xd_btn fileToolbar_button xd_btn_Blue xd_btn_Supper" style="width: auto; ">批量导出</button>')
}
// document.querySelectorAll(".xd_checkbox").forEach(item=>{
// console.log("debug for fileList_item_checkbox")
// parentDiv=item.parentNode.parentNode;
// item.addEventListener("click",(e)=>{
// if(parentDiv.getAttribute("class").indexOf("fileList_item_Active")==-1){
// //勾选
// console.log("click select")
// parentDiv.classList.add("fileList_item_Active");
// item.firstChild.classList.replace("xd_common_unselect-normal","xd_common_select-normal");
// }
// else{
// //取消勾选
// console.log("rever select")
// parentDiv.classList.remove("fileList_item_Active");
// item.firstChild.classList.replace("xd_common_select-normal","xd_common_unselect-normal");
// }
// })
// });
document.querySelectorAll(".fileList_item_checkbox").forEach(item=>{item.style.display="flex";});
//点击批量导出
document.querySelector("#batchExport").addEventListener("click",(e)=>{
console.log("batchExport")
if(list_data.length<=0){
console.warn("data is null")
return
}
var docList=document.querySelectorAll(".fileList_item_wrapper");
console.log(docList.length)
for(var i=0;i<docList.length;i++){
var docItem=docList[i];
console.log("i:"+i+","+docItem.firstChild.className+","+list_data[i].doc_id)
//选中
if(docItem.firstChild.className.includes("fileList_item_Active")){
// if(i>0){
// return;
// }
// 执行导出作业
var url=doc_export_api+docCookies.getItem("wedoc_sid")
console.log("docItem.doc_id:"+list_data[i].doc_id)
downLoadDoc(url,{"docId":list_data[i].doc_id})
.then((resp)=>{
console.log("downLoadDoc then:"+resp)
if(resp[0]){
//加入到待查询列表中
exporting_operationId.push(resp[1])
//清除选中状态,默认会清除
// docItem.firstChild.className.remove("fileList_item_Active")
}
})
}
}
})
//点击全选
document.querySelector("#selectAllItem").addEventListener("click",()=>{
//全选
if(document.querySelector(".fileList_item_wrapper > div:first-child").getAttribute("class").indexOf("fileList_item_Active")==-1){
console.log("click selectAll")
document.querySelectorAll(".fileList_item_wrapper > div:first-child").forEach(item=>item.classList.add("fileList_item_Active"));
document.querySelectorAll(".xd_checkbox > i").forEach(item=>item.classList.replace("xd_common_unselect-normal","xd_common_select-normal"));
}else{
//取消全选
console.log("rever selectAll")
document.querySelectorAll(".fileList_item_wrapper > div:first-child").forEach(item=>item.classList.remove("fileList_item_Active"));
document.querySelectorAll(".xd_checkbox > i").forEach(item=>item.classList.replace("xd_common_select-normal","xd_common_unselect-normal"));
}
})
console.log("pageOnload end")
}
let await_flag=false;
(function() {
document.onreadystatechange = function () {
if (document.readyState === "complete") {
setTimeout(()=>pageOnload(),1000)
}
};
//window.addEventListener("load", (event)=>pageOnload(event));
var wedoc_skey=docCookies.getItem("wedoc_skey");
var wedoc_ticket=docCookies.getItem("wedoc_ticket");
setInterval(async()=>{
if(await_flag){
console.log("busy")
return;
}
await_flag=true;
var time_stmap=new Date().getTime();
console.log(time_stmap+","+exporting_operationId.length)
var new_exporting_operationId=[];
for(var i=0 ;i<exporting_operationId.length;i++){
var item=exporting_operationId[i];
var url=doc_export_query_api+"operationId="+item+"×tamp="+new Date().getTime()
await queryProgress(url,item)
.then((resp)=>{
console.log("downLoadDoc retuen:"+resp)
if(resp[0]){
//下载
window.open(resp[1])
}else{
new_exporting_operationId.push(resp[1])
}
})
}
exporting_operationId=new_exporting_operationId;
await_flag=false;
},3000)
// alert("wedoc_skey:"+wedoc_skey+"\n"+"wedoc_ticket"+wedoc_ticket);
})();