Greasy Fork

百度网盘 - 更高级的重命名

你不知道的百度网盘重命名姿势~支持批量替换重命名、手动批量修改后一次提交、智能重命名,拒绝转圈圈!

当前为 2023-07-24 提交的版本,查看 最新版本

// ==UserScript==
// @name            百度网盘 - 更高级的重命名
// @version         1.0.3
// @description     你不知道的百度网盘重命名姿势~支持批量替换重命名、手动批量修改后一次提交、智能重命名,拒绝转圈圈!
// @author          Priate
// @match           https://pan.baidu.com/*
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_addStyle
// @icon            https://nd-static.bdstatic.com/m-static/v20-main/favicon-main.ico
// @require         https://unpkg.com/vue@2
// @require         https://unpkg.com/[email protected]/dist/sweetalert.min.js
// @require         https://unpkg.com/[email protected]/dist/jquery.min.js
// @require         https://greasyfork.org/scripts/435476-priatelib/code/PriateLib.js?version=1202493
// @supportURL      https://greasyfork.org/zh-CN/scripts/435495/feedback
// @homepageURL     https://greasyfork.org/zh-CN/scripts/435495
// @contributionURL https://afdian.net/@cyberubbish
// @license         MIT
// @namespace       https://greasyfork.org/users/219866
// ==/UserScript==

