diff --git a/.github/update.log b/.github/update.log index 05fa8815dd..eadf2e4139 100644 --- a/.github/update.log +++ b/.github/update.log @@ -679,3 +679,4 @@ Update On Mon Jun 17 20:31:27 CEST 2024 Update On Tue Jun 18 20:32:23 CEST 2024 Update On Wed Jun 19 20:31:46 CEST 2024 Update On Thu Jun 20 20:32:09 CEST 2024 +Update On Fri Jun 21 20:31:57 CEST 2024 diff --git a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs index 5c3060deff..879e3b5570 100644 --- a/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs +++ b/clash-nyanpasu/backend/tauri/src/config/nyanpasu/mod.rs @@ -223,6 +223,10 @@ impl IVerge { config.lighten_animation_effects = template.lighten_animation_effects; } + if config.enable_service_mode.is_none() { + config.enable_service_mode = template.enable_service_mode; + } + config } @@ -253,6 +257,7 @@ impl IVerge { max_log_files: Some(7), // 7 days enable_auto_check_update: Some(true), clash_tray_selector: Some(true), + enable_service_mode: Some(false), ..Self::default() } } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts index 4dc633f096..5a13d2640c 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts @@ -90,8 +90,8 @@ export const nyanpasu = { return { checked: (nyanpasuConfig?.[propName] as boolean) || false, - onChange: () => { - setNyanpasuConfig({ [propName]: !nyanpasuConfig?.[propName] }); + onChange: async () => { + await setNyanpasuConfig({ [propName]: !nyanpasuConfig?.[propName] }); }, }; }, diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx index 80f37ac925..560c9953d1 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-system-service.tsx @@ -9,6 +9,9 @@ import { import { useNyanpasu } from "@nyanpasu/interface"; import { BaseCard, SwitchItem } from "@nyanpasu/ui"; import { useTranslation } from "react-i18next"; +import { nyanpasu } from "./modules/create-props"; + +const { createBooleanProps } = nyanpasu; export const SettingSystemService = () => { const { t } = useTranslation(); @@ -65,7 +68,11 @@ export const SettingSystemService = () => { return ( - + {checkDisbale && ( diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx b/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx index 6c56ee01f8..e091984c65 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx +++ b/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx @@ -1,14 +1,41 @@ -import { Switch, SwitchProps } from "@mui/material"; +import { SwitchProps } from "@mui/material"; import { BaseItem } from "./baseItem"; +import { ChangeEvent, useState } from "react"; +import LoadingSwitch from "../loadingSwitch"; interface Props extends SwitchProps { label: string; + onChange?: ( + event: ChangeEvent, + checked: boolean, + ) => Promise | void; } -export const SwitchItem = ({ label, ...switchProps }: Props) => { +export const SwitchItem = ({ label, onChange, ...switchProps }: Props) => { + const [loading, setLoading] = useState(false); + + const handleChange = async ( + event: ChangeEvent, + checked: boolean, + ) => { + if (onChange) { + try { + setLoading(true); + + await onChange(event, checked); + } finally { + setLoading(false); + } + } + }; + return ( - + ); }; diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index ae4b610440..02fa48b22f 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -74,7 +74,7 @@ "@tauri-apps/cli": "1.5.14", "@types/fs-extra": "11.0.4", "@types/lodash-es": "4.17.12", - "@types/node": "20.14.6", + "@types/node": "20.14.7", "autoprefixer": "10.4.19", "conventional-changelog-conventionalcommits": "8.0.0", "cross-env": "7.0.3", @@ -101,13 +101,13 @@ "stylelint": "16.6.1", "stylelint-config-html": "1.1.0", "stylelint-config-recess-order": "5.0.1", - "stylelint-config-standard": "36.0.0", + "stylelint-config-standard": "36.0.1", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "6.0.4", "stylelint-scss": "6.3.2", "tailwindcss": "3.4.4", - "tsx": "4.15.6", - "typescript": "5.4.5" + "tsx": "4.15.7", + "typescript": "5.5.2" }, "packageManager": "pnpm@9.4.0", "engines": { diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index df161b01be..05707a90d4 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: devDependencies: '@commitlint/cli': specifier: 19.3.0 - version: 19.3.0(@types/node@20.14.6)(typescript@5.4.5) + version: 19.3.0(@types/node@20.14.7)(typescript@5.5.2) '@commitlint/config-conventional': specifier: 19.2.2 version: 19.2.2 @@ -38,8 +38,8 @@ importers: specifier: 4.17.12 version: 4.17.12 '@types/node': - specifier: 20.14.6 - version: 20.14.6 + specifier: 20.14.7 + version: 20.14.7 autoprefixer: specifier: 10.4.19 version: 10.4.19(postcss@8.4.38) @@ -111,34 +111,34 @@ importers: version: 5.2.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) stylelint: specifier: 16.6.1 - version: 16.6.1(typescript@5.4.5) + version: 16.6.1(typescript@5.5.2) stylelint-config-html: specifier: 1.1.0 - version: 1.1.0(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5)) + version: 1.1.0(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.5.2)) stylelint-config-recess-order: specifier: 5.0.1 - version: 5.0.1(stylelint@16.6.1(typescript@5.4.5)) + version: 5.0.1(stylelint@16.6.1(typescript@5.5.2)) stylelint-config-standard: - specifier: 36.0.0 - version: 36.0.0(stylelint@16.6.1(typescript@5.4.5)) + specifier: 36.0.1 + version: 36.0.1(stylelint@16.6.1(typescript@5.5.2)) stylelint-declaration-block-no-ignored-properties: specifier: 2.8.0 - version: 2.8.0(stylelint@16.6.1(typescript@5.4.5)) + version: 2.8.0(stylelint@16.6.1(typescript@5.5.2)) stylelint-order: specifier: 6.0.4 - version: 6.0.4(stylelint@16.6.1(typescript@5.4.5)) + version: 6.0.4(stylelint@16.6.1(typescript@5.5.2)) stylelint-scss: specifier: 6.3.2 - version: 6.3.2(stylelint@16.6.1(typescript@5.4.5)) + version: 6.3.2(stylelint@16.6.1(typescript@5.5.2)) tailwindcss: specifier: 3.4.4 version: 3.4.4 tsx: - specifier: 4.15.6 - version: 4.15.6 + specifier: 4.15.7 + version: 4.15.7 typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.2 + version: 5.5.2 frontend/interface: dependencies: @@ -178,7 +178,7 @@ importers: version: 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1) '@generouted/react-router': specifier: 1.19.5 - version: 1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) '@juggle/resize-observer': specifier: 3.4.0 version: 3.4.0 @@ -293,16 +293,16 @@ importers: version: 4.4.10 '@typescript-eslint/eslint-plugin': specifier: 7.13.1 - version: 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + version: 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) '@typescript-eslint/parser': specifier: 7.13.1 - version: 7.13.1(eslint@8.57.0)(typescript@5.4.5) + version: 7.13.1(eslint@8.57.0)(typescript@5.5.2) '@vitejs/plugin-react': specifier: 4.3.1 - version: 4.3.1(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 4.3.1(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) '@vitejs/plugin-react-swc': specifier: 3.7.0 - version: 3.7.0(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 3.7.0(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) sass: specifier: 1.77.6 version: 1.77.6 @@ -314,19 +314,19 @@ importers: version: 2.1.3 vite: specifier: 5.3.1 - version: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + version: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) vite-plugin-monaco-editor: specifier: npm:vite-plugin-monaco-editor-new@1.1.3 version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.50.0) vite-plugin-sass-dts: specifier: 1.3.22 - version: 1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) vite-plugin-svgr: specifier: 4.2.0 - version: 4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 4.2.0(rollup@4.17.2)(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) vite-tsconfig-paths: specifier: 4.3.2 - version: 4.3.2(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + version: 4.3.2(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) frontend/ui: dependencies: @@ -375,7 +375,7 @@ importers: version: 1.77.6 typescript-plugin-css-modules: specifier: 5.1.0 - version: 5.1.0(typescript@5.4.5) + version: 5.1.0(typescript@5.5.2) scripts: dependencies: @@ -1929,8 +1929,8 @@ packages: '@types/node@20.12.10': resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==} - '@types/node@20.14.6': - resolution: {integrity: sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==} + '@types/node@20.14.7': + resolution: {integrity: sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -5118,14 +5118,14 @@ packages: peerDependencies: stylelint: '>=16' - stylelint-config-recommended@14.0.0: - resolution: {integrity: sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==} + stylelint-config-recommended@14.0.1: + resolution: {integrity: sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==} engines: {node: '>=18.12.0'} peerDependencies: - stylelint: ^16.0.0 + stylelint: ^16.1.0 - stylelint-config-standard@36.0.0: - resolution: {integrity: sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==} + stylelint-config-standard@36.0.1: + resolution: {integrity: sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw==} engines: {node: '>=18.12.0'} peerDependencies: stylelint: ^16.1.0 @@ -5295,8 +5295,8 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tsx@4.15.6: - resolution: {integrity: sha512-is0VQQlfNZRHEuSSTKA6m4xw74IU4AizmuB6lAYLRt9XtuyeQnyJYexhNZOPCB59SqC4JzmSzPnHGBXxf3k0hA==} + tsx@4.15.7: + resolution: {integrity: sha512-u3H0iSFDZM3za+VxkZ1kywdCeHCn+8/qHQS1MNoO2sONDgD95HlWtt8aB23OzeTmFP9IU4/8bZUdg58Uu5J4cg==} engines: {node: '>=18.0.0'} hasBin: true @@ -5349,8 +5349,8 @@ packages: peerDependencies: typescript: '>=4.0.0' - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.5.2: + resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} hasBin: true @@ -5840,11 +5840,11 @@ snapshots: '@babel/helper-validator-identifier': 7.24.5 to-fast-properties: 2.0.0 - '@commitlint/cli@19.3.0(@types/node@20.14.6)(typescript@5.4.5)': + '@commitlint/cli@19.3.0(@types/node@20.14.7)(typescript@5.5.2)': dependencies: '@commitlint/format': 19.3.0 '@commitlint/lint': 19.2.2 - '@commitlint/load': 19.2.0(@types/node@20.14.6)(typescript@5.4.5) + '@commitlint/load': 19.2.0(@types/node@20.14.7)(typescript@5.5.2) '@commitlint/read': 19.2.1 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -5891,15 +5891,15 @@ snapshots: '@commitlint/rules': 19.0.3 '@commitlint/types': 19.0.3 - '@commitlint/load@19.2.0(@types/node@20.14.6)(typescript@5.4.5)': + '@commitlint/load@19.2.0(@types/node@20.14.7)(typescript@5.5.2)': dependencies: '@commitlint/config-validator': 19.0.3 '@commitlint/execute-rule': 19.0.0 '@commitlint/resolve-extends': 19.1.0 '@commitlint/types': 19.0.3 chalk: 5.3.0 - cosmiconfig: 9.0.0(typescript@5.4.5) - cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.6)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) + cosmiconfig: 9.0.0(typescript@5.5.2) + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.7)(cosmiconfig@9.0.0(typescript@5.5.2))(typescript@5.5.2) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -6273,13 +6273,13 @@ snapshots: postcss: 7.0.32 purgecss: 2.3.0 - '@generouted/react-router@1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': + '@generouted/react-router@1.19.5(react-router-dom@6.23.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': dependencies: fast-glob: 3.3.2 - generouted: 1.19.5(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) + generouted: 1.19.5(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)) react: 19.0.0-rc-fb9a90fa48-20240614 react-router-dom: 6.23.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614) - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) '@humanwhocodes/config-array@0.11.14': dependencies: @@ -6810,12 +6810,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.24.5) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.24.5) - '@svgr/core@8.1.0(typescript@5.4.5)': + '@svgr/core@8.1.0(typescript@5.5.2)': dependencies: '@babel/core': 7.24.5 '@svgr/babel-preset': 8.1.0(@babel/core@7.24.5) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.4.5) + cosmiconfig: 8.3.6(typescript@5.5.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -6826,11 +6826,11 @@ snapshots: '@babel/types': 7.24.5 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.4.5))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.5.2))': dependencies: '@babel/core': 7.24.5 '@svgr/babel-preset': 8.1.0(@babel/core@7.24.5) - '@svgr/core': 8.1.0(typescript@5.4.5) + '@svgr/core': 8.1.0(typescript@5.5.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: @@ -6974,12 +6974,12 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/responselike': 1.0.3 '@types/conventional-commits-parser@5.0.0': dependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/d3-array@3.2.1': {} @@ -7113,7 +7113,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/geojson@7946.0.14': {} @@ -7129,11 +7129,11 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/keyv@3.1.4': dependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/lodash-es@4.17.12': dependencies: @@ -7153,7 +7153,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@20.14.6': + '@types/node@20.14.7': dependencies: undici-types: 5.26.5 @@ -7175,7 +7175,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 '@types/unist@2.0.10': {} @@ -7183,37 +7183,37 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 optional: true - '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) '@typescript-eslint/scope-manager': 7.13.1 - '@typescript-eslint/type-utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) '@typescript-eslint/visitor-keys': 7.13.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@typescript-eslint/scope-manager': 7.13.1 '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.4 eslint: 8.57.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color @@ -7222,21 +7222,21 @@ snapshots: '@typescript-eslint/types': 7.13.1 '@typescript-eslint/visitor-keys': 7.13.1 - '@typescript-eslint/type-utils@7.13.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color '@typescript-eslint/types@7.13.1': {} - '@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.13.1(typescript@5.5.2)': dependencies: '@typescript-eslint/types': 7.13.1 '@typescript-eslint/visitor-keys': 7.13.1 @@ -7245,18 +7245,18 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.1 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.13.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 7.13.1 '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -7269,21 +7269,21 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.0(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': + '@vitejs/plugin-react-swc@3.7.0(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': dependencies: '@swc/core': 1.6.1 - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.1(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': + '@vitejs/plugin-react@4.3.1(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))': dependencies: '@babel/core': 7.24.5 '@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) transitivePeerDependencies: - supports-color @@ -7771,12 +7771,12 @@ snapshots: dependencies: is-what: 3.14.1 - cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.6)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5): + cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.7)(cosmiconfig@9.0.0(typescript@5.5.2))(typescript@5.5.2): dependencies: - '@types/node': 20.14.6 - cosmiconfig: 9.0.0(typescript@5.4.5) + '@types/node': 20.14.7 + cosmiconfig: 9.0.0(typescript@5.5.2) jiti: 1.21.0 - typescript: 5.4.5 + typescript: 5.5.2 cosmiconfig@7.1.0: dependencies: @@ -7786,23 +7786,23 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@8.3.6(typescript@5.4.5): + cosmiconfig@8.3.6(typescript@5.5.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 - cosmiconfig@9.0.0(typescript@5.4.5): + cosmiconfig@9.0.0(typescript@5.5.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 create-error-class@3.0.2: dependencies: @@ -8748,9 +8748,9 @@ snapshots: functions-have-names@1.2.3: {} - generouted@1.19.5(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): + generouted@1.19.5(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): dependencies: - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) gensync@1.0.0-beta.2: {} @@ -10708,45 +10708,45 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - stylelint-config-html@1.1.0(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.4.5)): + stylelint-config-html@1.1.0(postcss-html@1.7.0)(stylelint@16.6.1(typescript@5.5.2)): dependencies: postcss-html: 1.7.0 - stylelint: 16.6.1(typescript@5.4.5) + stylelint: 16.6.1(typescript@5.5.2) - stylelint-config-recess-order@5.0.1(stylelint@16.6.1(typescript@5.4.5)): + stylelint-config-recess-order@5.0.1(stylelint@16.6.1(typescript@5.5.2)): dependencies: - stylelint: 16.6.1(typescript@5.4.5) - stylelint-order: 6.0.4(stylelint@16.6.1(typescript@5.4.5)) + stylelint: 16.6.1(typescript@5.5.2) + stylelint-order: 6.0.4(stylelint@16.6.1(typescript@5.5.2)) - stylelint-config-recommended@14.0.0(stylelint@16.6.1(typescript@5.4.5)): + stylelint-config-recommended@14.0.1(stylelint@16.6.1(typescript@5.5.2)): dependencies: - stylelint: 16.6.1(typescript@5.4.5) + stylelint: 16.6.1(typescript@5.5.2) - stylelint-config-standard@36.0.0(stylelint@16.6.1(typescript@5.4.5)): + stylelint-config-standard@36.0.1(stylelint@16.6.1(typescript@5.5.2)): dependencies: - stylelint: 16.6.1(typescript@5.4.5) - stylelint-config-recommended: 14.0.0(stylelint@16.6.1(typescript@5.4.5)) + stylelint: 16.6.1(typescript@5.5.2) + stylelint-config-recommended: 14.0.1(stylelint@16.6.1(typescript@5.5.2)) - stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@16.6.1(typescript@5.4.5)): + stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@16.6.1(typescript@5.5.2)): dependencies: - stylelint: 16.6.1(typescript@5.4.5) + stylelint: 16.6.1(typescript@5.5.2) - stylelint-order@6.0.4(stylelint@16.6.1(typescript@5.4.5)): + stylelint-order@6.0.4(stylelint@16.6.1(typescript@5.5.2)): dependencies: postcss: 8.4.38 postcss-sorting: 8.0.2(postcss@8.4.38) - stylelint: 16.6.1(typescript@5.4.5) + stylelint: 16.6.1(typescript@5.5.2) - stylelint-scss@6.3.2(stylelint@16.6.1(typescript@5.4.5)): + stylelint-scss@6.3.2(stylelint@16.6.1(typescript@5.5.2)): dependencies: known-css-properties: 0.31.0 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.1 postcss-selector-parser: 6.1.0 postcss-value-parser: 4.2.0 - stylelint: 16.6.1(typescript@5.4.5) + stylelint: 16.6.1(typescript@5.5.2) - stylelint@16.6.1(typescript@5.4.5): + stylelint@16.6.1(typescript@5.5.2): dependencies: '@csstools/css-parser-algorithms': 2.6.3(@csstools/css-tokenizer@2.3.1) '@csstools/css-tokenizer': 2.3.1 @@ -10755,7 +10755,7 @@ snapshots: '@dual-bundle/import-meta-resolve': 4.1.0 balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 9.0.0(typescript@5.4.5) + cosmiconfig: 9.0.0(typescript@5.5.2) css-functions-list: 3.2.2 css-tree: 2.3.1 debug: 4.3.4 @@ -10969,17 +10969,17 @@ snapshots: trough@2.2.0: {} - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.5.2): dependencies: - typescript: 5.4.5 + typescript: 5.5.2 ts-custom-error@3.3.1: {} ts-interface-checker@0.1.13: {} - tsconfck@3.0.3(typescript@5.4.5): + tsconfck@3.0.3(typescript@5.5.2): optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 tsconfig-paths@3.15.0: dependencies: @@ -10996,7 +10996,7 @@ snapshots: tslib@2.6.2: {} - tsx@4.15.6: + tsx@4.15.7: dependencies: esbuild: 0.21.4 get-tsconfig: 4.7.5 @@ -11060,7 +11060,7 @@ snapshots: dependencies: csstype: 3.1.3 - typescript-plugin-css-modules@5.1.0(typescript@5.4.5): + typescript-plugin-css-modules@5.1.0(typescript@5.5.2): dependencies: '@types/postcss-modules-local-by-default': 4.0.2 '@types/postcss-modules-scope': 3.0.4 @@ -11078,12 +11078,12 @@ snapshots: source-map-js: 1.2.0 stylus: 0.62.0 tsconfig-paths: 4.2.0 - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - ts-node - typescript@5.4.5: {} + typescript@5.5.2: {} ufo@1.5.3: {} @@ -11220,43 +11220,43 @@ snapshots: esbuild: 0.19.12 monaco-editor: 0.50.0 - vite-plugin-sass-dts@1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): + vite-plugin-sass-dts@1.3.22(postcss@8.4.38)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): dependencies: postcss: 8.4.38 postcss-js: 4.0.1(postcss@8.4.38) prettier: 3.3.2 sass: 1.77.6 - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) - vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): + vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.17.2) - '@svgr/core': 8.1.0(typescript@5.4.5) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + '@svgr/core': 8.1.0(typescript@5.5.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.2)) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): + vite-tsconfig-paths@4.3.2(typescript@5.5.2)(vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)): dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5) + tsconfck: 3.0.3(typescript@5.5.2) optionalDependencies: - vite: 5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) + vite: 5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0) transitivePeerDependencies: - supports-color - typescript - vite@5.3.1(@types/node@20.14.6)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0): + vite@5.3.1(@types/node@20.14.7)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0): dependencies: esbuild: 0.21.4 postcss: 8.4.38 rollup: 4.17.2 optionalDependencies: - '@types/node': 20.14.6 + '@types/node': 20.14.7 fsevents: 2.3.3 less: 4.2.0 sass: 1.77.6 diff --git a/clash-verge-rev/package.json b/clash-verge-rev/package.json index 1f0aa4b859..ff98754816 100644 --- a/clash-verge-rev/package.json +++ b/clash-verge-rev/package.json @@ -36,7 +36,7 @@ "foxact": "^0.2.35", "i18next": "^23.11.5", "lodash-es": "^4.17.21", - "meta-json-schema": "1.18.5-alpha4", + "meta-json-schema": "1.18.5-alpha6", "monaco-editor": "^0.49.0", "monaco-yaml": "^5.2.0", "nanoid": "^5.0.7", diff --git a/clash-verge-rev/pnpm-lock.yaml b/clash-verge-rev/pnpm-lock.yaml index 456507feff..b6269b337b 100644 --- a/clash-verge-rev/pnpm-lock.yaml +++ b/clash-verge-rev/pnpm-lock.yaml @@ -62,8 +62,8 @@ importers: specifier: ^4.17.21 version: 4.17.21 meta-json-schema: - specifier: 1.18.5-alpha4 - version: 1.18.5-alpha4 + specifier: 1.18.5-alpha6 + version: 1.18.5-alpha6 monaco-editor: specifier: ^0.49.0 version: 0.49.0 @@ -3295,10 +3295,10 @@ packages: integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, } - meta-json-schema@1.18.5-alpha4: + meta-json-schema@1.18.5-alpha6: resolution: { - integrity: sha512-q+JzaM3tMssFPtfu7nxQmILKbJwq08c+0OfRnrdyYwiBaDd0Nim3LPIkiz9vJiuF4c3o5utLU39Q3z8VoUT0qQ==, + integrity: sha512-Qh1NOgM8HMKLdx59NUy+Um+r2xOJptD7ge/0rnwxGS+MuEFeBCmNF1lUjW3e1Iktngd8TCopji8KdmGPCla+cw==, } micromark-core-commonmark@2.0.1: @@ -6611,7 +6611,7 @@ snapshots: merge-stream@2.0.0: {} - meta-json-schema@1.18.5-alpha4: {} + meta-json-schema@1.18.5-alpha6: {} micromark-core-commonmark@2.0.1: dependencies: diff --git a/clash-verge-rev/src/components/setting/mods/hotkey-input.tsx b/clash-verge-rev/src/components/setting/mods/hotkey-input.tsx index a14658ac37..2e767465ca 100644 --- a/clash-verge-rev/src/components/setting/mods/hotkey-input.tsx +++ b/clash-verge-rev/src/components/setting/mods/hotkey-input.tsx @@ -2,6 +2,7 @@ import { useRef, useState } from "react"; import { alpha, Box, IconButton, styled } from "@mui/material"; import { DeleteRounded } from "@mui/icons-material"; import { parseHotkey } from "@/utils/parse-hotkey"; +import { useTranslation } from "react-i18next"; const KeyWrapper = styled("div")(({ theme }) => ({ position: "relative", @@ -41,9 +42,12 @@ const KeyWrapper = styled("div")(({ theme }) => ({ border: "1px solid", borderColor: alpha(theme.palette.text.secondary, 0.2), borderRadius: "2px", - padding: "1px 1px", + padding: "1px 5px", margin: "2px 0", - marginRight: 8, + }, + ".delimiter": { + lineHeight: "25px", + padding: "0 2px", }, })); @@ -54,6 +58,7 @@ interface Props { export const HotkeyInput = (props: Props) => { const { value, onChange } = props; + const { t } = useTranslation(); const changeRef = useRef([]); const [keys, setKeys] = useState(value); @@ -83,17 +88,22 @@ export const HotkeyInput = (props: Props) => { />
- {keys.map((key) => ( -
- {key} -
+ {keys.map((key, index) => ( + + +
+ {key} +
+
))}
{ onChange([]); diff --git a/lede/include/kernel-6.6 b/lede/include/kernel-6.6 index 9ea7e28645..b7e602675d 100644 --- a/lede/include/kernel-6.6 +++ b/lede/include/kernel-6.6 @@ -1,2 +1,2 @@ -LINUX_VERSION-6.6 = .33 -LINUX_KERNEL_HASH-6.6.33 = a13ebc20dc2a75722699949af74aa86a4ce5d544d6daaa6a7de4e8c81b40de97 +LINUX_VERSION-6.6 = .34 +LINUX_KERNEL_HASH-6.6.34 = c4e0ec8f593aa3717e85abad940466e7d7cbc362989426eb37f499330a461ba0 diff --git a/lede/package/base-files/Makefile b/lede/package/base-files/Makefile index b3656cd3e0..8cafce670c 100644 --- a/lede/package/base-files/Makefile +++ b/lede/package/base-files/Makefile @@ -90,6 +90,19 @@ define ImageConfigOptions echo 'pi_preinit_net_messages="$(CONFIG_TARGET_PREINIT_SHOW_NETMSG)"' >>$(1)/lib/preinit/00_preinit.conf echo 'pi_preinit_no_failsafe_netmsg="$(CONFIG_TARGET_PREINIT_SUPPRESS_FAILSAFE_NETMSG)"' >>$(1)/lib/preinit/00_preinit.conf echo 'pi_preinit_no_failsafe="$(CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE)"' >>$(1)/lib/preinit/00_preinit.conf +ifeq ($(CONFIG_TARGET_DEFAULT_LAN_IP_FROM_PREINIT),y) + mkdir -p $(1)/etc/board.d + echo '. /lib/functions/uci-defaults.sh' >$(1)/etc/board.d/99-lan-ip + echo 'logger -t 99-lan-ip "setting custom default LAN IP"' >>$(1)/etc/board.d/99-lan-ip + echo 'board_config_update' >>$(1)/etc/board.d/99-lan-ip + echo 'json_select network' >>$(1)/etc/board.d/99-lan-ip + echo 'json_select lan' >>$(1)/etc/board.d/99-lan-ip + echo 'json_add_string ipaddr $(if $(CONFIG_TARGET_PREINIT_IP),$(CONFIG_TARGET_PREINIT_IP),"192.168.1.1")' >>$(1)/etc/board.d/99-lan-ip + echo 'json_add_string netmask $(if $(CONFIG_TARGET_PREINIT_NETMASK),$(CONFIG_TARGET_PREINIT_NETMASK),"255.255.255.0")' >>$(1)/etc/board.d/99-lan-ip + echo 'json_select ..' >>$(1)/etc/board.d/99-lan-ip + echo 'json_select ..' >>$(1)/etc/board.d/99-lan-ip + echo 'board_config_flush' >>$(1)/etc/board.d/99-lan-ip +endif endef define Build/Prepare diff --git a/lede/package/base-files/image-config.in b/lede/package/base-files/image-config.in index ac406bc456..2de2130b84 100644 --- a/lede/package/base-files/image-config.in +++ b/lede/package/base-files/image-config.in @@ -5,6 +5,13 @@ # See /LICENSE for more information. # +config TARGET_DEFAULT_LAN_IP_FROM_PREINIT + bool "Use preinit IP configuration as default LAN IP" if IMAGEOPT + default n + help + Enabling this will set the default LAN IP address and netmask + to the preinit values set in the image config. + menuconfig PREINITOPT bool "Preinit configuration options" if IMAGEOPT default n diff --git a/lede/package/lean/cpufreq/Makefile b/lede/package/lean/cpufreq/Makefile new file mode 100644 index 0000000000..c71f1f36f2 --- /dev/null +++ b/lede/package/lean/cpufreq/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=cpufreq +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/cpufreq + TITLE:=CPU Frequency Scaling adjustment tool + DEPENDS:=@(arm||aarch64) + PKGARCH:=all +endef + +define Build/Compile +endef + +define Package/cpufreq/install + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) $(CURDIR)/files/cpufreq.config $(1)/etc/config/cpufreq + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(CURDIR)/files/cpufreq.init $(1)/etc/init.d/cpufreq + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) $(CURDIR)/files/cpufreq.uci $(1)/etc/uci-defaults/10-cpufreq +endef + +$(eval $(call BuildPackage,cpufreq)) diff --git a/lede/package/lean/cpufreq/files/cpufreq.config b/lede/package/lean/cpufreq/files/cpufreq.config new file mode 100644 index 0000000000..9004f1bd87 --- /dev/null +++ b/lede/package/lean/cpufreq/files/cpufreq.config @@ -0,0 +1,5 @@ + +config settings 'cpufreq' + +config settings 'global' + diff --git a/lede/package/lean/cpufreq/files/cpufreq.init b/lede/package/lean/cpufreq/files/cpufreq.init new file mode 100755 index 0000000000..fc5dc47776 --- /dev/null +++ b/lede/package/lean/cpufreq/files/cpufreq.init @@ -0,0 +1,58 @@ +#!/bin/sh /etc/rc.common + +START=15 +USE_PROCD=1 + +NAME="cpufreq" +CPUFREQ_PATH="/sys/devices/system/cpu/cpufreq" + +extra_command "get_policies" "Get CPU scaling governors and frequencies" + +get_policies() { + json_init + for policy in $(ls -d "$CPUFREQ_PATH"/policy[0-9]* 2>"/dev/null"); do + [ -s "$policy/scaling_available_frequencies" ] || continue + json_add_object "$(basename "$policy")" + json_add_string "index" "$(basename "$policy" | grep -Eo "[0-9]*$")" + json_add_string "cpus" "$(cat "$policy/affected_cpus")" + json_add_array "freqs" + for freq in $(cat "$policy/scaling_available_frequencies"); do + json_add_string "" "$freq" + done + json_close_array + json_add_array "governors" + for governor in $(cat "$policy/scaling_available_governors"); do + json_add_string "" "$governor" + done + json_close_array + json_close_object + done + json_dump +} + +write_cpufreq_config() { + local value + config_get value "$NAME" "$1" + [ -z "$value" ] || echo -n "$value" > "$2" +} + +start_service() { + config_load "$NAME" + + for i in $(ls -d "$CPUFREQ_PATH"/policy[0-9]* 2>"/dev/null" | grep -Eo "[0-9]*$") + do + [ -z "$(config_get "$NAME" "governor$i")" ] && return + + write_cpufreq_config "governor$i" "$CPUFREQ_PATH/policy$i/scaling_governor" + write_cpufreq_config "minfreq$i" "$CPUFREQ_PATH/policy$i/scaling_min_freq" + write_cpufreq_config "maxfreq$i" "$CPUFREQ_PATH/policy$i/scaling_max_freq" + if [ "$(config_get "$NAME" "governor$i")" = "ondemand" ]; then + write_cpufreq_config "sdfactor$i" "$CPUFREQ_PATH/ondemand/sampling_down_factor" + write_cpufreq_config "upthreshold$i" "$CPUFREQ_PATH/ondemand/up_threshold" + fi + done +} + +service_triggers() { + procd_add_reload_trigger "$NAME" +} diff --git a/lede/package/lean/cpufreq/files/cpufreq.uci b/lede/package/lean/cpufreq/files/cpufreq.uci new file mode 100644 index 0000000000..4ee49c9314 --- /dev/null +++ b/lede/package/lean/cpufreq/files/cpufreq.uci @@ -0,0 +1,75 @@ +#!/bin/sh + +uci_write_config() { + uci -q set "cpufreq.cpufreq.governor$1"="$2" + uci -q set "cpufreq.cpufreq.minfreq$1"="$3" + uci -q set "cpufreq.cpufreq.maxfreq$1"="$4" + [ -n "$5" ] && uci -q set "cpufreq.cpufreq.sdfactor$1"="$5" + [ -n "$6" ] && uci -q set "cpufreq.cpufreq.upthreshold$1"="$6" + uci -q commit cpufreq +} + +[ "$(uci -q get cpufreq.global.set)" -eq "1" ] && exit 0 + +CPU_FREQS="$(cat '/sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies')" +CPU_MIN_FREQ="$(cat '/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq')" +CPU_MAX_FREQ="$(cat '/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq')" +CPU_POLICYS="$(find '/sys/devices/system/cpu/cpufreq/policy'* -maxdepth 0 | grep -Eo '[0-9]+')" + +source "/etc/openwrt_release" +case "$DISTRIB_TARGET" in + "bcm27xx/bcm2710"|\ + "bcm27xx/bcm2711") + uci_write_config 0 ondemand 600000 "$CPU_MAX_FREQ" 10 50 + ;; + "ipq40xx/generic") + uci_write_config 0 performance 200000 "$CPU_MAX_FREQ" + ;; + "ipq806x/generic") + uci_write_config 0 performance 600000 "$CPU_MAX_FREQ" + # IPQ8064/5 + echo "$CPU_POLICYS" | grep -q "1" && uci_write_config 1 performance 600000 1200000 + ;; + "mediatek/mt7622") + uci_write_config 0 ondemand 600000 1350000 10 50 + ;; + "qualcommax/ipq60xx"|\ + "qualcommax/ipq807x") + uci_write_config 0 schedutil "$CPU_MIN_FREQ" "$CPU_MAX_FREQ" + ;; + "rockchip/armv8") + if echo "$CPU_POLICYS" | grep -q "6"; then + # RK3588/S + uci_write_config 0 schedutil 1008000 1800000 + uci_write_config 4 schedutil 816000 2208000 + uci_write_config 6 schedutil 816000 2208000 + elif echo "$CPU_POLICYS" | grep -q "4"; then + # RK3399 + uci_write_config 0 schedutil 600000 1608000 + uci_write_config 4 schedutil 600000 2016000 + else + if ! echo "$CPU_FREQS" | grep -q "1992000"; then + # RK3328 + CPU_MAX_FREQ="1512000" + fi + uci_write_config 0 schedutil 816000 "$CPU_MAX_FREQ" + fi + ;; + "sunxi/cortexa53") + if echo "$CPU_FREQS" | grep -q "1800000"; then + # H6 + uci_write_config 0 schedutil "888000" "$CPU_MAX_FREQ" + elif echo "$CPU_FREQS" | grep -q "1512000"; then + # H616/8 + uci_write_config 0 schedutil "936000" "1512000" + elif echo "$CPU_FREQS" | grep -q "1296000"; then + # H5 + uci_write_config 0 ondemand "$CPU_MIN_FREQ" "1296000" 10 50 + else + # A64 + uci_write_config 0 ondemand "$CPU_MIN_FREQ" "$CPU_MAX_FREQ" 10 50 + fi + ;; +esac + +exit 0 diff --git a/lede/package/qca/qca-nss-ecm/Makefile b/lede/package/qca/qca-nss-ecm/Makefile index c844e2f1de..f4248d4238 100644 --- a/lede/package/qca/qca-nss-ecm/Makefile +++ b/lede/package/qca/qca-nss-ecm/Makefile @@ -28,11 +28,10 @@ define KernelPackage/qca-nss-ecm +@NSS_DRV_VIRT_IF_ENABLE \ +@NSS_DRV_WIFI_ENABLE \ +kmod-qca-nss-drv \ - +kmod-bonding +kmod-nf-conntrack \ + +kmod-bonding +kmod-nf-conntrack +kmod-nat46 \ +kmod-ppp +kmod-pppoe +kmod-pptp \ +PACKAGE_kmod-pppol2tp:kmod-pppol2tp \ +PACKAGE_kmod-qca-mcs:kmod-qca-mcs \ - +PACKAGE_kmod-nat46:kmod-nat46 \ +PACKAGE_kmod-vxlan:kmod-vxlan TITLE:=QCA NSS Enhanced Connection Manager (ECM) FILES:=$(PKG_BUILD_DIR)/ecm.ko diff --git a/lede/package/wwan/driver/quectel_QMI_WWAN/Makefile b/lede/package/wwan/driver/quectel_QMI_WWAN/Makefile index b27dfad768..45452109ed 100755 --- a/lede/package/wwan/driver/quectel_QMI_WWAN/Makefile +++ b/lede/package/wwan/driver/quectel_QMI_WWAN/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qmi_wwan_q PKG_VERSION:=3.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk diff --git a/lede/package/wwan/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c b/lede/package/wwan/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c index 99a9e9fba5..4f1a468edc 100644 --- a/lede/package/wwan/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c +++ b/lede/package/wwan/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c @@ -828,26 +828,26 @@ static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, stats64 = per_cpu_ptr(dev->stats64, cpu); do { +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,6,0 )) start = u64_stats_fetch_begin_irq(&stats64->syncp); -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) +#else + start = u64_stats_fetch_begin(&stats64->syncp); +#endif rx_packets = stats64->rx_packets; rx_bytes = stats64->rx_bytes; tx_packets = stats64->tx_packets; tx_bytes = stats64->tx_bytes; -#else - rx_packets = u64_stats_read(&stats64->rx_packets); - rx_bytes = u64_stats_read(&stats64->rx_bytes); - tx_packets = u64_stats_read(&stats64->tx_packets); - tx_bytes = u64_stats_read(&stats64->tx_bytes); -#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,6,0 )) } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); +#else + } while (u64_stats_fetch_retry(&stats64->syncp, start)); +#endif - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; - stats->tx_packets += tx_packets; - stats->tx_bytes += tx_bytes; - + stats->rx_packets += u64_stats_read(&rx_packets); + stats->rx_bytes += u64_stats_read(&rx_bytes); + stats->tx_packets += u64_stats_read(&tx_packets); + stats->tx_bytes += u64_stats_read(&tx_bytes); +#endif } return stats; diff --git a/lede/target/linux/generic/backport-6.6/701-v6.8-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch b/lede/target/linux/generic/backport-6.6/701-v6.8-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch deleted file mode 100644 index 83145012b9..0000000000 --- a/lede/target/linux/generic/backport-6.6/701-v6.8-net-sfp-bus-fix-SFP-mode-detect-from-bitrate.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 97eb5d51b4a584a60e5d096bdb6b33edc9f50d8d Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 15 Jan 2024 12:43:38 +0000 -Subject: [PATCH] net: sfp-bus: fix SFP mode detect from bitrate - -The referenced commit moved the setting of the Autoneg and pause bits -early in sfp_parse_support(). However, we check whether the modes are -empty before using the bitrate to set some modes. Setting these bits -so early causes that test to always be false, preventing this working, -and thus some modules that used to work no longer do. - -Move them just before the call to the quirk. - -Fixes: 8110633db49d ("net: sfp-bus: allow SFP quirks to override Autoneg and pause bits") -Signed-off-by: Russell King (Oracle) -Reviewed-by: Maxime Chevallier -Link: https://lore.kernel.org/r/E1rPMJW-001Ahf-L0@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp-bus.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/drivers/net/phy/sfp-bus.c -+++ b/drivers/net/phy/sfp-bus.c -@@ -151,10 +151,6 @@ void sfp_parse_support(struct sfp_bus *b - unsigned int br_min, br_nom, br_max; - __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; - -- phylink_set(modes, Autoneg); -- phylink_set(modes, Pause); -- phylink_set(modes, Asym_Pause); -- - /* Decode the bitrate information to MBd */ - br_min = br_nom = br_max = 0; - if (id->base.br_nominal) { -@@ -339,6 +335,10 @@ void sfp_parse_support(struct sfp_bus *b - } - } - -+ phylink_set(modes, Autoneg); -+ phylink_set(modes, Pause); -+ phylink_set(modes, Asym_Pause); -+ - if (bus->sfp_quirk && bus->sfp_quirk->modes) - bus->sfp_quirk->modes(id, modes, interfaces); - diff --git a/lede/target/linux/generic/hack-6.6/902-debloat_proc.patch b/lede/target/linux/generic/hack-6.6/902-debloat_proc.patch index 2a311d327a..3b037a732c 100644 --- a/lede/target/linux/generic/hack-6.6/902-debloat_proc.patch +++ b/lede/target/linux/generic/hack-6.6/902-debloat_proc.patch @@ -235,7 +235,7 @@ Signed-off-by: Felix Fietkau if (!pe) --- a/mm/vmalloc.c +++ b/mm/vmalloc.c -@@ -4439,6 +4439,8 @@ static const struct seq_operations vmall +@@ -4438,6 +4438,8 @@ static const struct seq_operations vmall static int __init proc_vmalloc_init(void) { @@ -396,7 +396,7 @@ Signed-off-by: Felix Fietkau } --- a/net/ipv4/route.c +++ b/net/ipv4/route.c -@@ -380,6 +380,9 @@ static struct pernet_operations ip_rt_pr +@@ -381,6 +381,9 @@ static struct pernet_operations ip_rt_pr static int __init ip_rt_proc_init(void) { diff --git a/lede/target/linux/generic/pending-6.6/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/lede/target/linux/generic/pending-6.6/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch index f3b5ccf2c0..334460f9e6 100644 --- a/lede/target/linux/generic/pending-6.6/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch +++ b/lede/target/linux/generic/pending-6.6/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -110,7 +110,7 @@ Signed-off-by: Jonas Gorski return -EINVAL; --- a/net/ipv6/route.c +++ b/net/ipv6/route.c -@@ -97,6 +97,8 @@ static int ip6_pkt_discard(struct sk_bu +@@ -98,6 +98,8 @@ static int ip6_pkt_discard(struct sk_bu static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); static int ip6_pkt_prohibit(struct sk_buff *skb); static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); @@ -119,7 +119,7 @@ Signed-off-by: Jonas Gorski static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu, -@@ -317,6 +319,18 @@ static const struct rt6_info ip6_prohibi +@@ -318,6 +320,18 @@ static const struct rt6_info ip6_prohibi .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), }; @@ -138,7 +138,7 @@ Signed-off-by: Jonas Gorski static const struct rt6_info ip6_blk_hole_entry_template = { .dst = { .__rcuref = RCUREF_INIT(1), -@@ -1037,6 +1051,7 @@ static const int fib6_prop[RTN_MAX + 1] +@@ -1038,6 +1052,7 @@ static const int fib6_prop[RTN_MAX + 1] [RTN_BLACKHOLE] = -EINVAL, [RTN_UNREACHABLE] = -EHOSTUNREACH, [RTN_PROHIBIT] = -EACCES, @@ -146,7 +146,7 @@ Signed-off-by: Jonas Gorski [RTN_THROW] = -EAGAIN, [RTN_NAT] = -EINVAL, [RTN_XRESOLVE] = -EINVAL, -@@ -1072,6 +1087,10 @@ static void ip6_rt_init_dst_reject(struc +@@ -1073,6 +1088,10 @@ static void ip6_rt_init_dst_reject(struc rt->dst.output = ip6_pkt_prohibit_out; rt->dst.input = ip6_pkt_prohibit; break; @@ -157,7 +157,7 @@ Signed-off-by: Jonas Gorski case RTN_THROW: case RTN_UNREACHABLE: default: -@@ -4539,6 +4558,17 @@ static int ip6_pkt_prohibit_out(struct n +@@ -4543,6 +4562,17 @@ static int ip6_pkt_prohibit_out(struct n return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } @@ -175,7 +175,7 @@ Signed-off-by: Jonas Gorski /* * Allocate a dst for local (unicast / anycast) address. */ -@@ -5030,7 +5060,8 @@ static int rtm_to_fib6_config(struct sk_ +@@ -5034,7 +5064,8 @@ static int rtm_to_fib6_config(struct sk_ if (rtm->rtm_type == RTN_UNREACHABLE || rtm->rtm_type == RTN_BLACKHOLE || rtm->rtm_type == RTN_PROHIBIT || @@ -185,7 +185,7 @@ Signed-off-by: Jonas Gorski cfg->fc_flags |= RTF_REJECT; if (rtm->rtm_type == RTN_LOCAL) -@@ -6277,6 +6308,8 @@ static int ip6_route_dev_notify(struct n +@@ -6281,6 +6312,8 @@ static int ip6_route_dev_notify(struct n #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry->dst.dev = dev; net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); @@ -194,7 +194,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.dev = dev; net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); #endif -@@ -6288,6 +6321,7 @@ static int ip6_route_dev_notify(struct n +@@ -6292,6 +6325,7 @@ static int ip6_route_dev_notify(struct n in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); @@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); #endif } -@@ -6488,6 +6522,8 @@ static int __net_init ip6_route_net_init +@@ -6492,6 +6526,8 @@ static int __net_init ip6_route_net_init #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.fib6_has_custom_rules = false; @@ -211,7 +211,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, sizeof(*net->ipv6.ip6_prohibit_entry), GFP_KERNEL); -@@ -6498,11 +6534,21 @@ static int __net_init ip6_route_net_init +@@ -6502,11 +6538,21 @@ static int __net_init ip6_route_net_init ip6_template_metrics, true); INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached); @@ -234,7 +234,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, ip6_template_metrics, true); -@@ -6529,6 +6575,8 @@ out: +@@ -6533,6 +6579,8 @@ out: return ret; #ifdef CONFIG_IPV6_MULTIPLE_TABLES @@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski out_ip6_prohibit_entry: kfree(net->ipv6.ip6_prohibit_entry); out_ip6_null_entry: -@@ -6548,6 +6596,7 @@ static void __net_exit ip6_route_net_exi +@@ -6552,6 +6600,7 @@ static void __net_exit ip6_route_net_exi kfree(net->ipv6.ip6_null_entry); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.ip6_prohibit_entry); @@ -251,7 +251,7 @@ Signed-off-by: Jonas Gorski kfree(net->ipv6.ip6_blk_hole_entry); #endif dst_entries_destroy(&net->ipv6.ip6_dst_ops); -@@ -6631,6 +6680,9 @@ void __init ip6_route_init_special_entri +@@ -6635,6 +6684,9 @@ void __init ip6_route_init_special_entri init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); diff --git a/lede/target/linux/generic/pending-6.6/920-mangle_bootargs.patch b/lede/target/linux/generic/pending-6.6/920-mangle_bootargs.patch index 75f626579e..1d73cca11e 100644 --- a/lede/target/linux/generic/pending-6.6/920-mangle_bootargs.patch +++ b/lede/target/linux/generic/pending-6.6/920-mangle_bootargs.patch @@ -31,7 +31,7 @@ Signed-off-by: Imre Kaloz help --- a/init/main.c +++ b/init/main.c -@@ -609,6 +609,29 @@ static inline void setup_nr_cpu_ids(void +@@ -608,6 +608,29 @@ static inline void setup_nr_cpu_ids(void static inline void smp_prepare_cpus(unsigned int maxcpus) { } #endif @@ -61,7 +61,7 @@ Signed-off-by: Imre Kaloz /* * We need to store the untouched command line for future reference. * We also need to store the touched command line since the parameter -@@ -898,6 +921,7 @@ void start_kernel(void) +@@ -897,6 +920,7 @@ void start_kernel(void) pr_notice("%s", linux_banner); early_security_init(); setup_arch(&command_line); diff --git a/mieru/Makefile b/mieru/Makefile index d92f85c15e..72f9e45ad5 100644 --- a/mieru/Makefile +++ b/mieru/Makefile @@ -32,7 +32,7 @@ PROJECT_NAME=$(shell basename "${ROOT}") # - pkg/version/current.go # # Use `tools/bump_version.sh` script to change all those files at one shot. -VERSION="3.2.0" +VERSION="3.2.1" # Build binaries and installation packages. .PHONY: build diff --git a/mieru/build/package/mieru/amd64/debian/DEBIAN/control b/mieru/build/package/mieru/amd64/debian/DEBIAN/control index bd913b5c38..fb5a45cc4c 100755 --- a/mieru/build/package/mieru/amd64/debian/DEBIAN/control +++ b/mieru/build/package/mieru/amd64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mieru -Version: 3.2.0 +Version: 3.2.1 Section: net Priority: optional Architecture: amd64 diff --git a/mieru/build/package/mieru/amd64/rpm/mieru.spec b/mieru/build/package/mieru/amd64/rpm/mieru.spec index 13d5e9ee6d..a37b6a5c67 100644 --- a/mieru/build/package/mieru/amd64/rpm/mieru.spec +++ b/mieru/build/package/mieru/amd64/rpm/mieru.spec @@ -1,5 +1,5 @@ Name: mieru -Version: 3.2.0 +Version: 3.2.1 Release: 1%{?dist} Summary: Mieru proxy client License: GPLv3+ diff --git a/mieru/build/package/mieru/arm64/debian/DEBIAN/control b/mieru/build/package/mieru/arm64/debian/DEBIAN/control index b95e6b34f2..659b677fb9 100755 --- a/mieru/build/package/mieru/arm64/debian/DEBIAN/control +++ b/mieru/build/package/mieru/arm64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mieru -Version: 3.2.0 +Version: 3.2.1 Section: net Priority: optional Architecture: arm64 diff --git a/mieru/build/package/mieru/arm64/rpm/mieru.spec b/mieru/build/package/mieru/arm64/rpm/mieru.spec index 13d5e9ee6d..a37b6a5c67 100644 --- a/mieru/build/package/mieru/arm64/rpm/mieru.spec +++ b/mieru/build/package/mieru/arm64/rpm/mieru.spec @@ -1,5 +1,5 @@ Name: mieru -Version: 3.2.0 +Version: 3.2.1 Release: 1%{?dist} Summary: Mieru proxy client License: GPLv3+ diff --git a/mieru/build/package/mita/amd64/debian/DEBIAN/control b/mieru/build/package/mita/amd64/debian/DEBIAN/control index f827359e8c..1c557124e9 100755 --- a/mieru/build/package/mita/amd64/debian/DEBIAN/control +++ b/mieru/build/package/mita/amd64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mita -Version: 3.2.0 +Version: 3.2.1 Section: net Priority: optional Architecture: amd64 diff --git a/mieru/build/package/mita/amd64/rpm/mita.spec b/mieru/build/package/mita/amd64/rpm/mita.spec index 381436d112..a2f2309c05 100644 --- a/mieru/build/package/mita/amd64/rpm/mita.spec +++ b/mieru/build/package/mita/amd64/rpm/mita.spec @@ -1,5 +1,5 @@ Name: mita -Version: 3.2.0 +Version: 3.2.1 Release: 1%{?dist} Summary: Mieru proxy server License: GPLv3+ diff --git a/mieru/build/package/mita/arm64/debian/DEBIAN/control b/mieru/build/package/mita/arm64/debian/DEBIAN/control index 265ca1f791..3487aeef2e 100755 --- a/mieru/build/package/mita/arm64/debian/DEBIAN/control +++ b/mieru/build/package/mita/arm64/debian/DEBIAN/control @@ -1,5 +1,5 @@ Package: mita -Version: 3.2.0 +Version: 3.2.1 Section: net Priority: optional Architecture: arm64 diff --git a/mieru/build/package/mita/arm64/rpm/mita.spec b/mieru/build/package/mita/arm64/rpm/mita.spec index 3b5ca4db35..c7586f8eae 100644 --- a/mieru/build/package/mita/arm64/rpm/mita.spec +++ b/mieru/build/package/mita/arm64/rpm/mita.spec @@ -1,5 +1,5 @@ Name: mita -Version: 3.2.0 +Version: 3.2.1 Release: 1%{?dist} Summary: Mieru proxy server License: GPLv3+ diff --git a/mieru/docs/server-install.md b/mieru/docs/server-install.md index 134deb8509..daace0042e 100644 --- a/mieru/docs/server-install.md +++ b/mieru/docs/server-install.md @@ -8,32 +8,32 @@ Before installation and configuration, connect to the server via SSH and then ex ```sh # Debian / Ubuntu - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita_3.2.0_amd64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita_3.2.1_amd64.deb # Debian / Ubuntu - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita_3.2.0_arm64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita_3.2.1_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita-3.2.0-1.x86_64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita-3.2.1-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita-3.2.0-1.aarch64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita-3.2.1-1.aarch64.rpm ``` ## Install mita package ```sh # Debian / Ubuntu - X86_64 -sudo dpkg -i mita_3.2.0_amd64.deb +sudo dpkg -i mita_3.2.1_amd64.deb # Debian / Ubuntu - ARM 64 -sudo dpkg -i mita_3.2.0_arm64.deb +sudo dpkg -i mita_3.2.1_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -sudo rpm -Uvh --force mita-3.2.0-1.x86_64.rpm +sudo rpm -Uvh --force mita-3.2.1-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -sudo rpm -Uvh --force mita-3.2.0-1.aarch64.rpm +sudo rpm -Uvh --force mita-3.2.1-1.aarch64.rpm ``` Those instructions can also be used to upgrade the version of mita software package. diff --git a/mieru/docs/server-install.zh_CN.md b/mieru/docs/server-install.zh_CN.md index c4b7e1ec91..4be193ab59 100644 --- a/mieru/docs/server-install.zh_CN.md +++ b/mieru/docs/server-install.zh_CN.md @@ -8,32 +8,32 @@ ```sh # Debian / Ubuntu - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita_3.2.0_amd64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita_3.2.1_amd64.deb # Debian / Ubuntu - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita_3.2.0_arm64.deb +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita_3.2.1_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita-3.2.0-1.x86_64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita-3.2.1-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.0/mita-3.2.0-1.aarch64.rpm +curl -LSO https://github.com/enfein/mieru/releases/download/v3.2.1/mita-3.2.1-1.aarch64.rpm ``` ## 安装 mita 软件包 ```sh # Debian / Ubuntu - X86_64 -sudo dpkg -i mita_3.2.0_amd64.deb +sudo dpkg -i mita_3.2.1_amd64.deb # Debian / Ubuntu - ARM 64 -sudo dpkg -i mita_3.2.0_arm64.deb +sudo dpkg -i mita_3.2.1_arm64.deb # RedHat / CentOS / Rocky Linux - X86_64 -sudo rpm -Uvh --force mita-3.2.0-1.x86_64.rpm +sudo rpm -Uvh --force mita-3.2.1-1.x86_64.rpm # RedHat / CentOS / Rocky Linux - ARM 64 -sudo rpm -Uvh --force mita-3.2.0-1.aarch64.rpm +sudo rpm -Uvh --force mita-3.2.1-1.aarch64.rpm ``` 上述指令也可以用来升级 mita 软件包的版本。 diff --git a/mieru/pkg/cipher/cipher.go b/mieru/pkg/cipher/cipher.go index 3e11977a84..d17d109892 100644 --- a/mieru/pkg/cipher/cipher.go +++ b/mieru/pkg/cipher/cipher.go @@ -28,7 +28,7 @@ import ( ) const ( - noncePrintablePrefixLen = 12 + nonceRewritePrefixLen = 8 ) type AEADType uint8 @@ -288,11 +288,11 @@ func (c *AEADBlockCipher) newNonce() ([]byte, error) { } // Adjust the nonce such that the first a few bytes are printable ASCII characters. - rewriteLen := noncePrintablePrefixLen + rewriteLen := nonceRewritePrefixLen if rewriteLen > c.NonceSize() { rewriteLen = c.NonceSize() } - util.ToPrintableChar(nonce, 0, rewriteLen) + util.ToCommon64Set(nonce, 0, rewriteLen) return nonce, nil } diff --git a/mieru/pkg/cipher/cipher_test.go b/mieru/pkg/cipher/cipher_test.go index 167d7bfc85..3a7437f906 100644 --- a/mieru/pkg/cipher/cipher_test.go +++ b/mieru/pkg/cipher/cipher_test.go @@ -216,6 +216,10 @@ func TestAEADBlockCipherNewNonce(t *testing.T) { if err != nil { t.Fatalf("newXChaCha20Poly1305BlockCipher() failed: %v", err) } + s := make(map[byte]struct{}) + for _, c := range []byte(util.Common64Set) { + s[c] = struct{}{} + } distribution := make(map[byte]int32) for i := 0; i < 100000; i++ { nonce, err := c.newNonce() @@ -223,11 +227,11 @@ func TestAEADBlockCipherNewNonce(t *testing.T) { t.Fatalf("newNonce() failed: %v", err) } for j, b := range nonce { - if j >= noncePrintablePrefixLen { + if j >= nonceRewritePrefixLen { break } - if b < util.PrintableCharSub || b > util.PrintableCharSup { - t.Fatalf("Byte %v in position %d is not a printable ASCII character", b, j) + if _, ok := s[b]; !ok { + t.Fatalf("Byte %v in position %d is not allowed", b, j) } distribution[b]++ } diff --git a/mieru/pkg/util/ascii.go b/mieru/pkg/util/ascii.go index 9258b7c4cc..20e2525b73 100644 --- a/mieru/pkg/util/ascii.go +++ b/mieru/pkg/util/ascii.go @@ -23,13 +23,16 @@ import ( const ( PrintableCharSub = 0x20 // 0x20, i.e. ' ', is the first printable ASCII character PrintableCharSup = 0x7E // 0x7E, i.e. '~', is the last printable ASCII character + + // Common64Set contains 64 selected common characters. + Common64Set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-" ) var ( printableCharRange = big.NewInt(PrintableCharSup - PrintableCharSub + 1) ) -// ToPrintableChar rewrite [beginIdx, endIdx) of the byte slice with printable +// ToPrintableChar rewrites [beginIdx, endIdx) of the byte slice with printable // ASCII characters. func ToPrintableChar(b []byte, beginIdx, endIdx int) { if beginIdx > endIdx { @@ -59,3 +62,18 @@ func ToPrintableChar(b []byte, beginIdx, endIdx int) { } } } + +// ToCommon64Set rewrites [beginIdx, endIdx) of the byte slice with characters +// from Common64Set. +func ToCommon64Set(b []byte, beginIdx, endIdx int) { + if beginIdx > endIdx { + panic("begin index > end index") + } + if endIdx > len(b) { + panic("index out of range") + } + for i := beginIdx; i < endIdx; i++ { + setIdx := b[i] & 0x3f + b[i] = Common64Set[setIdx] + } +} diff --git a/mieru/pkg/util/ascii_test.go b/mieru/pkg/util/ascii_test.go index 3b69b36de1..8163ec98ab 100644 --- a/mieru/pkg/util/ascii_test.go +++ b/mieru/pkg/util/ascii_test.go @@ -27,10 +27,34 @@ func TestToPrintableChar(t *testing.T) { break } } + ToPrintableChar(b, 0, 1024) for i := 0; i < 1024; i++ { if b[i] < PrintableCharSub || b[i] > PrintableCharSup { - t.Fatalf("Found non printable character") + t.Errorf("Found non printable character") + } + } +} + +func TestToCommon64Set(t *testing.T) { + if len(Common64Set) != 64 { + t.Fatalf("Common64Set has %d characters, want 64", len(Common64Set)) + } + s := make(map[byte]struct{}) + for _, c := range []byte(Common64Set) { + s[c] = struct{}{} + } + b := make([]byte, 1024) + for { + if _, err := crand.Read(b); err == nil { + break + } + } + + ToCommon64Set(b, 0, 1024) + for i := 0; i < 1024; i++ { + if _, ok := s[b[i]]; !ok { + t.Errorf("Found character not in Common64Set") } } } diff --git a/mieru/pkg/version/current.go b/mieru/pkg/version/current.go index e081444a09..efe89c0fab 100644 --- a/mieru/pkg/version/current.go +++ b/mieru/pkg/version/current.go @@ -16,5 +16,5 @@ package version const ( - AppVersion = "3.2.0" + AppVersion = "3.2.1" ) diff --git a/openwrt-packages/luci-lib-taskd/Makefile b/openwrt-packages/luci-lib-taskd/Makefile index 2fa94dcd85..f33d094b28 100644 --- a/openwrt-packages/luci-lib-taskd/Makefile +++ b/openwrt-packages/luci-lib-taskd/Makefile @@ -11,7 +11,7 @@ LUCI_DEPENDS:=+luci-lib-xterm +taskd LUCI_EXTRA_DEPENDS:=taskd (>=1.0.3-1) LUCI_PKGARCH:=all -PKG_VERSION:=1.0.19 +PKG_VERSION:=1.0.20 PKG_RELEASE:= PKG_MAINTAINER:=jjm2473 diff --git a/openwrt-packages/luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js b/openwrt-packages/luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js index 14eefeea08..fd2f32f7b4 100644 --- a/openwrt-packages/luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js +++ b/openwrt-packages/luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js @@ -24,7 +24,7 @@ if (oReq.status == 403) { alert($gettext("Lost login status")); location.href = location.href; - } else if (oReq.status == 404) { + } else if (oReq.status >= 400) { reject(oEvent); } else { resolve(oReq); @@ -155,7 +155,7 @@ } }).catch(err => { if (showing) { - if (err.target.status == 0) { + if (err.target.status == 0 || err.target.status == 502) { title_view.innerText = task_id + ' (' + $gettext("Fetch log failed, retrying...") + ')'; setTimeout(()=>pulllog(true), 1000); } else if (err.target.status == 403 || err.target.status == 404) { @@ -183,23 +183,23 @@ // compat if (typeof(window.findParent) !== 'function') { const elem = function(e) { - return (e != null && typeof(e) == 'object' && 'nodeType' in e); - }; + return (e != null && typeof(e) == 'object' && 'nodeType' in e); + }; const matches = function(node, selector) { - var m = elem(node) ? node.matches || node.msMatchesSelector : null; - return m ? m.call(node, selector) : false; - }; + var m = elem(node) ? node.matches || node.msMatchesSelector : null; + return m ? m.call(node, selector) : false; + }; window.findParent = function (node, selector) { - if (elem(node) && node.closest) - return node.closest(selector); + if (elem(node) && node.closest) + return node.closest(selector); - while (elem(node)) - if (matches(node, selector)) - return node; - else - node = node.parentNode; + while (elem(node)) + if (matches(node, selector)) + return node; + else + node = node.parentNode; - return null; + return null; }; } if (typeof(window.cbi_submit) !== 'function') { diff --git a/shadowsocks-rust/README.md b/shadowsocks-rust/README.md index cc5a8c3c0f..16cc239ffb 100644 --- a/shadowsocks-rust/README.md +++ b/shadowsocks-rust/README.md @@ -50,8 +50,12 @@ Related Projects: - `local-dns` - Allow using dns protocol for `sslocal`, serves as a DNS server proxying queries to local or remote DNS servers by ACL rules +- `local-fake-dns` - FakeDNS, allocating an IP address for each individual Query from a specific IP pool + - `local-tun` - [TUN](https://en.wikipedia.org/wiki/TUN/TAP) interface support for `sslocal` +- `local-online-config` - [SIP008](https://shadowsocks.org/doc/sip008.html) Online Configuration Delivery + - `stream-cipher` - Enable deprecated stream ciphers. WARN: stream ciphers are UNSAFE! - `aead-cipher-extra` - Enable non-standard AEAD ciphers diff --git a/shadowsocks-rust/crates/shadowsocks-service/README.md b/shadowsocks-rust/crates/shadowsocks-service/README.md index be9ee1cdb8..63f373a8a5 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/README.md +++ b/shadowsocks-rust/crates/shadowsocks-service/README.md @@ -19,6 +19,8 @@ shadowsocks is a fast tunnel proxy that helps you bypass firewalls. * Redir, aka Transparent Proxy (`local-redir`) * DNS (`local-dns`) * Tun (`local-tun`) + * FakeDNS (`local-fake-dns`) + * SIP008 Online Config (`local-online-config`) * Server diff --git a/small/luci-app-passwall/luasrc/controller/passwall.lua b/small/luci-app-passwall/luasrc/controller/passwall.lua index e52338ca55..1440118983 100644 --- a/small/luci-app-passwall/luasrc/controller/passwall.lua +++ b/small/luci-app-passwall/luasrc/controller/passwall.lua @@ -21,10 +21,12 @@ function index() entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true - if uci:get(appname, "@global[0]", "hide_from_luci") == "1" then - return + local e + if uci:get(appname, "@global[0]", "hide_from_luci") ~= "1" then + e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("Pass Wall"), -1) + else + e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), nil, -1) end - e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("Pass Wall"), -1) e.dependent = true e.acl_depends = { "luci-app-passwall" } --[[ Client ]] diff --git a/small/luci-app-ssr-plus/Makefile b/small/luci-app-ssr-plus/Makefile index 82e06b3e78..7ea5e11e3f 100644 --- a/small/luci-app-ssr-plus/Makefile +++ b/small/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=188 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY \ diff --git a/small/luci-app-ssr-plus/po/zh-cn b/small/luci-app-ssr-plus/po/zh-cn new file mode 120000 index 0000000000..8d69574ddd --- /dev/null +++ b/small/luci-app-ssr-plus/po/zh-cn @@ -0,0 +1 @@ +zh_Hans \ No newline at end of file diff --git a/small/luci-app-ssr-plus/po/zh_Hans b/small/luci-app-ssr-plus/po/zh_Hans deleted file mode 120000 index 41451e4a19..0000000000 --- a/small/luci-app-ssr-plus/po/zh_Hans +++ /dev/null @@ -1 +0,0 @@ -zh-cn \ No newline at end of file diff --git a/small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po similarity index 100% rename from small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po rename to small/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index e2f86a4346..e17c75ce32 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -21,7 +21,7 @@ define Download/geoip HASH:=4d65e0bfc4976c65d7ce2c77ae7c06fe8bf8ab852c3d83bd2a2fa1f952e556e5 endef -GEOSITE_VER:=20240614093027 +GEOSITE_VER:=20240621090204 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ diff --git a/small/v2raya/Makefile b/small/v2raya/Makefile index edd9016abf..fcb61331f3 100644 --- a/small/v2raya/Makefile +++ b/small/v2raya/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2rayA -PKG_VERSION:=2.2.5.5 +PKG_VERSION:=2.2.5.6 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=2352da4ec7909d5f93157b37776c856a9353d6bd4e18209f38beb33deb202ede +PKG_HASH:=1089101d6ec657b8a39afcd89a0704925cff3de998b5196686ec239ca3090859 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/service PKG_LICENSE:=AGPL-3.0-only @@ -60,7 +60,7 @@ define Download/v2raya-web URL:=https://github.com/v2rayA/v2rayA/releases/download/v$(PKG_VERSION)/ URL_FILE:=web.tar.gz FILE:=$(WEB_FILE) - HASH:=ff6753b6e952347608119d56f4ad34ccfcd3d191df84a5b1b52735f0c137848c + HASH:=341548c4ec48a503ee9f89306b170378c7981fa20fb4bddb901a003923c8536d endef define Build/Prepare diff --git a/small/xray-core/Makefile b/small/xray-core/Makefile index 5757fad8d3..849baf3667 100644 --- a/small/xray-core/Makefile +++ b/small/xray-core/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=xray-core -PKG_VERSION:=1.8.13 +PKG_VERSION:=1.8.16 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=9e63fbeb4667c19e286389c370d30e9e904f4421784adcbe6cf4d6e172a2ac29 +PKG_HASH:=61a96fba9ae18e91ea163f317a3641bca21fa744c214fb912270a3e6b7a8da6d PKG_MAINTAINER:=Tianling Shen PKG_LICENSE:=MPL-2.0 diff --git a/v2raya/.github/workflows/beta_release_main.yml b/v2raya/.github/workflows/beta_release_main.yml index 0da7cb689c..ef7a2cd820 100644 --- a/v2raya/.github/workflows/beta_release_main.yml +++ b/v2raya/.github/workflows/beta_release_main.yml @@ -120,7 +120,7 @@ jobs: $env:GOARCH = $arch $filename = $((Get-Content ./install/friendly-filenames.json | ConvertFrom-Json)."openbsd-$arch")."friendlyName" Set-Location -Path service - go build -o ../v2raya_binaries/v2raya_${filename}_${env:VERSION}_${env:VERSION} -ldflags="-X github.com/v2rayA/v2rayA/conf.Version=${env:VERSION} -s -w" -trimpath + go build -o ../v2raya_binaries/v2raya_${filename}_${env:VERSION} -ldflags="-X github.com/v2rayA/v2rayA/conf.Version=${env:VERSION} -s -w" -trimpath Set-Location -Path .. } - name: Upload Artifact diff --git a/v2raya/.github/workflows/release_main.yml b/v2raya/.github/workflows/release_main.yml index f45346ce9d..5f17e00bcd 100644 --- a/v2raya/.github/workflows/release_main.yml +++ b/v2raya/.github/workflows/release_main.yml @@ -120,7 +120,7 @@ jobs: $env:GOARCH = $arch $filename = $((Get-Content ./install/friendly-filenames.json | ConvertFrom-Json)."openbsd-$arch")."friendlyName" Set-Location -Path service - go build -o ../v2raya_binaries/v2raya_${filename}_${env:VERSION}_${env:VERSION} -ldflags="-X github.com/v2rayA/v2rayA/conf.Version=${env:VERSION} -s -w" -trimpath + go build -o ../v2raya_binaries/v2raya_${filename}_${env:VERSION} -ldflags="-X github.com/v2rayA/v2rayA/conf.Version=${env:VERSION} -s -w" -trimpath Set-Location -Path .. } @@ -625,9 +625,11 @@ jobs: fetch-depth: 0 - name: Check Version id: prep + env: + REF: ${{ inputs.tag }} run: | echo "P_DIR=$(pwd)" >> $GITHUB_OUTPUT - tag=$(git describe --tags $(git rev-list --tags --max-count=1)) + tag=${{ inputs.tag }} version=$(echo $tag | sed 's/v//g') echo "VERSION=$version" >> $GITHUB_OUTPUT echo "VERSION=$version" >> $GITHUB_ENV @@ -706,6 +708,7 @@ jobs: fetch-depth: 0 - name: Check Version id: prep + shell: bash env: REF: ${{ inputs.tag }} run: | @@ -866,6 +869,7 @@ jobs: fetch-depth: 0 - name: Check Version id: prep + shell: bash env: REF: ${{ inputs.tag }} run: | diff --git a/v2raya/service/go.mod b/v2raya/service/go.mod index 68d33b0eff..910119684b 100644 --- a/v2raya/service/go.mod +++ b/v2raya/service/go.mod @@ -40,8 +40,8 @@ require ( github.com/v2rayA/v2rayA-lib4 v0.0.0-20230812094818-595f87cb2a49 github.com/vearutop/statigz v1.1.7 go.etcd.io/bbolt v1.3.8 - golang.org/x/net v0.18.0 - golang.org/x/sys v0.14.0 + golang.org/x/net v0.23.0 + golang.org/x/sys v0.18.0 google.golang.org/grpc v1.57.1 google.golang.org/protobuf v1.31.0 ) @@ -95,7 +95,7 @@ require ( gitlab.com/yawning/chacha20.git v0.0.0-20230427033715-7877545b1b37 // indirect go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.15.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/v2raya/service/go.sum b/v2raya/service/go.sum index 855f9971f8..688298a3ef 100644 --- a/v2raya/service/go.sum +++ b/v2raya/service/go.sum @@ -298,8 +298,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -311,8 +311,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= @@ -338,8 +338,8 @@ golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/v2rayn/v2rayN/v2rayN/App.xaml.cs b/v2rayn/v2rayN/v2rayN/App.xaml.cs index a857173762..7348d354b6 100644 --- a/v2rayn/v2rayN/v2rayN/App.xaml.cs +++ b/v2rayn/v2rayN/v2rayN/App.xaml.cs @@ -58,10 +58,12 @@ namespace v2rayN Environment.Exit(0); return; } - //if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64) - //{ - // _config.guiItem.enableStatistics = false; - //} + + //Under Win10 + if (Environment.OSVersion.Version.Major < 10) + { + Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.Process); + } } private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) diff --git a/v2rayn/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayn/v2rayN/v2rayN/Handler/ConfigHandler.cs index a8a248bbe7..c2a2857171 100644 --- a/v2rayn/v2rayN/v2rayN/Handler/ConfigHandler.cs +++ b/v2rayn/v2rayN/v2rayN/Handler/ConfigHandler.cs @@ -1184,49 +1184,33 @@ namespace v2rayN.Handler { return -1; } + var subRemarks = LazyConfig.Instance.GetSubItem(subid)?.remarks; - //判断str是否包含s的任意一个字符串 - static bool Contains(string str, params string[] s) + List? lstProfiles = null; + //Is sing-box array configuration + if (lstProfiles is null || lstProfiles.Count <= 0) { - foreach (var item in s) - { - if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true; - } - return false; + lstProfiles = SingboxFmt.ResolveFullArray(strData, subRemarks); } - //Is v2ray array configuration - var configObjects = JsonUtils.Deserialize(strData); - if (configObjects != null && configObjects.Length > 0) + if (lstProfiles is null || lstProfiles.Count <= 0) + { + lstProfiles = V2rayFmt.ResolveFullArray(strData, subRemarks); + } + if (lstProfiles != null && lstProfiles.Count > 0) { if (isSub && !Utils.IsNullOrEmpty(subid)) { RemoveServerViaSubid(config, subid, isSub); } - int count = 0; - foreach (var configObject in configObjects) + foreach (var it in lstProfiles) { - var objectString = JsonUtils.Serialize(configObject); - var v2rayCon = JsonUtils.Deserialize(objectString); - if (v2rayCon?.inbounds?.Count > 0 && v2rayCon.outbounds?.Count > 0) + it.subid = subid; + it.isSub = isSub; + if (AddCustomServer(config, it, true) == 0) { - var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); - File.WriteAllText(fileName, objectString); - - var profileIt = new ProfileItem - { - coreType = ECoreType.Xray, - address = fileName, - remarks = v2rayCon.remarks ?? "v2ray_custom", - subid = subid, - isSub = isSub - }; - - if (AddCustomServer(config, profileIt, true) == 0) - { - count++; - } + count++; } } if (count > 0) @@ -1235,58 +1219,39 @@ namespace v2rayN.Handler } } - ProfileItem profileItem = new(); - //Is v2ray configuration - var v2rayConfig = JsonUtils.Deserialize(strData); - if (v2rayConfig?.inbounds?.Count > 0 - && v2rayConfig.outbounds?.Count > 0) + ProfileItem? profileItem = null; + //Is sing-box configuration + if (profileItem is null) { - var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); - File.WriteAllText(fileName, strData); - - profileItem.coreType = ECoreType.Xray; - profileItem.address = fileName; - profileItem.remarks = v2rayConfig.remarks ?? "v2ray_custom"; + profileItem = SingboxFmt.ResolveFull(strData, subRemarks); + } + //Is v2ray configuration + if (profileItem is null) + { + profileItem = V2rayFmt.ResolveFull(strData, subRemarks); } //Is Clash configuration - else if (Contains(strData, "port", "socks-port", "proxies")) + if (profileItem is null) { - var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml"); - File.WriteAllText(fileName, strData); - - profileItem.coreType = ECoreType.mihomo; - profileItem.address = fileName; - profileItem.remarks = "clash_custom"; + profileItem = ClashFmt.ResolveFull(strData, subRemarks); } //Is hysteria configuration - else if (Contains(strData, "server", "up", "down", "listen", "", "")) + if (profileItem is null) { - var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); - File.WriteAllText(fileName, strData); - - profileItem.coreType = ECoreType.hysteria; - profileItem.address = fileName; - profileItem.remarks = "hysteria_custom"; + profileItem = Hysteria2Fmt.ResolveFull2(strData, subRemarks); + } + if (profileItem is null) + { + profileItem = Hysteria2Fmt.ResolveFull(strData, subRemarks); } //Is naiveproxy configuration - else if (Contains(strData, "listen", "proxy", "", "")) + if (profileItem is null) { - var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json"); - File.WriteAllText(fileName, strData); - - profileItem.coreType = ECoreType.naiveproxy; - profileItem.address = fileName; - profileItem.remarks = "naiveproxy_custom"; + profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks); } - //Is Other configuration - else + if (profileItem is null || Utils.IsNullOrEmpty(profileItem.address)) { return -1; - //var fileName = Utile.GetTempPath($"{Utile.GetGUID(false)}.txt"); - //File.WriteAllText(fileName, strData); - - //profileItem.address = fileName; - //profileItem.remarks = "other_custom"; } if (isSub && !Utils.IsNullOrEmpty(subid)) @@ -1299,12 +1264,6 @@ namespace v2rayN.Handler } profileItem.subid = subid; profileItem.isSub = isSub; - - if (Utils.IsNullOrEmpty(profileItem.address)) - { - return -1; - } - if (AddCustomServer(config, profileItem, true) == 0) { return 1; @@ -1327,31 +1286,12 @@ namespace v2rayN.Handler RemoveServerViaSubid(config, subid, isSub); } - //SsSIP008 - var lstSsServer = JsonUtils.Deserialize>(strData); - if (lstSsServer?.Count <= 0) - { - var ssSIP008 = JsonUtils.Deserialize(strData); - if (ssSIP008?.servers?.Count > 0) - { - lstSsServer = ssSIP008.servers; - } - } - + var lstSsServer = ShadowsocksFmt.ResolveSip008(strData); if (lstSsServer?.Count > 0) { int counter = 0; - foreach (var it in lstSsServer) + foreach (var ssItem in lstSsServer) { - var ssItem = new ProfileItem() - { - subid = subid, - remarks = it.remarks, - security = it.method, - id = it.password, - address = it.server, - port = Utils.ToInt(it.server_port) - }; ssItem.subid = subid; ssItem.isSub = isSub; if (AddShadowsocksServer(config, ssItem) == 0) diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs index 42b7625268..cc867c3612 100644 --- a/v2rayn/v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/BaseFmt.cs @@ -1,4 +1,5 @@ using System.Collections.Specialized; +using System.IO; using v2rayN.Enums; using v2rayN.Models; @@ -182,5 +183,21 @@ namespace v2rayN.Handler.Fmt } return 0; } + + protected static bool Contains(string str, params string[] s) + { + foreach (var item in s) + { + if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true; + } + return false; + } + + protected static string WriteAllText(string strData, string ext = "json") + { + var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.{ext}"); + File.WriteAllText(fileName, strData); + return fileName; + } } } \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs new file mode 100644 index 0000000000..90d96749fc --- /dev/null +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/ClashFmt.cs @@ -0,0 +1,26 @@ +using v2rayN.Enums; +using v2rayN.Models; + +namespace v2rayN.Handler.Fmt +{ + internal class ClashFmt : BaseFmt + { + public static ProfileItem? ResolveFull(string strData, string? subRemarks) + { + if (Contains(strData, "port", "socks-port", "proxies")) + { + var fileName = WriteAllText(strData, "yaml"); + + var profileItem = new ProfileItem + { + coreType = ECoreType.mihomo, + address = fileName, + remarks = subRemarks ?? "clash_custom" + }; + return profileItem; + } + + return null; + } + } +} \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs index 34ec25a337..af0cffe7d5 100644 --- a/v2rayn/v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/FmtHandler.cs @@ -32,7 +32,6 @@ namespace v2rayN.Handler.Fmt } } - public static ProfileItem? ResolveConfig(string config, out string msg) { msg = ResUI.ConfigurationFormatIncorrect; diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs index 6565e935c7..f205861f1e 100644 --- a/v2rayn/v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/Hysteria2Fmt.cs @@ -64,5 +64,41 @@ namespace v2rayN.Handler.Fmt url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}"; return url; } + + public static ProfileItem? ResolveFull(string strData, string? subRemarks) + { + if (Contains(strData, "server", "up", "down", "listen", "", "")) + { + var fileName = WriteAllText(strData); + + var profileItem = new ProfileItem + { + coreType = ECoreType.hysteria, + address = fileName, + remarks = subRemarks ?? "hysteria_custom" + }; + return profileItem; + } + + return null; + } + + public static ProfileItem? ResolveFull2(string strData, string? subRemarks) + { + if (Contains(strData, "server", "auth", "up", "down", "listen")) + { + var fileName = WriteAllText(strData); + + var profileItem = new ProfileItem + { + coreType = ECoreType.hysteria2, + address = fileName, + remarks = subRemarks ?? "hysteria2_custom" + }; + return profileItem; + } + + return null; + } } } \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs new file mode 100644 index 0000000000..3e523170b2 --- /dev/null +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/NaiveproxyFmt.cs @@ -0,0 +1,26 @@ +using v2rayN.Enums; +using v2rayN.Models; + +namespace v2rayN.Handler.Fmt +{ + internal class NaiveproxyFmt : BaseFmt + { + public static ProfileItem? ResolveFull(string strData, string? subRemarks) + { + if (Contains(strData, "listen", "proxy", "", "")) + { + var fileName = WriteAllText(strData); + + var profileItem = new ProfileItem + { + coreType = ECoreType.naiveproxy, + address = fileName, + remarks = subRemarks ?? "naiveproxy_custom" + }; + return profileItem; + } + + return null; + } + } +} \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs index 92f51400b3..495f0d50dc 100644 --- a/v2rayn/v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/ShadowsocksFmt.cs @@ -146,5 +146,38 @@ namespace v2rayN.Handler.Fmt return item; } + + public static List? ResolveSip008(string result) + { + //SsSIP008 + var lstSsServer = JsonUtils.Deserialize>(result); + if (lstSsServer?.Count <= 0) + { + var ssSIP008 = JsonUtils.Deserialize(result); + if (ssSIP008?.servers?.Count > 0) + { + lstSsServer = ssSIP008.servers; + } + } + + if (lstSsServer?.Count > 0) + { + List lst = []; + foreach (var it in lstSsServer) + { + var ssItem = new ProfileItem() + { + remarks = it.remarks, + security = it.method, + id = it.password, + address = it.server, + port = Utils.ToInt(it.server_port) + }; + lst.Add(ssItem); + } + return lst; + } + return null; + } } } \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs new file mode 100644 index 0000000000..c8221afeed --- /dev/null +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/SingboxFmt.cs @@ -0,0 +1,58 @@ +using v2rayN.Enums; +using v2rayN.Models; + +namespace v2rayN.Handler.Fmt +{ + internal class SingboxFmt : BaseFmt + { + public static List? ResolveFullArray(string strData, string? subRemarks) + { + var configObjects = JsonUtils.Deserialize(strData); + if (configObjects != null && configObjects.Length > 0) + { + List lstResult = []; + foreach (var configObject in configObjects) + { + var objectString = JsonUtils.Serialize(configObject); + var singboxCon = JsonUtils.Deserialize(objectString); + if (singboxCon?.inbounds?.Count > 0 + && singboxCon.outbounds?.Count > 0 + && singboxCon.route != null) + { + var fileName = WriteAllText(objectString); + + var profileIt = new ProfileItem + { + coreType = ECoreType.sing_box, + address = fileName, + remarks = subRemarks ?? "singbox_custom", + }; + lstResult.Add(profileIt); + } + } + return lstResult; + } + return null; + } + + public static ProfileItem? ResolveFull(string strData, string? subRemarks) + { + var singboxConfig = JsonUtils.Deserialize(strData); + if (singboxConfig?.inbounds?.Count > 0 + && singboxConfig.outbounds?.Count > 0 + && singboxConfig.route != null) + { + var fileName = WriteAllText(strData); + var profileItem = new ProfileItem + { + coreType = ECoreType.sing_box, + address = fileName, + remarks = subRemarks ?? "singbox_custom" + }; + + return profileItem; + } + return null; + } + } +} \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs b/v2rayn/v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs new file mode 100644 index 0000000000..ed34c9a29c --- /dev/null +++ b/v2rayn/v2rayN/v2rayN/Handler/Fmt/V2rayFmt.cs @@ -0,0 +1,59 @@ +using v2rayN.Enums; +using v2rayN.Models; + +namespace v2rayN.Handler.Fmt +{ + internal class V2rayFmt : BaseFmt + { + public static List? ResolveFullArray(string strData, string? subRemarks) + { + var configObjects = JsonUtils.Deserialize(strData); + if (configObjects != null && configObjects.Length > 0) + { + List lstResult = []; + foreach (var configObject in configObjects) + { + var objectString = JsonUtils.Serialize(configObject); + var v2rayCon = JsonUtils.Deserialize(objectString); + if (v2rayCon?.inbounds?.Count > 0 + && v2rayCon.outbounds?.Count > 0 + && v2rayCon.routing != null) + { + var fileName = WriteAllText(objectString); + + var profileIt = new ProfileItem + { + coreType = ECoreType.Xray, + address = fileName, + remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom", + }; + lstResult.Add(profileIt); + } + } + return lstResult; + } + return null; + } + + public static ProfileItem? ResolveFull(string strData, string? subRemarks) + { + var v2rayConfig = JsonUtils.Deserialize(strData); + if (v2rayConfig?.inbounds?.Count > 0 + && v2rayConfig.outbounds?.Count > 0 + && v2rayConfig.routing != null) + { + var fileName = WriteAllText(strData); + + var profileItem = new ProfileItem + { + coreType = ECoreType.Xray, + address = fileName, + remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom" + }; + + return profileItem; + } + return null; + } + } +} \ No newline at end of file diff --git a/v2rayn/v2rayN/v2rayN/v2rayN.csproj b/v2rayn/v2rayN/v2rayN/v2rayN.csproj index 7b2ba3a90c..629e562e81 100644 --- a/v2rayn/v2rayN/v2rayN/v2rayN.csproj +++ b/v2rayn/v2rayN/v2rayN/v2rayN.csproj @@ -10,7 +10,7 @@ enable v2rayN.ico Copyright © 2017-2024 (GPLv3) - 6.45 + 6.46 7.0 diff --git a/v2rayng/V2rayNG/app/build.gradle.kts b/v2rayng/V2rayNG/app/build.gradle.kts index edefe388b0..ac09ff4e6a 100644 --- a/v2rayng/V2rayNG/app/build.gradle.kts +++ b/v2rayng/V2rayNG/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "com.v2ray.ang" minSdk = 21 targetSdk = 34 - versionCode = 563 - versionName = "1.8.25" + versionCode = 565 + versionName = "1.8.26" multiDexEnabled = true splits.abi { reset() diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt index fe5c79192e..e15f5e4a54 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt @@ -139,6 +139,7 @@ data class V2rayConfig( var kcpSettings: KcpSettingsBean? = null, var wsSettings: WsSettingsBean? = null, var httpupgradeSettings: HttpupgradeSettingsBean? = null, + var splithttpSettings: SplithttpSettingsBean? = null, var httpSettings: HttpSettingsBean? = null, var tlsSettings: TlsSettingsBean? = null, var quicSettings: QuicSettingBean? = null, @@ -192,6 +193,10 @@ data class V2rayConfig( var host: String = "", val acceptProxyProtocol: Boolean? = null) + data class SplithttpSettingsBean(var path: String = "", + var host: String = "", + val maxUploadSize: Int? = null, + val maxConcurrentUploads: Int? = null) data class HttpSettingsBean(var host: List = ArrayList(), var path: String = "") @@ -279,6 +284,13 @@ data class V2rayConfig( httpupgradeSetting.path = path ?: "/" httpupgradeSettings = httpupgradeSetting } + "splithttp" -> { + val splithttpSetting = SplithttpSettingsBean() + splithttpSetting.host = host ?: "" + sni = splithttpSetting.host + splithttpSetting.path = path ?: "/" + splithttpSettings = splithttpSetting + } "h2", "http" -> { network = "h2" val h2Setting = HttpSettingsBean() @@ -418,6 +430,12 @@ data class V2rayConfig( httpupgradeSetting.host, httpupgradeSetting.path) } + "splithttp" -> { + val splithttpSetting = streamSettings?.splithttpSettings ?: return null + listOf("", + splithttpSetting.host, + splithttpSetting.path) + } "h2" -> { val h2Setting = streamSettings?.httpSettings ?: return null listOf("", diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt index abec724f3b..40eb9b2229 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt @@ -110,7 +110,9 @@ class ServerActivity : BaseActivity() { private val sp_network: Spinner? by lazy { findViewById(R.id.sp_network) } private val sp_header_type: Spinner? by lazy { findViewById(R.id.sp_header_type) } private val sp_header_type_title: TextView? by lazy { findViewById(R.id.sp_header_type_title) } + private val tv_request_host: TextView? by lazy { findViewById(R.id.tv_request_host) } private val et_request_host: EditText? by lazy { findViewById(R.id.et_request_host) } + private val tv_path: TextView? by lazy { findViewById(R.id.tv_path) } private val et_path: EditText? by lazy { findViewById(R.id.et_path) } private val sp_stream_alpn: Spinner? by lazy { findViewById(R.id.sp_stream_alpn) } //uTLS private val container_alpn: LinearLayout? by lazy { findViewById(R.id.l4) } @@ -162,6 +164,36 @@ class ServerActivity : BaseActivity() { et_request_host?.text = Utils.getEditable(transportDetails[1]) et_path?.text = Utils.getEditable(transportDetails[2]) } + + tv_request_host?.text = Utils.getEditable( + getString( + when (networks[position]) { + "tcp" -> R.string.server_lab_request_host_http + "ws" -> R.string.server_lab_request_host_ws + "httpupgrade" -> R.string.server_lab_request_host_httpupgrade + "splithttp" -> R.string.server_lab_request_host_splithttp + "h2" -> R.string.server_lab_request_host_h2 + "quic" -> R.string.server_lab_request_host_quic + "grpc" -> R.string.server_lab_request_host_grpc + else -> R.string.server_lab_request_host + } + ) + ) + + tv_path?.text = Utils.getEditable( + getString( + when (networks[position]) { + "kcp" -> R.string.server_lab_path_kcp + "ws" -> R.string.server_lab_path_ws + "httpupgrade" -> R.string.server_lab_path_httpupgrade + "splithttp" -> R.string.server_lab_path_splithttp + "h2" -> R.string.server_lab_path_h2 + "quic" -> R.string.server_lab_path_quic + "grpc" -> R.string.server_lab_path_grpc + else -> R.string.server_lab_path + } + ) + ) } override fun onNothingSelected(parent: AdapterView<*>?) { diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt index 050e10e5c9..636e0e98a4 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt @@ -194,10 +194,10 @@ object V2rayConfigUtil { val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: ERoutingMode.BYPASS_LAN_MAINLAND.value - // Hardcode googleapis.cn + // Hardcode googleapis.cn gstatic.com val googleapisRoute = V2rayConfig.RoutingBean.RulesBean( outboundTag = AppConfig.TAG_PROXY, - domain = arrayListOf("domain:googleapis.cn") + domain = arrayListOf("domain:googleapis.cn", "domain:gstatic.com") ) when (routingMode) { diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/TrojanFmt.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/TrojanFmt.kt index 0a42f8bd0c..5f50b1378a 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/TrojanFmt.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/TrojanFmt.kt @@ -123,7 +123,7 @@ object TrojanFmt { } } - "ws", "httpupgrade" -> { + "ws", "httpupgrade", "splithttp" -> { if (!TextUtils.isEmpty(transportDetails[1])) { dicQuery["host"] = Utils.urlEncode(transportDetails[1]) } diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VlessFmt.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VlessFmt.kt index 6ab3003be9..9c5fb6b301 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VlessFmt.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VlessFmt.kt @@ -123,7 +123,7 @@ object VlessFmt { } } - "ws", "httpupgrade" -> { + "ws", "httpupgrade", "splithttp" -> { if (!TextUtils.isEmpty(transportDetails[1])) { dicQuery["host"] = Utils.urlEncode(transportDetails[1]) } diff --git a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml index d861295cb6..1cf5801068 100644 --- a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml +++ b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml @@ -173,6 +173,7 @@ android:orientation="vertical"> @@ -192,6 +193,7 @@ android:orientation="vertical"> diff --git a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml index 88eb70f7c3..60c0d61791 100644 --- a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml +++ b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml @@ -154,6 +154,7 @@ android:orientation="vertical"> @@ -173,6 +174,7 @@ android:orientation="vertical"> diff --git a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vless.xml b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vless.xml index 8e70bd029c..0d11f7e836 100644 --- a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vless.xml +++ b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vless.xml @@ -193,6 +193,7 @@ android:orientation="vertical"> @@ -212,6 +213,7 @@ android:orientation="vertical"> diff --git a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml index ebfeb7e12e..7569a2daac 100644 --- a/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml +++ b/v2rayng/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml @@ -192,6 +192,7 @@ android:orientation="vertical"> @@ -211,6 +212,7 @@ android:orientation="vertical"> diff --git a/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml index ba5f54d932..27cbba7a35 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -48,8 +48,22 @@ النقل نوع الرأس وضع gRPC - مضيف الطلب (مضيف/مضيف ws/مضيف httpupgrade/مضيف h2)/أمان QUIC/جهة gRPC - المسار (مسار ws/مسار httpupgrade/مسار h2)/مفتاح QUIC/بذرة kcp/خدمة gRPC + host + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC security + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC key + kcp seed + gRPC serviceName TLS البصمة بروتوكول الطبقة الآخرى التالية (ALPN) diff --git a/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml index 7f6d6e6d7b..3392deaa74 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -46,8 +46,22 @@ انتقال نوع head حالت gRPC - gRPC Authority/میزبان درخواست (host/host ws/host h2)/امنیت QUIC - مسیر (مسیر ws/ مسیر h2) کلید QUIC/دانه kcp/نام‌خدمات gRPC + host + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC security + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC key + kcp seed + gRPC serviceName TLS مجوز ناامن SNI diff --git a/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml index c2b561ba0a..2fb3a18a05 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -46,8 +46,22 @@ Другие параметры Тип заголовка Режим gRPC - Запрос узла (WS/H2)/HTTPUpgrade/Шифрование QUIC/Полномочия gRPC - Путь (WS/H2)/HTTPUpgrade/Ключ QUIC/Сид KCP/Сервис gRPC + host + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC security + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC key + kcp seed + gRPC serviceName TLS Разрешать небезопасные SNI diff --git a/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml index 33acfa673b..2bd3ac2852 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -46,8 +46,22 @@ Nâng cao Kiểu ngụy trang (Type) Chế độ gRPC - Yêu cầu Host (Host / WS Host / H2 Host) / Bảo mật QUIC / gRPC Authority - Đường dẫn (WS Path / H2 Path) / Khóa QUIC / KCP Seed / Dịch vụ gRPC + host + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC security + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC key + kcp seed + gRPC serviceName TLS Bỏ qua xác minh chứng chỉ SNI diff --git a/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index ff3d54a73f..cac77acc9e 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -46,8 +46,22 @@ 底层传输方式(transport) 伪装类型(type) gRPC 传输模式(mode) - 伪装域名(host)(host/ws host/httpupgrade host/h2 host)/QUIC 加密方式/gRPC Authority - path(ws path/httpupgrade path/h2 path)/QUIC 加密密钥/kcp seed/gRPC serviceName + 伪装域名(host) + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC 加密方式 + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC 加密密钥 + kcp seed + gRPC serviceName 传输层安全(TLS) 跳过证书验证(allowInsecure) SNI diff --git a/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index a63e2a3d2f..b4b7724cea 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -46,8 +46,22 @@ 底層傳輸方式 (transport) 標頭類型 gRPC 傳輸模式 (mode) - 要求主機 (host)(host/ws host/httpupgrade host/h2 host)/QUIC 加密方式/gRPC Authority - path(ws path/httpupgrade path/h2 path)/QUIC 加密金鑰/kcp seed/gRPC serviceName + 要求主機 (host) + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC 加密方式 + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC 加密金鑰 + kcp seed + gRPC serviceName 傳輸層安全 (TLS) 跳過憑證驗證 (allowInsecure) SNI diff --git a/v2rayng/V2rayNG/app/src/main/res/values/arrays.xml b/v2rayng/V2rayNG/app/src/main/res/values/arrays.xml index b5eef4dfd1..2adc0c35e3 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values/arrays.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values/arrays.xml @@ -26,6 +26,7 @@ kcp ws httpupgrade + splithttp h2 quic grpc diff --git a/v2rayng/V2rayNG/app/src/main/res/values/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values/strings.xml index c38dcf63e2..d6adb90b54 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values/strings.xml @@ -47,8 +47,22 @@ Transport head type gRPC mode - request host(host/ws host/httpupgrade host/h2 host)/QUIC security/gRPC Authority - path(ws path/httpupgrade path/h2 path)/QUIC key/kcp seed/gRPC serviceName + host + http host + ws host + httpupgrade host + splithttp host + h2 host + QUIC security + gRPC Authority + path + ws path + httpupgrade path + splithttp path + h2 path + QUIC key + kcp seed + gRPC serviceName TLS Fingerprint Alpn diff --git a/v2rayu/Podfile.lock b/v2rayu/Podfile.lock index acb7c775e9..177acccf5d 100644 --- a/v2rayu/Podfile.lock +++ b/v2rayu/Podfile.lock @@ -1,7 +1,7 @@ PODS: - Alamofire (4.8.2) - - FirebaseAnalytics (10.27.0): - - FirebaseAnalytics/AdIdSupport (= 10.27.0) + - FirebaseAnalytics (10.24.0): + - FirebaseAnalytics/AdIdSupport (= 10.24.0) - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) @@ -9,10 +9,10 @@ PODS: - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - nanopb (< 2.30911.0, >= 2.30908.0) - - FirebaseAnalytics/AdIdSupport (10.27.0): + - FirebaseAnalytics/AdIdSupport (10.24.0): - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) - - GoogleAppMeasurement (= 10.27.0) + - GoogleAppMeasurement (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) @@ -49,21 +49,21 @@ PODS: - GoogleUtilities/Environment (~> 7.10) - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesSwift (~> 2.1) - - GoogleAppMeasurement (10.27.0): - - GoogleAppMeasurement/AdIdSupport (= 10.27.0) + - GoogleAppMeasurement (10.24.0): + - GoogleAppMeasurement/AdIdSupport (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - nanopb (< 2.30911.0, >= 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (10.27.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 10.27.0) + - GoogleAppMeasurement/AdIdSupport (10.24.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.24.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) - "GoogleUtilities/NSData+zlib (~> 7.11)" - nanopb (< 2.30911.0, >= 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (10.27.0): + - GoogleAppMeasurement/WithoutAdIdSupport (10.24.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/Network (~> 7.11) @@ -119,7 +119,7 @@ PODS: DEPENDENCIES: - Alamofire - - FirebaseAnalytics (> 10.24.0) + - FirebaseAnalytics (~> 10.24.0) - FirebaseCrashlytics - MASShortcut - Preferences (from `https://github.com/sindresorhus/Preferences.git`) @@ -164,7 +164,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Alamofire: ae5c501addb7afdbb13687d7f2f722c78734c2d3 - FirebaseAnalytics: f9211b719db260cc91aebee8bb539cb367d0dfd1 + FirebaseAnalytics: b5efc493eb0f40ec560b04a472e3e1a15d39ca13 FirebaseCore: 11dc8a16dfb7c5e3c3f45ba0e191a33ac4f50894 FirebaseCoreExtension: af5fd85e817ea9d19f9a2659a376cf9cf99f03c0 FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af @@ -172,7 +172,7 @@ SPEC CHECKSUMS: FirebaseInstallations: 766dabca09fd94aef922538aaf144cc4a6fb6869 FirebaseRemoteConfigInterop: 6c349a466490aeace3ce9c091c86be1730711634 FirebaseSessions: 2651b464e241c93fd44112f995d5ab663c970487 - GoogleAppMeasurement: f65fc137531af9ad647f1c0a42f3b6a4d3a98049 + GoogleAppMeasurement: f3abf08495ef2cba7829f15318c373b8d9226491 GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152 MASShortcut: 9c215e8a8a78f3d01ce56da48e2730ab66b538fa diff --git a/v2rayu/V2rayU/AppDelegate.swift b/v2rayu/V2rayU/AppDelegate.swift index 3fd7875645..ceb1e64947 100644 --- a/v2rayu/V2rayU/AppDelegate.swift +++ b/v2rayu/V2rayU/AppDelegate.swift @@ -112,10 +112,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { UserDefaults.set(forKey: .runMode, value: RunMode.global.rawValue) } V2rayServer.loadConfig() - if V2rayServer.count() == 0 { - // add default - V2rayServer.add(remark: "default", json: "", isValid: false) - } } @objc func handleAppleEvent(event: NSAppleEventDescriptor, replyEvent: NSAppleEventDescriptor) { diff --git a/v2rayu/V2rayU/Base.lproj/ConfigWindow.xib b/v2rayu/V2rayU/Base.lproj/ConfigWindow.xib index 8856af7679..a22aed4c72 100644 --- a/v2rayu/V2rayU/Base.lproj/ConfigWindow.xib +++ b/v2rayu/V2rayU/Base.lproj/ConfigWindow.xib @@ -2,7 +2,7 @@ - + @@ -192,106 +192,6 @@ Gw - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -301,7 +201,7 @@ Gw - + @@ -317,7 +217,7 @@ Gw - + @@ -342,7 +242,7 @@ Gw - + @@ -351,7 +251,7 @@ Gw - + @@ -414,7 +314,7 @@ Gw - + @@ -423,7 +323,7 @@ Gw - + @@ -473,7 +373,7 @@ Gw - + @@ -482,7 +382,7 @@ Gw - + @@ -491,7 +391,7 @@ Gw - + @@ -500,7 +400,7 @@ Gw - + @@ -509,7 +409,7 @@ Gw - + @@ -521,7 +421,7 @@ Gw - + @@ -534,7 +434,7 @@ Gw - + @@ -547,7 +447,7 @@ Gw - + @@ -559,7 +459,7 @@ Gw - + @@ -568,7 +468,7 @@ Gw - + @@ -605,7 +505,7 @@ Gw - + @@ -624,7 +524,7 @@ Gw - + @@ -633,7 +533,7 @@ Gw - + @@ -642,7 +542,7 @@ Gw - + @@ -651,7 +551,7 @@ Gw - + @@ -663,7 +563,7 @@ Gw - + @@ -676,7 +576,7 @@ Gw - + @@ -688,7 +588,7 @@ Gw - + @@ -697,7 +597,7 @@ Gw - + @@ -710,7 +610,7 @@ Gw - + @@ -722,7 +622,7 @@ Gw - + @@ -737,7 +637,7 @@ Gw - + @@ -746,7 +646,7 @@ Gw - + @@ -758,7 +658,7 @@ Gw - + @@ -770,7 +670,7 @@ Gw - + @@ -794,7 +694,7 @@ Gw - + @@ -803,7 +703,7 @@ Gw - + @@ -815,7 +715,7 @@ Gw - + @@ -830,7 +730,7 @@ Gw - + @@ -839,7 +739,7 @@ Gw - + @@ -851,7 +751,7 @@ Gw - + @@ -863,7 +763,7 @@ Gw - + @@ -872,7 +772,7 @@ Gw - + @@ -881,7 +781,7 @@ Gw - + @@ -890,7 +790,7 @@ Gw - + @@ -902,7 +802,7 @@ Gw - + @@ -917,7 +817,7 @@ Gw - + @@ -926,7 +826,7 @@ Gw - + @@ -938,7 +838,7 @@ Gw - + @@ -947,7 +847,7 @@ Gw - + @@ -956,7 +856,7 @@ Gw - + @@ -965,7 +865,7 @@ Gw - + @@ -974,7 +874,7 @@ Gw - + @@ -986,7 +886,7 @@ Gw - + @@ -995,7 +895,7 @@ Gw - + @@ -1004,7 +904,7 @@ Gw - + @@ -1040,7 +940,7 @@ Gw - + @@ -1065,7 +965,7 @@ Gw - + @@ -1077,7 +977,7 @@ Gw - + @@ -1086,7 +986,7 @@ Gw - + @@ -1097,7 +997,7 @@ Gw - + @@ -1137,7 +1037,7 @@ Gw - + @@ -1146,7 +1046,7 @@ Gw - + @@ -1158,7 +1058,7 @@ Gw - + @@ -1167,7 +1067,7 @@ Gw - + @@ -1179,7 +1079,7 @@ Gw - + @@ -1188,7 +1088,7 @@ Gw - + @@ -1200,7 +1100,7 @@ Gw - + @@ -1209,7 +1109,7 @@ Gw - + @@ -1225,7 +1125,7 @@ Gw - + @@ -1245,7 +1145,7 @@ Gw - + @@ -1272,7 +1172,7 @@ Gw - + @@ -1281,7 +1181,7 @@ Gw - + @@ -1301,7 +1201,7 @@ Gw - + @@ -1310,7 +1210,7 @@ Gw - + @@ -1325,7 +1225,7 @@ Gw - + @@ -1334,7 +1234,7 @@ Gw - + @@ -1346,7 +1246,7 @@ Gw - + @@ -1355,7 +1255,7 @@ Gw - + @@ -1367,7 +1267,7 @@ Gw - + @@ -1379,7 +1279,7 @@ Gw - + @@ -1388,7 +1288,7 @@ Gw - + @@ -1400,7 +1300,7 @@ Gw - + @@ -1409,7 +1309,7 @@ Gw - + @@ -1421,7 +1321,7 @@ Gw - + @@ -1430,7 +1330,7 @@ Gw - + @@ -1439,7 +1339,7 @@ Gw - + @@ -1489,7 +1389,7 @@ Gw - + @@ -1504,7 +1404,7 @@ Gw - + @@ -1513,7 +1413,7 @@ Gw - + @@ -1525,7 +1425,7 @@ Gw - + @@ -1537,7 +1437,7 @@ Gw - + @@ -1552,7 +1452,7 @@ Gw - + @@ -1561,7 +1461,7 @@ Gw - + @@ -1573,7 +1473,7 @@ Gw - + @@ -1585,7 +1485,7 @@ Gw - + @@ -1600,7 +1500,7 @@ Gw - + @@ -1612,7 +1512,7 @@ Gw - + @@ -1621,7 +1521,7 @@ Gw - + @@ -1630,7 +1530,7 @@ Gw - + @@ -1639,7 +1539,7 @@ Gw - + @@ -1665,7 +1565,7 @@ Gw - + @@ -1695,7 +1595,7 @@ Gw - + @@ -1704,7 +1604,7 @@ Gw - + @@ -1743,7 +1643,7 @@ Gw - + @@ -1772,7 +1672,7 @@ Gw - + @@ -1781,7 +1681,7 @@ Gw - + @@ -1801,7 +1701,7 @@ Gw - + @@ -1810,7 +1710,7 @@ Gw - + @@ -1881,9 +1781,109 @@ Gw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1949,7 +1949,7 @@ Gw - + diff --git a/v2rayu/V2rayU/Base.lproj/MainMenu.xib b/v2rayu/V2rayU/Base.lproj/MainMenu.xib index 67d0c21709..19542c388f 100644 --- a/v2rayu/V2rayU/Base.lproj/MainMenu.xib +++ b/v2rayu/V2rayU/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + diff --git a/v2rayu/V2rayU/ConfigWindow.swift b/v2rayu/V2rayU/ConfigWindow.swift index 26deb1f760..2949377078 100644 --- a/v2rayu/V2rayU/ConfigWindow.swift +++ b/v2rayu/V2rayU/ConfigWindow.swift @@ -11,23 +11,15 @@ import Alamofire var v2rayConfig: V2rayConfig = V2rayConfig() -var configWindow = ConfigWindowController() +let configWindow = ConfigWindowController() func OpenConfigWindow(){ - if configWindow != nil { - // close before - - } else { - // renew - configWindow = ConfigWindowController() - } - - _ = showDock(state: true) - // show window - configWindow.showWindow(nil) - configWindow.window?.makeKeyAndOrderFront(configWindow.self) - // bring to front - NSApp.activate(ignoringOtherApps: true) + // show window + configWindow.showWindow(nil) + configWindow.window?.makeKeyAndOrderFront(configWindow.self) + // bring to front + NSApp.activate(ignoringOtherApps: true) + showDock(state: true) } class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDelegate { @@ -165,7 +157,8 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel override func windowDidLoad() { super.windowDidLoad() - + + V2rayServer.loadConfig() // table view self.serversTableView.delegate = self self.serversTableView.dataSource = self @@ -177,60 +170,64 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel @IBAction func addRemoveServer(_ sender: NSSegmentedCell) { // 0 add,1 remove let seg = addRemoveButton.indexOfSelectedItem - - switch seg { + DispatchQueue.global().async { + switch seg { // add server config - case 0: - // add - V2rayServer.add() - - // reload data - self.serversTableView.reloadData() - // selected current row - self.serversTableView.selectRowIndexes(NSIndexSet(index: V2rayServer.count() - 1) as IndexSet, byExtendingSelection: false) - - break - + case 0: + // add + V2rayServer.add() + + DispatchQueue.main.sync { + V2rayServer.loadConfig() + // reload data + self.serversTableView.reloadData() + // selected current row + self.serversTableView.selectRowIndexes(NSIndexSet(index: V2rayServer.count() - 1) as IndexSet, byExtendingSelection: false) + } + break + // delete server config - case 1: - // get seleted index - let idx = self.serversTableView.selectedRow - // remove - V2rayServer.remove(idx: idx) - - // reload - V2rayServer.loadConfig() - menuController.showServers() - - // selected prev row - let cnt: Int = V2rayServer.count() - var rowIndex: Int = idx - 1 - if idx > 0 && idx < cnt { - rowIndex = idx - } - - // reload - self.serversTableView.reloadData() - - // fix - if cnt > 1 { - // selected row - self.serversTableView.selectRowIndexes(NSIndexSet(index: rowIndex) as IndexSet, byExtendingSelection: false) - } - - if rowIndex >= 0 { - self.loadJsonData(rowIndex: rowIndex) - } else { - self.serversTableView.becomeFirstResponder() - } - - // refresh menu - menuController.showServers() - break - + case 1: + // get seleted index + let idx = self.serversTableView.selectedRow + // remove + V2rayServer.remove(idx: idx) + + // reload + V2rayServer.loadConfig() + menuController.showServers() + + // selected prev row + let cnt: Int = V2rayServer.count() + var rowIndex: Int = idx - 1 + if idx > 0 && idx < cnt { + rowIndex = idx + } + + DispatchQueue.main.sync { + // reload + self.serversTableView.reloadData() + // fix + if cnt > 1 { + // selected row + self.serversTableView.selectRowIndexes(NSIndexSet(index: rowIndex) as IndexSet, byExtendingSelection: false) + } + + if rowIndex >= 0 { + self.loadJsonData(rowIndex: rowIndex) + } else { + self.serversTableView.becomeFirstResponder() + } + } + + // refresh menu + menuController.showServers() + break + // unknown action - default: - return + default: + return + } } } @@ -273,7 +270,6 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel func switchToImportView() { // reset error self.errTip.stringValue = "" - self.exportData() v2rayConfig.checkManualValid() @@ -554,7 +550,7 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel self.configText.string = item?.json ?? "" v2rayConfig.isValid = item?.isValid ?? false self.jsonUrl.stringValue = item?.url ?? "" - + v2rayConfig.parseJson(jsonText: self.configText.string) if v2rayConfig.errors.count > 0 { self.errTip.stringValue = v2rayConfig.errors[0] @@ -567,7 +563,9 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel v2rayConfig.parseJson(jsonText: self.configText.string) if v2rayConfig.errors.count > 0 { - self.errTip.stringValue = v2rayConfig.errors[0] + DispatchQueue.main.sync { + self.errTip.stringValue = v2rayConfig.errors[0] + } } // save @@ -582,7 +580,9 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel } self.refreshServerList(ok: errMsg.count == 0) } else { - self.errTip.stringValue = errMsg + DispatchQueue.main.sync { + self.errTip.stringValue = errMsg + } } } @@ -591,8 +591,8 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel menuController.showServers() // if server is current if let curName = UserDefaults.get(forKey: .v2rayCurrentServerName) { - let v2rayItemList = V2rayServer.list() - if curName == v2rayItemList[self.serversTableView.selectedRow].name { + let v2rayItemList = V2rayServer.all() + if v2rayItemList.count > self.serversTableView.selectedRow && curName == v2rayItemList[self.serversTableView.selectedRow].name { if ok { V2rayLaunch.startV2rayCore() } else { @@ -649,12 +649,16 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel // download json file Alamofire.request(jsonUrl.stringValue).responseString { DataResponse in if (DataResponse.error != nil) { - self.errTip.stringValue = "error: " + DataResponse.error.debugDescription + DispatchQueue.main.async{ + self.errTip.stringValue = "error: " + DataResponse.error.debugDescription + } return } if DataResponse.value != nil { - self.configText.string = v2rayConfig.formatJson(json: DataResponse.value ?? text) + DispatchQueue.main.async{ + self.configText.string = v2rayConfig.formatJson(json: DataResponse.value ?? text) + } } } } @@ -664,115 +668,142 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel guard let url = URL(string: "https://www.v2ray.com/chapter_02/transport/tcp.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } @IBAction func goDsHelp(_ sender: Any) { guard let url = URL(string: "https://www.v2ray.com/chapter_02/transport/domainsocket.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } @IBAction func goQuicHelp(_ sender: Any) { guard let url = URL(string: "https://www.v2ray.com/chapter_02/transport/quic.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } @IBAction func goProtocolHelp(_ sender: NSButton) { guard let url = URL(string: "https://www.v2ray.com/chapter_02/protocols/vmess.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } @IBAction func goVersionHelp(_ sender: Any) { guard let url = URL(string: "https://www.v2ray.com/chapter_02/01_overview.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } @IBAction func goStreamHelp(_ sender: Any) { guard let url = URL(string: "https://www.v2ray.com/chapter_02/05_transport.html") else { return } - NSWorkspace.shared.open(url) + DispatchQueue.main.async{ + NSWorkspace.shared.open(url) + } } func switchSteamView(network: String) { - networkView.subviews.forEach { - $0.isHidden = true - } - - switch network { - case "tcp": - self.tcpView.isHidden = false - break; - case "kcp": - self.kcpView.isHidden = false - break; - case "domainsocket": - self.dsView.isHidden = false - break; - case "ws": - self.wsView.isHidden = false - break; - case "h2": - self.h2View.isHidden = false - break; - case "quic": - self.quicView.isHidden = false - break; - case "grpc": - self.grpcView.isHidden = false - break; - default: // vmess - self.tcpView.isHidden = false - break + DispatchQueue.main.async{ + self.networkView.subviews.forEach { + $0.isHidden = true + } + + switch network { + case "tcp": + self.tcpView.isHidden = false + break; + case "kcp": + self.kcpView.isHidden = false + break; + case "domainsocket": + self.dsView.isHidden = false + break; + case "ws": + self.wsView.isHidden = false + break; + case "h2": + self.h2View.isHidden = false + break; + case "quic": + self.quicView.isHidden = false + break; + case "grpc": + self.grpcView.isHidden = false + break; + default: // vmess + self.tcpView.isHidden = false + break + } } } func switchOutboundView(protocolTitle: String) { - serverView.subviews.forEach { - $0.isHidden = true - } - - switch protocolTitle { - case "vmess": - self.VmessView.isHidden = false - break - case "vless": - self.VlessView.isHidden = false - break - case "shadowsocks": - self.ShadowsocksView.isHidden = false - break - case "socks": - self.SocksView.isHidden = false - break - case "trojan": - self.TrojanView.isHidden = false - break - default: // vmess - self.VmessView.isHidden = true - break + DispatchQueue.main.async{ + self.serverView.subviews.forEach { + $0.isHidden = true + } + + switch protocolTitle { + case "vmess": + self.VmessView.isHidden = false + break + case "vless": + self.VlessView.isHidden = false + break + case "shadowsocks": + self.ShadowsocksView.isHidden = false + break + case "socks": + self.SocksView.isHidden = false + break + case "trojan": + self.TrojanView.isHidden = false + break + default: // vmess + self.VmessView.isHidden = true + break + } } } func switchSecurityView(securityTitle: String) { - print("switchSecurityView",securityTitle) - self.tlsView.isHidden = true - self.realityView.isHidden = true - if securityTitle == "reality" { - self.realityView.isHidden = false - } else { - self.tlsView.isHidden = false + DispatchQueue.main.async{ + print("switchSecurityView",securityTitle) + self.tlsView.isHidden = true + self.realityView.isHidden = true + if securityTitle == "reality" { + self.realityView.isHidden = false + } else { + self.tlsView.isHidden = false + } } } + func reloadData(){ + DispatchQueue.main.async{ + if self.serversTableView != nil { + V2rayServer.loadConfig() + self.serversTableView.reloadData() + } + } + } + @IBAction func switchSteamSecurity(_ sender: NSPopUpButtonCell) { if let item = switchSecurity.selectedItem { self.switchSecurityView(securityTitle: item.title) @@ -795,43 +826,47 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel guard let item = sender.selectedItem else { return } - // url - if item.title == "url" { - jsonUrl.stringValue = "" - selectFileBtn.isHidden = true - importBtn.isHidden = false - jsonUrl.isEditable = true - } else { - // local file - jsonUrl.stringValue = "" - selectFileBtn.isHidden = false - importBtn.isHidden = true - jsonUrl.isEditable = false + DispatchQueue.main.async{ + // url + if item.title == "url" { + self.jsonUrl.stringValue = "" + self.selectFileBtn.isHidden = true + self.importBtn.isHidden = false + self.jsonUrl.isEditable = true + } else { + // local file + self.jsonUrl.stringValue = "" + self.selectFileBtn.isHidden = false + self.importBtn.isHidden = true + self.jsonUrl.isEditable = false + } } } @IBAction func browseFile(_ sender: NSButton) { - jsonUrl.stringValue = "" - let dialog = NSOpenPanel() - - dialog.title = "Choose a .json file"; - dialog.showsResizeIndicator = true; - dialog.showsHiddenFiles = false; - dialog.canChooseDirectories = true; - dialog.canCreateDirectories = true; - dialog.allowsMultipleSelection = false; - dialog.allowedFileTypes = ["json", "txt"]; - - if (dialog.runModal() == NSApplication.ModalResponse.OK) { - let result = dialog.url // Pathname of the file - - if (result != nil) { - jsonUrl.stringValue = result?.absoluteString ?? "" - self.importJson() + DispatchQueue.main.async{ + self.jsonUrl.stringValue = "" + let dialog = NSOpenPanel() + + dialog.title = "Choose a .json file"; + dialog.showsResizeIndicator = true; + dialog.showsHiddenFiles = false; + dialog.canChooseDirectories = true; + dialog.canCreateDirectories = true; + dialog.allowsMultipleSelection = false; + dialog.allowedFileTypes = ["json", "txt"]; + + if (dialog.runModal() == NSApplication.ModalResponse.OK) { + let result = dialog.url // Pathname of the file + + if (result != nil) { + self.jsonUrl.stringValue = result?.absoluteString ?? "" + self.importJson() + } + } else { + // User clicked on "Cancel" + return } - } else { - // User clicked on "Cancel" - return } } @@ -845,19 +880,25 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel @IBAction func cancel(_ sender: NSButton) { // hide dock icon and close all opened windows - _ = showDock(state: false) + showDock(state: false) } @IBAction func goAdvanceSetting(_ sender: Any) { - preferencesWindowController.show(preferencePane: .advanceTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .advanceTab) + } } @IBAction func goSubscribeSetting(_ sender: Any) { - preferencesWindowController.show(preferencePane: .subscribeTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .subscribeTab) + } } @IBAction func goRoutingRuleSetting(_ sender: Any) { - preferencesWindowController.show(preferencePane: .routingTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .routingTab) + } } } @@ -883,12 +924,16 @@ extension ConfigWindowController: NSTableViewDataSource { NSLog("remark is nil") return } - // edit item remark - V2rayServer.edit(rowIndex: row, remark: remark) - // reload table - tableView.reloadData() - // reload menu - menuController.showServers() + DispatchQueue.global().async { + // edit item remark + V2rayServer.edit(rowIndex: row, remark: remark) + // reload table + DispatchQueue.main.async { + tableView.reloadData() + } + // reload menu + menuController.showServers() + } } } @@ -942,16 +987,18 @@ extension ConfigWindowController: NSTableViewDelegate { newIndexOffset += 1 } } - - // move - V2rayServer.move(oldIndex: oldIndexLast, newIndex: newIndexLast) - // set selected - self.serversTableView.selectRowIndexes(NSIndexSet(index: newIndexLast) as IndexSet, byExtendingSelection: false) - // reload table - self.serversTableView.reloadData() - // reload menu - menuController.showServers() - + DispatchQueue.global().async { + // move + V2rayServer.move(oldIndex: oldIndexLast, newIndex: newIndexLast) + DispatchQueue.main.async { + // set selected + self.serversTableView.selectRowIndexes(NSIndexSet(index: newIndexLast) as IndexSet, byExtendingSelection: false) + // reload table + self.serversTableView.reloadData() + } + // reload menu + menuController.showServers() + } return true } } diff --git a/v2rayu/V2rayU/MainMenu.swift b/v2rayu/V2rayU/MainMenu.swift index d0aa946e36..fdb578b8cb 100644 --- a/v2rayu/V2rayU/MainMenu.swift +++ b/v2rayu/V2rayU/MainMenu.swift @@ -31,6 +31,7 @@ class MenuController: NSObject, NSMenuDelegate { // when menu.xib loaded override func awakeFromNib() { print("awakeFromNib") + super.awakeFromNib() statusMenu.delegate = self statusItem.menu = statusMenu @@ -42,89 +43,85 @@ class MenuController: NSObject, NSMenuDelegate { } func setStatusOff() { - v2rayStatusItem.title = "v2ray-core: Off" + (" (v" + appVersion + ")") - toggleV2rayItem.title = "Turn v2ray-core On" + DispatchQueue.main.async { + self.v2rayStatusItem.title = "v2ray-core: Off" + (" (v" + appVersion + ")") + self.toggleV2rayItem.title = "Turn v2ray-core On" - if let button = statusItem.button { - // UI API called on a background thread: -[NSStatusBarButton setImage:] - DispatchQueue.main.async { + if let button = self.statusItem.button { button.image = NSImage(named: NSImage.Name("IconOff")) } + + self.pacMode.state = .off + self.globalMode.state = .off + self.manualMode.state = .off + + // set off + UserDefaults.setBool(forKey: .v2rayTurnOn, value: false) } - - self.pacMode.state = .off - self.globalMode.state = .off - self.manualMode.state = .off - - // set off - UserDefaults.setBool(forKey: .v2rayTurnOn, value: false) } func setModeIcon(mode: RunMode) { - var iconName = "IconOn" + DispatchQueue.main.async { - switch mode { - case .global: - iconName = "IconOnG" - self.pacMode.state = .off - self.globalMode.state = .on - self.manualMode.state = .off - case .manual: - iconName = "IconOnM" - self.pacMode.state = .off - self.globalMode.state = .off - self.manualMode.state = .on - case .pac: - iconName = "IconOnP" - self.pacMode.state = .on - self.globalMode.state = .off - self.manualMode.state = .off - default: - break - } + var iconName = "IconOn" - if let button = statusItem.button { - // UI API called on a background thread: -[NSStatusBarButton setImage:] - DispatchQueue.main.async { + switch mode { + case .global: + iconName = "IconOnG" + self.pacMode.state = .off + self.globalMode.state = .on + self.manualMode.state = .off + case .manual: + iconName = "IconOnM" + self.pacMode.state = .off + self.globalMode.state = .off + self.manualMode.state = .on + case .pac: + iconName = "IconOnP" + self.pacMode.state = .on + self.globalMode.state = .off + self.manualMode.state = .off + default: + break + } + + if let button = self.statusItem.button { button.image = NSImage(named: NSImage.Name(iconName)) } } } - + func setStatusOn(mode: RunMode) { - v2rayStatusItem.title = "v2ray-core: On" + (" (v" + appVersion + ")") - toggleV2rayItem.title = "Turn v2ray-core Off" - - self.setModeIcon(mode: mode) - - // set on - UserDefaults.setBool(forKey: .v2rayTurnOn, value: true) + DispatchQueue.main.async { + self.v2rayStatusItem.title = "v2ray-core: On" + (" (v" + appVersion + ")") + self.toggleV2rayItem.title = "Turn v2ray-core Off" + self.setModeIcon(mode: mode) + UserDefaults.setBool(forKey: .v2rayTurnOn, value: true) + } } func setStatusMenuTip(pingTip: String) { - do { - DispatchQueue.main.async { - if self.statusMenu.item(withTag: 1) != nil { - self.statusMenu.item(withTag: 1)!.title = pingTip - } + DispatchQueue.main.async { + if let item = self.statusMenu.item(withTag: 1) { + item.title = pingTip } } } func showServers() { - print("showServers") - let _subMenus = getServerMenus() - lock.lock() - do { + DispatchQueue.global().async { + self.lock.lock() + defer { self.lock.unlock() } + + print("showServers") + let _subMenus = self.getServerMenus() + DispatchQueue.main.async { self.serverItems.submenu = _subMenus // fix: must be used from main thread only - if configWindow != nil && configWindow.serversTableView != nil { - configWindow.serversTableView.reloadData() - } + configWindow.reloadData() } } - lock.unlock() } func getServerMenus() -> NSMenu { @@ -135,10 +132,8 @@ class MenuController: NSObject, NSMenuDelegate { var validCount = 0 var groupMenus: Dictionary = [String: NSMenu]() var chooseGroup = "" - // reload servers - V2rayServer.loadConfig() // for each - for item in V2rayServer.list() { + for item in V2rayServer.all() { validCount+=1 let menuItem: NSMenuItem = self.buildServerItem(item: item, curSer: curSer) var groupTag: String = item.subscribe @@ -217,45 +212,43 @@ class MenuController: NSObject, NSMenuDelegate { } @IBAction func openPreferenceGeneral(_ sender: NSMenuItem) { - preferencesWindowController.show(preferencePane: .generalTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .generalTab) + } } @IBAction func openPreferenceSubscribe(_ sender: NSMenuItem) { - preferencesWindowController.show(preferencePane: .subscribeTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .subscribeTab) + } } @IBAction func openPreferencePac(_ sender: NSMenuItem) { - preferencesWindowController.show(preferencePane: .pacTab) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .pacTab) + } } - // switch server @IBAction func switchServer(_ sender: NSMenuItem) { guard let obj = sender.representedObject as? V2rayItem else { NSLog("switchServer err") return } - // set current UserDefaults.set(forKey: .v2rayCurrentServerName, value: obj.name) - // restart V2rayLaunch.restartV2ray() } - // open config window @IBAction func openConfig(_ sender: NSMenuItem) { OpenConfigWindow() } - /// When a window was closed this methods takes care of releasing its controller. - /// - /// - parameter notification: The notification. @objc private func configWindowWillClose(notification: Notification) { guard let object = notification.object as? NSWindow else { return } - // config window title is "V2rayU" if object.title == "V2rayU" { - _ = showDock(state: false) + showDock(state: false) } } @@ -276,7 +269,6 @@ class MenuController: NSObject, NSMenuDelegate { V2rayLaunch.restartV2ray() } - // MARK: - actions @IBAction func switchGlobalMode(_ sender: NSMenuItem) { UserDefaults.set(forKey: .runMode, value: RunMode.global.rawValue) V2rayLaunch.restartV2ray() diff --git a/v2rayu/V2rayU/Ping.swift b/v2rayu/V2rayU/Ping.swift index 29bc78022b..59de2a6e2d 100644 --- a/v2rayu/V2rayU/Ping.swift +++ b/v2rayu/V2rayU/Ping.swift @@ -18,7 +18,7 @@ let second: Double = 1000000 let pingURL = URL(string: "http://www.gstatic.com/generate_204")! class PingSpeed: NSObject { - let semaphore = DispatchSemaphore(value: 30) // work pool + let maxConcurrentTasks = 30 func pingAll() { NSLog("ping start") @@ -33,7 +33,7 @@ class PingSpeed: NSObject { inPing = true killAllPing() - + let itemList = V2rayServer.all() if itemList.count == 0 { NSLog("no items") @@ -47,9 +47,7 @@ class PingSpeed: NSObject { } else { pingTip = "Ping Speed - 测试中" } - DispatchQueue.main.async { - menuController.setStatusMenuTip(pingTip: pingTip) - } + menuController.setStatusMenuTip(pingTip: pingTip) Task { do { try await pingTaskGroup(items: itemList) @@ -59,29 +57,36 @@ class PingSpeed: NSObject { } } - func pingTaskGroup(items: [V2rayItem]) async throws { - await withThrowingTaskGroup(of: Int.self) { group in - for item in items { - group.addTask { - do { - await self.semaphore.wait() - defer { - self.semaphore.signal() - } - try await self.pingEachServer(item: item) - } catch let error { - NSLog("pingEachServer error: \(error)") - } - return 1 - } - } + func pingTaskGroup(items: [V2rayItem]) async throws { + let taskChunks = stride(from: 0, to: items.count, by: maxConcurrentTasks).map { + Array(items[$0.. String { if !userRuleTxt.contains("api.github.com") { userRuleTxt.append("\n||api.github.com") } - if !userRuleTxt.contains("api.github.com") { - userRuleTxt.append("\n||api.github.com") - } if !userRuleTxt.contains("openai.com") { userRuleTxt.append("\n||openai.com") } diff --git a/v2rayu/V2rayU/Preference/PreferenceSubscription.swift b/v2rayu/V2rayU/Preference/PreferenceSubscription.swift index 17aff10d5e..b16e199443 100644 --- a/v2rayu/V2rayU/Preference/PreferenceSubscription.swift +++ b/v2rayu/V2rayU/Preference/PreferenceSubscription.swift @@ -41,12 +41,12 @@ final class PreferenceSubscribeViewController: NSViewController, PreferencePane, self.logView.isHidden = true self.subscribeView.isHidden = false self.logArea.string = "" + // reload tableview + V2raySubscription.loadConfig() // table view self.tableView.delegate = self self.tableView.dataSource = self self.tableView.reloadData() - // reload tableview - V2raySubscription.loadConfig() // set global hotkey NotificationCenter.default.addObserver(self, selector: #selector(self.updateTip), name: NOTIFY_UPDATE_SubSync, object: nil) @@ -105,6 +105,7 @@ final class PreferenceSubscribeViewController: NSViewController, PreferencePane, self.url.stringValue = "" // reload tableview + V2raySubscription.loadConfig() self.tableView.reloadData() } @@ -130,6 +131,7 @@ final class PreferenceSubscribeViewController: NSViewController, PreferencePane, } // reload tableview + V2raySubscription.loadConfig() self.tableView.reloadData() // fix @@ -138,12 +140,7 @@ final class PreferenceSubscribeViewController: NSViewController, PreferencePane, self.tableView.selectRowIndexes(NSIndexSet(index: rowIndex) as IndexSet, byExtendingSelection: true) } - do { - // refresh server - DispatchQueue.main.async { - menuController.showServers() - } - } + menuController.showServers() } } diff --git a/v2rayu/V2rayU/ToastWindow.swift b/v2rayu/V2rayU/ToastWindow.swift index f08ed43c95..ea9a4a1ffa 100644 --- a/v2rayu/V2rayU/ToastWindow.swift +++ b/v2rayu/V2rayU/ToastWindow.swift @@ -11,22 +11,33 @@ import Cocoa var toastWindow = ToastWindowController() func makeToast(message: String, displayDuration: Double? = 3) { - print("makeToast", message) - toastWindow.close() - toastWindow = ToastWindowController() - toastWindow.message = message - toastWindow.showWindow(Any.self) - toastWindow.fadeInHud(displayDuration) - - NSApp.activate(ignoringOtherApps: true) + // UI 更新需要在主线程上执行 + DispatchQueue.main.async { + print("makeToast", message) + toastWindow.close() + toastWindow = ToastWindowController() + toastWindow.message = message + toastWindow.showWindow(Any.self) + toastWindow.fadeInHud(displayDuration) + + NSApp.activate(ignoringOtherApps: true) + } } -func alertDialog(title: String, message: String) -> Bool { - let myPopup = NSAlert() - myPopup.messageText = title - myPopup.informativeText = message - myPopup.alertStyle = .warning - return myPopup.runModal() == NSApplication.ModalResponse.alertFirstButtonReturn +func alertDialog(title: String, message: String) { + DispatchQueue.main.async { + let alert = NSAlert() + alert.messageText = title + alert.informativeText = message + alert.alertStyle = .warning + let response = alert.runModal() + + if response == .alertFirstButtonReturn { + print("OK clicked") + } else { + print("Cancel clicked") + } + } } class ToastWindowController: NSWindowController { diff --git a/v2rayu/V2rayU/Util.swift b/v2rayu/V2rayU/Util.swift index 1782ff5d8c..91234a91fb 100644 --- a/v2rayu/V2rayU/Util.swift +++ b/v2rayu/V2rayU/Util.swift @@ -568,20 +568,20 @@ func ClearLogs() { try! txt.write(to: URL.init(fileURLWithPath: logFilePath), atomically: true, encoding: String.Encoding.utf8) } -func showDock(state: Bool) -> Bool { - // Get transform state. - var transformState: ProcessApplicationTransformState - if state { - transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication) - } else { - transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication) +func showDock(state: Bool) { + DispatchQueue.main.async { + // Get transform state. + var transformState: ProcessApplicationTransformState + if state { + transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication) + } else { + transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication) + } + + // Show / hide dock icon. + var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess)) + TransformProcessType(&psn, transformState) } - - // Show / hide dock icon. - var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess)) - let transformStatus: OSStatus = TransformProcessType(&psn, transformState) - - return transformStatus == 0 } func noticeTip(title: String = "", informativeText: String = "") { diff --git a/v2rayu/V2rayU/V2rayLaunch.swift b/v2rayu/V2rayU/V2rayLaunch.swift index e5e3d3c8b5..6197927242 100644 --- a/v2rayu/V2rayU/V2rayLaunch.swift +++ b/v2rayu/V2rayU/V2rayLaunch.swift @@ -175,12 +175,10 @@ class V2rayLaunch: NSObject { // start and show servers self.startV2rayCore() } else { - DispatchQueue.main.async { - // show off status - menuController.setStatusOff() - // show servers - menuController.showServers() - } + // show off status + menuController.setStatusOff() + // show servers + menuController.showServers() } // auto update subscribe servers @@ -244,9 +242,8 @@ class V2rayLaunch: NSObject { self.setRunMode(mode: runMode) // reload menu - DispatchQueue.main.async { - menuController.showServers() - } + menuController.showServers() + // ping current PingCurrent(item: v2ray).doPing() } @@ -256,12 +253,10 @@ class V2rayLaunch: NSObject { V2rayLaunch.Stop() // off system proxy V2rayLaunch.setSystemProxy(mode: .off) - DispatchQueue.main.async { - // set status - menuController.setStatusOff() - // reload menu - menuController.showServers() - } + // set status + menuController.setStatusOff() + // reload menu + menuController.showServers() } static func Start() -> Bool { @@ -279,8 +274,10 @@ class V2rayLaunch: NSObject { toast = "http port \(httpPort) has been used, please replace it from advance setting" title = "Port is already in use" } - _ = alertDialog(title: title, message: toast) - preferencesWindowController.show(preferencePane: .advanceTab) + alertDialog(title: title, message: toast) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .advanceTab) + } return false } @@ -292,8 +289,10 @@ class V2rayLaunch: NSObject { toast = "socks port \(sockPort) has been used, please replace it from advance setting" title = "Port is already in use" } - _ = alertDialog(title: title, message: toast) - preferencesWindowController.show(preferencePane: .advanceTab) + alertDialog(title: title, message: toast) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .advanceTab) + } return false } @@ -384,8 +383,10 @@ class V2rayLaunch: NSObject { toast = "pac port \(pacPort) has been used, please replace from advance setting" title = "Port is already in use" } - _ = alertDialog(title: title, message: toast) - preferencesWindowController.show(preferencePane: .advanceTab) + alertDialog(title: title, message: toast) + DispatchQueue.main.async { + preferencesWindowController.show(preferencePane: .advanceTab) + } return } @@ -468,11 +469,13 @@ func checkV2rayUVersion() { let curVer = newVer.replacingOccurrences(of: "v", with: "").versionToInt() // compare with [Int] - if oldVer.lexicographicallyPrecedes(curVer) { - menuController.newVersionItem.isHidden = false - menuController.newVersionItem.title = "has new version " + newVer - } else { - menuController.newVersionItem.isHidden = true + DispatchQueue.main.async { + if oldVer.lexicographicallyPrecedes(curVer) { + menuController.newVersionItem.isHidden = false + menuController.newVersionItem.title = "has new version " + newVer + } else { + menuController.newVersionItem.isHidden = true + } } } } diff --git a/v2rayu/V2rayU/V2raySubscription.swift b/v2rayu/V2rayU/V2raySubscription.swift index 5264acb30b..fba04ce134 100644 --- a/v2rayu/V2rayU/V2raySubscription.swift +++ b/v2rayu/V2rayU/V2raySubscription.swift @@ -236,7 +236,7 @@ let NOTIFY_UPDATE_SubSync = Notification.Name(rawValue: "NOTIFY_UPDATE_SubSync") class V2raySubSync: NSObject { var V2raySubSyncing = false - let semaphore = DispatchSemaphore(value: 2) // work pool + let maxConcurrentTasks = 1 // work pool static var shared = V2raySubSync() // Initialization @@ -253,8 +253,6 @@ class V2raySubSync: NSObject { } self.V2raySubSyncing = true NSLog("V2raySubSync start") - - V2raySubscription.loadConfig() let list = V2raySubscription.list() @@ -272,23 +270,29 @@ class V2raySubSync: NSObject { } func syncTaskGroup(items: [V2raySubItem]) async throws { - await withThrowingTaskGroup(of: Int.self) { group in - for item in items { - group.addTask { - do { - await self.semaphore.wait() - defer { - self.semaphore.signal() - } - try await self.dlFromUrl(url: item.url, subscribe: item.name) - } catch let error { - NSLog("syncTaskGroup error: \(error)") - } - return 1 - } - } + let taskChunks = stride(from: 0, to: items.count, by: maxConcurrentTasks).map { + Array(items[$0.. 50 { - break // limit 50 - } // import every server if (uri.count > 0) { let filterUri = uri.trimmingCharacters(in: .whitespacesAndNewlines) diff --git a/xray-core/core/core.go b/xray-core/core/core.go index 0cccfd77c4..53f58841e2 100644 --- a/xray-core/core/core.go +++ b/xray-core/core/core.go @@ -21,7 +21,7 @@ import ( var ( Version_x byte = 1 Version_y byte = 8 - Version_z byte = 15 + Version_z byte = 16 ) var ( diff --git a/xray-core/transport/internet/splithttp/dialer.go b/xray-core/transport/internet/splithttp/dialer.go index 43dccf8523..b064cc56d7 100644 --- a/xray-core/transport/internet/splithttp/dialer.go +++ b/xray-core/transport/internet/splithttp/dialer.go @@ -16,6 +16,7 @@ import ( "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/session" + "github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/semaphore" "github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/transport/internet" @@ -44,18 +45,6 @@ var ( globalDialerAccess sync.Mutex ) -func destroyHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) { - globalDialerAccess.Lock() - defer globalDialerAccess.Unlock() - - if globalDialerMap == nil { - globalDialerMap = make(map[dialerConf]reusedClient) - } - - delete(globalDialerMap, dialerConf{dest, streamSettings}) - -} - func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) reusedClient { globalDialerAccess.Lock() defer globalDialerAccess.Unlock() @@ -77,7 +66,7 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in } dialContext := func(ctxInner context.Context) (net.Conn, error) { - conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) + conn, err := internet.DialSystem(ctxInner, dest, streamSettings.SocketSettings) if err != nil { return nil, err } @@ -85,7 +74,7 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in if gotlsConfig != nil { if fingerprint := tls.GetFingerprint(tlsConfig.Fingerprint); fingerprint != nil { conn = tls.UClient(conn, gotlsConfig, fingerprint) - if err := conn.(*tls.UConn).HandshakeContext(ctx); err != nil { + if err := conn.(*tls.UConn).HandshakeContext(ctxInner); err != nil { return nil, err } } else { @@ -171,49 +160,73 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me var remoteAddr gonet.Addr var localAddr gonet.Addr + // this is done when the TCP/UDP connection to the server was established, + // and we can unblock the Dial function and print correct net addresses in + // logs + gotConn := done.New() - trace := &httptrace.ClientTrace{ - GotConn: func(connInfo httptrace.GotConnInfo) { - remoteAddr = connInfo.Conn.RemoteAddr() - localAddr = connInfo.Conn.LocalAddr() - }, - } + var downResponse io.ReadCloser + gotDownResponse := done.New() sessionIdUuid := uuid.New() sessionId := sessionIdUuid.String() - req, err := http.NewRequestWithContext( - httptrace.WithClientTrace(ctx, trace), - "GET", - requestURL.String()+"?session="+sessionId, - nil, - ) - if err != nil { - return nil, err - } + go func() { + trace := &httptrace.ClientTrace{ + GotConn: func(connInfo httptrace.GotConnInfo) { + remoteAddr = connInfo.Conn.RemoteAddr() + localAddr = connInfo.Conn.LocalAddr() + gotConn.Close() + }, + } - req.Header = transportConfiguration.GetRequestHeader() + // in case we hit an error, we want to unblock this part + defer gotConn.Close() - downResponse, err := httpClient.download.Do(req) - if err != nil { - // workaround for various connection pool related issues, mostly around - // HTTP/1.1. if the http client ever fails to send a request, we simply - // delete it entirely. - // in HTTP/1.1, it was observed that pool connections would immediately - // fail with "context canceled" if the previous http response body was - // not explicitly BOTH drained and closed. at the same time, sometimes - // the draining itself takes forever and causes more problems. - // see also https://github.com/golang/go/issues/60240 - destroyHTTPClient(ctx, dest, streamSettings) - return nil, newError("failed to send download http request, destroying client").Base(err) - } + req, err := http.NewRequestWithContext( + httptrace.WithClientTrace(context.WithoutCancel(ctx), trace), + "GET", + requestURL.String()+sessionId, + nil, + ) + if err != nil { + newError("failed to construct download http request").Base(err).WriteToLog() + gotDownResponse.Close() + return + } - if downResponse.StatusCode != 200 { - downResponse.Body.Close() - return nil, newError("invalid status code on download:", downResponse.Status) - } + req.Header = transportConfiguration.GetRequestHeader() - uploadUrl := requestURL.String() + "?session=" + sessionId + "&seq=" + response, err := httpClient.download.Do(req) + gotConn.Close() + if err != nil { + newError("failed to send download http request").Base(err).WriteToLog() + gotDownResponse.Close() + return + } + + if response.StatusCode != 200 { + response.Body.Close() + newError("invalid status code on download:", response.Status).WriteToLog() + gotDownResponse.Close() + return + } + + // skip "ok" response + trashHeader := []byte{0, 0} + _, err = io.ReadFull(response.Body, trashHeader) + if err != nil { + response.Body.Close() + newError("failed to read initial response").Base(err).WriteToLog() + gotDownResponse.Close() + return + } + + downResponse = response.Body + gotDownResponse.Close() + }() + + uploadUrl := requestURL.String() + sessionId + "/" uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(maxUploadSize)) @@ -266,7 +279,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me for i := 0; i < 5; i++ { uploadConn = httpClient.uploadRawPool.Get() if uploadConn == nil { - uploadConn, err = httpClient.dialUploadConn(ctx) + uploadConn, err = httpClient.dialUploadConn(context.WithoutCancel(ctx)) if err != nil { newError("failed to connect upload").Base(err).WriteToLog() uploadPipeReader.Interrupt() @@ -293,21 +306,27 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me } }() - // skip "ok" response - trashHeader := []byte{0, 0} - _, err = io.ReadFull(downResponse.Body, trashHeader) - if err != nil { - downResponse.Body.Close() - return nil, newError("failed to read initial response") - } + // we want to block Dial until we know the remote address of the server, + // for logging purposes + <-gotConn.Wait() // necessary in order to send larger chunks in upload bufferedUploadPipeWriter := buf.NewBufferedWriter(uploadPipeWriter) bufferedUploadPipeWriter.SetBuffered(false) + lazyDownload := &LazyReader{ + CreateReader: func() (io.ReadCloser, error) { + <-gotDownResponse.Wait() + if downResponse == nil { + return nil, newError("downResponse failed") + } + return downResponse, nil + }, + } + conn := splitConn{ writer: bufferedUploadPipeWriter, - reader: downResponse.Body, + reader: lazyDownload, remoteAddr: remoteAddr, localAddr: localAddr, } diff --git a/xray-core/transport/internet/splithttp/hub.go b/xray-core/transport/internet/splithttp/hub.go index 1883bf237b..412f686a63 100644 --- a/xray-core/transport/internet/splithttp/hub.go +++ b/xray-core/transport/internet/splithttp/hub.go @@ -7,6 +7,7 @@ import ( gonet "net" "net/http" "strconv" + "strings" "sync" "time" @@ -28,20 +29,65 @@ type requestHandler struct { localAddr gonet.TCPAddr } +type httpSession struct { + uploadQueue *UploadQueue + // for as long as the GET request is not opened by the client, this will be + // open ("undone"), and the session may be expired within a certain TTL. + // after the client connects, this becomes "done" and the session lives as + // long as the GET request. + isFullyConnected *done.Instance +} + +func (h *requestHandler) maybeReapSession(isFullyConnected *done.Instance, sessionId string) { + shouldReap := done.New() + go func() { + time.Sleep(30 * time.Second) + shouldReap.Close() + }() + + select { + case <-isFullyConnected.Wait(): + return + case <-shouldReap.Wait(): + h.sessions.Delete(sessionId) + } +} + +func (h *requestHandler) upsertSession(sessionId string) *httpSession { + currentSessionAny, ok := h.sessions.Load(sessionId) + if ok { + return currentSessionAny.(*httpSession) + } + + s := &httpSession{ + uploadQueue: NewUploadQueue(int(2 * h.ln.config.GetNormalizedMaxConcurrentUploads())), + isFullyConnected: done.New(), + } + + h.sessions.Store(sessionId, s) + go h.maybeReapSession(s.isFullyConnected, sessionId) + return s +} + func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { if len(h.host) > 0 && request.Host != h.host { newError("failed to validate host, request:", request.Host, ", config:", h.host).WriteToLog() writer.WriteHeader(http.StatusNotFound) return } - if request.URL.Path != h.path { + + if !strings.HasPrefix(request.URL.Path, h.path) { newError("failed to validate path, request:", request.URL.Path, ", config:", h.path).WriteToLog() writer.WriteHeader(http.StatusNotFound) return } - queryString := request.URL.Query() - sessionId := queryString.Get("session") + sessionId := "" + subpath := strings.Split(request.URL.Path[len(h.path):], "/") + if len(subpath) > 0 { + sessionId = subpath[0] + } + if sessionId == "" { newError("no sessionid on request:", request.URL.Path).WriteToLog() writer.WriteHeader(http.StatusBadRequest) @@ -60,15 +106,14 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req } } + currentSession := h.upsertSession(sessionId) + if request.Method == "POST" { - uploadQueue, ok := h.sessions.Load(sessionId) - if !ok { - newError("sessionid does not exist").WriteToLog() - writer.WriteHeader(http.StatusBadRequest) - return + seq := "" + if len(subpath) > 1 { + seq = subpath[1] } - seq := queryString.Get("seq") if seq == "" { newError("no seq on request:", request.URL.Path).WriteToLog() writer.WriteHeader(http.StatusBadRequest) @@ -89,7 +134,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req return } - err = uploadQueue.(*UploadQueue).Push(Packet{ + err = currentSession.uploadQueue.Push(Packet{ Payload: payload, Seq: seqInt, }) @@ -107,10 +152,9 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req panic("expected http.ResponseWriter to be an http.Flusher") } - uploadQueue := NewUploadQueue(int(2 * h.ln.config.GetNormalizedMaxConcurrentUploads())) - - h.sessions.Store(sessionId, uploadQueue) - // the connection is finished, clean up map + // after GET is done, the connection is finished. disable automatic + // session reaping, and handle it in defer + currentSession.isFullyConnected.Close() defer h.sessions.Delete(sessionId) // magic header instructs nginx + apache to not buffer response body @@ -130,7 +174,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req downloadDone: downloadDone, responseFlusher: responseFlusher, }, - reader: uploadQueue, + reader: currentSession.uploadQueue, remoteAddr: remoteAddr, } diff --git a/xray-core/transport/internet/splithttp/lazy_reader.go b/xray-core/transport/internet/splithttp/lazy_reader.go new file mode 100644 index 0000000000..5ae4ed558d --- /dev/null +++ b/xray-core/transport/internet/splithttp/lazy_reader.go @@ -0,0 +1,57 @@ +package splithttp + +import ( + "io" + "sync" +) + +type LazyReader struct { + readerSync sync.Mutex + CreateReader func() (io.ReadCloser, error) + reader io.ReadCloser + readerError error +} + +func (r *LazyReader) getReader() (io.ReadCloser, error) { + r.readerSync.Lock() + defer r.readerSync.Unlock() + if r.reader != nil { + return r.reader, nil + } + + if r.readerError != nil { + return nil, r.readerError + } + + reader, err := r.CreateReader() + if err != nil { + r.readerError = err + return nil, err + } + + r.reader = reader + return reader, nil +} + +func (r *LazyReader) Read(b []byte) (int, error) { + reader, err := r.getReader() + if err != nil { + return 0, err + } + n, err := reader.Read(b) + return n, err +} + +func (r *LazyReader) Close() error { + r.readerSync.Lock() + defer r.readerSync.Unlock() + + var err error + if r.reader != nil { + err = r.reader.Close() + r.reader = nil + r.readerError = newError("closed reader") + } + + return err +} diff --git a/youtube-dl/test/test_jsinterp.py b/youtube-dl/test/test_jsinterp.py index 91b12f5441..da8e980207 100644 --- a/youtube-dl/test/test_jsinterp.py +++ b/youtube-dl/test/test_jsinterp.py @@ -577,9 +577,11 @@ class TestJSInterpreter(unittest.TestCase): def test_unary_operators(self): jsi = JSInterpreter('function f(){return 2 - - - 2;}') self.assertEqual(jsi.call_function('f'), 0) - # fails - # jsi = JSInterpreter('function f(){return 2 + - + - - 2;}') - # self.assertEqual(jsi.call_function('f'), 0) + jsi = JSInterpreter('function f(){return 2 + - + - - 2;}') + self.assertEqual(jsi.call_function('f'), 0) + # https://github.com/ytdl-org/youtube-dl/issues/32815 + jsi = JSInterpreter('function f(){return 0 - 7 * - 6;}') + self.assertEqual(jsi.call_function('f'), 42) """ # fails so far def test_packed(self): diff --git a/youtube-dl/test/test_youtube_signature.py b/youtube-dl/test/test_youtube_signature.py index f45dfec7cf..cafba7a5cd 100644 --- a/youtube-dl/test/test_youtube_signature.py +++ b/youtube-dl/test/test_youtube_signature.py @@ -158,6 +158,10 @@ _NSIG_TESTS = [ 'https://www.youtube.com/s/player/b7910ca8/player_ias.vflset/en_US/base.js', '_hXMCwMt9qE310D', 'LoZMgkkofRMCZQ', ), + ( + 'https://www.youtube.com/s/player/590f65a6/player_ias.vflset/en_US/base.js', + '1tm7-g_A9zsI8_Lay_', 'xI4Vem4Put_rOg', + ), ] diff --git a/youtube-dl/youtube_dl/extractor/common.py b/youtube-dl/youtube_dl/extractor/common.py index b10e844168..9b0016d07e 100644 --- a/youtube-dl/youtube_dl/extractor/common.py +++ b/youtube-dl/youtube_dl/extractor/common.py @@ -3033,7 +3033,6 @@ class InfoExtractor(object): transform_source=transform_source, default=None) def _extract_jwplayer_data(self, webpage, video_id, *args, **kwargs): - # allow passing `transform_source` through to _find_jwplayer_data() transform_source = kwargs.pop('transform_source', None) kwfind = compat_kwargs({'transform_source': transform_source}) if transform_source else {} diff --git a/youtube-dl/youtube_dl/extractor/palcomp3.py b/youtube-dl/youtube_dl/extractor/palcomp3.py index fb29d83f9f..60f7a4d48d 100644 --- a/youtube-dl/youtube_dl/extractor/palcomp3.py +++ b/youtube-dl/youtube_dl/extractor/palcomp3.py @@ -8,7 +8,7 @@ from ..compat import compat_str from ..utils import ( int_or_none, str_or_none, - try_get, + traverse_obj, ) @@ -109,7 +109,7 @@ class PalcoMP3ArtistIE(PalcoMP3BaseIE): } name''' - @ classmethod + @classmethod def suitable(cls, url): return False if re.match(PalcoMP3IE._VALID_URL, url) else super(PalcoMP3ArtistIE, cls).suitable(url) @@ -118,7 +118,8 @@ class PalcoMP3ArtistIE(PalcoMP3BaseIE): artist = self._call_api(artist_slug, self._ARTIST_FIELDS_TMPL)['artist'] def entries(): - for music in (try_get(artist, lambda x: x['musics']['nodes'], list) or []): + for music in traverse_obj(artist, ( + 'musics', 'nodes', lambda _, m: m['musicID'])): yield self._parse_music(music) return self.playlist_result( @@ -137,7 +138,7 @@ class PalcoMP3VideoIE(PalcoMP3BaseIE): 'title': 'Maiara e Maraisa - Você Faz Falta Aqui - DVD Ao Vivo Em Campo Grande', 'description': 'md5:7043342c09a224598e93546e98e49282', 'upload_date': '20161107', - 'uploader_id': 'maiaramaraisaoficial', + 'uploader_id': '@maiaramaraisaoficial', 'uploader': 'Maiara e Maraisa', } }] diff --git a/youtube-dl/youtube_dl/jsinterp.py b/youtube-dl/youtube_dl/jsinterp.py index 86d902248d..02adf66784 100644 --- a/youtube-dl/youtube_dl/jsinterp.py +++ b/youtube-dl/youtube_dl/jsinterp.py @@ -14,6 +14,7 @@ from .utils import ( remove_quotes, unified_timestamp, variadic, + write_string, ) from .compat import ( compat_basestring, @@ -53,15 +54,16 @@ def wraps_op(op): # NB In principle NaN cannot be checked by membership. # Here all NaN values are actually this one, so _NaN is _NaN, -# although _NaN != _NaN. +# although _NaN != _NaN. Ditto Infinity. _NaN = float('nan') +_Infinity = float('inf') def _js_bit_op(op): def zeroise(x): - return 0 if x in (None, JS_Undefined, _NaN) else x + return 0 if x in (None, JS_Undefined, _NaN, _Infinity) else x @wraps_op(op) def wrapped(a, b): @@ -84,7 +86,7 @@ def _js_arith_op(op): def _js_div(a, b): if JS_Undefined in (a, b) or not (a or b): return _NaN - return operator.truediv(a or 0, b) if b else float('inf') + return operator.truediv(a or 0, b) if b else _Infinity def _js_mod(a, b): @@ -220,6 +222,42 @@ class LocalNameSpace(ChainMap): return 'LocalNameSpace%s' % (self.maps, ) +class Debugger(object): + ENABLED = False + + @staticmethod + def write(*args, **kwargs): + level = kwargs.get('level', 100) + + def truncate_string(s, left, right=0): + if s is None or len(s) <= left + right: + return s + return '...'.join((s[:left - 3], s[-right:] if right else '')) + + write_string('[debug] JS: {0}{1}\n'.format( + ' ' * (100 - level), + ' '.join(truncate_string(compat_str(x), 50, 50) for x in args))) + + @classmethod + def wrap_interpreter(cls, f): + def interpret_statement(self, stmt, local_vars, allow_recursion, *args, **kwargs): + if cls.ENABLED and stmt.strip(): + cls.write(stmt, level=allow_recursion) + try: + ret, should_ret = f(self, stmt, local_vars, allow_recursion, *args, **kwargs) + except Exception as e: + if cls.ENABLED: + if isinstance(e, ExtractorError): + e = e.orig_msg + cls.write('=> Raises:', e, '<-|', stmt, level=allow_recursion) + raise + if cls.ENABLED and stmt.strip(): + if should_ret or not repr(ret) == stmt: + cls.write(['->', '=>'][should_ret], repr(ret), '<-|', stmt, level=allow_recursion) + return ret, should_ret + return interpret_statement + + class JSInterpreter(object): __named_object_counter = 0 @@ -307,8 +345,7 @@ class JSInterpreter(object): def __op_chars(cls): op_chars = set(';,[') for op in cls._all_operators(): - for c in op[0]: - op_chars.add(c) + op_chars.update(op[0]) return op_chars def _named_object(self, namespace, obj): @@ -326,9 +363,8 @@ class JSInterpreter(object): # collections.Counter() is ~10% slower in both 2.7 and 3.9 counters = dict((k, 0) for k in _MATCHING_PARENS.values()) start, splits, pos, delim_len = 0, 0, 0, len(delim) - 1 - in_quote, escaping, skipping = None, False, 0 - after_op, in_regex_char_group = True, False - + in_quote, escaping, after_op, in_regex_char_group = None, False, True, False + skipping = 0 for idx, char in enumerate(expr): paren_delta = 0 if not in_quote: @@ -382,10 +418,12 @@ class JSInterpreter(object): return separated[0][1:].strip(), separated[1].strip() @staticmethod - def _all_operators(): - return itertools.chain( - # Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence - _SC_OPERATORS, _LOG_OPERATORS, _COMP_OPERATORS, _OPERATORS) + def _all_operators(_cached=[]): + if not _cached: + _cached.extend(itertools.chain( + # Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence + _SC_OPERATORS, _LOG_OPERATORS, _COMP_OPERATORS, _OPERATORS)) + return _cached def _operator(self, op, left_val, right_expr, expr, local_vars, allow_recursion): if op in ('||', '&&'): @@ -416,7 +454,7 @@ class JSInterpreter(object): except Exception as e: if allow_undefined: return JS_Undefined - raise self.Exception('Cannot get index {idx:.100}'.format(**locals()), expr=repr(obj), cause=e) + raise self.Exception('Cannot get index {idx!r:.100}'.format(**locals()), expr=repr(obj), cause=e) def _dump(self, obj, namespace): try: @@ -438,6 +476,7 @@ class JSInterpreter(object): _FINALLY_RE = re.compile(r'finally\s*\{') _SWITCH_RE = re.compile(r'switch\s*\(') + @Debugger.wrap_interpreter def interpret_statement(self, stmt, local_vars, allow_recursion=100): if allow_recursion < 0: raise self.Exception('Recursion limit reached') @@ -511,7 +550,6 @@ class JSInterpreter(object): expr = self._dump(inner, local_vars) + outer if expr.startswith('('): - m = re.match(r'\((?P[a-z])%(?P[a-z])\.length\+(?P=e)\.length\)%(?P=e)\.length', expr) if m: # short-cut eval of frequently used `(d%e.length+e.length)%e.length`, worth ~6% on `pytest -k test_nsig` @@ -693,7 +731,7 @@ class JSInterpreter(object): (?P{_OPERATOR_RE})? =(?!=)(?P.*)$ )|(?P - (?!if|return|true|false|null|undefined)(?P{_NAME_RE})$ + (?!if|return|true|false|null|undefined|NaN|Infinity)(?P{_NAME_RE})$ )|(?P (?P{_NAME_RE})\[(?P.+)\]$ )|(?P @@ -727,11 +765,12 @@ class JSInterpreter(object): raise JS_Break() elif expr == 'continue': raise JS_Continue() - elif expr == 'undefined': return JS_Undefined, should_return elif expr == 'NaN': return _NaN, should_return + elif expr == 'Infinity': + return _Infinity, should_return elif md.get('return'): return local_vars[m.group('name')], should_return @@ -760,18 +799,28 @@ class JSInterpreter(object): right_expr = separated.pop() # handle operators that are both unary and binary, minimal BODMAS if op in ('+', '-'): + # simplify/adjust consecutive instances of these operators undone = 0 while len(separated) > 1 and not separated[-1].strip(): undone += 1 separated.pop() if op == '-' and undone % 2 != 0: right_expr = op + right_expr + elif op == '+': + while len(separated) > 1 and separated[-1].strip() in self.OP_CHARS: + right_expr = separated.pop() + right_expr + # hanging op at end of left => unary + (strip) or - (push right) left_val = separated[-1] for dm_op in ('*', '%', '/', '**'): bodmas = tuple(self._separate(left_val, dm_op, skip_delims=skip_delim)) if len(bodmas) > 1 and not bodmas[-1].strip(): expr = op.join(separated) + op + right_expr - right_expr = None + if len(separated) > 1: + separated.pop() + right_expr = op.join((left_val, right_expr)) + else: + separated = [op.join((left_val, right_expr))] + right_expr = None break if right_expr is None: continue @@ -797,6 +846,8 @@ class JSInterpreter(object): def eval_method(): if (variable, member) == ('console', 'debug'): + if Debugger.ENABLED: + Debugger.write(self.interpret_expression('[{}]'.format(arg_str), local_vars, allow_recursion)) return types = { 'String': compat_str, diff --git a/youtube-dl/youtube_dl/utils.py b/youtube-dl/youtube_dl/utils.py index cd43035667..113c913df5 100644 --- a/youtube-dl/youtube_dl/utils.py +++ b/youtube-dl/youtube_dl/utils.py @@ -2406,7 +2406,7 @@ class ExtractorError(YoutubeDLError): """ tb, if given, is the original traceback (so that it can be printed out). If expected is set, this is a normal error message and most likely not a bug in youtube-dl. """ - + self.orig_msg = msg if sys.exc_info()[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError): expected = True if video_id is not None: diff --git a/yt-dlp/yt_dlp/extractor/cloudflarestream.py b/yt-dlp/yt_dlp/extractor/cloudflarestream.py index f902daacf6..8a409461a8 100644 --- a/yt-dlp/yt_dlp/extractor/cloudflarestream.py +++ b/yt-dlp/yt_dlp/extractor/cloudflarestream.py @@ -6,11 +6,11 @@ from .common import InfoExtractor class CloudflareStreamIE(InfoExtractor): _SUBDOMAIN_RE = r'(?:(?:watch|iframe|customer-\w+)\.)?' _DOMAIN_RE = r'(?:cloudflarestream\.com|(?:videodelivery|bytehighway)\.net)' - _EMBED_RE = rf'embed\.{_DOMAIN_RE}/embed/[^/]+\.js\?.*?\bvideo=' - _ID_RE = r'[\da-f]{32}|[\w-]+\.[\w-]+\.[\w-]+' + _EMBED_RE = rf'(?:embed\.|{_SUBDOMAIN_RE}){_DOMAIN_RE}/embed/[^/?#]+\.js\?(?:[^#]+&)?video=' + _ID_RE = r'[\da-f]{32}|eyJ[\w-]+\.[\w-]+\.[\w-]+' _VALID_URL = rf'https?://(?:{_SUBDOMAIN_RE}{_DOMAIN_RE}/|{_EMBED_RE})(?P{_ID_RE})' _EMBED_REGEX = [ - rf']+\bsrc=(["\'])(?P(?:https?:)?//{_EMBED_RE}(?:{_ID_RE}).*?)\1', + rf']+\bsrc=(["\'])(?P(?:https?:)?//{_EMBED_RE}(?:{_ID_RE})(?:(?!\1).)*)\1', rf']+\bsrc=["\'](?Phttps?://{_SUBDOMAIN_RE}{_DOMAIN_RE}/[\da-f]{{32}})', ] _TESTS = [{ @@ -24,6 +24,14 @@ class CloudflareStreamIE(InfoExtractor): 'params': { 'skip_download': 'm3u8', }, + }, { + 'url': 'https://watch.cloudflarestream.com/embed/sdk-iframe-integration.fla9.latest.js?video=0e8e040aec776862e1d632a699edf59e', + 'info_dict': { + 'id': '0e8e040aec776862e1d632a699edf59e', + 'ext': 'mp4', + 'title': '0e8e040aec776862e1d632a699edf59e', + 'thumbnail': 'https://videodelivery.net/0e8e040aec776862e1d632a699edf59e/thumbnails/thumbnail.jpg', + }, }, { 'url': 'https://watch.cloudflarestream.com/9df17203414fd1db3e3ed74abbe936c1', 'only_matching': True, @@ -36,6 +44,9 @@ class CloudflareStreamIE(InfoExtractor): }, { 'url': 'https://customer-aw5py76sw8wyqzmh.cloudflarestream.com/2463f6d3e06fa29710a337f5f5389fd8/iframe', 'only_matching': True, + }, { + 'url': 'https://watch.cloudflarestream.com/eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJraWQiOiJmYTA0YjViMzQ2NDkwYTM5NWJiNzQ1NWFhZTA2YzYwZSIsInN1YiI6Ijg4ZDQxMDhhMzY0MjA3M2VhYmFhZjg3ZGExODJkMjYzIiwiZXhwIjoxNjAwNjA5MzE5fQ.xkRJwLGkt0nZ%5F0BlPiwU7iW4pqb4lKkznbKfAhGg0tGcxSS6ZBA3lcTUwu7W%2DyCFbnAl%2Dhqk3Fn%5FqeQS%5FQydP27qTHpB9iIFFsMtk1tqzGZV5v4yrYDnwLSKzEKvVd6QwJnfABtxH2JdpSNuWlMUiVXFxGWgjOw6QeTNDDklTQYXV%5FNLV7sErSn5CeOPeRRkdXb%2D8ip%5FVOcfk1nDsFoOo4fctFtGP0wYMyY5ae8nhhatydHwevuvJCcEvEfh%2D4qjq9mCZOodevmtSQ4YWmggf4BxtWnDWYrGW8Otp6oqezrR8oY4%2DbKdV6PaqBj49aJdcls6xK7PmM8%5Fvjy3xfm0Mg', + 'only_matching': True, }] _WEBPAGE_TESTS = [{ 'url': 'https://upride.cc/incident/shoulder-pass-at-light/', diff --git a/yt-dlp/yt_dlp/extractor/common.py b/yt-dlp/yt_dlp/extractor/common.py index e5efd08b4f..f63bd78258 100644 --- a/yt-dlp/yt_dlp/extractor/common.py +++ b/yt-dlp/yt_dlp/extractor/common.py @@ -2222,6 +2222,11 @@ class InfoExtractor: 'quality': quality, 'has_drm': has_drm, } + + # YouTube-specific + if yt_audio_content_id := last_stream_inf.get('YT-EXT-AUDIO-CONTENT-ID'): + f['language'] = yt_audio_content_id.split('.')[0] + resolution = last_stream_inf.get('RESOLUTION') if resolution: mobj = re.search(r'(?P\d+)[xX](?P\d+)', resolution) diff --git a/yt-dlp/yt_dlp/extractor/youtube.py b/yt-dlp/yt_dlp/extractor/youtube.py index a89744eb10..ab6201dae6 100644 --- a/yt-dlp/yt_dlp/extractor/youtube.py +++ b/yt-dlp/yt_dlp/extractor/youtube.py @@ -3797,6 +3797,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor): def _extract_formats_and_subtitles(self, streaming_data, video_id, player_url, live_status, duration): CHUNK_SIZE = 10 << 20 + PREFERRED_LANG_VALUE = 10 + original_language = None itags, stream_ids = collections.defaultdict(set), [] itag_qualities, res_qualities = {}, {0: None} q = qualities([ @@ -3894,10 +3896,12 @@ class YoutubeIE(YoutubeBaseInfoExtractor): throttled = True tbr = float_or_none(fmt.get('averageBitrate') or fmt.get('bitrate'), 1000) - language_preference = ( - 10 if audio_track.get('audioIsDefault') and 10 - else -10 if 'descriptive' in (audio_track.get('displayName') or '').lower() and -10 - else -1) + is_default = audio_track.get('audioIsDefault') + is_descriptive = 'descriptive' in (audio_track.get('displayName') or '').lower() + language_code = audio_track.get('id', '').split('.')[0] + if language_code and is_default: + original_language = language_code + format_duration = traverse_obj(fmt, ('approxDurationMs', {lambda x: float_or_none(x, 1000)})) # Some formats may have much smaller duration than others (possibly damaged during encoding) # E.g. 2-nOtRESiUc Ref: https://github.com/yt-dlp/yt-dlp/issues/2823 @@ -3924,8 +3928,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor): 'filesize': int_or_none(fmt.get('contentLength')), 'format_id': f'{itag}{"-drc" if fmt.get("isDrc") else ""}', 'format_note': join_nonempty( - join_nonempty(audio_track.get('displayName'), - language_preference > 0 and ' (default)', delim=''), + join_nonempty(audio_track.get('displayName'), is_default and ' (default)', delim=''), name, fmt.get('isDrc') and 'DRC', try_get(fmt, lambda x: x['projectionType'].replace('RECTANGULAR', '').lower()), try_get(fmt, lambda x: x['spatialAudioType'].replace('SPATIAL_AUDIO_TYPE_', '').lower()), @@ -3944,9 +3947,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor): 'filesize_approx': filesize_from_tbr(tbr, format_duration), 'url': fmt_url, 'width': int_or_none(fmt.get('width')), - 'language': join_nonempty(audio_track.get('id', '').split('.')[0], - 'desc' if language_preference < -1 else '') or None, - 'language_preference': language_preference, + 'language': join_nonempty(language_code, 'desc' if is_descriptive else '') or None, + 'language_preference': PREFERRED_LANG_VALUE if is_default else -10 if is_descriptive else -1, # Strictly de-prioritize broken, damaged and 3gp formats 'preference': -20 if is_broken else -10 if is_damaged else -2 if itag == '17' else None, } @@ -4007,6 +4009,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor): elif itag: f['format_id'] = itag + if original_language and f.get('language') == original_language: + f['format_note'] = join_nonempty(f.get('format_note'), '(default)', delim=' ') + f['language_preference'] = PREFERRED_LANG_VALUE + if f.get('source_preference') is None: f['source_preference'] = -1