Last active
January 26, 2024 12:00
-
-
Save hdk5/d5e896431de6253d67beeb7ef7f9f8fb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Danbooru - Upload to Gelbooru | |
| // @namespace danbooru.hdk5 | |
| // @match *://*.donmai.us/* | |
| // @grant GM_xmlhttpRequest | |
| // @version 1.2.3 | |
| // @author hdk5 | |
| // @connect gelbooru.com | |
| // @downloadURL https://gist.github.com/hdk5/d5e896431de6253d67beeb7ef7f9f8fb/raw/danbooru_upload_to_gelbooru.user.js | |
| // @updateURL https://gist.github.com/hdk5/d5e896431de6253d67beeb7ef7f9f8fb/raw/danbooru_upload_to_gelbooru.user.js | |
| // ==/UserScript== | |
| /* globals $ Danbooru*/ | |
| const METATAGS = [ | |
| 'user', 'approver', 'commenter', 'comm', 'noter', 'noteupdater', 'artcomm', 'commentaryupdater', | |
| 'flagger', 'appealer', 'upvote', 'downvote', 'fav', 'ordfav', 'favgroup', 'ordfavgroup', 'reacted', 'pool', | |
| 'ordpool', 'note', 'comment', 'commentary', 'id', 'rating', 'source', 'status', 'filetype', | |
| 'disapproved', 'parent', 'child', 'search', 'embedded', 'md5', 'pixelhash', 'width', 'height', 'mpixels', 'ratio', | |
| 'score', 'upvotes', 'downvotes', 'favcount', 'filesize', 'date', 'age', 'order', 'limit', 'tagcount', 'pixiv_id', 'pixiv', | |
| 'unaliased', 'exif', 'duration', 'random', 'is', 'has', 'ai', | |
| ]; | |
| const TAG_MAP = { | |
| "covered_nipples": "covered_erect_nipples", | |
| } | |
| const GIRLS = makeGenderTags('girl'); | |
| const BOYS = makeGenderTags('boy'); | |
| const OTHERS = makeGenderTags('other'); | |
| function makeGenderTags(gender) { | |
| let result = [`multiple_${gender}s`]; | |
| function addTag(prefix) { | |
| result.push(`${prefix}${gender}`); | |
| result.push(`${prefix}${gender}s`); | |
| } | |
| for (let i = 1; i <= 6; ++i) { | |
| addTag(i); | |
| if (i >= 6) { | |
| addTag(`${i}+`); | |
| } | |
| } | |
| return result; | |
| } | |
| function GM_fetch(options) { | |
| return new Promise((resolve, reject) => { | |
| GM_xmlhttpRequest({ | |
| ...options, | |
| onload(response) { | |
| resolve(response); | |
| }, | |
| onerror(error) { | |
| reject(error); | |
| }, | |
| }); | |
| }); | |
| } | |
| function extractTags() { | |
| let tagString = $('#post_tag_string').val().toLowerCase(); | |
| let tags = Danbooru.Utility.splitWords(tagString); | |
| return tags; | |
| } | |
| (() => { | |
| if (typeof $ === typeof undefined) return; | |
| let $image = $('img.media-asset-image'); | |
| if ($image.length === 0) $image = $('img#image'); | |
| if ($image.length === 0) return; | |
| let imgUrl = $image.attr('src'); | |
| if (imgUrl.endsWith('.webp')) { | |
| imgUrl = imgUrl.replace('/original/', '/full/').replace('.webp', '.jpg'); | |
| } | |
| let imgName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1); | |
| let imgExt = imgName.substring(imgName.lastIndexOf('.') + 1); | |
| let imgMime = ({ | |
| "jpg": "image/jpeg", | |
| "png": "image/png", | |
| "gif": "image/gif", | |
| // "avif": "image/avif", | |
| // "mp4": "video/mp4", | |
| // "webp": "image/webp", | |
| // "webm": "video/webm", | |
| // "swf": "application/x-shockwave-flash", | |
| // "ugoira": "application/zip", | |
| })[imgExt]; | |
| if (imgMime === undefined) return; | |
| $('#post_tag_string').closest('form').find('input[type=submit]').after( | |
| $('<button></button>', { | |
| text: 'Post to Gelbooru', | |
| class: 'btn button-sm', | |
| click: async (e) => { | |
| e.preventDefault(); | |
| $(e.target).attr('disabled', true); | |
| await upload(); | |
| $(e.target).attr('disabled', false); | |
| }, | |
| }) | |
| ); | |
| async function upload() { | |
| let tagString = extractTags(); | |
| let allowedRatings = $('div.input.post_rating input[type="radio"]').map((i, el) => $(el).val()).get(); | |
| let rating = $('div.input.post_rating input:checked').val(); | |
| for (const tag of tagString) { | |
| let match = tag.match(/^([^:]*):(.*)$/); | |
| if (match === null) continue; | |
| let [_, metaTag, metaValue] = match; | |
| if (metaTag === 'rating') { | |
| metaValue = metaValue[0]; | |
| if (allowedRatings.includes(metaValue)) { | |
| rating = metaValue; | |
| } | |
| } | |
| } | |
| if (rating === undefined) { | |
| $('div.input.post_rating').addClass('field_with_errors'); | |
| return; | |
| } | |
| tagString = tagString.filter((tag) => { | |
| let match = tag.match(/^([^:]*):(.*)$/); | |
| if (match) { | |
| let [_, metaTag, metaValue] = match; | |
| if (METATAGS.includes(metaTag)) return false; | |
| } | |
| return !( | |
| ['commentary_request', 'commentary', 'translated', 'annotated'].includes(tag) || | |
| tag.endsWith('_commentary') | |
| ) | |
| }); | |
| let hasGirls = tagString.some(v => GIRLS.includes(v)); | |
| let hasBoys = tagString.some(v => BOYS.includes(v)); | |
| let hasOthers = tagString.some(v => OTHERS.includes(v)); | |
| if (hasGirls && !hasBoys && !hasOthers) tagString.push('female_focus'); | |
| if (!hasGirls && hasBoys && !hasOthers) tagString.push('male_focus'); | |
| tagString = tagString.map(tag => tag in TAG_MAP ? TAG_MAP[tag] : tag); | |
| let source = $('#post_source').val(); | |
| let imgData = await fetch(imgUrl).then(response => response.arrayBuffer()); | |
| let url = 'https://gelbooru.com/index.php?page=post&s=add'; | |
| let response = await GM_fetch({ | |
| method: "POST", | |
| url: url, | |
| data: (() => { | |
| let formData = new FormData(); | |
| formData.append( | |
| 'upload', | |
| new Blob([imgData], { type: imgMime }), | |
| imgName, | |
| ); | |
| formData.append('source', source); | |
| formData.append('title', ''); | |
| formData.append('tags', tagString.join(" ")); | |
| formData.append('rating', rating); | |
| formData.append('submit', "Upload"); | |
| return formData; | |
| })(), | |
| }); | |
| console.log(response); | |
| let responseHtml = (() => { | |
| let document = (new DOMParser).parseFromString(response.responseText, 'text/html'); | |
| let base = document.createElement('base'); | |
| base.href = 'https://gelbooru.com/'; | |
| document.head.appendChild(base); | |
| return document; | |
| })(); | |
| let newPostUrl = undefined; | |
| let error = $(responseHtml).find('.alert-warning'); | |
| if (error.length === 0) { | |
| newPostUrl = response.finalUrl; | |
| } else if (error.text().startsWith('That image already exists. You can find it here')) { | |
| newPostUrl = error.find('a').prop('href'); | |
| } | |
| if (newPostUrl === undefined) { | |
| Danbooru.error('Upload to Gelbooru failed. See console for details.'); | |
| return; | |
| } | |
| window.open(newPostUrl, '_blank').focus(); | |
| await GM_fetch({ | |
| method: "POST", | |
| url: '/uploads.json', | |
| data: (() => { | |
| let formData = new FormData(); | |
| formData.append('upload[source]', newPostUrl); | |
| return formData; | |
| })(), | |
| }); | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment