Skip to content

Instantly share code, notes, and snippets.

@xyuanmu
Last active May 15, 2022 13:59
Show Gist options
  • Save xyuanmu/bae56ca925b9421fe716218ac136ab1b to your computer and use it in GitHub Desktop.
Save xyuanmu/bae56ca925b9421fe716218ac136ab1b to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name 百度网盘一键批量修改后缀-替换文件及文件夹名
// @namespace dupanBatchRename
// @version 0.1.4
// @description 感谢wealding,修改自【百度网盘一键批量修改后缀&批量替换文件名】;增加了批量修改文件夹名的功能;百度网盘一键批量修改后缀,默认修改为MP4;批量替换文件名【说明:批量改后缀强制改所有后缀,批量替换文件名可以替换一些垃圾版权信息】
// @author ding(AT)gong.si - Modified By Moka
// @match *://pan.baidu.com/disk/home*
// @match *://yun.baidu.com/disk/home*
// @icon https://pan.baidu.com/m-static/base/static/images/favicon.ico
// @run-at document-end
// @grant unsafeWindow
// @grant GM_addStyle
// ==/UserScript==
//日志函数
var debug = false;
var log_count = 1;
function slog(c1,c2,c3){
c1 = c1||'';
c2 = c2||'';
c3 = c3||'';
if(debug) console.log('#'+ log_count++ +'-ScriptLog:',c1,c2,c3);
}
var max_traverse_dir = 10; // 当遍历文件夹数量超过这个数值时提示用户一次
var traverseCount = 0;
var traversePause = 0;
var instance;
var fileList={};
var Traverse={path:[]};
var panAPIUrl = location.protocol + "//" + location.host + "/api/";
var taskAPIUrl = location.protocol + "//" + location.host + "/share/taskquery/";
var restAPIUrl = location.protocol + "//pcs.baidu.com/rest/2.0/pcs/";
var clientAPIUrl = location.protocol + "//d.pcs.baidu.com/rest/2.0/pcs/";
function getPath() {
return instance.listInstance.currentKey;
}
// 对 fileList 作了修改,不同目录返回不同的文件列表,遍历时会传入 path 参数
function getFileList(path){
let isTraverse;
if (path) {
isTraverse = true;
} else {
path = getPath();
// 获取用户选中项
let currentList = instance.listInstance.getCheckedItems();
// 没有选中项,则获取此目录文件列表
if (!currentList.length) {
currentList = instance.listInstance.getCurrentDataList();
if (path==="/") {
currentList = currentList.filter(function(e){return !e.mountPath}); // 过滤系统目录
}
}
if (currentList.length < 100) {
slog('getFileList from listInstance:',path);
return currentList;
}
}
if (fileList[path] && fileList[path].length) {
slog('getFileList from cache:',path);
return fileList[path];
}
if (isTraverse) {
if (traverseCount === max_traverse_dir) {
traversePause = !confirm("此目录包含的文件夹过多,请确认是否继续");
}
traverseCount++;
slog('traverseCount:', traverseCount);
if (traversePause) {
slog('traverse pause because of too much dir');
return false;
}
}
// 文件列表超过100个,通过 api 获取所有文件
slog('getFileList by path:',path);
let listUrl = panAPIUrl + "list";
let params = {
dir:path,
//bdstoken:bdstoken, // ajax 发送链接时会自动补全参数 2020年11月27日 19:31:28
//logid:logid,
order:'name',
desc:0,
showempty:0,
};
$.ajax({
url:listUrl,
async:false,
method:'GET',
data:params,
success:function(response){
fileList[path] = 0===response.errno ? response.list : [];
}
});
return fileList[path];
}
// 遍历文件夹内容
function traverseFileList(listUpper) {
let listArray = [];
$(listUpper).each(function(){
if (this.isdir === 1) {
let sublist = getFileList(this.path);
if (!sublist) {
return false;
}
listArray = listArray.concat(traverseFileList(sublist));
Traverse.path.push(this.path);
//slog('Traverse path cache:', Traverse.path);
} else {
listArray = listArray.concat(this);
}
});
return listArray;
}
// 刷新文件列表
function refreshList() {
let path = getPath();
delete fileList[path];
Traverse.path.forEach(function(e){
delete fileList[e];
});
delete Traverse[path];
instance.message.trigger("system-refresh");
}
function rename(filelist){
let url = panAPIUrl + 'filemanager?opera=rename&async=2'; // ajax 发送链接时会自动补全参数 2020年11月27日 19:31:28
let params = {
filelist:JSON.stringify(filelist),
};
$.ajax({
url:url,
method:'POST',
async:false,
data:params,
success:function(response){
slog('response :',response);
if(response.errno === 0){
tip('共修改 ' + filelist.length + ' 个文件,请等待修改完成</a>');
renameTaskProcess(response.taskid);
} else if(response.errno === 12) {
tip('当前还有任务未完成,请稍后再试。');
} else {
tip('修改失败,请尝试重新登录。如果持续失败,可能是百度接口发生改变。', 4e3);
}
}
});
}
// 重命名任务进度
function renameTaskProcess(taskid, progress) {
progress = progress || 0;
$.ajax({
url: taskAPIUrl + "?taskid=" + taskid,
success: function(e) {
if ("pending" === e.status) {
instance.ui.tip({
msg: '准备替换中...',
mode: 'loading',
autoClose: false
})
}
else if ("running" === e.status) {
progress = e.progress ? Math.min(Math.max(parseInt(e.progress), 0), 100) : progress;
showProcessTips("重命名进度: ", progress);
}
else if ("success" === e.status) {
instance.ui.tip({
msg:"重命名成功",
mode:"success"
});
setTimeout(function(){
refreshList();
panel.hide();
}, 1500);
return;
}
setTimeout(function(){
renameTaskProcess(taskid, progress);
}, 600);
},
error: function() {
instance.ui.tip({
msg:"出现未知错误"
});
}
})
}
// 提示信息
var tip_timeout;
function tip(msg, timeout) {
clearTimeout(tip_timeout);
timeout = timeout || 1500;
let $tip = $('#tip');
$tip.html(msg).css({
'margin-left': -$tip.outerWidth()/2,
'margin-top': -$tip.outerHeight()/2
}).fadeIn(120);
tip_timeout = setTimeout(function() {
$tip.fadeOut();
}, timeout);
}
// 显示进度条,取自: https://pannss.bdstatic.com/m-static/disk-system/pkg/common-chunks-all_860f963.js
function showProcessTips(e, t) {
var a = '<span class="asyn-tip-process" style="float: right;width: 180px;height: 5px;background: #1b71f0;margin: 17px 0 0 17px;border-radius: 4px;overflow: hidden;"><span class="asyn-tip-process-inner" style="float: left;display: inline-block;background: #fff;height: 5px;font-size: 0;width:' + t + '%"></span></span>';
instance.ui.tip({
mode: "none",
msg: '<span style="float: left;">' + e + t + "%</span>" + a,
autoClose: !1,
hasClose: !1
})
}
// 筛选文件,默认删除不匹配项,设置 keep 保留原始项比如预览的时候
function filter(keep) {
let chosen = $('.rename-chosen')[0];
var isReplace = chosen.classList.contains('rename-replace');
var isAdd = chosen.classList.contains('rename-add');
if (isReplace) {
var str_to_find = $('#rename-from').val();
if (!keep && !str_to_find){
tip('请输入关键词');
return;
}
var pattern;
var str_to_replace = $('#rename-to').val();
let renameType = $('#rename-type').val();
let g = '';
if (renameType !== "regexp") {
str_to_find = str_to_find.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
if (renameType === "global") g = 'g';
}
try {
pattern = new RegExp(str_to_find, g);
} catch(e) {
tip('正则表达式有误,请检查');
return;
}
} else if (isAdd) {
var thestart = $('#rename-start').val().replace(/(^\s*)/g,"");
var theend = $('#rename-end').val().replace(/(\s*$)/g,"");
if (!keep && !thestart && !theend){
tip('请输入前缀或后缀');
return;
}
} else {
var theext = $('#rename-ext').val().trim();
if (!keep && !theext){
tip('请输入扩展名');
return;
}
var oldext = $('#rename-oldext').val().trim();
}
let list = Traverse[getPath()] || getFileList();
slog('list_Length:' + list.length, 'list:',list);
if(list.length > 0){
let toRename = [];
// 替换关键词
if (isReplace) {
$(list).each(function (i){
slog('list '+ i +':',this.path);
let fileName = this.server_filename;
if (keep && str_to_find === '') {
toRename.push({"path":this.path,"newname":fileName});
} else {
let newName = fileName.replace(pattern, str_to_replace);
if (keep || newName !== '' && newName !== fileName) {
slog('newName:',newName);
toRename.push({"path":this.path,"newname":newName});
}
}
});
}
// 改前后缀
else {
$(list).each(function (i){
slog('list '+ i +':',this.path);
if (!isAdd && this.isdir === 1) return true; // 改拓展名跳过目录
let fileNameArray = this.server_filename.split(".");
let fileext = fileNameArray.length>1 ? fileNameArray.pop() : '';
if (isAdd) {
let last = fileNameArray.length-1;
fileNameArray[0] = thestart + fileNameArray[0];
fileNameArray[last] = fileNameArray[last] + theend;
if (fileext) fileNameArray.push(fileext);
slog('Add start:' + thestart,'end:' + theend);
} else {
// 当设置原扩展名时不替换其他扩展名
if (oldext && oldext !== fileext) {
if (!keep) {
return true;
}
if (fileext) fileNameArray.push(fileext);
} else {
// 排除相同扩展名
if (fileext === theext && !keep) {
return true;
}
fileNameArray.push(theext);
slog('FileExt :',fileext);
}
}
let newName = fileNameArray.join('.');
slog('newName:',newName);
toRename.push({"path":this.path,"newname":newName});
});
}
return toRename;
}
tip('这个目录是空的哦');
return;
}
var panel = {
traverse: function(){
instance.ui.tip({
msg: '遍历文件夹中...',
mode: 'loading',
autoClose: false
});
setTimeout(function() {
let list = Traverse[getPath()];
if (list === undefined) {
list = getFileList();
list = traverseFileList(list);
Traverse[getPath()] = list;
panel.preview();
traverseCount = 0;
traversePause = 0;
}
instance.ui.hideTip();
}, 30);
},
preview: function(){
let toRename = filter(true);
if (toRename) {
if (toRename.length) {
let i = 0;
let html = '';
$(toRename).each(function (){
let fileName = this.path.split("/").pop();
let newName = this.newname === "" ? fileName : this.newname;
let changed = fileName !== newName;
html += '<li class="' + (changed ? 'item-changed' : 'item-hide') + '">';
html += '<span class="item-name" title="' + fileName + '">' + fileName + '</span>';
html += '<span class="item-name" title="' + newName + '">' + newName + '</span>';
if (changed) i++;
html += '</li>';
});
html = '<p style="padding:0 6px 6px;color:red">查询到 ' + toRename.length + ' 个文件,将替换 ' + i + ' 个文件'
+ (i === 0 ? '<style>#dialog-rename .item-hide{display:block}</style>' : i < toRename.length ? ',<a class="toggle-item" href="javascript:;">查看所有文件</a>' : '')
+ '</p><div style="padding:6px 15px 0;background:#f7f7f7"><span class="item-name"><b>原文件名</b></span><span class="item-name"><b>新文件名</b></span></div>'
+ '<ul>' + html + '</ul>';
$('#rename-preview').html(html);
if (window.innerHeight<$('#dialog-rename').offset().top + $('#dialog-rename').height()) panel.show();
} else {
tip("未找到替换项");
}
}
},
rename: function(){
let toRename = filter();
if (toRename) {
slog('toRename :',toRename);
if (toRename.length){
rename(toRename);
} else {
$('.rename-chosen').hasClass('rename-replace') ? tip('好像没有替换') : tip('无需更改扩展名');
}
}
},
show: function(){
$('#rename-canvas').show();
let $rename = $('#dialog-rename');
$rename.css({
'left': (window.innerWidth - $rename.width())/2,
'top': (window.innerHeight - $rename.height())/2
}).show();
},
hide: function(){
$('#rename-canvas').hide();
$('#dialog-rename').hide();
$('#rename-preview').text('');
delete Traverse[getPath()];
},
};
//入口函数
try {
instance = require("system-core:context/context.js").instanceForSystem;
} catch(e) {
console.warn('页面未正常加载,或者百度已经更新!');
return;
}
var i = 1;
var addBtn = setInterval(function(){
let q_sel = document.querySelector('[data-button-index="3"]'); // 离线下载按钮,如果不是则需要修改
if (q_sel) {
clearInterval(addBtn);
// 构建样式和弹窗
$('head').append('<style>#dialog-rename .rename-field{text-align:center;display:none}#dialog-rename .rename-chosen{text-align:center;display:block}#dialog-rename input[type=text]{border:1px solid #e0e1e4;border-radius:4px;width:150px;line-height:30px;margin-right:18px;padding:0 6px;}#dialog-rename input[type=text]:last-child{margin-right:0;}#dialog-rename .item-name{width:50%;display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}#dialog-rename .item-changed{color:#478de4;}#dialog-rename .item-hide{display:none;}#dialog-rename ul{max-height:150px;padding:0 15px 6px;overflow-y:auto;background:#f7f7f7;}#dialog-rename .dialog-asyn-view .asyn-view-content li{padding-left:0}#dialog-rename .g-button-right .text{padding:0 18px;}#dialog-rename .tab-button .text{padding:0;}#tip{position:absolute;top:50%;left:50%;background:rgba(0,0,0,.75);color:#fff;padding:6px 12px;font-size:120%;border-radius:4px;white-space:nowrap;display:none}#rename-type{border:1px solid #e0e1e4;outline:0;border-radius:4px;height:30px;line-height:30px;padding-left: 4px;margin-right:18px;box-sizing:content-box;}</style>');
$('body').append('<div id="rename-canvas" style="position:fixed;left:0px;top:0px;z-index:50;background:rgb(0,0,0);opacity:0.5;width:100%;height:100%;display:none"></div><div style="width:540px;z-index:53;display:none;" id="dialog-rename" class="dialog alert-dialog-asyn-view"><div class="dialog-header dialog-drag"><h3><span class="dialog-header-title" style="font-weight:200;font-style:normal">批量重命名</span></h3><div class="dialog-control"></div></div><div class="dialog-body"><div class="rename-choose" style="text-align:center;margin-top:15px;"><a class="g-button g-button-blue tab-button" style="margin-right:-6px;border-radius:4px 0 0 4px;"><span class="g-button-right"><span class="text">替换关键词</span></a><a class="g-button tab-button" style="margin-right:-6px;border-radius:0"></span><span class="g-button-right"><span class="text">添加前后缀</span></span></a><a class="g-button tab-button" style="border-radius:0 4px 4px 0;"></span><span class="g-button-right"><span class="text">修改扩展名</span></a></div><div class="dialog-asyn-view"><div class="rename-form"><div class="rename-field rename-replace rename-chosen"><input id="rename-from" type="text" placeholder="关键词"><select id="rename-type"><option value="normal">替换一次</option><option value="global">替换全局</option><option value="regexp">正则匹配</option></select><input id="rename-to" type="text" placeholder="替换为"></div><div class="rename-field rename-add"><input id="rename-start" type="text" placeholder="前缀"><input id="rename-end" type="text" placeholder="后缀"></div><div class="rename-field"><input id="rename-oldext" type="text" placeholder="原扩展名, 可不填"><input id="rename-ext" type="text" value="mp4" placeholder="扩展名"></div></div><div id="rename-preview" style="margin-top:12px;"></div></div></div><div class="dialog-footer"></div><div id="tip"></div></div>');
// 添加按钮
let button_to_add = [
{name: '遍历文件夹', action: 'traverse', blue: 1},
{name: '预览', action: 'preview', blue: 1},
{name: '替换', action: 'rename', blue: 1},
{name: '取消', action: 'hide'}
];
$(button_to_add).each(function() {
let a = document.createElement('a');
a.className = "g-button" + (this.blue ? ' g-button-blue-large' : '');
a.innerHTML = '<span class="g-button-right"><span class="text">' + this.name + '</span></span>';
a.onclick = panel[this.action];
$('#dialog-rename .dialog-footer').append(a);
});
let btn_close = document.createElement('span');
btn_close.className = "dialog-icon dialog-close icon icon-close";
btn_close.onclick = panel.hide;
$('#dialog-rename .dialog-control').append(btn_close);
let btn_edit = document.createElement('a');
btn_edit.className = "g-button";
btn_edit.href = "javascript:;";
btn_edit.innerHTML = '<span class="g-button-right"><i class="icon icon-edit" title="批量重命名"></i><span class="text">批量重命名</span></span>';
btn_edit.onclick = panel.show;
$(q_sel).before(btn_edit);
// 防止按钮被遮挡
let hasChecked = instance.listInstance.getCheckedItems();
if (hasChecked.length) {
instance.Broker.getButtonBroker("listTools").filesSelect(hasChecked, {
paddingLeft:q_sel.parentNode.clientWidth
})
}
// 弹窗标题栏添加拖拽效果
let target, active, startX, startY;
$('#dialog-rename .dialog-header').on("mousedown touchstart", function(e) {
active = true;
target = $(this).parent();
startX = e.originalEvent.pageX - target.offset().left;
startY = e.originalEvent.pageY - target.offset().top;
if (window.mozInnerScreenX == null) return false;
});
$(document).on("mousemove touchmove", function(e) {
if ("mousemove" === e.type && active) target.offset({
left:e.originalEvent.pageX - startX,
top:e.originalEvent.pageY - startY
});
if ("touchmove" === e.type && active) target.offset({
left:e.originalEvent.pageX - startX,
top:e.originalEvent.pageY - startY
});
}).on("mouseup touchend", function() {
active = false;
});
// 功能切换按钮点击事件
$(document).on('click', '.rename-choose a', function() {
$(this).addClass("g-button-blue").siblings().removeClass("g-button-blue");
$('.rename-field').eq($('.rename-choose a').index(this)).show().addClass('rename-chosen').siblings().hide().removeClass('rename-chosen');
});
// 显隐替换项
$(document).on('click', '.toggle-item', function() {
let $this = $(this);
if ($this.hasClass('show')) {
$('.item-hide').hide();
$this.removeClass('show').text('查看所有文件');
} else {
$('.item-hide').show();
$this.addClass('show').text('查看替换文件');
}
this.blur()
});
} else if (i>30) {
console.warn('按钮添加失败,请检查百度页面是否更新!');
clearInterval(addBtn);
}
i++;
}, 1000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment