// ==UserScript==
// @name Photopea 之——一键转为 PNG/WebP
// @description 单张图片格式快捷转换
// @mechanism 不过是个鼠标和输入的宏
// @version 1.0.2~20221211
// @match https://www.photopea.com/
// @license Unlicense
// @namespace https://greasyfork.org/users/871942
// ==/UserScript==
// 自定义预设之例子:`localStorage.setItem('convertOptions', JSON.stringify({width:1280}))`
const fnName = '一键转 PNG/WebP'
const [$, $$] = ['', 'All'].map(_ => document[`querySelector${_}`].bind(document))
addEventListener('load', () => {
console.log(`「${fnName}」已加载!`)
topbar(1).addEventListener('click', () => {
const cp = $(`.contextpanel`), el = cp.querySelector('div:last-child').cloneNode(true)
cp.insertAdjacentElement('beforeend', el).addEventListener('click', main)
el.querySelector('.label').innerHTML = fnName
}, { once: true })
})
function main() {
if (/*当前无打开的项目*/!$('.panelhead > .active')) {
clickMenu.msg = '打开文件'
clickMenu(1,2)
/*一开就转*/onAppend($('.panelhead'), main, {once:true})
return
}
const { width, fmt = 'PNG' } = JSON.parse(localStorage.getItem('convertOptions')) || {}
if (!isNaN(width)) {
clickMenu.msg = `调整图片大小为 ${width} px`
clickMenu(3,9)
setParam([document.activeElement, width])
click('.spread')
}
clickMenu.msg = '调整视图大小'
clickMenu(7,3)
clickMenu.msgEnd =
clickMenu.msg = `导出 ${fmt}`
switch (fmt.toLowerCase()) {
case 'png': clickMenu(1,9,1); break
case 'webp': clickMenu(1,9,-1,1); setParam([$('.trangeinput > input'), '100%']); break
default: unsafeWindow.alert(`不支持一键导出 ${fmt} 格式`, 7000); return
}
click('.spread',0)
// 移除假阳性的反反广告弹框
setTimeout(() => onAppend($('.app'), () => dE($('.confirm .cross'), 'pointerup'), {once:true, timeout:10000}))
}
function clickMenu(..._) {
// 最核心的函数,移植定制你自己的其他操作流程之利器。系检试而成且即使某天原站界面大改大变也只需修改此处的CSS选择器
let __, ___
_[0] && (___ = topbar(_[0])) && ___.dispatchEvent(new Event('pointerdown'))
Array.from(Array(_.length - 1).keys(), _ => ++_).every(n =>
_[n] && (__ = $$(`.contextpanel`)[n-1]) && (__ = __.querySelector(`div:nth${_[n]<0?'-last':''}-of-type(${_[n]<0?-_[n]:_[n]})`)) && ((___ = __).click(), true)
)
clickMenu.msg && console.log(`${clickMenu.msgEnd?'✅ ':''}${clickMenu.msg}`)
delete clickMenu.msg; delete clickMenu.msgEnd
return [___, $$('[style^="position: absolute; z-index: 10"]')]
}
function topbar(n) { return $(`.topbar > span:nth-child(1) > button:nth-child(${n})`) }
function click(selector, instant) { instant === undefined ? $(selector).click() : setTimeout(()=>$(selector).click(),instant) }
function onAppend(el, cb, {once, timeout}={}) {
const mr = el._onAppend ??= new MutationObserver(function ([m]) { (cb(m)||once) && this.disconnect() })
mr.observe(el, {childList:true, subtree:true})
timeout && setTimeout(mr.disconnect, timeout)
}
function setParam(...inputs) { inputs.forEach(([input,val]) => { input.value = val; input.dispatchEvent(new Event('change')) }) }
function dE(el, ev) { el.dispatchEvent(new Event(ev)) }
'clickMenu setParam dE'.split(' ').forEach(f => unsafeWindow[`_${f}`] = eval(f))