// ==UserScript==
// @name GGn Steam Uploady (edited)
// @namespace https://gazellegames.net/
// @version 30k
// @description Fill upload form with Steam info. Edited from "GGn New Uploady"
// @author NeutronNoir, ZeDoCaixao, ingts
// @match https://gazellegames.net/upload.php*
// @match https://gazellegames.net/torrents.php?action=editgroup*
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @connect store.steampowered.com
// @connect steamcdn-a.akamaihd.net
// @require https://update.greasyfork.org/scripts/540511/1632198/GGn%20Formatters.js
// ==/UserScript==
if (typeof GM_getValue('get_languages') === 'undefined')
GM_setValue('get_languages', true)
if (typeof GM_getValue('get_image_res') === 'undefined')
GM_setValue('get_image_res', false)
const allowedTags = new Set([
// "Casual", allowed but too common
// "Exploration", allowed but too common
"Action",
"Adventure",
"Simulation",
"Strategy",
"RPG",
"Puzzle",
"Fantasy",
"Shooter",
"Platformer",
"Horror",
"Visual Novel",
"Open World",
"Survival",
"Sports",
"Comedy",
"FPS",
"Mystery",
"Sandbox",
"Fighting",
"Racing",
"Shoot 'Em Up",
"Point & Click",
"Building",
"Management",
"Turn-Based Strategy",
"Drama",
"Romance",
"Interactive Fiction",
"Hidden Object",
"Hack and Slash",
"Education",
"Bullet Hell",
"Dungeon Crawler",
"Dating Sim",
"Historical",
"Walking Simulator",
"Card Game",
"Third-Person Shooter",
"RTS",
"Life Sim",
"Clicker",
"Board Game",
"Driving",
"Tower Defense",
"Time Management",
"City Builder",
"Thriller",
"Wargame",
"Beat 'em up",
"Runner",
"Stealth",
"Trivia",
"Typing",
"Minigames",
"4X",
"Cooking",
"Match 3",
"Rhythm",
"Cricket",
"Rugby",
"Mahjong",
"Snowboarding",
"Hockey",
"Bowling",
"Skateboarding",
"Tennis",
"Cycling",
"Wrestling",
"Basketball",
"Golf",
"Chess",
"Boxing",
"Gambling",
"Fishing",
"Auto Battler",
"Solitaire",
"Hunting",
"Grand Strategy",
"Space Sim",
])
const tagMap = new Map([
["Sci-fi", "science.fiction"],
["NSFW", "adult"],
["Hentai", "adult"],
["Roguelike", "roguelike"],
["Roguelite", "roguelike"],
["Text-Based", "text.adventure"],
["Flight", "flight.simulation"],
["Party", "party"],
["Party Game", "party"],
["Football (American)", "american.football"],
["Football (Soccer)", "soccer"],
])
function html2bb(str) {
if (!str) return ""
str = str.replace(/<h2 class="bb_tag"><strong>(.*?)<\/strong><\/h2>/g, `<h2 class="bb_tag">$1</h2>`)
str = str.replace(/<picture>.*?<\/picture>/g, "")
str = str.replace(/<li><p class="bb_paragraph">/g, "\n[*]")
str = str.replace(/(?:<p class="bb_paragraph"><div class="bb_img_ctn">.*?<\/div><\/p>)+/g, "")
str = str.replace(/<p class="bb_paragraph"><strong>/g, "\n[b]")
str = str.replace(/<\/div>/g, "")
str = str.replace(/<div .*?>/g, "")
str = str.replace(/< *br *\/*>/g, "\n\n") //*/
str = str.replace(/< *b *>/g, "[b]")
str = str.replace(/< *\/ *b *>/g, "[/b]")
str = str.replace(/< *u *>/g, "[u]")
str = str.replace(/< *\/ *u *>/g, "[/u]")
str = str.replace(/< *i *>/g, "[i]")
str = str.replace(/< *\/ *i *>/g, "[/i]")
str = str.replace(/<strong><\/strong>/g, " ")
str = str.replace(/< *strong *>/g, "[b]")
str = str.replace(/< *\/ *strong *>/g, "[/b]")
str = str.replace(/< *em *>/g, "[i]")
str = str.replace(/< *\/ *em *>/g, "[/i]")
str = str.replace(/< *\/ *li *>/g, "")
str = str.replace(/< *ul *class=\\*"bb_ul\\*" *>/g, "")
str = str.replace(/< *\/ *ul *>/g, "")
str = str.replace(/< *h2 *class="bb_tag" *>/g, "\n[align=center][b][u]")
str = str.replace(/< *h[12] *>/g, "\n[align=center][b][u]")
str = str.replace(/< *\/ *h[12] *>/g, "[/u][/b][/align]\n")
str = str.replace(/"/g, "\"")
str = str.replace(/&/g, "&")
str = str.replace(/< *a [^>]*>/g, "")
str = str.replace(/<p class="bb_paragraph"><\/p>/g, '\n\n')
str = str.replace(/<p class="bb_paragraph">/g, '\n')
str = str.replace(/< *li *>/g, "[*]")
str = str.replace(/< *\/ *a *>/g, "")
str = str.replace(/< *p *>/g, "\n\n")
str = str.replace(/<\/p>/g, "")
str = str.replace(//g, "\"")
str = str.replace(//g, "\"")
str = str.replace(/ +/g, " ")
str = str.replace(/< *img.*?>/g, "\n")
str = str.replace(/\n +/g, "\n")
str = str.replace(/\[\/b]\[\/u]\[\/align]\n\n/g, "[/b][/u][/align]\n")
str = str.replace(/\n\n\n+/gm, "\n\n")
str = str.replace(/\n\n\[\*]/g, "\n[*]")
str = str.replace(/.*]\[u]\s?\[\/u]\[.*/g, "") // remove empty tags
return str.trim()
}
/*function fix_emptylines(str) {
const lst = str.split("\n")
let result = ""
let empty = 1
lst.forEach(function (s) {
if (s) {
empty = 0
result = result + s + "\n"
} else if (empty < 1) {
empty = empty + 1
result = result + "\n"
}
})
return result
}*/
/**
* @param {SteamAppDetails} data
*/
function fill_form(data) {
let recfield = data.pc_requirements
let platform = "Windows"
platform = $("#platform").val()
switch (platform) {
case "Windows":
recfield = data.pc_requirements
break
case "Linux":
recfield = data.linux_requirements
break
case "Mac":
recfield = data.mac_requirements
break
}
let desc = html2bb(`${data.about_the_game}
[quote][align=center][b][u]System Requirements[/u][/b][/align]
${recfield.minimum + (recfield.recommended ? '\n' + recfield.recommended : '')}[/quote]`)
const descField = isEditPage ? document.querySelector("textarea[name='body']") : document.getElementById('album_desc')
createUnformattedArea(descField, desc)
descField.value = formatAll(desc, data.name)
const year = data.release_date.date.split(", ").pop()
const groupScreenshots = document.getElementsByName("screens[]")
const add_screen = $("#image_block a[href='#']").first()
const screenshots = data.screenshots
if (isEditPage) {
while (groupScreenshots.length < screenshots.length) {
add_screen.click()
}
}
for (let i = 0; i < screenshots.length; i++) {
if (i === 20) break
if (!isEditPage && i >= 4) add_screen.click()
groupScreenshots[i].value = screenshots[i].path_full.split("?")[0]
if (GM_getValue('get_image_res')) {
new Promise((resolve, reject) => {
let img = new Image()
img.src = screenshots[i].path_full.split("?")[0]
img.onload = () => resolve(img)
img.onerror = () => reject()
}).then(img => {
groupScreenshots[i].parentElement.style.position = 'relative'
groupScreenshots[i].insertAdjacentHTML('afterend',
`<span style="position:absolute;top: -115%;right: 9.5%;">${img.naturalWidth}x${img.naturalHeight}</span>`)
})
}
}
const ratings = data.ratings
const ratingInput = document.getElementById('Rating')
if (ratings) {
const ratingMap = new Map([
['pegi', new Map([
['3', 1],
['7', 3],
['12', 5],
['16', 7],
['18', 9],
])],
['esrb', new Map([
['e', 1],
['e10', 3],
['t', 5],
['m', 7],
['ao', 9],
])],
['nzoflc', new Map([
['g', 1],
['r13', 7],
['r16', 7],
['r18', 9],
])],
['cero', new Map([
['a', 1],
['b', 3],
['c', 5],
['d', 7],
['z', 9],
])],
['csrr', new Map([ // gsrr?
['g', 1],
['p', 3],
['pg12', 5],
['pg15', 7],
['r', 9],
])],
['usk', new Map([
['0', 1],
['6', 3],
['12', 5],
['16', 7],
['18', 9],
])],
['steam_germany', new Map([
['0', 1],
['6', 3],
['10', 5],
['12', 5],
['16', 7],
['18', 9],
])],
])
for (const [board, map] of ratingMap) {
if (Object.hasOwn(ratings, board)) {
ratingInput.value = map.get(ratings[board].rating)
ratingInput.closest('tr').firstElementChild
.insertAdjacentHTML('beforeend', `<span style="color: #d6c9b6;display: block;">Source: ${board}</span>`)
break
}
}
}
if (!ratings || !ratingInput.value)
ratingInput.value = 13
if (isEditPage) {
$("input[name='year']").val(year)
$("input[name='name']").val(data.name)
if ($("#trailer~a").attr("href").includes("Linux")) {
platform = "Linux"
} else if ($("#trailer~a").attr("href").includes("Mac")) {
platform = "Mac"
}
} else {
const parseSteamLanguage = unsafeWindow?.GetLanguagesFromSteam?.parseSteamLanguage // from Get Languages From Steam script
if (parseSteamLanguage && GM_getValue('get_languages') && !document.getElementById('empty_group').checked) {
parseSteamLanguage(data.supported_languages)
}
$("#title").val(data.name)
$("#gameswebsiteuri").val(data.website)
$("#year").val(year)
}
const coverField = $("input[name='image']")
coverField.val(data.header_image.split("?")[0])
const big_cover = "https://steamcdn-a.akamaihd.net/steam/apps/" + steamIdInput.value + "/library_600x900_2x.jpg"
GM_xmlhttpRequest({
method: "GET",
url: big_cover,
responseType: "json",
onload: function (response) {
if (response.status === 200) {
coverField.val(big_cover)
return
}
coverField.after(`<span style="color:yellow;">
Big cover could not be found. Until a way to retrieve it for newer games is found, take the <a href=https://steamdb.info/app/${steamIdInput.value}/info target="_blank">library_capsule_2x link</a>
</span>`)
}
})
// $(desc_field).val(fix_emptylines($(desc_field).val()))
if (data.metacritic) {
$("#meta").val(data.metacritic.score)
$("#metauri").val(data.metacritic.url.split("?")[0] + "/critic-reviews")
}
if (data.hasOwnProperty('movies')) {
$("#trailer").val(data.movies[0].webm.max.split("?")[0].replace("http:", "https:"))
}
}
let steamIdInput
if (isEditPage) {
$("td.center").parent().after("<tr><td class='label'>Steam ID</td><td><input id='steamid' /></td></tr>")
steamIdInput = document.getElementById('steamid')
} else {
steamIdInput = document.getElementById('steamid')
steamIdInput.type = 'text'
steamIdInput.size = 20
steamIdInput.removeAttribute('min')
steamIdInput.insertAdjacentHTML('afterend',
'<a href="javascript:;" id="fill_win">Win</a> <a href="javascript:;" id="fill_lin">Lin</a> <a href="javascript:;" id="fill_mac">Mac</a>')
$('#fill_win').click(function () {
$("#platform").val("Windows")
})
$('#fill_lin').click(function () {
$("#platform").val("Linux")
})
$('#fill_mac').click(function () {
$("#platform").val("Mac")
})
}
steamIdInput.onblur = () => {
if (steamIdInput.value.includes('store.steampowered')) {
steamIdInput.value = /\d+/.exec(steamIdInput.value)[0]
}
GM_xmlhttpRequest({
method: "GET",
url: "https://store.steampowered.com/api/appdetails?l=en&appids=" + steamIdInput.value,
responseType: "json",
onload: response => fill_form(response.response[steamIdInput.value].data)
})
if (location.href.includes('upload.php')) {
GM_xmlhttpRequest({
url: `https://store.steampowered.com/app/${steamIdInput.value}`,
onload: function (res) {
const page = new DOMParser().parseFromString(res.responseText, "text/html")
let uploadTags = new Set()
for (const steamTag of page.querySelectorAll('.glance_tags a')) {
const text = steamTag.textContent.trim()
if (text === 'Survival Horror') {
uploadTags.add('survival')
uploadTags.add('horror')
continue
}
if (allowedTags.has(text)) {
uploadTags.add(text.toLowerCase()
.replace(/sim(?!\w)/, "simulation").replace("simulator", "simulation")
.replace(/'/g, '').replace(/&/g, 'and').replace(/-/g, ' ').replace(/ /g, '.'))
continue
}
const t = tagMap.get(text)
if (t) {
uploadTags.add(t)
}
}
document.getElementById('tags').value = Array.from(uploadTags).join(', ')
if (uploadTags.has('adult'))
document.getElementById('Rating').value = 9
}
})
}
}