// ==UserScript==
// @name GGn vndb uploady new
// @namespace none
// @version 1
// @description gazellegames vndb uploady. input game title in game title field or vndb id (anything with v(digits)) and click vndb to fill
// @author ingts
// @match https://gazellegames.net/upload.php*
// @connect api.vndb.org/kana
// @icon none
// @grant GM_xmlhttpRequest
// ==/UserScript==
'use strict';
const autoTitleCase = true
const autoSearchTrailer = true
const autoPTPimg = true
const tagsDictionary = {
'romance': ["Love", "Polyamory", "Polygamy", "Swinging", "Romance"],
'horror': ["Horror", "Graphic Violence"],
'science.fiction': ["Science Fiction", "AI"],
'drama': ["Drama", "Suicide", "Suicidal", "Desperation"],
'crime': ["Crime", "Slave"],
'mystery': ["Mystery"],
'comedy': ["Comedy", "Slapstick"],
'fantasy': ["Fantasy", "Magic", "Mahou", "Superpowers"]
}
const tagExclusions = {
'romance': ["No Romance Plot"]
};
/* To Title Case © 2018 David Gouch | https://github.com/gouch/to-title-case */
// eslint-disable-next-line no-extend-native
String.prototype.toTitleCase = function () {
var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|v.?|vs.?|via)$/i
var alphanumericPattern = /([A-Za-z0-9\u00C0-\u00FF])/
var wordSeparators = /([ :–—-])/
return this.split(wordSeparators)
.map(function (current, index, array) {
if (
/* Check for small words */
current.search(smallWords) > -1 &&
/* Skip first and last word */
index !== 0 &&
index !== array.length - 1 &&
/* Ignore title end and subtitle start */
array[index - 3] !== ':' &&
array[index + 1] !== ':' &&
/* Ignore small words that start a hyphenated phrase */
(array[index + 1] !== '-' ||
(array[index - 1] === '-' && array[index + 1] === '-'))
) {
return current.toLowerCase()
}
/* Ignore URLs */
if (array[index + 1] === ':' && array[index + 2] !== '') {
return current
}
/* Capitalize the first letter */
return current.replace(alphanumericPattern, function (match) {
return match.toUpperCase()
})
})
.join('')
}
function replaceTildeAndDash(title) {
if (title.includes('~')) {
return title.replace(/ ~ /g, ': ').replace(/ ~/g, ': ').replace(/~$/g, '').replace(/ ~$/g, '');
} else if (title.includes('-')) {
return title.replace(/ - /g, ': ').replace(/ -/g, ': ').replace(/-$/g, '');
} else {
return title;
}
}
function removeLastBracket(str) {
if (!str.endsWith(']')) return str
let i = str.length - 1
let bracketCounter = 0;
for (; i >= 0; i--) {
if (str[i] === ']') {
bracketCounter++;
} else if (str[i] === '[') {
bracketCounter--;
if (bracketCounter === 0) {
break;
}
}
}
return str.substring(0, i).trim();
}
const gameTitleInput = document.getElementById('title');
gameTitleInput.insertAdjacentHTML("afterend", '<a href="javascript:" id="fill_vndb">vndb</a>');
const fill_vndb = document.getElementById('fill_vndb')
function fill(results) {
document.getElementById('platform').value = 'Windows'
const englishTitle = results.titles.find(a => a.lang === 'en')
if (englishTitle) {
if (autoTitleCase) gameTitleInput.value = replaceTildeAndDash(englishTitle.title).toLowerCase().toTitleCase()
else replaceTildeAndDash(englishTitle.title)
} else {
if (autoTitleCase) gameTitleInput.value = results.title
else gameTitleInput.value = results.title.toLowerCase().toTitleCase()
}
if (autoSearchTrailer) window.open(`https://www.youtube.com/results?search_query=${gameTitleInput.value} trailer`, '_blank').focus()
document.getElementById('aliases').value = [results.alttitle, results.aliases.join(", ")].filter(Boolean).join(', ')
const tagsInput = document.getElementById('tags')
let foundTags = []
Object.keys(tagsDictionary).forEach(ggnTag => {
const words = tagsDictionary[ggnTag];
let exclude = false;
if (tagExclusions.hasOwnProperty(ggnTag)) {
results.tags.forEach(tag => {
tagExclusions[ggnTag].forEach(exclusion => {
if (tag.name.includes(exclusion)) {
exclude = true;
}
});
});
}
if (!exclude) {
results.tags.forEach(tag => {
words.forEach(word => {
if (tag.name.includes(word) && !foundTags.includes(ggnTag)) {
foundTags.push(ggnTag);
}
});
});
}
});
foundTags.length === 0 ? tagsInput.value = 'visual.novel'
: tagsInput.value = `visual.novel, ${foundTags.join(', ')}`
if (results.released === 'TBA') document.getElementById('year').value = new Date().getFullYear();
else document.getElementById('year').value = results.released.split('-')[0]
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.vndb.org/kana/release',
headers: {'Content-Type': 'application/json'},
data: JSON.stringify({
"filters": ["vn", "=", ["id", "=", results.id]],
"fields": "minage, has_ero",
"results": 100
}),
responseType: "json",
onload: function (response) {
let ratingSelectValue
const highestMinAge = Math.max(...response.response.results.map(result => result.minage));
if (highestMinAge === 12 || highestMinAge === 13) ratingSelectValue = 5
else if (highestMinAge === 16 || highestMinAge === 17) ratingSelectValue = 7
else if (highestMinAge >= 18) ratingSelectValue = 9
else ratingSelectValue = 13
document.getElementById('Rating').value = ratingSelectValue
if (response.response.results.some(r => r.has_ero))
tagsInput.value += ', adult'
}
})
document.getElementById('image').value = results.image.url
if (autoPTPimg) document.getElementById('image').nextElementSibling.click()
const systemRequirements = `
[quote][align=center][b][u]System Requirements[/u][/b][/align]
[*][b]OS[/b]:
[*][b]Processor[/b]:
[*][b]Memory[/b]:
[*][b]Graphics[/b]:
[*][b]DirectX[/b]:
[*][b]Storage[/b]: [/quote]`
document.getElementById('album_desc').value =
`[align=center][b][u]About the game[/u][/b][/align]
${removeLastBracket(results.description)}
${systemRequirements}
`
if (results.platforms.some(p => !['win', 'lin', 'mac'].includes(p))) {
fill_vndb.removeEventListener('click', firstClick)
fill_vndb.textContent = 'console version found. remove system requirements?'
fill_vndb.addEventListener('click', () => {
document.getElementById('album_desc').value = document.getElementById('album_desc').value.replace(systemRequirements, '')
fill_vndb.outerHTML = '<span>removed</span>'
})
}
const screens = document.getElementsByName("screens[]");
const add_screen = document.querySelector("#image_block a[href='#']");
results.screenshots.forEach(function (screen, index) {
if (index >= 20) return;
if (index >= 4) add_screen.click();
screens[index].value = screen.url;
if (autoPTPimg) screens[index].nextElementSibling.click()
});
}
function firstClick() {
if (gameTitleInput.value !== "") {
let vndbFilter;
const linkmatch = gameTitleInput.value.match(/v(\d+)/)
linkmatch ? vndbFilter = ["id", "=", `${linkmatch[1]}`] : vndbFilter = ["search", "=", `${gameTitleInput.value}`]
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.vndb.org/kana/vn',
headers: {'Content-Type': 'application/json'},
data: JSON.stringify({
"filters": vndbFilter,
"fields": "alttitle, titles.title, title, aliases, description, image.url, screenshots.url, released, titles.lang, tags.name, platforms",
"results": 1
}),
responseType: "json",
onload: function (response) {
fill(response.response.results[0])
}
})
}
}
fill_vndb.addEventListener('click', firstClick)