GGn Formatters

Formatters

Tento skript by neměl být instalován přímo. Jedná se o knihovnu, kterou by měly jiné skripty využívat pomocí meta příkazu // @require https://update.greasyfork.org/scripts/540511/1614945/GGn%20Formatters.js

// ==UserScript==
// @name         GGn Formatters
// @version      2
// @description  Formatters
// @author       ingts
// @match        https://gazellegames.net/
// ==/UserScript==
function formatTitle(str, alias) {
    const japaneseLowercase = new Map([
        ["ga", ["が", "ガ"]],
        ["no", ["の", "ノ"]],
        ["wa", ["わ", "ワ"]],
        ["mo", ["も", "モ"]],
        ["kara", ["から", "カラ"]],
        ["made", ["まで", "マデ"]],
        ["to", ["と", "ト"]],
        ["ya", ["や", "ヤ"]],
        ["de", ["で", "デ"]],
        ["ni", ["に", "ニ"]],
        ["so", ["そ", "ソ"]],
        ["na", ["な", "ナ"]],
        ["i", ["い", "イ"]],
        ["u", ["う", "ウ"]],
        ["e", ["え", "エ"]],
        ["o", ["お", "オ"]],
        ["san", ["さん"]],
        ["sama", ["さま"]],
        ["kun", ["くん"]],
        ["chan", ["ちゃん"]]
    ])

    const smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|v.?|vs.?|via)$/i
    const alphanumericPattern = /([A-Za-z0-9\u00C0-\u00FF])/
    const wordSeparators = /([ :–—-]|[^a-zA-Z0-9'’])/
    const allUppercase = new Set(['rpg', 'fps', 'tps', 'rts', 'tbs', 'mmo', 'mmorpg', 'arpg', 'jrpg', 'pvp', 'pve', 'ntr', 'td', 'vr', 'npc', 'ost'])
    return str
        .replace(/\s/g, ' ').replace('—', ' - ')
        .replace(/~$/, '').replace(/ ~$/, '').replace(/-$/, '').replace(/^-/, '').replace(/ ~ /, ': ').replace(/ ~/, ': ').replace(/ - /, ': ').replace(/ -/, ': ')
        .replace('™', '').replace('®', '').replace(' : ', ': ')
        .toLowerCase().trim()
        .split(wordSeparators)
        .map(function (current, index, array) {
            if (allUppercase.has(current.trim()) || /\b([IVX])(X{0,3}I{0,3}|X{0,2}VI{0,3}|X{0,2}I?[VX])(?![A-Za-z'])\b/i.test(current))
                return current.toUpperCase()
            if (alias) {
                const jpWords = japaneseLowercase.get(current)
                if (jpWords?.some(w => alias.includes(w))) return current
            }
            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
            }
            /* Capitalize the first letter */
            return current.replace(alphanumericPattern, function (match) {
                return match.toUpperCase()
            })
        })
        .join('')
}

function formatAbout(about) {
    function fixSplitLinesInListItems(input) {
        let lines = input.split('\n')
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].startsWith("[*]")) {
                while (i + 1 < lines.length && !lines[i].match(/[.?!。?!]$/)) {
                    if (lines[i + 1].startsWith("[*]")) {
                        lines[i] += '.'
                        break
                    } else if (lines[i + 1].trim() !== '') {
                        lines[i] += ' ' + lines.splice(i + 1, 1)[0]
                    } else {
                        lines.splice(i + 1, 1)
                    }
                }
            }
        }
        return lines.join('\n')
    }

    // If a line starts with [u], [i], or [b], there is no other text on that line, and it contains 'features', replace tags with [align=center][b][u]
    about = about.replace(/^(\[b]|\[u]|\[i])*(.*?)(\[\/b]|\[\/u]|\[\/i])*$/gm, (match, p1, p2, p3) => {
        return (p1 && p3 && /features/i.test(p2)) ? `[align=center][b][u]${p2}[/u][/b][/align]` : match
    })

    // Title case text inside [align=center][b][u]
    about = about.replace(/\[align=center]\[([bu])]\[([bu])]([\s\S]*?)\[\/\2]\[\/\1]\[\/align]/g, (match, p1, p2, p3) => {
        return `[align=center][b][u]${formatTitle(p3)}[/u][/b][/align]`
    })

    // Add a newline before lines with [align=center] if there isn't already a double newline before it
    about = about.replace(/(?<!\n\n)(\[align=center])/g, '\n\$1')

    // Remove colons in text inside [align=center][b][u]
    about = about.replace(/\[align=center]\[b]\[u](.*?)\[\/u]\[\/b]\[\/align]/g, (match, p1) => {
        return match.replace(/:/g, '')
    })

    // Replace different list symbols at the start with [*]
    about = about.replace(/^[-•◦■・]\s*/gm, '[*]')

    // If a line starts with [u], [i], or [b] and it is not the only text on that line, add [*] at the start and replace tags with [b]
    about = about.replace(/^(\[b]|\[u]|\[i])*(.*?)(\[\/b]|\[\/u]|\[\/i])+(.*$)/gm, (match, p1, p2, p3, p4) => {
        if (p4.trim() === '') {
            return match
        }
        return p1 && p3 ? `[*][b]${p2}[/b]${p4}` : match
    })

    // If a line starts with [*] followed by a [u] or [i], replace them with [b]
    about = about.replace(/^\[\*]\[[ui]](.*?)\[\/[ui]]/gm, '[b]$1[/b]')

    // Title case text inside tags for lines starting with [u], [i], or [b] and has nothing else after the closing tag
    about = about.replace(/(^|\n)(\[([uib])](.*?)\[\/([uib])]\s*$)/gm, (match, p1, p2, p3, p4) => `${p1}[${p3}]${formatTitle(p4)}[/${p3}]`)

    // For lines that start with [*], replace newlines with spaces until that line ends with ., ?, or !
    // and add a full stop if there is no punctuation before another [*]
    about = fixSplitLinesInListItems(about)

    // Remove double newlines between [*] lines
    about = about.replace(/(\[\*][^\n]*)(\n{2,})(?=\[\*])/g, '$1\n')

    // Add a newline when next line doesn't start with [*]
    about = about.replace(/(\[\*][^\n]*\n)([^\[*\]\n])/g, '$1\n$2')

    // Move : and . outside of closing tags
    about = about.replace(/(\[([bui])])(.*?)([:.])\[\/([bui])]/g, '$1\$3[/b]\$4')

    // Remove [u], [i], or [b] if the line starts with [*] followed by a [u], [i], or [b], and ends with punctuation after the closing tag
    about = about.replace(/^\[\*]\[([bui])](.*?)\[\/([bui])]([.?!。?!])$/gm, "[*]$2$4")

    // If a line ends with [/align] replace double newlines with one newline
    about = about.replace(/(\[\/align])\n\n/g, '$1\n')

    return about
}