您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Formats title, sets alias if applicable and has buttons to undo. Adds buttons in edit page to format name and alias. Exposes title case function to other scripts
// ==UserScript== // @name GGn Title Formatter // @namespace none // @version 31 // @description Formats title, sets alias if applicable and has buttons to undo. Adds buttons in edit page to format name and alias. Exposes title case function to other scripts // @author ingts // @match https://gazellegames.net/upload.php // @match https://gazellegames.net/torrents.php?id=* // @match https://gazellegames.net/torrents.php?action=editgroup&groupid=* // @match https://gazellegames.net/upload.php?action=copy&groupid=* // @exclude https://gazellegames.net/upload.php?groupid=* // @grant unsafeWindow // ==/UserScript== let titleInput, aliasInput const globals = unsafeWindow.TitleAndScreenshotsFormatter = {} globals.toTitleCase = function (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('®', '') .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 formatText() { let origTitle = titleInput.value aliasInput = document.getElementById('aliases') let origAlias = aliasInput.value let titleAfterTitleCase = globals.toTitleCase(titleInput.value, aliasInput.value) titleInput.value = titleAfterTitleCase if (document.getElementById('categories').value === 'Games') { const excludePattern = /[^a-zA-Z0-9 .~?’!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/]+/g let excluded = titleInput.value.match(excludePattern) if (excluded) { if (excluded.length === 1) { aliasInput.value ? aliasInput.value += ', ' + excluded.join('') : aliasInput.value = excluded.join('') titleInput.value = titleInput.value.replace(excludePattern, "").trim() } else { aliasInput.value ? aliasInput.value += ', ' + titleInput.value : titleInput.value titleInput.value = '' startTextFormat(false) return } } } if (titleAfterTitleCase !== origTitle || aliasInput.value !== origAlias) { document.querySelector("#title_tr > td.label").insertAdjacentHTML('beforeend', `<span style="color: #ebaf51;display: block;">Undo Title Formatter</span> <div id="tf-undo-buttons"></div>`) const buttonDiv = document.getElementById('tf-undo-buttons') if (titleAfterTitleCase !== origTitle) { const button1 = document.createElement('button') button1.textContent = 'Formatting' button1.type = 'button' button1.onclick = () => { titleInput.value = origTitle } buttonDiv.append(button1) } if (aliasInput.value !== origAlias) { const button2 = document.createElement('button') button2.textContent = 'Alias' button2.type = 'button' button2.onclick = () => { titleInput.value = titleAfterTitleCase aliasInput.value = origAlias } buttonDiv.append(button2) } } } function startTextFormat(wait) { const tInterval = setInterval(() => { if (document.activeElement === titleInput || !titleInput.value) return clearInterval(tInterval) if (wait) { // to allow upload scripts that use the title input's value to set the title before formatting setTimeout(formatText, 2000) } else formatText() }, 500) } function addButton(input) { const button = document.createElement('button') button.type = 'button' button.textContent = 'Format' button.addEventListener('click', () => { input.value = globals.toTitleCase(input.value, aliasInput?.value || aliasInput?.textContent) }) input.after(button) } if (location.href.includes('upload.php')) { titleInput = document.getElementById('title') // changing the category changes the form using a server request and the title input is replaced document.getElementById('categories').addEventListener('change', () => { new MutationObserver((mutations, observer) => { titleInput = document.getElementById('title') startTextFormat(true) observer.disconnect() }).observe(document.getElementById('dynamic_form'), {childList: true, subtree: true}) }) startTextFormat(true) } else if (location.href.includes('editgroup')) { titleInput = document.querySelector("input[name=name]") aliasInput = document.querySelector('input[name=aliases]') addButton(aliasInput) addButton(titleInput) } else { // wait to make sure the editor helper loads first setTimeout(() => { const editHelperRename = document.getElementById('titleEdit') if (editHelperRename) { editHelperRename.addEventListener('click', () => { titleInput = document.querySelector("input[name=name]") aliasInput = document.getElementById('group_aliases')?.childNodes[2] addButton(titleInput) }) } }, 80) }