(function() {
    'use strict';

    function initSetting() {
        var setting;
        if (!GM_getValue('priate_script_bdwp_data')) {
            GM_setValue('priate_script_bdwp_data', {
                left: 20,
                top: 100,
            })
        }
        setting = GM_getValue('priate_script_bdwp_data')
        GM_setValue('priate_script_bdwp_data', setting)
    }

    function injectDiv() {
        var priate_script_div = document.createElement("div")
        priate_script_div.innerHTML = `
<div id="priate_script_div">
<b style='font-size:30px; font-weight:300; margin: 10px 20px'>更高级的重命名</b>
<p id='priate_script_setting' style='margin: 0 0'>
❤️ by <a @click='openDonate' style='color:#337ab7'>Priate</a> |
v <a href="//greasyfork.org/scripts/443771" target="_blank" style='color:#ff6666'>{{version}}</a> |
<a @click="switchDrag">📌</a> | <a @click="recoverText">♻️</a> | <a v-show="data.length > 0" @click="smartRename">🤖️ |</a> <a @click="clearData">❌</a>
<br>
文件夹重命名 : <a @click='todo' :style='"color:" + (false ? "#00947e" : "#CC0F35")'> 关闭 </a> |
正则 : <a @click='todo' :style='"color:" + (false ? "#00947e" : "#CC0F35")'> 关闭 </a>
<div v-show="data.length">
<a style='color:#946C00;' @click="changeOriginText" v-show="showOriginText">{{'【' + originText + '】'}}</a>
<textarea class="replaceArea" ref="originTextInput" v-show="!showOriginText" @blur="recoverOriginText" type="text" v-model="originText" ></textarea>
<a @click="autoRename">➡️ ➡️ ➡️</a>
<a style='color:#00947e' @click="changeReplaceText" v-show="showReplaceText">{{'【' + replaceText + '】' }}</a>
<textarea class="replaceArea" ref="replaceTextInput" v-show="!showReplaceText" @blur="recoverReplaceText" type="text" v-model="replaceText" ></textarea>
</div>
</p>
<button @click="loadData">{{data.length > 0 ? '重载数据' : '加载数据'}}</button>
<button @click="postRename" v-show="musicList.length > 0"> 确定修改 </button>
</br>
<table v-show="data.length > 0">
<thead><tr><th></th><th>原始文件名</th><th>修改后文件名</th></tr></thead>
<tbody id="priate_script_table">
<tr v-for="(item, index) in data" :key="index">
<td><input class="checkMusicBox" v-model="musicList" :value='item' type="checkbox" :disabled="item.replace == item.origin"></td>
<td><a @click="originText = item.origin" style='color:#337ab7'>{{item.origin}}</a></td>
<td><a v-show="!item.isChanging" @click="manualRename(item)" style='color:#C01D07'>{{item.replace}}</a><textarea class="replaceArea" :ref="item.id" @blur="modifyReplace(item)" v-show="item.isChanging" v-model="item.replace"></textarea></td>
</tr>
</tbody>
</table>
</div>
`
        GM_addStyle(`
#priate_script_div{
font-size : 15px;
position: fixed;
background-color: rgb(240, 223, 175);
color : #660000;
text-align : center;
padding: 10px;
z-index : 9999;
border-radius : 20px;
border:2px solid #660000;
font-weight: 300;
text-stroke: 0.5px;
box-shadow: 5px 15px 15px rgba(0,0,0,0.4);
user-select : none;
-webkit-user-select : none;
-moz-user-select : none;
-ms-user-select:none;
}
#priate_script_div:hover{
box-shadow: 5px 15px 15px rgba(0,0,0,0.8);
transition: box-shadow 0.3s;
}

#priate_script_div a{
margin-bottom: 2px !important;
}
.priate_script_hide{
padding: 0 !important;
border:none !important;
}
a{
cursor : pointer;
text-decoration : none;
}
/*表格样式*/
#priate_script_div table{
text-align: center;
// border:2px solid #660000;
margin: 5px auto;
padding: 2px;
border-collapse: collapse;
display: block;
height : 400px;
overflow-y: scroll;
}
/*表格框样式*/
#priate_script_div td{
border:2px solid #660000;
padding: 8px 12px;
max-width : 300px;
word-wrap : break-word;
}
/*表头样式*/
#priate_script_div th{
border:2px solid #660000;
padding: 8px 12px;
font-weight: 300;
-webkit-text-stroke: 0.5px;
text-stroke: 0.5px;
}

/*脚本按钮样式*/
#priate_script_div button{
display: inline-block;
border-radius: 4px;
border: 1px solid #660000;
background-color: transparent;
color: #660000;
text-decoration: none;
padding: 5px 10px;
margin : 5px 10px;
font-weight: 300;
-webkit-text-stroke: 0.5px;
text-stroke: 0.5px;
}
/*脚本按钮悬浮样式*/
#priate_script_div button:hover{
cursor : pointer;
color: rgb(240, 223, 175);
background-color: #660000;
transition: background-color 0.2s;
}
/*设置区域 p 标签*/
#priate_script_setting{
user-select : none;
-webkit-user-select : none;
-moz-user-select : none;
-ms-user-select:none;
}
/*swal按钮*/
.swal-button--1{
background-color: #FFFAEB !important;
color: #946C00;
}
.swal-button--2{
background-color: #ebfffc !important;
color: #00947e;
}
.swal-button--3{
background-color: #ECF6FD !important;
color: #55ACEE;
}
.checkMusicBox{
transform: scale(1.7,1.7);
cursor: pointer;
}
.replaceArea{
height : 100%;
width : 100%;
background-color: #fff;
border:1px solid #000000;
padding: 4px;
border-radius: 4px;
}
.replaceInput{
height : 100%;
width : 40%;
background-color: #fff;
border:1px solid #000000;
padding: 4px;
border-radius: 4px;
}
`);
        document.querySelector("html").appendChild(priate_script_div)
        var setting = GM_getValue('priate_script_bdwp_data')
        document.getElementById("priate_script_div").style.left = (setting.left || 20) + "px";
        document.getElementById("priate_script_div").style.top = (setting.top || 100) + "px";
    }

    function dragFunc(id) {
        var Drag = document.getElementById(id);
        var setting = GM_getValue('priate_script_bdwp_data')
        Drag.onmousedown = function(event) {
            var ev = event || window.event;
            event.stopPropagation();
            var disX = ev.clientX - Drag.offsetLeft;
            var disY = ev.clientY - Drag.offsetTop;
            document.onmousemove = function(event) {
                var ev = event || window.event;
                setting.left = ev.clientX - disX
                Drag.style.left = setting.left + "px";
                setting.top = ev.clientY - disY
                Drag.style.top = setting.top + "px";
                Drag.style.cursor = "move";
                GM_setValue('priate_script_bdwp_data', setting)
            };
        };
        Drag.onmouseup = function() {
            document.onmousemove = null;
            this.style.cursor = "default";
        };
    };

    function unDragFunc(id) {
        var Drag = document.getElementById(id);
        Drag.onmousedown = function(event) {
            var ev = event || window.event;
            event.stopPropagation();
        };
        Drag.onmouseup = function() {};
        Drag.onmousemove = function() {};
    };

    //初始化脚本设置
    initSetting()
    //注入脚本div
    injectDiv()

    function getToken() {
        return document.querySelector(".nd-main-list, .nd-new-main-list").__vue__.yunData.bdstoken;
    }

    function getLogid() {
        let ut = unsafeWindow.require("system-core:context/context.js").instanceForSystem.tools.baseService;
        return ut.base64Encode(base.getCookie("BAIDUID"));
    }

    function getPath() {
        var nowPath = location.href.match(/path=(.+?)(?:&|$)/);
        var pathValue;
        if (nowPath)
            pathValue = decodeURIComponent(nowPath[1]);
        else
            pathValue = "/";
        if (pathValue.charAt(0) !== "/")
            pathValue = "/" + pathValue; // 补齐路径前缀斜杠
        if (pathValue.charAt(pathValue.length - 1) !== "/")
            pathValue += "/"
        return pathValue
    }

    function reloadList() {
        document.querySelector(".nd-main-list, .nd-new-main-list").__vue__.reloadList();
    }

    // 处理数据等逻辑
    var vm = new Vue({
        el: '#priate_script_div',
        data: {
            version: "1.0.3",
            setting: GM_getValue('priate_script_bdwp_data'),
            data: [],
            musicList: [],
            showOriginText: true,
            showReplaceText: true,
            originText: "需要替换的内容",
            replaceText: "",
            path: '/',
            isDrag: true,
        },
        methods: {
            loadData() {
                const path = getPath()
                this.path = path
                const all_tr = document.querySelectorAll('table.wp-s-pan-table__body-table tbody>tr');
                var result = [];
                var _this = this
                all_tr.forEach((item) => {
                    const type = item.querySelector('img[alt]') ? item.querySelector('img[alt]').getAttribute('alt') : 'unknow'
                    if (!item.querySelector('a')) return
                    const music = {
                        id: item.getAttribute('data-id'),
                        origin: item.querySelector('a').getAttribute('title'),
                        replace: item.querySelector('a').getAttribute('title'),
                        isChanging: false,
                        type,
                        isFolder: type == 'folder',
                    }
                    result.push(music)
                })
                // 如果仍未获取到数据
                if (result.length == 0) {
                    swal("未获取到数据,请确认此目录下有文件或文件夹!", {
                        icon: "error",
                        buttons: false,
                        timer: 3000,
                    });
                }
                this.data = result
                this.musicList = []
            },
            clearData() {
                if (this.data.length == 0) swal(`已经是最简形态了!`, {
                    buttons: false,
                    timer: 2000,
                });
                this.data = []
                this.musicList = []
            },
            openDonate() {
                showDonate()
            },
            async manualRename(item) {
                this.unDrag()
                item.isChanging = true
                await Sleep(0.01)
                this.$refs[item.id][0].focus();
            },
            modifyReplace(item) {
                this.drag()
                item.isChanging = false
                if (item.replace != item.origin) {
                    if (!this.musicList.find(el => el.id == item.id)) {
                        this.musicList.push(item)
                    }
                } else {
                    this.musicList = this.musicList.filter(el => el.id != item.id)
                }

            },
            autoRename() {
                var _this = this
                const origin = this.originText
                const replace = this.replaceText
                var hasChanged = false
                var hasEmpty = false
                this.data.forEach(item => {
                    item.replace = item.replace.replace(origin, replace)
                    if (item.replace !== item.origin) {
                        hasChanged = true
                    }
                    if (item.replace == "") {
                        hasEmpty = true
                        item.replace = item.origin
                    }
                    _this.modifyReplace(item)
                })
                if (!hasChanged) swal(`没有匹配到任何需要修改的文件!`, {
                    icon: "error",
                    buttons: false,
                    timer: 3000,
                });
                if (hasEmpty) swal(`替换后某个文件名为空!`, {
                    icon: "error",
                    buttons: false,
                    timer: 3000,
                });
            },
            async postRename() {
                var _this = this
                const token = getToken()
                // const logid = getLogid()
                const data = this.musicList.map(item => {
                    return {
                        id: item.id,
                        path: `${_this.path}${item.origin}`,
                        newname: item.replace,
                    }
                })
                $.ajax(`https://pan.baidu.com/api/filemanager?async=2&onnest=fail&opera=rename&bdstoken=${getToken()}&clienttype=0&app_id=250528&web=1`, {
                    type: 'post',
                    data: {
                        filelist: JSON.stringify(data)
                    },
                    complete: function(res) {
                        const resp = res.responseJSON
                        if (resp['errno'] == 0) {
                            swal(`重命名已完成!\n如部分文件显示未修改请点击 ♻️ 按钮手动刷新!`, {
                                icon: "success",
                                buttons: false,
                                timer: 3000,
                            });
                        } else {
                            swal(`重命名失败!`, {
                                icon: "error",
                                buttons: false,
                                timer: 3000,
                            });
                        }
                        _this.clearData()
                    }
                });
                await Sleep(3)
                reloadList()
            },
            switchDrag() {
                if (this.isDrag) {
                    this.unDrag()
                    swal(`悬浮窗已固定`, {
                        buttons: false,
                        timer: 2000,
                    });
                } else {
                    this.drag()
                    swal(`悬浮窗可以拖动了`, {
                        buttons: false,
                        timer: 2000,
                    });
                }
            },
            unDrag() {
                this.isDrag = false
                unDragFunc("priate_script_div")
            },
            drag() {
                this.isDrag = true
                dragFunc("priate_script_div")
            },
            async changeOriginText() {
                this.unDrag()
                this.showOriginText = false
                await Sleep(0.01)
                this.$refs.originTextInput.focus();
            },
            async changeReplaceText() {
                this.unDrag()
                this.showReplaceText = false
                await Sleep(0.01)
                this.$refs.replaceTextInput.focus();
            },
            recoverOriginText() {
                this.drag()
                this.showOriginText = true
            },
            recoverReplaceText() {
                this.drag()
                this.showReplaceText = true
            },
            recoverText() {
                reloadList()
            },
            smartRename() {
                var _this = this
                var hasChanged = false
                var hasEmpty = false
                var lengthStatistics = {}
                var maxLength = 0
                this.data.forEach(item => {
                    const suffix = item.origin.split('.').length > 1 ? '.' + item.origin.split('.')[item.origin.split('.').length - 1] : ''
                    item.numArr = item.origin.replace(suffix, '').match(/\d+/g) || []
                    // 寻找出现次数最多的匹配项
                    if (lengthStatistics[item.numArr.length] == undefined) lengthStatistics[item.numArr.length] = 1
                    else lengthStatistics[item.numArr.length] += 1
                })
                for (var i in lengthStatistics) {
                    maxLength = lengthStatistics[i] > maxLength ? i : maxLength
                }
                var seq = -1
                for (var index = 0; index < maxLength; index++) {
                    const tempList = this.data.map(item => {
                        if (item.numArr.length == maxLength) {
                            return item.numArr[index]
                        }
                    }).filter(l => l != undefined)
                    // 判断是否有重复元素
                    if (Array.from(new Set(tempList)).length == tempList.length) {
                        seq = index
                        break
                    }
                }
                if (seq < 0) return swal(`智能重命名失败,找不到唯一的数字序号!`, {
                    icon: "error",
                    buttons: false,
                    timer: 3000,
                });
                this.data.forEach(item => {
                    if (item.numArr.length == maxLength) {
                        const suffix = item.origin.split('.').length > 1 ? '.' + item.origin.split('.')[item.origin.split('.').length - 1] : ''
                        item.replace = `${item.numArr[seq]}${suffix}`
                    }
                    if (item.replace !== item.origin) {
                        hasChanged = true
                    }
                    if (item.replace == "") {
                        hasEmpty = true
                        item.replace = item.origin
                    }
                    _this.modifyReplace(item)
                })

                if (!hasChanged) swal(`没有匹配到任何需要修改的文件!`, {
                    icon: "error",
                    buttons: false,
                    timer: 3000,
                });
                if (hasEmpty) swal(`替换后某个文件名为空!`, {
                    icon: "error",
                    buttons: false,
                    timer: 3000,
                });
            },
            todo() {
                swal(`🈲️🈲️🈲️ 此功能暂不可用,请等待版本更新 🔞🔞🔞`, {
                    buttons: false,
                    timer: 2000,
                });
            }
        },
        computed: {},
        mounted() {}
    })
    //设置div可拖动
    dragFunc("priate_script_div");
})();