您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
请自己研究尝试
当前为
// ==UserScript== // @name 清水河畔表情包计划 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 请自己研究尝试 // @author DARK-FLAME-MASTER FROM RIVERSIDE // @match https://bbs.uestc.edu.cn/forum.php?mod=viewthread* // @match *://bbs-uestc-edu-cn-s.vpn.uestc.edu.cn:*/forum.php?mod=viewthread* // @icon https://www.google.com/s2/favicons?sz=64&domain=uestc.edu.cn // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.slim.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/cfb.min.js // @require https://cdn.bootcdn.net/ajax/libs/vue/3.2.40/vue.global.prod.min.js // @license WTFPL // @run-at document-body // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_listValues // @grant unsafeWindow // ==/UserScript== (function () { 'use strict'; unsafeWindow.Vue = Vue let setAddedImg; let storageVar = "emojiSet"; let storageAlbum = "emojiAlbum" let storageGroup = "selectedGroup" //GM_setValue('version','0.1') let version = GM_getValue('version', 'NULL') if(version != '0.2' && version != 'NULL'){ let temp = [] let emoji_set = GM_getValue('emoji_set') for(let tagName in emoji_set){ let images = [] for(let i = 0;i<emoji_set[tagName].length;++i){ images.push({id:emoji_set[tagName][i][0],src:emoji_set[tagName][i][1]}) } temp.push({tag:tagName,tagImg:images[0],images:images}) } GM_setValue(storageVar,temp) GM_setValue(storageAlbum,GM_getValue('emoji_album_id')) } GM_setValue('version','0.2') document.addEventListener('DOMContentLoaded', function () { let post_params = unsafeWindow.upload.settings.post_params; let emoji = GM_getValue(storageVar,[{tag:"default",tagImg:{id:'default',src:'data/attachment/common/star/common_25_icon.png'}, images:[]}]) let emojiAlbum = GM_getValue(storageAlbum,-1) let selectedGroup = GM_getValue(storageGroup,0) let formhash = $('#modactions :nth-child(1)').attr('value'); $('body').prepend('<style>\n#mine\n{\n background: #F2F2F2;\n text-indent: 0;\n display: inline;\n}\n.menu \n{\n margin: 0;\n background: #fff;\n z-index: 3000;\n position: absolute;\n list-style-type: none;\n padding: 5px 0;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 400;\n color: #333;\n box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);\n}\n\n.menu li {\n margin: 0;\n padding: 7px 16px;\n cursor: pointer;\n}\n\n.menu li:hover {\n background: #eee;\n}\n\n.clicked:hover {\n cursor: pointer;\n}\n\n#emojiPreview {\n width: 30%;\n}\n\n#emojiPreview>img {\n max-width: 100%;\n}\n\n#mine_menu {\n display: flex;\n align-items: flex-end;\n z-index: 999; \n position: absolute; \n width: 70%;\n}\n\nimg.emoji {\n height: 50px;\n}\n\n#emoHead {\n padding: 3px;\n display: flex;\n border-bottom: 2px dashed lightsteelblue;\n justify-content: center;\n}\n\n#emoHead>div {\n font-size: 20px;\n}\n\n#emoContent {\n display: flex;\n overflow: auto;\n max-height: 300px;\n display: flex;\n flex-wrap: wrap;\n justify-content: space-evenly;\n align-items: center;\n scrollbar-gutter: stable;\n}\n\n#emoji {\n background: rgb(232, 241, 252);\n border: 2px solid lightsteelblue;\n border-radius: 5px;\n width: 50%;\n height: fit-content;\n\n}\n\n#emoTag {\n display: flex;\n height: 45px;\n background-color: lightsteelblue;\n align-items: center;\n width: fit-content;\n border-radius: 0px 0px 4px;\n border: 0px solid lightsteelblue;\n}\n\n#emoAdd {\n font-size: 40px;\n line-height: 109%;\n margin-right: 5px;\n}\n\n#groupAdd {\n font-size: 25px;\n}\n\nimg.emoji {\n padding: 2px;\n border-radius: 10px;\n}\n\n.emoDel {\n position: absolute;\n top: 38px;\n right: -2px;\n font-size: 10px;\n}\n\n.emoSel {\n position: absolute;\n top: -2px;\n left: -2px;\n font-size: 10px;\n}\n\n.emoMov {\n position: absolute;\n top: -2px;\n right: -2px;\n font-size: 13px;\n}\n\n#emoContent>div {\n position: relative;\n}\n\n.selectedEmoji {\n display: inline;\n}\n\ndiv.tag {\n height: 45px;\n padding: 0 3px 0 3px;\n border-radius: 2px;\n display: flex;\n align-items: center;\n}\n\ndiv.tag>img {\n height: 30px;\n border-radius: 2px;\n}\n\n.selected {\n background: rgb(232, 241, 252);\n}\n</style>\n<div id="emojiTemplate">\n <div id="mine" ref="mine" class="clicked" @click="emojiVisible=!emojiVisible">\n 🤤 \n </div>\n <div v-show="emojiVisible" :style="position" id="mine_menu">\n <div id="init" v-if="emojiAlbum==-1">\n <button @click="setEmojiAlbum()">设置相册(初始化)</button>\n </div>\n <div id="emoji" v-else>\n <div id="emoHead">\n <input v-if="renameGroup" v-model="emoji[selectedGroup].tag" @blur="renameGroup= false"></input>\n <div v-else>{{emoji[selectedGroup].tag}}</div>\n\n\n <div @click="renameGroup=true" class="clicked">✍</div>\n <div @click="delGroup(selectedGroup)" class="clicked">❌</div>\n <div>⚙️</div>\n </div>\n <div id=\'emoContent\'>\n <input ref="upload" type="file" accept="image/*" @input="uploadFiles(getFiles($event),selectedGroup)"\n multiple style="display: none;">\n <div id="emoAdd" @click="this.$refs.upload.click()" v-if="uploadTotalCount==0" class="clicked">➕</div>\n <svg width="55" height="55" viewBox="0 0 200 200" v-else>\n <circle id="circleBg" transform="rotate(-90 100 100)" cx="100" cy="100" r="70" fill="none"\n stroke-width="30" stroke="gray" stroke-dasharray="434" :stroke-dashoffset="434-progress*434">\n </circle>\n <circle id="circle" stroke-linecap="round" transform="rotate(-90 100 100)" cx="100" cy="100" r="70"\n fill="none" stroke-width="30" stroke="green" stroke-dasharray="434"\n :stroke-dashoffset="434-progress*434"></circle>\n <text x="100" y="100" fill="#6b778c" text-anchor="middle" dominant-baseline="central"\n font-size="32">\n <tspan id="percent">{{parseInt(progress*100)}}% </tspan>\n </text>\n </svg>\n <div v-for="(img,index) in emoji[selectedGroup].images" @mouseenter="switchEmoji(index)" @mouseleave="switchEmoji(-1)">\n <img class="emoji" :src="`${img.src}`" @click="insertEmojiInForum(img)">\n <div class="emoMov clicked" v-show="selectedEmoji==index" @click="emoAsTagImg(img)">🕊️</div>\n <div class="emoDel clicked" v-show="selectedEmoji==index" @click="delEmoji(index)">❎</div>\n <div class="emoSel clicked" v-show="selectedEmoji==index" @click="emoAsTagImg(img)">❇️</div>\n\n </div>\n </div>\n <div id=\'emoTag\'>\n <div v-for="(group,index) in emoji" @click="switchTag(index)"\n :class="[{selected:selectedGroup==index},\'tag\']">\n <img :src="`${group.tagImg.src}`">\n\n </div>\n <div id="groupAdd" class="tag clicked"\n @click="addGroup({tag:\'default\',tagImg:{id:\'default\',src:\'data/attachment/common/star/common_25_icon.png\'}, images:[]})">\n 🗃️</div>\n <input ref="uploadEif" type="file" accept=".eif"\n @input="uploadEif(getFiles($event),[\'jpg\', \'gif\', \'bmp\', \'png\'])" style="display: none;">\n <svg @click="this.$refs.uploadEif.click()" class="icon clicked"\n style="width: 35px;height: 35px;vertical-align: middle;fill: currentColor;overflow: hidden;float: right;"\n viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">\n <path\n d="M511.09761 957.257c-80.159 0-153.737-25.019-201.11-62.386-24.057 6.702-54.831 17.489-74.252 30.864-16.617 11.439-14.546 23.106-11.55 27.816 13.15 20.689 225.583 13.211 286.912 6.767v-3.061z"\n fill="#FAAD08" p-id="4607"></path>\n <path\n d="M496.65061 957.257c80.157 0 153.737-25.019 201.11-62.386 24.057 6.702 54.83 17.489 74.253 30.864 16.616 11.439 14.543 23.106 11.55 27.816-13.15 20.689-225.584 13.211-286.914 6.767v-3.061z"\n fill="#FAAD08" p-id="4608"></path>\n <path\n d="M497.12861 474.524c131.934-0.876 237.669-25.783 273.497-35.34 8.541-2.28 13.11-6.364 13.11-6.364 0.03-1.172 0.542-20.952 0.542-31.155C784.27761 229.833 701.12561 57.173 496.64061 57.162 292.15661 57.173 209.00061 229.832 209.00061 401.665c0 10.203 0.516 29.983 0.547 31.155 0 0 3.717 3.821 10.529 5.67 33.078 8.98 140.803 35.139 276.08 36.034h0.972z"\n fill="#000000" p-id="4609"></path>\n <path\n d="M860.28261 619.782c-8.12-26.086-19.204-56.506-30.427-85.72 0 0-6.456-0.795-9.718 0.148-100.71 29.205-222.773 47.818-315.792 46.695h-0.962C410.88561 582.017 289.65061 563.617 189.27961 534.698 185.44461 533.595 177.87261 534.063 177.87261 534.063 166.64961 563.276 155.56661 593.696 147.44761 619.782 108.72961 744.168 121.27261 795.644 130.82461 796.798c20.496 2.474 79.78-93.637 79.78-93.637 0 97.66 88.324 247.617 290.576 248.996a718.01 718.01 0 0 1 5.367 0C708.80161 950.778 797.12261 800.822 797.12261 703.162c0 0 59.284 96.111 79.783 93.637 9.55-1.154 22.093-52.63-16.623-177.017"\n fill="#000000" p-id="4610"></path>\n <path\n d="M434.38261 316.917c-27.9 1.24-51.745-30.106-53.24-69.956-1.518-39.877 19.858-73.207 47.764-74.454 27.875-1.224 51.703 30.109 53.218 69.974 1.527 39.877-19.853 73.2-47.742 74.436m206.67-69.956c-1.494 39.85-25.34 71.194-53.24 69.956-27.888-1.238-49.269-34.559-47.742-74.435 1.513-39.868 25.341-71.201 53.216-69.974 27.909 1.247 49.285 34.576 47.767 74.453"\n fill="#FFFFFF" p-id="4611"></path>\n <path\n d="M683.94261 368.627c-7.323-17.609-81.062-37.227-172.353-37.227h-0.98c-91.29 0-165.031 19.618-172.352 37.227a6.244 6.244 0 0 0-0.535 2.505c0 1.269 0.393 2.414 1.006 3.386 6.168 9.765 88.054 58.018 171.882 58.018h0.98c83.827 0 165.71-48.25 171.881-58.016a6.352 6.352 0 0 0 1.002-3.395c0-0.897-0.2-1.736-0.531-2.498"\n fill="#FAAD08" p-id="4612"></path>\n <path\n d="M467.63161 256.377c1.26 15.886-7.377 30-19.266 31.542-11.907 1.544-22.569-10.083-23.836-25.978-1.243-15.895 7.381-30.008 19.25-31.538 11.927-1.549 22.607 10.088 23.852 25.974m73.097 7.935c2.533-4.118 19.827-25.77 55.62-17.886 9.401 2.07 13.75 5.116 14.668 6.316 1.355 1.77 1.726 4.29 0.352 7.684-2.722 6.725-8.338 6.542-11.454 5.226-2.01-0.85-26.94-15.889-49.905 6.553-1.579 1.545-4.405 2.074-7.085 0.242-2.678-1.834-3.786-5.553-2.196-8.135"\n fill="#000000" p-id="4613"></path>\n <path\n d="M504.33261 584.495h-0.967c-63.568 0.752-140.646-7.504-215.286-21.92-6.391 36.262-10.25 81.838-6.936 136.196 8.37 137.384 91.62 223.736 220.118 224.996H506.48461c128.498-1.26 211.748-87.612 220.12-224.996 3.314-54.362-0.547-99.938-6.94-136.203-74.654 14.423-151.745 22.684-215.332 21.927"\n fill="#FFFFFF" p-id="4614"></path>\n <path\n d="M323.27461 577.016v137.468s64.957 12.705 130.031 3.91V591.59c-41.225-2.262-85.688-7.304-130.031-14.574"\n fill="#EB1C26" p-id="4615"></path>\n <path\n d="M788.09761 432.536s-121.98 40.387-283.743 41.539h-0.962c-161.497-1.147-283.328-41.401-283.744-41.539l-40.854 106.952c102.186 32.31 228.837 53.135 324.598 51.926l0.96-0.002c95.768 1.216 222.4-19.61 324.6-51.924l-40.855-106.952z"\n fill="#EB1C26" p-id="4616"></path>\n </svg>\n </div>\n </div>\n <div id="emojiPreview"><img :src="selectedEmoji!=-1?`${emoji[selectedGroup].images[selectedEmoji].src}`:\'\'">\n </div>\n </div>\n <div id="addEmojiOutside">\n <div id="likeEmo" style="display:none" @click="addEmoji(addedImg,selectedGroup,true)" @contextmenu.prevent="openMenu($event,item)">❤️</div>\n <div v-show="menu.visible" :style="{left:menu.left+\'px\',top:menu.top+\'px\'}" class="menu">\n <li v-for="(group,index) in emoji" @click="addEmoji(addedImg,index,true)">添加至{{group.tag}}</li>\n </div>\n </div>\n</div>\n' ) Vue.createApp({ data() { return { //version, menu: { left:0, top:0, visible:false }, emojiVisible:false, addedImg:{id:'default',src:'data/attachment/common/star/common_25_icon.png'}, uploadTotalCount: 0, uploadNowCount: 0, renameGroup: false, emojiAlbum: emojiAlbum, selectedGroup: selectedGroup, selectedEmoji: -1, post_params: post_params, formhash: formhash, emojiTemp: [], emoji: emoji } }, methods: { switchTag(index) { this.selectedGroup = index }, switchEmoji(index) { this.selectedEmoji = index }, delEmoji(index, group = this.selectedGroup) { this.emoji[group].images.splice(index, 1) }, addEmoji(emoji, group = this.selectedGroup, notice = false) { this.emoji[group].images.unshift(emoji) if(notice) this.notice(`已将表情添加至${this.emoji[group].tag}`) }, addGroup(group) { this.emoji.push(group) return this.emoji.length - 1 }, delGroup(index) { if(confirm(`您确定要删除分组${this.emoji[index].tag}吗?`)){ if (index == this.emoji.length - 1) this.selectedGroup -= 1 this.emoji.splice(index, 1) this.notice("已删除该分组") } }, emoAsTagImg(img, group = this.selectedGroup) { this.emoji[group].tagImg = img }, insertEmojiInForum(emoji) { eval("seditor_insertunit(document.getElementById('postat') != null ? 'post' : 'fastpost' ,'[img]" + emoji.src + "[/img]')") }, notice(message) { Notification.requestPermission().then((result) => { if (result === 'granted') { let n = new Notification(message); setTimeout(n.close.bind(n), 1800) } }) }, setEmojiAlbum() { emojiAlbum = prompt('请输入表情保存的相册ID:') if (emojiAlbum != null) { this.emojiAlbum = emojiAlbum GM_setValue(storageAlbum,emojiAlbum) notice("相册设置成功") } }, storageEmoji() { GM_setValue(storageVar, this.emoji) }, getFiles(event) { return event.target.files }, uploadFiles(files, group) { this.uploadTotalCount += 2*files.length; for (let i = 0; i < files.length; ++i) { let file = { name: files[i].name, size: files[i].size, type: files[i].type, dom: files[i], }; let data = new FormData(); for (let k in this.post_params) data.append(k, this.post_params[k]); data.append('type', 'image'); data.append('filetype', file.type) data.append('Filename', file.name); data.append('Filedata', file.dom); let pid, src; fetch("/misc.php?mod=swfupload&action=swfupload&operation=album", { "headers": { }, "method": "POST", "mode": "cors", "body": data, "credentials": "include", }).then((res) => res.json()).then((data) => { this.uploadNowCount += 1; pid = data.picid; src = data.bigimg; return fetch("/home.php?mod=spacecp&ac=upload", { "headers": { "content-type": "application/x-www-form-urlencoded", }, "body": "title[" + pid + "]=&albumid=" + this.emojiAlbum + "&albumsubmit=true&albumsubmit_btn=true&formhash=" + this.formhash, "method": "POST", "mode": "cors", "credentials": "include" }) }).then((data) => { this.emojiTemp.push({ group: group, img: { id: pid, src: src } }); this.uploadNowCount += 1; }) } }, uploadEif(files, allowedExts = []) { let f = new FileReader() f.readAsBinaryString(files[0]); let addGroup = this.addGroup let uploadFiles = this.uploadFiles f.onload = function () { let eif = CFB.read(this.result, { type: 'binary' }) let validPaths = [] let validContent = eif.FileIndex.filter((e, i) => { if (e.size > 0) { validPaths.push(eif.FullPaths[i]) return true } return false }) let s = new Set() let fileList = {} for (let idx in validContent) { let entry = validContent[idx] let extName = entry.name.substring(entry.name.lastIndexOf(".") + 1) if (entry.type == 2 && (!allowedExts || allowedExts.includes(extName))) { let name = validPaths[idx].substring(0, validPaths[idx].lastIndexOf(".")) if (!s.has(name)) { let group = validPaths[idx].match(/Entry\/(\d+)\//)[1] let f = new File([new Uint8Array(entry.content)], entry.name, { type: "image/" + extName }) if (fileList[group]) { fileList[group].push(f) } else { fileList[group] = [f] } s.add(name + 'fix') } } } for (let group in fileList) { uploadFiles(fileList[group], addGroup({tag:group,tagImg:{id:'default',src:'data/attachment/common/star/common_25_icon.png'}, images:[]})) } } }, setAddedImg(img){ this.addedImg = img }, openMenu(e, item) { this.rightClickItem = item; let x = e.pageX; let y = e.pageY; this.menu.top = y; this.menu.left = x; this.menu.visible = true; }, closeMenu() { this.menu.visible = false; } }, watch: { uploadNowCount(newCount) { if (newCount == this.uploadTotalCount) { for (let data of this.emojiTemp) { this.addEmoji(data.img, data.group) } this.emojiTemp = [] this.notice("表情上传完成") this.uploadNowCount = 0 this.uploadTotalCount = 0 } }, 'menu.visible'(value) { if (value) { document.body.addEventListener('click', this.closeMenu) } else { document.body.removeEventListener('click', this.closeMenu) } }, selectedGroup(newIndex){ GM_setValue(storageGroup,newIndex) } }, mounted() { setInterval(this.storageEmoji, 500) setInterval(()=>console.log("运行中"),1000) setAddedImg = this.setAddedImg }, computed: { progress() { return this.uploadTotalCount != 0 ? this.uploadNowCount / this.uploadTotalCount : 0 }, position(){ return this.emojiVisible?{left:this.$refs.mine.getBoundingClientRect().left+'px',bottom:unsafeWindow.innerHeight-this.$refs.mine.getBoundingClientRect().top-document.documentElement.scrollTop+'px'}:{} } } }).mount('#emojiTemplate'); $('#fastpostat').before($('#mine')) }) setTimeout(function () { $('.t_f>img.zoom').each(function(i){ $(this.parentElement).append($('<div class="emojiImg" style="display:inline"></div>').append($(this)))}) $('.aimg_tip').mouseenter(function(){ $('#likeEmo').css({ 'font-size':'15px', 'position':'absolute', 'cursor':'pointer', 'display':'inline', }) setAddedImg({id:$(this.previousElementSibling).attr('id'),src:$(this.previousElementSibling).attr('src')}) $(this).append($('#likeEmo')) }) $('.emojiImg').mouseenter(function(){ $('#likeEmo').css({ 'font-size':$(this.firstChild).attr('width')* 0.15 + 'px', 'position':'absolute', 'cursor':'pointer', 'display':'inline', }) setAddedImg({id:$(this.firstChild).attr('id'),src:$(this.firstChild).attr('src')}) $(this).prepend($('#likeEmo')) }) $('.emojiImg').mouseleave(function(){ $('#likeEmo').css('display','none') $('#mine_menu').append($('#likeEmo')) }) }, 200) let trueHideWindow = unsafeWindow.hideWindow unsafeWindow.hideWindow=function(k,all,clear){ if(k=='reply') $('#fastpostat').before($('#mine')) trueHideWindow(k,all,clear) } let trueShowWindow = unsafeWindow.showWindow unsafeWindow.showWindow=function(k, url, mode, cache, menuv){ trueShowWindow(k, url, mode, cache, menuv) if(k=='reply') setTimeout(()=>$('#postat').before($('#mine')),300) } //setInterval(function(){$('#postat').before($('#mine'))},1000) })();