您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
突破图片尺寸、GIF帧数限制,无损上传
当前为
// ==UserScript== // @name Discuz论坛头像上传助手 // @author 枫谷剑仙 // @description 突破图片尺寸、GIF帧数限制,无损上传 // @version 2.0.3 // @namespace http://www.mapaler.com/ // @include */home.php?mod=spacecp&ac=avatar* // @icon https://gitee.com/ComsenzDiscuz/DiscuzX/raw/master/upload/uc_server/images/noavatar_small.gif // @run-at document-end // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== (function(){ 'use strict'; const avatarform = document.querySelector("#avatarform") || document.querySelector("form[action^=home]"); //以前没有HTML5的老版本,没有#avatarform if (!avatarform) return; //仿GM_xmlhttpRequest函数v1.4 if (typeof(GM_xmlhttpRequest) == 'undefined') { var GM_xmlhttpRequest = function(GM_param) { const xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象 xhr.open(GM_param.method, GM_param.url, true); if (GM_param.responseType) xhr.responseType = GM_param.responseType; if (GM_param.overrideMimeType) xhr.overrideMimeType(GM_param.overrideMimeType); xhr.onreadystatechange = function(e) //设置回调函数 { const _xhr = e.target; if (_xhr.readyState === _xhr.DONE) { //请求完成时 if (_xhr.status === 200 && GM_param.onload) //正确加载时 { GM_param.onload(_xhr); } if (_xhr.status !== 200 && GM_param.onerror) //发生错误时 { GM_param.onerror(_xhr); } } }; if (GM_param.onprogress) xhr.upload.onprogress = function(e){GM_param.onprogress(e.target)}; //添加header for (let header in GM_param.headers) { xhr.setRequestHeader(header, GM_param.headers[header]); } //发送数据 xhr.send(GM_param.data ? GM_param.data : null); }; } const avatarsDefine = [ {name:'大头像',code:'big',maxWidth:200,maxHeight:250,blob:null}, {name:'中头像',code:'middle',maxWidth:120,maxHeight:120,blob:null}, {name:'大小像',code:'small',maxWidth:48,maxHeight:48,blob:null}, ]; const html5mode = Boolean(avatarform.querySelector('#avatardesigner')); //HTML5模式还是Flash const insertPlace = avatarform.parentNode; // HTML5版本才会有的几个提交按钮 const ipt_avatarArr = [ avatarform.querySelector('[name="avatar1"]'), avatarform.querySelector('[name="avatar2"]'), avatarform.querySelector('[name="avatar3"]'), ]; const ipt_Filedata = avatarform.querySelector('[name="Filedata"]'); const ipt_confirm = avatarform.querySelector('[name="confirm"]'); const data = (typeof(unsafeWindow) == 'undefined' ? window : unsafeWindow).data; // Flash版本的Flash const swf_mycamera = avatarform.querySelector('[name="mycamera"]'); const swfUrl = new URL(html5mode ? data[data.indexOf('src')+1] : swf_mycamera.src); const maxSize = parseInt(swfUrl.searchParams.get('uploadSize') || 2048, 10) * 1024; const styleCss = `.discuz-avatar{ border: 1px solid #ccc; padding: 5px 15px; width:auto; display:inline-block; width: 450px; box-sizing: border-box; } .discuz-avatar h3{ text-align:center; } .pic-type-div{ display:inline-block; vertical-align:top; margin-right: 15px; } .pic-type-div:last-of-type{ margin-right: unset; } .pic-div{ border: 1px solid #ccc; cursor: pointer; position: relative; display: table-cell; text-align:center; vertical-align: middle; background: #fff; background-image: linear-gradient(45deg, #eee 25%, transparent 26%, transparent 74%, #eee 75%), linear-gradient(45deg, #eee 25%, transparent 26%, transparent 74%, #eee 75%); background-position: 0 0, 10px 10px; background-size: 20px 20px; } .pic-type-big .pic-div{ width: 200px; height: 250px; } .pic-type-big .pic-img{ max-width: 200px; max-height: 250px; } .pic-type-middle .pic-div{ width: 120px; height: 120px; } .pic-type-middle .pic-img{ max-width: 120px; max-height: 120px; } .pic-type-small .pic-div{ width: 48px; height: 48px; } .pic-type-small .pic-img{ max-width: 48px; max-height: 48px; } .choose-file{ display: none; } .pic-div.nopic::before{ content:"➕"; font-size: 2em; } .pic-tag{ text-align:center; } .submit-bar{ text-align:center; } /*Flash AJAX状态使用*/ .status-bar{ font-size:2em; background-repeat: no-repeat; background-position: center; margin:0px auto; display:none; text-align: center; } .status-bar[data-status]{ display:block; } @keyframes loading-animate{ from { transform: rotate(0deg); } to { transform: rotate(3600deg); } } .status-bar[data-status="loading"]::before { display: inline-block; border: 4px SteelBlue dotted; border-radius: 50%; content:""; width: 1em; height: 1em; animation: loading-animate 50s infinite linear; } .status-bar[data-status="success"]::before { content:"✔️"; } .status-bar[data-status="error"]::before { content:"❌"; } .progress-bar{ padding: 5px; text-align: center; }`; const fragment = document.createDocumentFragment(); const ctlDiv = fragment.appendChild(document.createElement('div')); ctlDiv.className = 'discuz-avatar'; const style = ctlDiv.appendChild(document.createElement('style')); style.type = 'text/css'; style.innerHTML = styleCss; const caption = ctlDiv.appendChild(document.createElement('h3')); caption.appendChild(document.createTextNode(typeof(GM_info) != 'undefined' ?`${GM_info.script.name} ${GM_info.script.version}`:'debug')); caption.appendChild(document.createElement('br')); caption.appendChild(document.createTextNode(`${html5mode?'HTML5':'Flash'}模式`)); const picTable = ctlDiv.appendChild(document.createElement('div')); const picImgs = []; avatarsDefine.forEach((obj,idx)=>{ const picTypeDiv = picTable.appendChild(document.createElement('div')); picTypeDiv.className = 'pic-type-div pic-type-' + obj.code; const picDiv = picTypeDiv.appendChild(document.createElement('div')); picDiv.className = 'pic-div nopic'; const pic = new Image(); picDiv.appendChild(pic); pic.className = 'pic-img img-' + obj.code; picImgs.push(pic); const file = picDiv.appendChild(document.createElement('input')); file.type = "file"; file.className = "choose-file"; picDiv.onclick = function(){ file.click(); } file.onchange = function(e){ const file = e.target.files[0]; const imageType = /image\/.*/i; if (!imageType.test(file.type)) { alert('不是有效的图像文件!'); pic.src = ''; picDiv.classList.add('nopic'); return; } if (file.size > maxSize) { alert(`文件大小超出 ${maxSize/1048576}MiB,可能上传失败!`); } picDiv.classList.remove('nopic'); if (pic.src.length>0) URL.revokeObjectURL(pic.src); pic.src = URL.createObjectURL(file); obj.blob = file; } const tagDiv = picTypeDiv.appendChild(document.createElement('div')); tagDiv.className = 'pic-tag'; const span1 = tagDiv.appendChild(document.createElement('span')); span1.appendChild(document.createTextNode(obj.name)); tagDiv.appendChild(document.createElement('br')); const span2 = tagDiv.appendChild(document.createElement('span')); span2.appendChild(document.createTextNode(`${obj.maxWidth}×${obj.maxHeight}`)); }); const statusDiv = ctlDiv.appendChild(document.createElement('div')); statusDiv.className = 'status-bar'; const progressDiv = ctlDiv.appendChild(document.createElement('div')); progressDiv.className = 'progress-bar'; const submitDiv = ctlDiv.appendChild(document.createElement('div')); submitDiv.className = 'submit-bar'; const submit = submitDiv.appendChild(document.createElement('button')); submit.className = 'submit-btn'; submit.innerHTML = '📤提交'; submit.onclick = function(){ if (!avatarsDefine.every(obj=>obj.blob)) { alert('还有未添加的头像!'); return; } submit.disabled = true; const fileDataArr = []; function readBlobs(blobArr,type,callback) { if (blobArr.length<1) { callback(fileDataArr); return; } const file = blobArr.shift(); const fileReader = new FileReader(); fileReader.onload = function (e) { fileDataArr.push(e.target.result); readBlobs(blobArr, type, callback); } if (type == 'base64') fileReader.readAsDataURL(file); else //if (type == 'arrayBuffer') fileReader.readAsArrayBuffer(file); } readBlobs(avatarsDefine.map(obj=>obj.blob), html5mode ? 'base64':'arrayBuffer', (html5mode ? sumbitAvatarsHTML5 : sumbitAvatarsFlash)); } if (!html5mode) { ctlDiv.appendChild(document.createElement('hr')); const tipsDiv = ctlDiv.appendChild(document.createElement('div')); tipsDiv.className = 'tips-bar'; let quote = null,code = null; quote = tipsDiv.appendChild(document.createElement('div')); quote.className = 'quote'; quote.appendChild(document.createTextNode('由于 UCenter 服务端限制了头像尺寸(默认限制尺寸标注在头像下面)。若上传100%后显示')); code = quote.appendChild(document.createElement('div')); code.className = 'blockcode'; code.appendChild(document.createTextNode('<?xml version="1.0" ?><root><face success="0"/></root>')); quote.appendChild(document.createTextNode('则可能是该原因,或者是图片文件过大,或格式不被服务器支持。')); quote = tipsDiv.appendChild(document.createElement('div')); quote.className = 'quote'; quote.appendChild(document.createTextNode('若上传显示')); code = quote.appendChild(document.createElement('div')); code.className = 'blockcode'; code.appendChild(document.createTextNode('Access denied for agent changed')); quote.appendChild(document.createTextNode('可能是你的活动状态失效了需要刷新,或者是 Discuz 和 UCenter 通信没配好,请直接联系网站管理员。')); } insertPlace.appendChild(fragment); //HTML5模式提交 function sumbitAvatarsHTML5(base64Arr) { progressDiv.textContent = '已提交,HTML5 模式成功状态请直接参考上方编辑器'; const dataArr = base64Arr.map(str=>str.substr(str.indexOf(",") + 1)); //拿到3个头像的Base64字符串 dataArr.forEach((str,idx)=>{ ipt_avatarArr[idx].value = str; }); ipt_Filedata.value = ''; ipt_confirm.value = ''; avatarform.action = swfUrl.toString().replace('images/camera.swf?inajax=1', 'index.php?m=user&a=rectavatar&base64=yes'); //来自官方代码: static/avatar/avatar.js?EMK avatarform.target='rectframe'; avatarform.submit(); submit.disabled = false; } //Flash模式提交 function sumbitAvatarsFlash(arrayBufferArr) { statusDiv.setAttribute('data-status','loading'); const dataArr = arrayBufferArr.map(bytes=>{ const uint8Array = new Uint8Array(bytes); const numArray = Array.from(uint8Array); const strArray = numArray.map(bit=>`${bit<16?0:''}${bit.toString(16)}`); return strArray.join('').toUpperCase(); }); const sp = swfUrl.searchParams; let loc1 = sp.get('ucapi'); if (loc1.length > 0 && !(loc1.substring((loc1.length - 1)) == "/")) { loc1 = loc1 + "/"; } if (loc1.length > 0 && !new RegExp("^https?://", "i").test(loc1)) { loc1 = "http://" + loc1; } const apiUrl = new URL(`${loc1}index.php`); apiUrl.protocol = location.protocol; //解决http和https混合内容的问题 const asp = apiUrl.searchParams; asp.set('m','user'); asp.set('inajax',1); asp.set('a','rectavatar'); asp.set('appid',sp.get('appid')); asp.set('input',sp.get('input')); asp.set('agent',sp.get('agent')); asp.set('avatartype',sp.get('avatartype')); const post = new URLSearchParams(); dataArr.forEach((str,idx)=>{ post.set(`avatar${idx+1}`,str) }); post.set('urlReaderTS',Date.now()); GM_xmlhttpRequest({ method: "POST", url: apiUrl, data: post, headers: {"Content-Type": "application/x-www-form-urlencoded"}, onload: onloadHandler, onerror: onerrorHandler, onprogress: uploadOnprogressHandler }); } //Flash模式的传统方法 function onloadHandler(response) { progressDiv.textContent = "100%"; const xml = response.responseXML; console.log(xml) if (xml) { const success = xml.querySelector('face'); if (success != null && success.getAttribute("success") == 1) { statusDiv.setAttribute('data-status','success'); } else { statusDiv.setAttribute('data-status','error'); const message = xml.querySelector('message'); if (message) progressDiv.textContent = message.getAttribute('type') + ': ' + message.getAttribute('value'); else progressDiv.textContent = response.responseText; } } else { statusDiv.setAttribute('data-status','error'); progressDiv.textContent = 'error: no responseXML'; } onloadendHandler(); } function onerrorHandler(e) { statusDiv.setAttribute('data-status','error'); onloadendHandler(); } function onloadendHandler(e) { submit.disabled = false; } function uploadOnprogressHandler(e) { if (e.lengthComputable) { progressDiv.textContent = (e.loaded / e.total).toLocaleString(undefined,{style:'percent'}); } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址