Skip to content

Instantly share code, notes, and snippets.

@hdk5
Last active January 26, 2024 12:00
Show Gist options
  • Select an option

  • Save hdk5/d5e896431de6253d67beeb7ef7f9f8fb to your computer and use it in GitHub Desktop.

Select an option

Save hdk5/d5e896431de6253d67beeb7ef7f9f8fb to your computer and use it in GitHub Desktop.
// ==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