// ==UserScript==
// @name Baha imgur upload
// @namespace https://blog.maple3142.net/
// @version 0.7.4
// @description add upload to imgur in bahamut
// @author maple3142
// @match https://*.gamer.com.tw/*
// @match https://blog.maple3142.net/bahamut-imgur-upload.html
// @require https://code.jquery.com/jquery-3.2.1.min.js
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
;(function($) {
'use strict'
/*
* ALBUM_TO_UPLOAD 是你想要上傳的目標相簿 id
* 例如相簿 https://imgur.com/a/C8763 的 id 是 C8763
* 請把他貼到 GM_getValue('ALBUM_TO_UPLOAD','') 後面的引號中,變成 GM_getValue('ALBUM_TO_UPLOAD','C8763')
* 這樣可以確保 id 不會在腳本更新後被清除,不過如果要修改的需要自己去腳本管理器的儲存空間修改
* Tampermonkey 直接在編輯頁面上面的 Storage 頁面修改就好,其他我就不知道了
*/
const ALBUM_TO_UPLOAD = GM_getValue('ALBUM_TO_UPLOAD', '')
if (ALBUM_TO_UPLOAD) GM_setValue('ALBUM_TO_UPLOAD', ALBUM_TO_UPLOAD)
const debounce = delay => fn => {
let de = false
return (...args) => {
if (de) return
de = true
fn(...args)
setTimeout(() => (de = false), delay)
}
}
const qs = o =>
Object.keys(o)
.map(k => k + '=' + encodeURIComponent(o[k]))
.join('&')
const insertToRte = c => {
// copy from utility_fx.js
let a
a = bahaRte.win.getSelection()
a.getRangeAt &&
a.rangeCount &&
((a = a.getRangeAt(0)), a.deleteContents(), (c = a.createContextualFragment(c)), a.insertNode(c))
}
const insertUrlToField = url => {
if (unsafeWindow.bahaRte != null) {
// full rte editor
const ht = $('<div>')
.append($('<img>').attr('src', url))
.html()
insertToRte(ht)
} else if ($('#balaTextId').length) {
// guild/bala reply
const id = $('#balaTextId')
.html()
.trim()
const $tx = $('#' + id)
$tx.val($tx.val() + url)
} else if ($('#msgtalk').length) {
// guild/bala new
const $msgtalk = $('#msgtalk')
$msgtalk.val($msgtalk.val() + url)
} else if (
typeof Forum !== 'undefined' &&
typeof Forum.C !== 'undefined' &&
typeof Forum.C.quills !== 'undefined'
) {
// quick reply
const q = Forum.C.quills[0]
const { index } = q.getSelection() || {}
q.insertEmbed(index || 0, 'image', url)
} else {
//others
prompt('暫時還不支援這種編輯器,不過可以複製下方的網址來貼上', url)
}
}
unsafeWindow.balaInsertImage = () => (insertUrlToField($('#bhImgImageUrl').val()), egg.lightbox.close()) // polyfill original buggy image insert
const isOldImgBoxChecked = i => $(`input[name=bhImgMode][value=${i}]`).prop('checked')
if (location.hostname === 'blog.maple3142.net') {
const access_token = /access_token=(.*?)&/.exec(location.hash)[1]
if (access_token) {
GM_setValue('access_token', access_token)
}
} else {
if (typeof Dropzone !== 'undefined') {
// hook dropzone instances
Dropzone.instances = []
const _Dropzone = Dropzone
const Dropzone$ = function(...o) {
const i = new _Dropzone(...o)
_Dropzone.instances.push(i)
return i
}
unsafeWindow.Dropzone = Object.assign(Dropzone$, _Dropzone)
}
const observer = new MutationObserver(
debounce(10)(_ => {
// new image box
if ($('.tab-menu__item1.active').css('display') === 'block') {
// 上傳圖片 tab1 打開了
if ($('#imgur_uplbtn').length) return // ignore it if exists
const $uplbtn = $('<button>')
.addClass('btn')
.addClass('btn-insert')
.addClass('btn-primary')
.addClass('unchecked')
.attr('id', 'imgur_uplbtn')
.text('imgur 模式: 停用')
const $cancelbtn = $('.dialogify .btn:contains(取消)')
$('.dialogify .btn.btn-insert.btn-primary').before($uplbtn)
$uplbtn.on('click', e => {
e.preventDefault()
e.stopPropagation()
if (!chk_isAuthorized()) {
login()
return
}
imgurEnable = !imgurEnable
if (imgurEnable) $uplbtn.removeClass('unchecked').text('imgur 模式: 啟用')
else $uplbtn.addClass('unchecked').text('imgur 模式: 停用')
})
// Dropzone handling
let imgurEnable = false
const dz = Dropzone.instances[Dropzone.instances.length - 1]
if (dz.hooked) return
dz.hooked = true
dz.on('sending', (e, xhr, fd) => {
if (imgurEnable) dzupload(xhr)
})
const originalcb = dz._callbacks.success[1]
dz._callbacks.success[1] = (file, r) => {
console.log('dz success', r, originalcb)
if (r.token) {
// normal baha file upload
originalcb.apply(dz, [file, r])
} else {
$cancelbtn.click()
insertUrlToField(r.data.link)
}
}
document.onpaste = e => {
const { items } = e.clipboardData
for (let i = 0; i < items.length; i++) {
// It doesn't have iterator protocol...
const item = items[i]
if (item.kind === 'file') {
dz.addFile(item.getAsFile())
}
}
}
} else {
$('#imgur_uplbtn').remove()
}
if ($('.tab-menu__item3.active').css('display') === 'block') {
if ($('#imgur_urlcvt').length) return
const $urlinput = $('#insertImageUrl')
const $cvtbutton = $('<button>')
.attr('id', 'imgur_urlcvt')
.addClass('btn')
.addClass('btn-primary')
.text('轉換為 imgur 網址')
$urlinput.after($cvtbutton)
$cvtbutton.on('click', e => {
e.preventDefault()
if (!chk_isAuthorized()) {
login()
return
}
const url = $urlinput.val()
if (!url) {
alert('請輸入網址')
return
}
$cvtbutton.text('圖片上傳中, 請稍候...').show()
upload(url)
.then(r => {
$urlinput.val(r.data.link)
$cvtbutton.text('轉換為 imgur 網址')
})
.catch(e => {
console.error(e)
alert('上傳失敗')
$cvtbutton.text('轉換為 imgur 網址')
})
})
} else {
$('#bahaimgur_cvt').remove()
}
// old image box
if (isOldImgBoxChecked(1) && !$('#imgurold_upl').length) {
const $uplbtn = $('<button>')
.text('上傳 imgur')
.css('margin-left', '3px')
const $uplfile = $('<input>')
.attr('type', 'file')
.width(220)
const $wrap = $('<div>').attr('id', 'imgurold_upl')
$('#bhImgModeUpload').append($wrap.append($uplfile).append($uplbtn))
$uplbtn.on('click', e => {
e.preventDefault()
e.stopPropagation()
if (!chk_isAuthorized()) {
login()
return
}
const file = $uplfile[0].files[0]
if (!file) return //no file
$uplbtn.text('上傳中...')
upload(file)
.then(r => {
insertUrlToField(r.data.link)
egg.lightbox.close()
})
.catch(e => {
console.error(e)
alert('上傳失敗')
egg.lightbox.close()
})
})
} else if (isOldImgBoxChecked(3) && !$('#imgurold_cvt').length) {
const $urlinput = $('#bhImgImageUrl')
const $cvtbutton = $('<button>')
.text('轉換為 imgur 網址')
.css('display', 'block')
.attr('id', 'imgurold_cvt')
$urlinput
.after($cvtbutton)
.parent()
.css('display', 'flex')
.css('flex-direction', 'column')
.css('align-items', 'center')
$cvtbutton.on('click', e => {
e.preventDefault()
if (!chk_isAuthorized()) {
login()
return
}
const url = $urlinput.val()
if (!url) {
alert('請輸入網址')
return
}
$cvtbutton.text('圖片上傳中, 請稍候...').show()
upload(url)
.then(r => {
$urlinput.val(r.data.link)
$cvtbutton.text('轉換為 imgur 網址')
})
.catch(e => {
console.error(e)
alert('上傳失敗')
$cvtbutton.text('轉換為 imgur 網址')
})
})
}
})
)
observer.observe(document.body, { attributes: true, childList: true, characterData: true, subtree: true })
}
function getInitialUploadData() {
const data = new FormData()
if (ALBUM_TO_UPLOAD) {
data.append('album', ALBUM_TO_UPLOAD)
}
return data
}
function upload(image) {
const data = getInitialUploadData()
data.append('image', image)
return fetch('https://api.imgur.com/3/image', {
method: 'POST',
credentials: 'omit',
body: data,
headers: {
Authorization: `Bearer ${GM_getValue('access_token')}`
}
})
.then(r => r.json())
.then(r => {
if (!r.success) throw new Error(r)
return r
})
}
function dzupload(xhr) {
const data = getInitialUploadData()
const fd$ = new Promise(res => {
xhr._send = xhr.send
xhr.send = res
})
return fd$.then(fd => {
xhr.withCredentials = false
xhr.open('POST', 'https://api.imgur.com/3/image')
xhr.setRequestHeader('Authorization', `Bearer ${GM_getValue('access_token')}`)
data.append('image', fd.get('dzfile'))
xhr._send(data)
})
}
function chk_isAuthorized() {
return GM_getValue('access_token', null) !== null
}
function login() {
window.open(
'https://api.imgur.com/oauth2/authorize?client_id=41e93183c27ec0e&response_type=token',
'oauth',
'height=700,width=700'
)
}
const css = document.createElement('style')
css.textContent = `.btn.unchecked{box-shadow: inset 0 1px 1px rgba(0,0,0,0.2);opacity:0.5;}`
document.body.appendChild(css)
})(jQuery)