Skip to content

Commit a8a5b33

Browse files
committed
feat: add userscript [App Store Connect - Auto NO Age Ratings]
1 parent dc849d3 commit a8a5b33

4 files changed

Lines changed: 119 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- [Reddit Search Options Persist](./src/plugins/reddit-search-options-persist/README.md): Keep Reddit search filters when searching with new keywords.
55
- [YouTube Music Background Play](./src/plugins/youtube-music-background-play/README.md): Enable background play on YouTube Music.
66
- [TVTropes Anti-Adblock Bypass](./src/plugins/tvtropes-anti-adblock-bypass/README.md): Bypass anti-adblock detection on TVTropes.org.
7+
- [App Store Connect - Auto NO Age Ratings](./src/plugins/appstore-auto-age-ratings/README.md): Auto-select NO/NONE for all age rating questions in App Store Connect.
78

89
## FAQ
910

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# App Store Connect - Auto NO Age Ratings
2+
3+
A userscript that automatically selects NO/NONE/false for all age rating questions in App Store Connect.
4+
5+
## What it does
6+
7+
When triggered via the userscript menu, it automatically selects all "NO", "NONE", or "false" radio buttons on the age ratings page, clicks "Next" to proceed through each step, and stops when the "Save" button appears.
8+
9+
## Installation
10+
11+
1. Install a userscript manager like [Tampermonkey](https://www.tampermonkey.net/) or [Greasemonkey](https://www.greasespot.net/)
12+
2. Download the userscript from <https://github.com/rxliuli/userscripts/releases/latest/download/appstore-auto-age-ratings.user.js>
13+
14+
## Usage
15+
16+
1. Navigate to your app's distribution info page in App Store Connect
17+
2. Open the age ratings dialog
18+
3. Click the userscript menu and select "Auto-select NO/NONE (Age Ratings)"
19+
4. The script will automatically select all NO/NONE options and advance through each step
20+
21+
## Discord
22+
23+
Join the discussion: <https://discord.gg/C2baQRZUCW>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { MonkeyUserScript } from 'vite-plugin-monkey'
2+
3+
export function manifest(): MonkeyUserScript {
4+
return {
5+
name: 'App Store Connect - Auto NO Age Ratings',
6+
namespace: 'https://github.com/rxliuli',
7+
description: 'Auto-select false/NONE on menu click until Save appears; warns only once if no false/NONE found',
8+
match: ['https://appstoreconnect.apple.com/apps/*'],
9+
icon: 'https://www.apple.com/favicon.ico',
10+
grant: ['GM_registerMenuCommand'],
11+
'run-at': 'document-end',
12+
author: 'rxliuli',
13+
license: 'GPL-3.0-only',
14+
}
15+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
const CHECK_INTERVAL = 500
2+
const NEXT_DELAY = 500
3+
const MAX_ATTEMPTS = 60
4+
5+
function hasSaveButton(): boolean {
6+
return [...document.querySelectorAll('[id^="modal-dialog"] button')].some((b) =>
7+
(b as HTMLButtonElement).innerText.toLowerCase().includes('save'),
8+
)
9+
}
10+
11+
function findNextButton(): HTMLButtonElement | undefined {
12+
return [...document.querySelectorAll<HTMLButtonElement>('[id^="modal-dialog"] button')].find(
13+
(b) => b.innerText.trim().toLowerCase() === 'next',
14+
)
15+
}
16+
17+
function autoClickNoUntilSave() {
18+
console.log('[AutoAge] Started: auto-selecting false/NONE until Save')
19+
20+
let attempt = 0
21+
let seenSave = false
22+
let warnedNoFalse = false
23+
24+
function processStep() {
25+
attempt++
26+
27+
if (hasSaveButton()) {
28+
console.log('[AutoAge] Save button detected, stopping')
29+
seenSave = true
30+
return
31+
}
32+
33+
if (attempt >= MAX_ATTEMPTS) {
34+
console.warn('[AutoAge] Max attempts reached, stopping')
35+
return
36+
}
37+
38+
const targets = document.querySelectorAll(
39+
'[id^="modal-dialog"] input[type="radio"][value="false"]:not(:checked), ' +
40+
'[id^="modal-dialog"] input[type="radio"][value="NONE"]:not(:checked), ' +
41+
'[id^="modal-dialog"] input[type="radio"][value="NO"]:not(:checked)',
42+
)
43+
44+
if (targets.length > 0) {
45+
console.log(`[AutoAge] Found ${targets.length} false/NONE/NO options, clicking...`)
46+
targets.forEach((el) => (el as HTMLElement).click())
47+
warnedNoFalse = false
48+
// Wait for user to see the selections before clicking Next
49+
setTimeout(() => {
50+
clickNextAndContinue(targets.length)
51+
}, NEXT_DELAY)
52+
return
53+
} else {
54+
if (!warnedNoFalse) {
55+
console.log('[AutoAge] No false/NONE/NO options found in this step (may be the last step or already selected)')
56+
warnedNoFalse = true
57+
}
58+
}
59+
60+
clickNextAndContinue(targets.length)
61+
}
62+
63+
function clickNextAndContinue(targetCount: number) {
64+
if (!seenSave) {
65+
const nextBtn = findNextButton()
66+
if (nextBtn) {
67+
console.log('[AutoAge] Found Next button, clicking...')
68+
nextBtn.click()
69+
} else if (targetCount === 0) {
70+
console.log('[AutoAge] No Next button found and no false/NONE to click, checking if Save step is reached')
71+
}
72+
}
73+
setTimeout(processStep, CHECK_INTERVAL)
74+
}
75+
76+
setTimeout(processStep, 1200)
77+
}
78+
79+
GM_registerMenuCommand('Auto-select NO/NONE (Age Ratings)', autoClickNoUntilSave, 'n')
80+
console.log('[AutoAge] Script loaded. Use menu "Auto-select NO/NONE (Age Ratings)" to start')

0 commit comments

Comments
 (0)