// ==UserScript== // @name 仓库用度盘投稿助手 // @namespace moe.jixun.dupan.galacg // @version 1.2.1 // @description 简易功能增强, 方便仓库投稿用 // @author Jixun // @include http://pan.baidu.com/disk/home* // @include http://yun.baidu.com/disk/home* // @include https://pan.baidu.com/disk/home* // @include https://yun.baidu.com/disk/home* // @compatible firefox GreaseMonkey (有限) // @compatible firefox Violentmonkey // @compatible chrome Violentmonkey // @grant none // @run-at document-start // @downloadURL none // ==/UserScript== const isGm = (typeof unsafeWindow !== 'undefined') && (unsafeWindow !== window); if (isGm) { const INFO = '[仓库助手]'; console.info("%s 以 GreaseMonkey 兼容模式执行。该脚本管理器所遇到的问题不能保证能够修复。", INFO); unsafeWindow.eval(`;(${entry})();`); } else { entry(); } function entry () { const INFO = '[仓库助手]'; var oRequire; if (window.require) { console.warn("%s 覆盖方式安装,若无效请强制刷新。", INFO); oRequire = window.require; window.require = fakeRequire; Object.assign(fakeRequire, oRequire); } else { console.info("%s 钩子方式安装,若失效请报告。", INFO); Object.defineProperty(window, 'require', { set: function (require) { oRequire = require; }, get: function () { return fakeRequire; } }); } const __AppId = 250528; const pluginBlacklist = ['右上角广告位', '网盘APP下载', '满减活动', '会员提醒']; var _G = {}; // window.__debug_G = _G; function fakeRequire(module) { // console.info('%s Load module: %s', INFO, module); if (module == 'disk-system:widget/system/uiRender/menu/listMenu.js') { if (!_G.injected) { initScript(); _G.injected = true; } } else if (module == 'system-core:pluginHub/register/register.js') { if (!_G.btnInjected) { registerPlugin(); _G.btnInjected = true; } } return oRequire.apply(this, arguments); } function menuInsertAfter(list, name, item, noPush) { for (var i = 0; i < list.length; i++) { if (list[i] instanceof Array) { if (menuInsertAfter(list[i], name, item, true)) { return; } } else if (list[i].title === name) { i++; list.splice(i, i, item); return true; } } if (!noPush) list.push(item); } function initScript() { // Load module _G.FaceData = oRequire('system-core:data/faceData.js'); _G.ListInit = oRequire("disk-system:widget/pageModule/list/listInit.js"); var fileCtxMenu = _G.FaceData.getData().contextMenu.file; menuInsertAfter(fileCtxMenu, '分享', { index: 8, keyboard: 'u', title: '自定义分享', display: isFileChecked, action: lazyDialog('loadCustomShareDialog') }); fileCtxMenu.forEach(m => { if (m.index >= 2) { m.index++; } }); fileCtxMenu.push({ index: 2, // '删除' 的 index。 keyboard: 'r', position: 'bottom', title: '批量重命名', display: isFileChecked, action: lazyDialog('loadBatchRenameDialog') }); setTimeout(delayLoad, 200); delayLoadDuCode(); // ESC 将关闭所有漂浮窗口 document.addEventListener('keyup', function(e) { if (e.keyCode == 0x1b) { $('.dialog-close').click(); } }, false); } function registerPlugin() { window.define('function-widget:jixun/standard-code.js', function(require, exports, module) { exports.start = lazyDialog('loadStandardCodeDialog'); }); window.manifest = window.manifest.filter(plugin => pluginBlacklist.indexOf(plugin.name) === -1); window.manifest.push({ "name": "标准提取码插件", "group": "moe.jixun.code", "version": '1.0', "type": "1", "description": "类似于 115 的标准提取码", "filesType": "*", "buttons": [{ "index": 2, "disabled": "none", "title": "标准提取码", "buttonStyle": "normal", "pluginId": "JIXUNSTDCODE", "position": 'tools' }], "preload": false, "depsFiles": [], "entranceFile": "function-widget:jixun/standard-code.js", "pluginId": "JIXUNSTDCODE" }); } function isFileChecked() { return _G.ListInit.getCheckedItems().length > 0; } function lazyDialog(name) { return function() { if (_G[name]) { _G[name](); } else { loadDependencies(); _G.Tip.show({ mode: 'loading', msg: '正在努力加载中 ...' }); } }; } function nextId() { if (!nextId.id) nextId.id = 0; return nextId.id++; } function confirmDialog(data) { loadDependencies(); var dialog; var dialogData = { id: "confirm-" + nextId(), show: true, title: data.title, body: $('
').append(data.body), buttons: [{ name: "confirm", title: data.sureText || "确定", type: "big", color: "blue", padding: ["50px", "50px"], click: function() { if ($.isFunction(data.onSure)) { data.onSure.apply(this, arguments); } else { dialog.hide(); } } }, { name: "cancel", title: data.cancelText || "取消", type: "big", padding: ["50px", "50px"], click: function() { if ($.isFunction(data.onCancel)) { data.onCancel.apply(this, arguments); } else { dialog.hide(); } } }] }; if (data.cancel === false) { dialogData.buttons.pop(); } dialog = new _G.Dialog(dialogData); return dialog; } function delayLoad() { _G.loadCustomShareDialog = (function() { var _tplCustomShare = `

