Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions Build/build-ai-cidr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { fastIpVersion } from 'foxts/fast-ip-version';
import { SHARED_DESCRIPTION } from './constants/description';
import { $$fetch } from './lib/fetch-retry';
import { RulesetOutput } from './lib/rules/ruleset';
import { task } from './trace';

const OPENAI_VOICE_IP_URL = 'https://openai.com/chatgpt-voice.json';

function parseOpenAIVoiceJSON(data: unknown) {
if (
data === null
|| typeof data !== 'object'
|| !('prefixes' in data)
|| !Array.isArray(data.prefixes)
) {
throw new TypeError('Invalid OpenAI Voice IP list: missing prefixes array');
}

if (!('creationTime' in data) || typeof data.creationTime !== 'string') {
throw new TypeError('Invalid OpenAI Voice IP list: missing creationTime');
}

const lastUpdated = new Date(data.creationTime);
if (Number.isNaN(lastUpdated.getTime())) {
throw new TypeError('Invalid OpenAI Voice IP list: invalid creationTime');
}

const cidr4 = new Set<string>();
const cidr6 = new Set<string>();

for (let i = 0, len = data.prefixes.length; i < len; i++) {
const entry = data.prefixes[i];
if (typeof entry !== 'object' || entry == null) {
throw new TypeError(`Invalid OpenAI Voice IP list entry at prefixes[${i}]`);
}

const prefixes = Object.values(entry);
if (prefixes.length === 0) {
continue;
}

for (let j = 0, prefixLen = prefixes.length; j < prefixLen; j++) {
const prefix = prefixes[j];
if (typeof prefix !== 'string') {
throw new TypeError(`Invalid IP prefix at prefixes[${i}]`);
}

const version = fastIpVersion(prefix);
if (version === 4) {
cidr4.add(prefix);
} else if (version === 6) {
cidr6.add(prefix);
} else {
throw new TypeError(`Invalid IP prefix at prefixes[${i}]`);
}
}
}

return {
cidr4: Array.from(cidr4),
cidr6: Array.from(cidr6),
lastUpdated
};
}

export const buildAICIDR = task(require.main === module, __filename)(async (span) => {
const { cidr4, cidr6, lastUpdated } = await span.traceChildAsync('get OpenAI Voice IP ranges', async () => {
const response = await $$fetch(OPENAI_VOICE_IP_URL);
return parseOpenAIVoiceJSON(await response.json());
});

return new RulesetOutput(span, 'ai', 'ip')
.withTitle('Sukka\'s Ruleset - ChatGPT Voice IP CIDR')
.appendDescription(
SHARED_DESCRIPTION,
'',
'This file contains IP ranges used by ChatGPT Voice.'
)
.withDate(lastUpdated)
.appendDataSource(`${OPENAI_VOICE_IP_URL} (last updated: ${lastUpdated.toISOString()})`)
.bulkAddCIDR4NoResolve(cidr4)
.bulkAddCIDR6NoResolve(cidr6)
.write();
});
2 changes: 2 additions & 0 deletions Build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { downloadPreviousBuild } from './download-previous-build';
import { buildCommon } from './build-common';
import { buildRejectIPList } from './build-reject-ip-list';
import { buildAppleCdn } from './build-apple-cdn';
import { buildAICIDR } from './build-ai-cidr';
import { buildRejectDomainSet } from './build-reject-domainset';
import { buildChnCidr } from './build-chn-cidr';
import { buildSpeedtestDomainSet } from './build-speedtest-domainset';
Expand Down Expand Up @@ -103,6 +104,7 @@ const buildFinishedLock = path.join(ROOT_DIR, '.BUILD_FINISHED');
downloadPreviousBuildPromise.then(() => buildCommon()),
downloadPreviousBuildPromise.then(() => buildRejectIPList()),
downloadPreviousBuildPromise.then(() => buildAppleCdn()),
downloadPreviousBuildPromise.then(() => buildAICIDR()),
downloadPreviousBuildPromise.then(() => cdnDownloadWorker.buildCdnDownloadConf()),
downloadPreviousBuildPromise.then(() => buildRejectDomainSet()),
downloadPreviousBuildPromise.then(() => telegramCidrWorker.buildTelegramCIDR()),
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,22 @@ rules:

#### AI

- 域名规则 人工维护
- 域名和 IP 规则,人工维护 + 自动更新
- 包含 OpenAI、Google Gemini、Claude、Perplexity 等

**Surge**

```ini
# Non IP
RULE-SET,https://ruleset.skk.moe/List/non_ip/ai.conf,[Replace with your policy]
RULE-SET,https://ruleset.skk.moe/List/non_ip/apple_intelligence.conf,[Replace with your policy],extended-matching
```

```ini
# IP
RULE-SET,https://ruleset.skk.moe/List/ip/ai.conf,[Replace with your policy]
```

**Mihomo**

```yaml
Expand All @@ -451,10 +457,19 @@ rule-providers:
interval: 43200
url: https://ruleset.skk.moe/Clash/non_ip/apple_intelligence.txt
path: ./sukkaw_ruleset/apple_intelligence_non_ip.txt
ai_ip:
type: http
behavior: classical
format: text
interval: 43200
url: https://ruleset.skk.moe/Clash/ip/ai.txt
path: ./sukkaw_ruleset/ai_ip.txt

rules:
- RULE-SET,ai_non_ip,[Replace with your policy]
- RULE-SET,apple_intelligence_non_ip,[Replace with your policy]

- RULE-SET,ai_ip,[Replace with your policy]
```

#### Telegram
Expand Down