Greasy Fork

来自缓存

Greasy Fork is available in English.

仓库用度盘投稿助手

简易功能增强, 方便仓库投稿用

当前为 2015-08-02 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        仓库用度盘投稿助手
// @namespace   org.jixun.dupan.galacg
// @description 简易功能增强, 方便仓库投稿用
// @include     http://pan.baidu.com/disk/home
// @include     http://pan.baidu.com/disk/home#*
// @include     http://pan.baidu.com/disk/home/
// @include     http://pan.baidu.com/disk/home/*
// @version     1.0.5.2
// @grant       none
// @run-at      document-end
// ==/UserScript==

var script = document.createElement('script');
script.innerHTML = ';(' + (function () {
	var __AppId = 250528;
	var _ = function (foo) {
		return foo.toString().match(/\/\*([\s\S]+)\*\//)[1];
	};
	
	function sprintf () {
		var arg = arguments,
			len = arg.length - 1,
			inp = arg[0];
		
		if (len < 1) return;
		
		for (var i=len; i>0; i--) {
			inp = inp.replace (new RegExp('(\\$|%)'+i,'g'), arg[i])
		}
		return inp;
	}

	// 第三方百度盘用户脚本 SDK
	var $fileAPI = require("clouddisk-ui:widget/list-view/disk-home.js");
	var $dataCenter = require("common:widget/data-center/data-center.js");
	var $dialog = require ('common:widget/dialog/dialog.js');

	// 刷新当前视图
	var _reload = function () { $fileAPI.render(); };

	// 消息提示
	var Toast = require("common:widget/toast/toast.js");
	var $panel = require ('common:widget/panel/panel.js');
	/*
	 Toast.obtain.useToast ({
	    toastMode:
	        Toast.obtain.MODE_LOADING
	        | Toast.obtain.MODE_CAUTION
	        | Toast.obtain.MODE_SUCCESS
	        | Toast.obtain.MODE_FAILURE
	        | Toast.obtain.MODE_NONE,
	    msg: '消息',
	    sticky: true, // 是否保留显示不消失 (除非用户交互)
		position: $panel.TOP, // 如果不是这个则为 0,0 (内置)
	    closeType: true, // True 直接显示; False 单击后隐藏
	    relativeDOM: 定位用元素 DOM
	 });
	 */

	/**
	 * @namespace $dataCenter
	    appVersion: Object
		currentDir: "/目录"
		is-timeline: true
		isDesc: 1
		isOnlyRenderTypeChange: false
		orderKey: "time"
		page: "disk-home"
		quota: Object
		selectedItemList: [ 选中的项目的元素列表 ]
		selectedList: [ 选中的项目的 id 列表 ]
		tmpl-selected-list: <回调, 生成选中列表文字>
	 */
	// require('clouddisk-ui:widget/context-menu/context-menu.js');


	$('<style>').text (_(function () {/*
.jx_btn {
	background: #fefefe;
	background: -moz-linear-gradient(top,  #fefefe 0%, #f2f2f2 88%);
	background: -webkit-linear-gradient(top,  #fefefe 0%,#f2f2f2 88%);
	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_hide   { display: none }
.jx_c_warn { color: red }

.dialog-panel .jx_list {
	text-align: left;
	max-height: 3em;
	overflow-y: scroll;
	overflow-x: hidden;
	line-height: 1;
	padding: .2em;
	margin-bottom: .5em;
}

.jx_list .name {
	color: black;
}
.jx_list .size {
	color: #777;
}

textarea.jx{
	width: 100%;
}
	*/})).appendTo (document.body);
	
	var parseDu = (function () {
		var proto = Array.prototype;
		var _slice = proto.slice;
		
		function toStdHex (n) {
			return ('0' + n.toString(16)).slice(-2);
		}
		
		function readUnicode(buf, index, size) {
			if (size % 2 == 1)
				size ++;
			
			var bufText = _slice.call(buf, index, index + size).map(toStdHex);
			
			var buf = [''];
			for (var i = 0; i < size; i+=2)
				buf.push(bufText[i+1] + bufText[i]);
			
			return JSON.parse('"' + buf.join('\\u') + '"');
		}

		function readNumber_slow (buf, index, size) {
			var x = _slice.call(buf, index, index + size).reverse().map(toStdHex);
			return parseInt(x.join(''), 16)
		}
		
		function readNumber (buf, index, size) {
			var ret = 0;
			
			for (var i = index + size - 1; i >= index; i--)
				// ret = buf[i] + (ret << 8);
				// Change to *unsigned* method.
				ret = buf[i] + (ret * 256);
			
			return ret;
		}
		
		function readUInt (buf, index) {
			return readNumber(buf, index, 4);
		}
		
		var readULong = typeof bigInt === 'function' ? function (buf, index) {
			var x = new bigInt(readUInt(buf, index + 4))
			return (x.shiftLeft(32).add(readUInt(buf, index)).toString());
		} : function (buf, index) {
			return readNumber(buf, index, 8).toString();
		};
		
		function readHex (buf, index, size) {
			return _slice.call(buf, index, index + size).map(toStdHex).join('');
		}

		function parseDu_v1 (szUrl) {
			var raw = atob(szUrl.slice(6).replace(/\s/g, ''));
			if (raw.slice(0, 5) !== 'BDFS\x00')
				return null;
			
			var len = raw.length;
			var buf = new Uint8Array(len);
			for (var i = 0; i < len; i++) {
				buf[i] = raw.charCodeAt(i);
			}
			
			var arrFiles = [];
			window.buf = buf;
			var total = readUInt(buf, 5);
			var ptr = 9;
			var block ;
			var fileInfo;
			var nameSize = 0;
			
			for (var i = 0; i < total; i++) {
				block = _slice.call(buf, ptr, ptr + 0x2C);
				ptr += 0x2C;
				
				// 大小 (8 bytes)
				// MD5 + MD5S (0x20)
				// nameSize (4 bytes)
				fileInfo = {};
				fileInfo.size = readULong(block, 0);
				fileInfo.md5  = readHex(block,    8, 0x10);
				fileInfo.md5s = readHex(block, 0x18, 0x10);
				nameSize = readUInt(block, 0x28) << 1;
				fileInfo.nameSize = nameSize;
				fileInfo.name = readUnicode(buf, ptr, nameSize);
				arrFiles.push(fileInfo);
				ptr += nameSize;
			}
			
			return arrFiles;
		}

		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]
				}
			});
		}

		return function (szUrl) {
			var r;
			if (szUrl.indexOf('BDLINK') === 0) {
				r = parseDu_v1(szUrl);
				r.ver = '游侠 v1';
			} else {
				r = parseDu_v2(szUrl);
				r.ver = '梦姬标准';
			}
			return r;
		};
	})();

	(function (hookVer) {
		console.info ('Dupan Hooker [ v%s ] ready.', hookVer);
		var customHookers = {};
		var msgSystem = window.mdev.message;

		// Check if is already hooked;
		if (msgSystem.hasOwnProperty ('hookVer')) {
			if (hookVer !== msgSystem.hookVer) {
				throw new Error('Custom Hooker version does not match!\n'
					+ 'Current: ' + hookVer + ', On-page: ' + msgSystem.hookVer);
			} else {
				console.info('Already hooked, skipping...', hookVer);
			}
			return;
		}

		msgSystem.hookVer = hookVer;
		msgSystem.oldTrigger = msgSystem.trigger;
		msgSystem.hookEve = function (eve, fooCb) {
			if (!customHookers.hasOwnProperty(eve))
				customHookers[eve] = [];
			customHookers[eve].push(fooCb);

			return msgSystem;
		};
		msgSystem.trigger = function (eve) {
			console.debug ('Trigger event: %s', eve);

			var args = [].slice.call(arguments, 1);
			if (customHookers.hasOwnProperty(eve)) {
				for (var i = 0; i < customHookers[eve].length; i++) {
					try {
						customHookers[eve][i].apply(undefined, args);
					} catch (e) {
						// 抛出消息,表示这个事件不应该继续了。
						if (e.exit)
							return;
					}
				}
			}

			msgSystem.oldTrigger.apply(msgSystem, [eve].concat(args));
		};
	})('1.0');

	function parseLargeSize (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';
	}

	var $menuBase = $('div.module-context-menu > ul.menu-main');
	$menuBase.find('a[data-key="rename"]').parent().after ($('<li>').append($('<a>').attr({
		hidefocus: true,
		href: "javascript: ;",
		class: "list-node",
		'node-type': "item"
	}).data('key', 'batch-rename').text('批量重命名')));

	$menuBase.find('a[data-key="share"]').parent().after ($('<li>').append($('<a>').attr({
		hidefocus: true,
		href: "javascript: ;",
		class: "list-node",
		'node-type': "item"
	}).data('key', 'custom-share').text('自定义分享')));

	var btnRef = $('.icon-btn-createfile');
	$(_(function () {/*
		<a node-type="btn-reload" href="javascript: ;" class="jx_btn jx_btn_code">通用提取码</a>
	*/})).insertAfter(btnRef).click(function () {
		var $wndEnterCode = new $dialog ();
		var $tplEnterCode = $(_(function () {/*
			<div>
				<p><textarea class="jx jx_code" rows="7" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea></p>
				<p style="line-height: 1;   padding: .5em 0;">
					扩展阅读: 
					<a href="http://game.ali213.net/thread-5465798-1-1.html" target="_blank">肚娘代码说明 [游侠]</a>
					| <a href="http://jixun.org/p/3232" target="_blank">标准度娘提取码 [梦姬]</a>
				</p>
				<p style="text-align:left">
					<b>文件列表</b> (版本: <span class="jx_version" style="color:black">--</span>):
				</p>
				<ul class="jx_list"></ul>
				<p class="jx_c_warn jx_hide jx_errmsg">无效的提取码! 请确保您输入的神秘代码无误。</p>
			</div>
		*/}));
		
		var codeInfo;
		var jx_list = $('.jx_list', $tplEnterCode);
		var jx_code = $('.jx_code', $tplEnterCode);
		var jx_errmsg = $('.jx_errmsg', $tplEnterCode);
		var jx_version = $('.jx_version', $tplEnterCode);
		jx_code.blur(function () {
			var code = jx_code.val();
			codeInfo = parseDu(code);
			jx_errmsg.toggleClass('jx_hide', !code || !!codeInfo);
			if (codeInfo) {
				jx_version.text(codeInfo.ver);
				jx_list.text('');
				codeInfo.forEach(function (file) {
					jx_list.append(
						$('<li>')
							.append(
								$('<span>')
									.addClass('name')
									.text(file.name)
							)
							.append(
								$('<span>')
									.addClass('size')
									.text(sprintf(' (~%1)', parseLargeSize(file.size)))
							)
					);
				});
			} else {
				jx_version.text('--');
			}
		}).focus(function () {
			jx_errmsg.addClass('jx_hide');
			jx_list.text('');
			jx_version.text('--');
		});
		
		$wndEnterCode.Confirm('从通用提取码导入文件', $tplEnterCode, function () {
			if (!codeInfo)
				return ;
		
			this.setVisible (0);
			var parsed = codeInfo.slice();
			codeInfo = null;
			var failed = 0;
			var total = parsed.length;
			
			function saveFile (i) {
				if (i >= total) {
					Toast.obtain.useToast ({
						toastMode: Toast.obtain.MODE_SUCCESS,
						msg: sprintf('转存完毕 (失败 %1 个)!', failed),
						sticky: false
					});
					_reload();
					return ;
				}
				
				Toast.obtain.useToast ({
					toastMode: Toast.obtain.MODE_LOADING,
					msg: sprintf('正在转存文件 (%1/%2), 请稍后 ..', i + 1, total),
					sticky: true
				});
				
				var _curDir = $dataCenter.get('currentDir') + '/';
				// "path=//%s&content-md5=%s&slice-md5=%s&content-length=%I64d"
				
				var file = parsed[i];
				
				$.ajax ({
					url: '/api/rapidupload',
					type: 'POST',
					data: {
						path: _curDir + file.name,
						'content-md5': file.md5,
						'slice-md5':   file.md5s,
						'content-length': file.size
					}
				}).success(function (r) {
					Toast.obtain.useCloseToast();
					if (r.errno) failed++;
				}).fail(function (r) {
					failed++;
				}).always(function () {
					saveFile(i + 1);
				});
			}
			
			saveFile(0);
		});
	});
	$(_(function () {/*
		<a node-type="btn-reload" href="javascript: ;" class="jx_btn jx_btn_reload">刷新</a>
	*/})).insertAfter(btnRef).click(function () {
		_reload ();
	});

	var _batchRename = function () {
		var $wndConfirmRename = new $dialog ();
		var $tplConfirmRename = $(_(function () {/*
			<p>请输入新的命名规则 (自动储存):  <input id="jx_nameRule" style="width:20em" /></p>
			<p style="line-height: 1; padding-top: 1em;">
				<code>:n</code> 表示不带扩展名的文件名; <code>:e</code> 表示扩展名; <code>:E</code> 表示 .扩展名;
			<br><code>:d</code> 表示一位随机数字; <code>:c</code> 表示一位随机字符; <code>:t</code> 表示当前时间戳</p>
		*/}));
		$('#jx_nameRule', $tplConfirmRename).val(localStorage.jxRenameRule || '[GalACG] :d:d:d:d:d:d:d:d:d:d:E');
		$wndConfirmRename.Confirm('确认批量重命名', $tplConfirmRename, function () {
			// 确认重命名
			var _nameRule = $('#jx_nameRule', $tplConfirmRename).val();

			// 储存命名规则
			localStorage.jxRenameRule = _nameRule;

			var _curDir = $dataCenter.get('currentDir');
			if (_curDir.substr(-1) !== '/')
				_curDir += '/';
			var _fixName = function (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(/\.[^.]+$/) || '';
				}
			};

			var _list = $dataCenter.get ('selectedList');
			var _flist = [].slice.call($dataCenter.get ('selectedItemList').map(function (e) {
				// [{"path":"/1.rar","newname":"2.rar"}]
				var file = e.find('.name-text').text();
				return {
					path: _curDir + file,
					newname: _nameRule.replace(/:([cdeEn])/g, _fixName.bind(file))
				};
			}));

			Toast.obtain.useToast ({
				toastMode: Toast.obtain.MODE_LOADING,
				msg: '正在重命名…',
				sticky: true
			});
			$.ajax ({
				url: '/api/filemanager?' + $.param({
					channel: 'chunlei',
					bdstoken: yunData.MYBDSTOKEN,
					app_id: __AppId,
					opera: 'rename'
				}),
				type: 'POST',
				data: {
					filelist: JSON.stringify(_flist)
				}
			}).success(function () {
				Toast.obtain.useCloseToast();
				_reload ();
			});
			this.setVisible (0);
		}, function () {
			// 取消重命名
			this.setVisible (0);
		});
	};
	var _genKey = function (size) {
		// length => 26 + 10, 36
		var keySet = 'abcdefghijklmnopqrstuvwxyz0123456789';
		for (var i = (size || 4) | 0, r = ''; i--; )
			r += keySet[0 | (Math.random() * 36)];
		
		return r;
	};
	var _customShare = function () {
		console.debug ('customShare');
		var $wndCustomShare = new $dialog ();
		var $tplCustomShare = $(_(function () {/*
			<div>
				<p>请输入提取码:  <input id="jx_shareKey" style="width: 6em" /></p>
				<p id="jx_errmsg" class="jx_c_warn jx_hide">无效的提取码, 脚本将随机生成一个分享代码 :&lt;</p>
			</div>
			<div class="jx_hide">
				<p>分享地址: <input id="jx_shortUrl" style="width: 20em" readonly /></p>
				<p>提取码: <input id="jx_shareCode" style="width: 5em; text-align: center" readonly /></p>

				<p style="text-align: left">投稿代码:<br /><textarea readonly id="jx_dlboxCode" class="jx"></textarea></p>
			</div>
		*/}));
		var _isCodeValid = function (t) {
			return encodeURIComponent(t).replace(/%[A-F\d]{2}/g, '-').length == 4;
		};
		var _fixCode = function (s) {
			return s.replace(/"/g, '&#x22;').replace(/\]/g, '&#x5D;');
		};
		var _fixWidthDigits = function (d) {
			return ('0' + d.toString()).slice(-2);
		}
		var _date = function (d) {
			return sprintf('%1.%2.%3', d.getFullYear (),
				_fixWidthDigits(d.getMonth () + 1),
				_fixWidthDigits(d.getDate ())
			);
		};
		var _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));
		$wndCustomShare.Confirm('自定义分享', $tplCustomShare, function () {
			var key = _isCodeValid(_key.val()) ? _key.val() : _genKey (4);

			Toast.obtain.useToast ({
				toastMode: Toast.obtain.MODE_LOADING,
				msg: '正在分享…',
				sticky: true
			});
			var $pane = $(this._mUI.pane);
			$.ajax ({
				url: '/share/set?' + $.param({
					channel: 'chunlei',
					bdstoken: this.token,
					app_id: __AppId
				}),
				type: 'POST',
				data:  {
					fid_list: JSON.stringify($dataCenter.get ('selectedList')),
					schannel: 4,
					channel_list: '[]',
					pwd: key
				},
				dataType: 'json'
			}).success(function (r) {
				$pane.find ('a.okay').hide ();
				$pane.find ('a.cancel>b').text ('关闭');
				$tplCustomShare.toggleClass ('jx_hide');
				$('#jx_shortUrl',  $tplCustomShare).val (r.shorturl || '很抱歉, 分享失败 :<');
				$('#jx_shareCode', $tplCustomShare).val (key);


				var selList = $dataCenter.get ('selectedItemList');
				var title = _fixCode($('.name-text', selList[0]).text().trim()) +
							(selList.length == 1 ? '' : ' 等文件');
				
				$('#jx_dlboxCode', $tplCustomShare).val ('[dlbox title="' + 
					title + '" from="浩瀚的宇宙" time="' +
					_date(new Date()) + '" info="提取:' + key +
					'" link1="度娘|' + r.shorturl + '#' + key + '"][/dlbox]'
				);

				Toast.obtain.useCloseToast();
				_reload ();
			});

			// this.setVisible (0);
		}, function () {
			this.setVisible (0);
		});
	};

	// 通过 Hook 确保菜单项被显示、处理后续事件
	window.mdev.message.hookEve ('context-menu', function (action, options) {
		if (action == 'render')
			options.buttons['batch-rename'] =
			options.buttons['custom-share'] =
				'enable';
	}).hookEve ('file-operate', function (op) {
		switch (op) {
			case 'batch-rename':
				_batchRename ();
				break;
			case 'custom-share':
				_customShare ();
				break;
			default:
				return ;
		}

		throw {exit: true};
	});

	$('.side-options').remove();
	$('.remaining').prepend ($('<p>').css({
		textAlign: 'center'
	}).text('用户 ID: ' + yunData.MYUK));
}).toString () + ')();';
document.body.appendChild(script);