请输入提取码:

无效的提取码, 脚本将随机生成一个分享代码 :<

分享地址:

提取码:

投稿代码:

`; var dialog, $footer, $key, $tplCustomShare; function showDialog() { $tplCustomShare = $(_tplCustomShare); dialog = confirmDialog({ title: '自定义分享', body: $tplCustomShare, onSure: function() { handleConfirm(); dialog.hide(); }, onCancel: function() { dialog.hide(); }, }); $footer = dialog.$dialog.find(_G.Dialog.QUERY.dialogFooter); $key = $('#jx_shareKey', $tplCustomShare) .blur(function() { if (!isCodeValid(this.value = this.value.trim())) { $('#jx_errmsg', $tplCustomShare) .removeClass('jx_hide'); } }) .focus(function() { $('#jx_errmsg', $tplCustomShare) .addClass('jx_hide'); }) .val(genKey(4)); } function handleConfirm() { var key = $key.val(); if (!isCodeValid(key)) { key = genKey(4); $key.val(key); } _G.Tip.show({ mode: 'loading', msg: '正在分享,请稍后 ...', autoClose: false }); var sharedItems = _G.ListInit.getCheckedItems(); $.ajax({ url: '/share/set?' + $.param({ channel: 'chunlei', bdstoken: yunData.MYBDSTOKEN, app_id: __AppId }), type: 'POST', data: { fid_list: JSON.stringify(sharedItems.map(getFileId)), schannel: 4, channel_list: '[]', pwd: key }, dataType: 'json' }).success(function(r) { _G.Tip.hide(); _G.Tip.show({ mode: 'success', msg: '分享成功!' }); $footer.children('.g-button-blue-large').hide(); $footer.children('.g-button-large').find('.text').text('关闭'); let url = r.shorturl ? `${r.shorturl}#${key}` : '很抱歉, 分享失败 :<'; $('#jx_shortUrl', $tplCustomShare).val(url); $('#jx_shareCode', $tplCustomShare).val(key); $tplCustomShare.toggleClass('jx_hide'); var title = fixCode(sharedItems[0].server_filename) + (sharedItems.length == 1 ? '' : ' 等文件'); $('#jx_dlboxCode', $tplCustomShare).val( `[dlbox title="${escapeHtml(title)}" from="浩瀚的宇宙" time="${makeDate(new Date())}" info="提取:${escapeHtml(key)}" link1="度娘|${url}"][/dlbox]]` ); dialog.show(); }).fail(function() { _G.Tip.hide(); _G.Tip.show({ mode: 'failure', msg: '网络错误,请稍后重试。' }); }); } /* 依赖函数表 */ function isCodeValid(code) { return encodeURIComponent(code).replace(/%[A-F\d]{2}/g, '-').length == 4; } function fixCode(code) { return code.replace(/"/g, '"').replace(/\]/g, ']'); } function fixWidthDigits(d) { return ('0' + d.toString()).slice(-2); } function makeDate(d) { return `${d.getFullYear()}.${fixWidthDigits(d.getMonth() + 1)}.${fixWidthDigits(d.getDate())}`; } function genKey(size) { // length => 26 + 10, 36 var keySet = 'abcdefghijklmnopqrstuvwxyz0123456789'; for (var i = (size || 4) | 0, r = ''; i--;) r += keySet[0 | (Math.random() * 36)]; return r; } function getFileId(item) { return item.fs_id; } /* 收尾 */ return showDialog; })(); _G.loadBatchRenameDialog = (function() { var _tplConfirmRename = `

