// ==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 // @downloadURL none // ==/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 intentional capitalization */ if (current.substr(1).search(/[A-Z]|\../) > -1) { return current } /* 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", 'vndb'); const fill_vndb = document.getElementById('fill_vndb') function fill(results) { document.getElementById('platform').value = 'Windows' if (results.languages.includes("en")) { if (autoTitleCase) gameTitleInput.value = replaceTildeAndDash(results.titles[0].title).toLowerCase().toTitleCase() else replaceTildeAndDash(results.titles[0].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(', ')}` 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 = 'removed' }) } 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, languages, tags.name, platforms", "results": 1 }), responseType: "json", onload: function (response) { fill(response.response.results[0]) } }) } } fill_vndb.addEventListener('click', firstClick)