├── .eslintrc.json ├── .gitignore ├── README.md ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages ├── _app.tsx ├── api │ ├── arg.ts │ └── temp.ts └── index.tsx ├── pnpm-lock.yaml ├── public ├── favicon.ico └── vercel.svg ├── styles └── globals.css ├── tsconfig.json └── utils └── index.ts /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Sgmodule Argument Proxy](https://sgmodule-argument-proxy.vercel.app) 2 | 3 | 用于需要修改 argument 的 sgmodule 模版,无需 fork 修改,直接通过配置即可生成对应的 sgmodule URL 4 | 5 | [立即使用](https://sgmodule-argument-proxy.vercel.app) 6 | 7 | ## 示例 8 | 9 | https://raw.githubusercontent.com/baranwang/Surge-Resources/master/Modules/SubInfoPanel/SubInfoPanel.sgmodule 10 | 11 | 原 sgmodule 模版内容为 12 | 13 | ```properties 14 | #!name=Sub Info Panel 15 | #!desc=build argument use sgmodule-argument-proxy.vercel.app 16 | 17 | [Script] 18 | Sub_info = type=generic,timeout=10,script-path=https://raw.githubusercontent.com/lhie1/Rules/master/Surge/Surge%204/Script/sub_info_panel.js,script-update-interval=0,argument=url=[URL encode 后的机场节点链接]&reset_day=1&title=AmyInfo&icon=bonjour&color=#007aff 19 | 20 | [Panel] 21 | Sub_info = script-name=Sub_info,update-interval=600 22 | ``` 23 | 24 | 使用转换工具配置 argument 25 | 26 | ``` 27 | url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2Ffoobar&reset_day=1&title=Dlercloud&icon=network&color=#1473e6 28 | ``` 29 | 30 | 生成 sgmodule 链接为 31 | 32 | ``` 33 | https://sgmodule-argument-proxy.vercel.app/api/temp?url=https%3A%2F%2Fraw.githubusercontent.com%2Fbaranwang%2FSurge-Resources%2Fmaster%2FModules%2FSubInfoPanel%2FSubInfoPanel.sgmodule&arg=url%3Dhttps%253A%252F%252Fdler.cloud%252Fsubscribe%252Ffoobar%26reset_day%3D1%26title%3DDlercloud%26icon%3Dnetwork%26color%3D%231473e6 34 | ``` 35 | 36 | 输出内容为 37 | 38 | ```properties 39 | #!name=Sub Info Panel 40 | #!desc=build argument use sgmodule-argument-proxy.vercel.app 41 | 42 | [Script] 43 | Sub_info = type=generic, timeout=10, script-path=https://raw.githubusercontent.com/lhie1/Rules/master/Surge/Surge%204/Script/sub_info_panel.js, script-update-interval=0, argument=url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2Ffoobar&reset_day=1&title=Dlercloud&icon=network&color=#1473e6 44 | 45 | [Panel] 46 | Sub_info = script-name=Sub_info,update-interval=600 47 | ``` 48 | 49 | ## 声明 50 | 51 | **纯字符串处理,不储存任何数据** 不放心可自行 [fork](https://github.com/baranwang/sgmodule-argument-proxy/fork?fragment=1) 本仓库搭建 52 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true, 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sgmodule-argument-proxy", 3 | "displayName": "Sgmodule Argument Proxy", 4 | "private": false, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "ahooks": "^3.1.5", 13 | "antd": "^4.18.3", 14 | "next": "12.0.7", 15 | "node-fetch": "^3.1.0", 16 | "react": "17.0.2", 17 | "react-dom": "17.0.2" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "17.0.8", 21 | "@types/react": "17.0.38", 22 | "eslint": "8.6.0", 23 | "eslint-config-next": "12.0.7", 24 | "typescript": "4.5.4" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { Layout, Typography } from "antd"; 2 | import { displayName } from "../package.json"; 3 | import Head from "next/head"; 4 | import type { AppProps } from "next/app"; 5 | 6 | import "antd/dist/antd.css"; 7 | import "../styles/globals.css"; 8 | 9 | function MyApp({ Component, pageProps }: AppProps) { 10 | return ( 11 | <> 12 | 13 | {displayName} 14 | 15 | 16 | 17 | 18 | {displayName} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | 29 | export default MyApp; 30 | -------------------------------------------------------------------------------- /pages/api/arg.ts: -------------------------------------------------------------------------------- 1 | 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | import { getTemp } from '../../utils' 4 | 5 | export default async function handler( 6 | req: NextApiRequest, 7 | res: NextApiResponse 8 | ) { 9 | let { url } = req.query 10 | if (Array.isArray(url) || !url) { 11 | return res.status(400).json({ error: 'invalid query' }) 12 | } 13 | 14 | try { 15 | const temp = await getTemp(url) 16 | const data: string[] = [] 17 | 18 | for (let index = 0, isScript = false; index < temp.length; index += 1) { 19 | let line = temp[index]; 20 | if (line.startsWith('#')) { 21 | continue 22 | } 23 | if (isScript && /^\[/.test(line)) { 24 | isScript = false 25 | } 26 | if (line.includes('[Script]')) { 27 | isScript = true 28 | } 29 | if (!isScript) { 30 | continue 31 | } 32 | 33 | const argument = line.split(',').find(item => item.trim().startsWith('argument=')) 34 | if (argument) { 35 | data.push(argument.trim().replace(/^argument=/, '')) 36 | } 37 | } 38 | 39 | res.status(200).json({ data }) 40 | } catch (e) { 41 | const error = (e as Error).toString() 42 | return res.status(400).json({ error }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pages/api/temp.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next' 2 | import { getTemp } from '../../utils' 3 | 4 | export default async function handler( 5 | req: NextApiRequest, 6 | res: NextApiResponse 7 | ) { 8 | let { url, arg } = req.query 9 | if (Array.isArray(url) || !url) { 10 | return res.status(400).send('invalid query') 11 | } 12 | if (arg && !Array.isArray(arg)) { 13 | arg = [arg] 14 | } 15 | try { 16 | const temp = await getTemp(url) 17 | const result: string[] = [] 18 | 19 | for (let index = 0, isScript = false, argIndex = 0; index < temp.length; index += 1) { 20 | let line = temp[index]; 21 | if (line.startsWith('#')) { 22 | result.push(line) 23 | continue 24 | } 25 | 26 | if (isScript && /^\[/.test(line)) { 27 | isScript = false 28 | } 29 | if (line.includes('[Script]')) { 30 | isScript = true 31 | } 32 | if (!isScript) { 33 | result.push(line) 34 | continue 35 | } 36 | 37 | line = line.split(',').map(item => { 38 | if (item.trim().startsWith('argument=')) { 39 | const argument = `argument=${arg[argIndex] || arg[0]}` 40 | argIndex += 1 41 | return argument 42 | } 43 | return item.trim() 44 | }).join(', ') 45 | 46 | result.push(line) 47 | } 48 | 49 | res.status(200).send(result.join('\n')) 50 | } catch (e) { 51 | const error = (e as Error).toString() 52 | return res.status(400).send(error) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from "next"; 2 | import { Button, Card, Form, Input, Spin, Typography } from "antd"; 3 | import { CSSProperties, useEffect } from "react"; 4 | import { useRequest } from "ahooks"; 5 | 6 | type Data = { 7 | url: string; 8 | arg: string[]; 9 | }; 10 | 11 | const Home: NextPage = () => { 12 | const [form] = Form.useForm(); 13 | 14 | const { 15 | data: tempArgs, 16 | run: getTempArgs, 17 | loading, 18 | } = useRequest( 19 | (url) => 20 | fetch(`/api/arg?url=${encodeURIComponent(url)}`) 21 | .then((res) => res.json()) 22 | .then((res) => res.data), 23 | { manual: true } 24 | ); 25 | 26 | useEffect(() => { 27 | if (!tempArgs) return; 28 | let arg = tempArgs; 29 | if (arg.every((item) => item === arg[0])) { 30 | arg = [arg[0]]; 31 | } 32 | form.setFieldsValue({ arg }); 33 | }, [form, tempArgs]); 34 | 35 | return ( 36 | 37 |
38 | 39 | { 43 | try { 44 | getTempArgs(new URL(e.target.value).toString()); 45 | } catch (error) {} 46 | }} 47 | /> 48 | 49 | 50 | 51 | 52 | {(fields) => ( 53 | <> 54 | {fields.map((field, index) => ( 55 | 59 | 60 | 61 | ))} 62 | 63 | )} 64 | 65 | 66 | shouldUpdate noStyle> 67 | {({ getFieldsValue }) => { 68 | if (!process.browser) return <>; 69 | const { url, arg } = getFieldsValue(); 70 | if (!url) return <>; 71 | const result = new URL("/api/temp", window.location.origin); 72 | result.searchParams.set("url", url); 73 | arg?.forEach((item) => result.searchParams.append("arg", item)); 74 | return ( 75 | 76 | 80 | { 82 | const style: CSSProperties = { 83 | marginTop: "8px", 84 | marginBottom: "8px", 85 | marginLeft: "-4px", 86 | }; 87 | return { 88 | text: result.toString(), 89 | tooltips: "", 90 | icon: [ 91 | , 94 | , 97 | ], 98 | }; 99 | })()} 100 | /> 101 | 102 | ); 103 | }} 104 | 105 | 106 |
107 |
108 | ); 109 | }; 110 | 111 | export default Home; 112 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baranwang/sgmodule-argument-proxy/40b5827200b91d9a12311735777882e1943a9b4f/public/favicon.ico -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #__next { 4 | min-height: 100%; 5 | } 6 | 7 | #__next { 8 | display: flex; 9 | flex-direction: column; 10 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /utils/index.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch' 2 | import { URL } from 'url' 3 | 4 | export const getTemp = async (url: string) => { 5 | const temp = await fetch(new URL(url).toString()).then(response => response.text()) 6 | return temp.split('\n') 7 | } --------------------------------------------------------------------------------