请输入新的命名规则 (自动储存):

:n 表示不带扩展名的文件名; :e 表示扩展名; :E 表示 .扩展名;
:d 表示一位随机数字; :c 表示一位随机字符; :t 表示当前时间戳

`; var dialog, $tplConfirmRename; function showDialog() { $tplConfirmRename = $(_tplConfirmRename); $('#jx_nameRule', $tplConfirmRename).val(localStorage.jxRenameRule || '[GalACG] :d:d:d:d:d:d:d:d:d:d:E'); dialog = confirmDialog({ title: '确认批量重命名', body: $tplConfirmRename, onSure: function() { handleConfirm(); dialog.hide(); }, onCancel: function() { dialog.hide(); }, }); } function handleConfirm() { // 储存批量重命名记录 var _nameRule = $('#jx_nameRule', $tplConfirmRename).val(); localStorage.jxRenameRule = _nameRule; var _flist = _G.ListInit.getCheckedItems().map(toReplacePayload); _G.Tip.show({ mode: 'loading', msg: '正在批量重命名,请稍后 ...', autoClose: false }); $.ajax({ url: '/api/filemanager?' + $.param({ channel: 'chunlei', bdstoken: yunData.MYBDSTOKEN, app_id: __AppId, opera: 'rename' }), type: 'POST', data: { filelist: JSON.stringify(_flist) } }).success(function() { _G.Tip.hide(); _G.Message.trigger('system-refresh'); }).fail(function() { _G.Tip.hide(); _G.Tip.show({ mode: 'failure', msg: '批量重命名失败, 请稍后重试!' }); }); function toReplacePayload(item) { return { path: item.path, newname: _nameRule.replace(/:([cdeEn])/g, fixName.bind(item.server_filename)) }; } } /* 依赖函数表 */ function fixName(z, code) { switch (code) { case 'n': var name = this.match(/^(.+)\./); return name ? name[1] : this; case 'c': return String.fromCharCode(97 + Math.random() * 26); case 'd': return Math.random().toString().slice(3, 4); case 't': return +new Date(); case 'e': var ext = this.match(/\.([^.]+)$/); return ext ? ext[1] : ''; case 'E': return this.match(/\.[^.]+$/) || ''; } } /* 收尾 */ return showDialog; })(); } let div = document.createElement('a'); let escapeDict = { '"': 'quot', "'": 'apos', }; function escapeHtml(text) { div.textContent = text; const result = div.innerHTML.replace(/["']/g, x => `&${escapeDict[x]};`); div.textContent = ''; return result; } function parseSize(size) { // 超过 GB if (size.length > 9) { size = size.slice(0, -7); return size.slice(0, -2) + '.' + size.slice(-2) + ' GB'; } return (parseInt(size) / 1024 / 1024).toFixed(2) + ' MB'; } function itemInfo(item) { const name = escapeHtml(item.name); return ` ${name} (${escapeHtml(parseSize(item.size))}) `; } function delayLoadDuCode() { _G.loadStandardCodeDialog = delayLoadDuStdCode(); function delayLoadDuStdCode() { var _tplStandardCode = `

扩展阅读: 肚娘代码说明 [游侠] | 标准度娘提取码 [梦姬]

文件列表 (版本: --):

    无效的提取码! 请确保您输入的提取码无误。

    `; var dialog, $tplStandardCode, codeInfo, jx_list, jx_code, jx_errmsg, jx_version; var failed = 0; function showDialog() { $tplStandardCode = $(_tplStandardCode); dialog = confirmDialog({ title: '通用提取码', body: $tplStandardCode, onSure: function() { handleConfirm(); dialog.hide(); }, onCancel: function() { dialog.hide(); }, }); jx_list = $('.jx_list', $tplStandardCode); jx_code = $('.jx_code', $tplStandardCode); jx_errmsg = $('.jx_errmsg', $tplStandardCode); jx_version = $('.jx_version', $tplStandardCode); function updatePreview () { var code = jx_code.val(); codeInfo = DuParser.parse(code); jx_errmsg.toggleClass('jx_hide', Boolean(!code || codeInfo.length)); if (codeInfo.length) { jx_version.text(codeInfo.ver); jx_list.html(codeInfo.map(itemInfo).map(x => `
  • ${x}
  • `).join('')); } else { jx_version.text('--'); jx_list.text(''); } } const debounce = fn => { let timer; return () => { cancelAnimationFrame(timer); timer = requestAnimationFrame(fn); }; }; jx_code.on('blur input', debounce(updatePreview)).focus(function() { jx_errmsg.addClass('jx_hide'); }); } var _curDir; function handleConfirm() { _curDir = _G.ListInit.currentKey; if (_curDir.slice(-1) != '/') _curDir += '/'; failed = 0; saveFile(0); } function statusHtml(success) { const text = success ? '成功' : '失败'; const className = success ? 'success' : 'fail'; return `${text}`; } function saveFile(i) { if (i >= codeInfo.length) { _G.Message.trigger('system-refresh'); const dialog = confirmDialog({ title: `转存完毕 (失败 ${failed} 个, 共 ${i} 个)!`, body: ` `, onSure: function() { dialog.hide(); }, cancel: false, }); return; } _G.Tip.show({ mode: 'loading', msg: `正在转存文件 (${ i + 1 }/${ codeInfo.length }), 请稍后 ..`, autoClose: false }); var file = codeInfo[i]; $.ajax({ url: '/api/rapidupload?rtype=1', type: 'POST', data: { path: _curDir + file.name, 'content-md5': file.md5, 'slice-md5': file.md5s, 'content-length': file.size, 'local_mtime': '' } }).success(function(r) { _G.Tip.hide(); if (r.errno) { failed++; } else { codeInfo[i].success = true; } }).fail(function(r) { failed++; }).always(function() { saveFile(i + 1); }); } /** * 一个简单的类似于 NodeJS Buffer 的实现. * 用于解析游侠度娘提取码。 * @param {SimpleBuffer} */ function SimpleBuffer(str) { this.fromString(str); } SimpleBuffer.toStdHex = function toStdHex(n) { return ('0' + n.toString(16)).slice(-2); }; SimpleBuffer.prototype.fromString = function fromString(str) { var len = str.length; this.buf = new Uint8Array(len); for (var i = 0; i < len; i++) { this.buf[i] = str.charCodeAt(i); } }; SimpleBuffer.prototype.readUnicode = function readUnicode(index, size) { if (size & 1) size++; var bufText = Array.prototype.slice.call(this.buf, index, index + size).map(SimpleBuffer.toStdHex); var buf = ['']; for (var i = 0; i < size; i += 2) buf.push(bufText[i + 1] + bufText[i]); return JSON.parse('"' + buf.join('\\u') + '"'); }; SimpleBuffer.prototype.readNumber = function readNumber(index, size) { var ret = 0; for (var i = index + size; i > index;) ret = this.buf[--i] + (ret * 256); return ret; }; SimpleBuffer.prototype.readUInt = function readUInt(index) { return this.readNumber(index, 4); }; SimpleBuffer.prototype.readULong = function readULong(index) { return this.readNumber(index, 8); }; SimpleBuffer.prototype.readHex = function readHex(index, size) { return Array.prototype.slice.call(this.buf, index, index + size).map(SimpleBuffer.toStdHex).join(''); }; function DuParser() {} DuParser.parse = function generalDuCodeParse(szUrl) { var r; if (szUrl.indexOf('BDLINK') === 0) { r = DuParser.parseDu_v1(szUrl); r.ver = '游侠 v1'; } else if (szUrl.indexOf('bdpan://') === 0) { r = DuParser.parseDu_bdpan(szUrl); r.ver = 'PanDownload'; } else { r = DuParser.parseDu_v2(szUrl); r.ver = '梦姬标准'; } return r; }; DuParser.parseDu_v1 = function parseDu_v1(szUrl) { var raw = atob(szUrl.slice(6).replace(/\s/g, '')); if (raw.slice(0, 5) !== 'BDFS\x00') return null; var buf = new SimpleBuffer(raw); var ptr = 9; var arrFiles = []; var fileInfo, nameSize; var total = buf.readUInt(5); for (i = 0; i < total; i++) { // 大小 (8 bytes) // MD5 + MD5S (0x20) // nameSize (4 bytes) // Name (unicode) fileInfo = {}; fileInfo.size = buf.readULong(ptr + 0); fileInfo.md5 = buf.readHex(ptr + 8, 0x10); fileInfo.md5s = buf.readHex(ptr + 0x18, 0x10); nameSize = buf.readUInt(ptr + 0x28) << 1; fileInfo.nameSize = nameSize; ptr += 0x2C; fileInfo.name = buf.readUnicode(ptr, nameSize); arrFiles.push(fileInfo); ptr += nameSize; } return arrFiles; }; DuParser.parseDu_v2 = function parseDu_v2(szUrl) { return szUrl.split('\n').map(function(z) { // unsigned long long: 0~18446744073709551615 return z.trim().match(/([\dA-F]{32})#([\dA-F]{32})#([\d]{1,20})#([\s\S]+)/); }).filter(function(z) { return z; }).map(function(info) { return { md5: info[1], md5s: info[2], size: info[3], name: info[4] }; }); }; DuParser.parseDu_bdpan = function parseDu_bdpan(szUrl) { return szUrl.split('\n').map(z => z.trim()).filter(url => szUrl.indexOf('bdpan://') === 0).map(z => { return atob(z.slice('bdpan://'.length)).trim().match(/^([\s\S]+)\|([\d]{1,20})\|([\dA-F]{32})\|([\dA-F]{32})$/i); }).filter(function(z) { return z; }).map(function([, name, size, md5, md5s]) { name = decodeURIComponent(name.split('').map(z => `%${('0' + z.charCodeAt(0).toString(16)).slice(-2)}`).join('')); return { name, size, md5, md5s }; }); }; /* 收尾 */ return showDialog; } } function loadDependencies() { _G.Message = oRequire("system-core:system/baseService/message/message.js"); _G.Tip = oRequire("system-core:system/uiService/tip/tip.js"); _G.Dialog = oRequire("system-core:system/uiService/dialog/dialog.js"); _G.Context = oRequire("system-core:context/context.js").instanceForSystem; _G.ui = _G.Context.ui; } }; // Inject style var style = document.createElement('style'); style.textContent = ` .jx_btn { background: #fefefe; background: linear-gradient(to bottom, #fefefe 0%,#f2f2f2 88%); display: inline-block; line-height: 25px; vertical-align: middle; margin: 0 0 0 10px; text-decoration: none; border: 1px solid #AAA; padding: 0px 20px; height: 26px; border-radius: 2px; min-width: 3em; text-align: center; } .jx_btn, .jx_btn:hover, .jx_btn:focus { color: #666; } .jx_btn:active { color: #06C; background: #e3e3e3; background: -moz-linear-gradient(top, #e3e3e3 0%, #f7f7f7 12%); background: -webkit-linear-gradient(top, #e3e3e3 0%,#f7f7f7 12%); background: linear-gradient(to bottom, #e3e3e3 0%,#f7f7f7 12%); } .jx-input { margin: 9px 0; _margin: 7px 0; padding: 0 0 0 5px; width: 200px; height: 24px; vertical-align: middle; border: 1px solid #3b8cff; border: 1px solid rgba(58,140,255,.3); background: #fff; border-radius: 2px; } .jx_hide { display: none } .jx_c_warn { color: red } .jx_list { text-align: left; max-height: 5.5em; overflow-y: scroll; overflow-x: hidden; line-height: 1; padding: .2em; margin-bottom: .5em; } /* .jx_list:not(:empty) { border: 1px solid #ddd; } */ .jx_list > li { display: flex; white-space: nowrap; line-height: 1.3; } .jx_list .name { color: black; overflow: hidden; text-overflow: ellipsis; } .jx_list .size { color: #777; flex-grow: 1; } .save-complete-details { max-height: 30em; } .jx-status { padding-left: 0.25em; } .jx-status-success { color: green; } .jx-status-fail { color: red; } textarea.jx{ width: 100%; min-height: 5em; line-height: 1; } `; document.head.appendChild(style);