mirror of
https://github.com/bolucat/Archive.git
synced 2025-10-17 05:31:27 +08:00
Update On Tue Mar 4 19:36:21 CET 2025
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -931,3 +931,4 @@ Update On Fri Feb 28 19:34:20 CET 2025
|
||||
Update On Sat Mar 1 19:31:26 CET 2025
|
||||
Update On Sun Mar 2 19:33:02 CET 2025
|
||||
Update On Mon Mar 3 19:34:32 CET 2025
|
||||
Update On Tue Mar 4 19:36:12 CET 2025
|
||||
|
File diff suppressed because it is too large
Load Diff
4
clash-nyanpasu/backend/Cargo.lock
generated
4
clash-nyanpasu/backend/Cargo.lock
generated
@@ -9247,9 +9247,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.139"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"indexmap 2.7.1",
|
||||
"itoa 1.0.14",
|
||||
|
@@ -53,7 +53,7 @@
|
||||
"@csstools/normalize.css": "12.1.1",
|
||||
"@emotion/babel-plugin": "11.13.5",
|
||||
"@emotion/react": "11.14.0",
|
||||
"@iconify/json": "2.2.312",
|
||||
"@iconify/json": "2.2.313",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@tanstack/react-query": "5.66.11",
|
||||
"@tanstack/react-router": "1.112.0",
|
||||
|
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.19.2",
|
||||
"mihomo_alpha": "alpha-a7e56f1",
|
||||
"mihomo": "v1.19.3",
|
||||
"mihomo_alpha": "alpha-8bc6f77",
|
||||
"clash_rs": "v0.7.6",
|
||||
"clash_premium": "2023-09-05-gdcc8d87",
|
||||
"clash_rs_alpha": "0.7.6-alpha+sha.14e7d32"
|
||||
"clash_rs_alpha": "0.7.6-alpha+sha.167eccd"
|
||||
},
|
||||
"arch_template": {
|
||||
"mihomo": {
|
||||
@@ -69,5 +69,5 @@
|
||||
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
||||
}
|
||||
},
|
||||
"updated_at": "2025-03-02T22:21:03.218Z"
|
||||
"updated_at": "2025-03-03T22:31:23.606Z"
|
||||
}
|
||||
|
@@ -65,7 +65,7 @@
|
||||
"@tauri-apps/cli": "2.2.7",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "22.13.8",
|
||||
"@types/node": "22.13.9",
|
||||
"@typescript-eslint/eslint-plugin": "8.25.0",
|
||||
"@typescript-eslint/parser": "8.25.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
|
150
clash-nyanpasu/pnpm-lock.yaml
generated
150
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -20,7 +20,7 @@ importers:
|
||||
devDependencies:
|
||||
'@commitlint/cli':
|
||||
specifier: 19.7.1
|
||||
version: 19.7.1(@types/node@22.13.8)(typescript@5.8.2)
|
||||
version: 19.7.1(@types/node@22.13.9)(typescript@5.8.2)
|
||||
'@commitlint/config-conventional':
|
||||
specifier: 19.7.1
|
||||
version: 19.7.1
|
||||
@@ -43,8 +43,8 @@ importers:
|
||||
specifier: 4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: 22.13.8
|
||||
version: 22.13.8
|
||||
specifier: 22.13.9
|
||||
version: 22.13.9
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: 8.25.0
|
||||
version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
@@ -104,7 +104,7 @@ importers:
|
||||
version: 16.0.0
|
||||
knip:
|
||||
specifier: 5.45.0
|
||||
version: 5.45.0(@types/node@22.13.8)(typescript@5.8.2)
|
||||
version: 5.45.0(@types/node@22.13.9)(typescript@5.8.2)
|
||||
lint-staged:
|
||||
specifier: 15.4.3
|
||||
version: 15.4.3
|
||||
@@ -333,8 +333,8 @@ importers:
|
||||
specifier: 11.14.0
|
||||
version: 11.14.0(@types/react@19.0.10)(react@19.0.0)
|
||||
'@iconify/json':
|
||||
specifier: 2.2.312
|
||||
version: 2.2.312
|
||||
specifier: 2.2.313
|
||||
version: 2.2.313
|
||||
'@monaco-editor/react':
|
||||
specifier: 4.7.0
|
||||
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
@@ -349,7 +349,7 @@ importers:
|
||||
version: 1.112.6(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@tanstack/router-plugin':
|
||||
specifier: 1.112.3
|
||||
version: 1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
'@tauri-apps/plugin-clipboard-manager':
|
||||
specifier: 2.2.1
|
||||
version: 2.2.1
|
||||
@@ -385,13 +385,13 @@ importers:
|
||||
version: 13.12.2
|
||||
'@vitejs/plugin-legacy':
|
||||
specifier: 6.0.2
|
||||
version: 6.0.2(terser@5.36.0)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 6.0.2(terser@5.36.0)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.4
|
||||
version: 4.3.4(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 4.3.4(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: 3.8.0
|
||||
version: 3.8.0(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 3.8.0(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
change-case:
|
||||
specifier: 5.4.4
|
||||
version: 5.4.4
|
||||
@@ -430,19 +430,19 @@ importers:
|
||||
version: 13.12.0
|
||||
vite:
|
||||
specifier: 6.2.0
|
||||
version: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
version: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite-plugin-html:
|
||||
specifier: 3.2.2
|
||||
version: 3.2.2(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 3.2.2(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
vite-plugin-sass-dts:
|
||||
specifier: 1.3.30
|
||||
version: 1.3.30(postcss@8.5.3)(prettier@3.5.2)(sass-embedded@1.85.1)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 1.3.30(postcss@8.5.3)(prettier@3.5.2)(sass-embedded@1.85.1)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
vite-plugin-svgr:
|
||||
specifier: 4.3.0
|
||||
version: 4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
vite-tsconfig-paths:
|
||||
specifier: 5.1.4
|
||||
version: 5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
zod:
|
||||
specifier: 3.24.2
|
||||
version: 3.24.2
|
||||
@@ -478,7 +478,7 @@ importers:
|
||||
version: 19.0.10
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.4
|
||||
version: 4.3.4(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 4.3.4(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
ahooks:
|
||||
specifier: 3.8.4
|
||||
version: 3.8.4(react@19.0.0)
|
||||
@@ -508,10 +508,10 @@ importers:
|
||||
version: 4.0.9
|
||||
vite:
|
||||
specifier: 6.2.0
|
||||
version: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
version: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite-tsconfig-paths:
|
||||
specifier: 5.1.4
|
||||
version: 5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
devDependencies:
|
||||
'@emotion/react':
|
||||
specifier: 11.14.0
|
||||
@@ -536,7 +536,7 @@ importers:
|
||||
version: 5.1.0(typescript@5.8.2)
|
||||
vite-plugin-dts:
|
||||
specifier: 4.5.3
|
||||
version: 4.5.3(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
version: 4.5.3(@types/node@22.13.9)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
|
||||
|
||||
scripts:
|
||||
dependencies:
|
||||
@@ -1666,8 +1666,8 @@ packages:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
|
||||
'@iconify/json@2.2.312':
|
||||
resolution: {integrity: sha512-sujKsprCACPMVZHeNaxvc7HyONW916tUVw4zfEK+GmT7PkH73PdplmW1w2UWC07IC6oUYPZ2EE0pfdWHhWHjpQ==}
|
||||
'@iconify/json@2.2.313':
|
||||
resolution: {integrity: sha512-lzZ0KFpb0/IN4TVp/9lkUQQx6pmDqe6UD6lWiwkjnPMUVfFXYFMOfy6Qna5zb2cKwVQLTcOUgKk82Ah4qilKlw==}
|
||||
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
@@ -3122,8 +3122,8 @@ packages:
|
||||
'@types/node@22.10.1':
|
||||
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
|
||||
|
||||
'@types/node@22.13.8':
|
||||
resolution: {integrity: sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==}
|
||||
'@types/node@22.13.9':
|
||||
resolution: {integrity: sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -9005,11 +9005,11 @@ snapshots:
|
||||
|
||||
'@bufbuild/protobuf@2.2.3': {}
|
||||
|
||||
'@commitlint/cli@19.7.1(@types/node@22.13.8)(typescript@5.8.2)':
|
||||
'@commitlint/cli@19.7.1(@types/node@22.13.9)(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.5.0
|
||||
'@commitlint/lint': 19.7.1
|
||||
'@commitlint/load': 19.6.1(@types/node@22.13.8)(typescript@5.8.2)
|
||||
'@commitlint/load': 19.6.1(@types/node@22.13.9)(typescript@5.8.2)
|
||||
'@commitlint/read': 19.5.0
|
||||
'@commitlint/types': 19.5.0
|
||||
tinyexec: 0.3.1
|
||||
@@ -9056,7 +9056,7 @@ snapshots:
|
||||
'@commitlint/rules': 19.6.0
|
||||
'@commitlint/types': 19.5.0
|
||||
|
||||
'@commitlint/load@19.6.1(@types/node@22.13.8)(typescript@5.8.2)':
|
||||
'@commitlint/load@19.6.1(@types/node@22.13.9)(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 19.5.0
|
||||
'@commitlint/execute-rule': 19.5.0
|
||||
@@ -9064,7 +9064,7 @@ snapshots:
|
||||
'@commitlint/types': 19.5.0
|
||||
chalk: 5.4.1
|
||||
cosmiconfig: 9.0.0(typescript@5.8.2)
|
||||
cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.8)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2)
|
||||
cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.9)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
@@ -9426,7 +9426,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@iconify/json@2.2.312':
|
||||
'@iconify/json@2.2.313':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
pathe: 1.1.2
|
||||
@@ -9489,23 +9489,23 @@ snapshots:
|
||||
|
||||
'@material/material-color-utilities@0.3.0': {}
|
||||
|
||||
'@microsoft/api-extractor-model@7.30.3(@types/node@22.13.8)':
|
||||
'@microsoft/api-extractor-model@7.30.3(@types/node@22.13.9)':
|
||||
dependencies:
|
||||
'@microsoft/tsdoc': 0.15.1
|
||||
'@microsoft/tsdoc-config': 0.17.1
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.8)
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.9)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@microsoft/api-extractor@7.51.0(@types/node@22.13.8)':
|
||||
'@microsoft/api-extractor@7.51.0(@types/node@22.13.9)':
|
||||
dependencies:
|
||||
'@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.8)
|
||||
'@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.9)
|
||||
'@microsoft/tsdoc': 0.15.1
|
||||
'@microsoft/tsdoc-config': 0.17.1
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.8)
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.9)
|
||||
'@rushstack/rig-package': 0.5.3
|
||||
'@rushstack/terminal': 0.15.0(@types/node@22.13.8)
|
||||
'@rushstack/ts-command-line': 4.23.5(@types/node@22.13.8)
|
||||
'@rushstack/terminal': 0.15.0(@types/node@22.13.9)
|
||||
'@rushstack/ts-command-line': 4.23.5(@types/node@22.13.9)
|
||||
lodash: 4.17.21
|
||||
minimatch: 3.0.8
|
||||
resolve: 1.22.8
|
||||
@@ -10175,7 +10175,7 @@ snapshots:
|
||||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@rushstack/node-core-library@5.11.0(@types/node@22.13.8)':
|
||||
'@rushstack/node-core-library@5.11.0(@types/node@22.13.9)':
|
||||
dependencies:
|
||||
ajv: 8.13.0
|
||||
ajv-draft-04: 1.0.0(ajv@8.13.0)
|
||||
@@ -10186,23 +10186,23 @@ snapshots:
|
||||
resolve: 1.22.8
|
||||
semver: 7.5.4
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@rushstack/rig-package@0.5.3':
|
||||
dependencies:
|
||||
resolve: 1.22.8
|
||||
strip-json-comments: 3.1.1
|
||||
|
||||
'@rushstack/terminal@0.15.0(@types/node@22.13.8)':
|
||||
'@rushstack/terminal@0.15.0(@types/node@22.13.9)':
|
||||
dependencies:
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.8)
|
||||
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.9)
|
||||
supports-color: 8.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@rushstack/ts-command-line@4.23.5(@types/node@22.13.8)':
|
||||
'@rushstack/ts-command-line@4.23.5(@types/node@22.13.9)':
|
||||
dependencies:
|
||||
'@rushstack/terminal': 0.15.0(@types/node@22.13.8)
|
||||
'@rushstack/terminal': 0.15.0(@types/node@22.13.9)
|
||||
'@types/argparse': 1.0.38
|
||||
argparse: 1.0.10
|
||||
string-argv: 0.3.2
|
||||
@@ -10519,7 +10519,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@tanstack/react-router': 1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
|
||||
'@tanstack/router-plugin@1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
'@tanstack/router-plugin@1.112.3(@tanstack/react-router@1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.26.9
|
||||
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9)
|
||||
@@ -10540,7 +10540,7 @@ snapshots:
|
||||
zod: 3.24.2
|
||||
optionalDependencies:
|
||||
'@tanstack/react-router': 1.112.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -10693,12 +10693,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.4
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
'@types/responselike': 1.0.3
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@types/d3-array@3.2.1': {}
|
||||
|
||||
@@ -10834,7 +10834,7 @@ snapshots:
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@types/geojson@7946.0.14': {}
|
||||
|
||||
@@ -10852,11 +10852,11 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
@@ -10876,7 +10876,7 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.20.0
|
||||
|
||||
'@types/node@22.13.8':
|
||||
'@types/node@22.13.9':
|
||||
dependencies:
|
||||
undici-types: 6.20.0
|
||||
|
||||
@@ -10906,7 +10906,7 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
|
||||
'@types/retry@0.12.2': {}
|
||||
|
||||
@@ -10926,7 +10926,7 @@ snapshots:
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.21.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
@@ -11045,7 +11045,7 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vitejs/plugin-legacy@6.0.2(terser@5.36.0)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
'@vitejs/plugin-legacy@6.0.2(terser@5.36.0)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.26.9
|
||||
'@babel/preset-env': 7.26.9(@babel/core@7.26.9)
|
||||
@@ -11056,25 +11056,25 @@ snapshots:
|
||||
regenerator-runtime: 0.14.1
|
||||
systemjs: 6.15.1
|
||||
terser: 5.36.0
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-react-swc@3.8.0(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
'@vitejs/plugin-react-swc@3.8.0(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@swc/core': 1.10.15
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
'@vitejs/plugin-react@4.3.4(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
'@vitejs/plugin-react@4.3.4(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -11717,9 +11717,9 @@ snapshots:
|
||||
|
||||
core-js@3.41.0: {}
|
||||
|
||||
cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.8)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2):
|
||||
cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.9)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2):
|
||||
dependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
cosmiconfig: 9.0.0(typescript@5.8.2)
|
||||
jiti: 2.4.2
|
||||
typescript: 5.8.2
|
||||
@@ -13699,11 +13699,11 @@ snapshots:
|
||||
|
||||
kind-of@6.0.3: {}
|
||||
|
||||
knip@5.45.0(@types/node@22.13.8)(typescript@5.8.2):
|
||||
knip@5.45.0(@types/node@22.13.9)(typescript@5.8.2):
|
||||
dependencies:
|
||||
'@nodelib/fs.walk': 3.0.1
|
||||
'@snyk/github-codeowners': 1.1.0
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
easy-table: 1.2.0
|
||||
enhanced-resolve: 5.18.1
|
||||
fast-glob: 3.3.3
|
||||
@@ -16206,9 +16206,9 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
vite-plugin-dts@4.5.3(@types/node@22.13.8)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
vite-plugin-dts@4.5.3(@types/node@22.13.9)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
dependencies:
|
||||
'@microsoft/api-extractor': 7.51.0(@types/node@22.13.8)
|
||||
'@microsoft/api-extractor': 7.51.0(@types/node@22.13.9)
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.3)
|
||||
'@volar/typescript': 2.4.11
|
||||
'@vue/language-core': 2.2.0(typescript@5.8.2)
|
||||
@@ -16219,13 +16219,13 @@ snapshots:
|
||||
magic-string: 0.30.17
|
||||
typescript: 5.8.2
|
||||
optionalDependencies:
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
vite-plugin-html@3.2.2(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
vite-plugin-html@3.2.2(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
colorette: 2.0.20
|
||||
@@ -16239,45 +16239,45 @@ snapshots:
|
||||
html-minifier-terser: 6.1.0
|
||||
node-html-parser: 5.4.2
|
||||
pathe: 0.2.0
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
|
||||
vite-plugin-sass-dts@1.3.30(postcss@8.5.3)(prettier@3.5.2)(sass-embedded@1.85.1)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
vite-plugin-sass-dts@1.3.30(postcss@8.5.3)(prettier@3.5.2)(sass-embedded@1.85.1)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
dependencies:
|
||||
postcss: 8.5.3
|
||||
postcss-js: 4.0.1(postcss@8.5.3)
|
||||
prettier: 3.5.2
|
||||
sass-embedded: 1.85.1
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
|
||||
vite-plugin-svgr@4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
vite-plugin-svgr@4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.3(rollup@4.34.3)
|
||||
'@svgr/core': 8.1.0(typescript@5.8.2)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.2))
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
|
||||
dependencies:
|
||||
debug: 4.3.7
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.8.2)
|
||||
optionalDependencies:
|
||||
vite: 6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
vite: 6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@6.2.0(@types/node@22.13.8)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0):
|
||||
vite@6.2.0(@types/node@22.13.9)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.1)(sass-embedded@1.85.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.0
|
||||
postcss: 8.5.3
|
||||
rollup: 4.34.3
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.8
|
||||
'@types/node': 22.13.9
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.4.2
|
||||
less: 4.2.0
|
||||
|
@@ -2,7 +2,7 @@ import * as path from 'jsr:@std/path'
|
||||
import { globby } from 'npm:globby'
|
||||
import { consola } from './utils/logger.ts'
|
||||
|
||||
const WORKSPACE_ROOT = path.join(Deno.cwd(), '../..')
|
||||
const WORKSPACE_ROOT = path.join(import.meta.dirname!, '../..')
|
||||
consola.info(`WORKSPACE_ROOT: ${WORKSPACE_ROOT}`)
|
||||
|
||||
const GITHUB_TOKEN = Deno.env.get('GITHUB_TOKEN') || Deno.env.get('GH_TOKEN')
|
||||
@@ -29,8 +29,10 @@ for (let file of files) {
|
||||
file = path.join(BACKEND_BUILD_DIR, file)
|
||||
const p = path.parse(file)
|
||||
consola.info(`Found file: ${p.base}`)
|
||||
if (p.base.endsWith('.app.tar.gz')) {
|
||||
const newName = p.name.split('.')[0] + `.${TARGET_ARCH}.app.tar.gz`
|
||||
if (p.base.includes('.app')) {
|
||||
const components = p.base.split('.')
|
||||
const newName =
|
||||
components[0] + `.${TARGET_ARCH}.${components.slice(1).join('.')}`
|
||||
const newPath = path.join(p.dir, newName)
|
||||
consola.info(`Renaming ${file} to ${newPath}`)
|
||||
await Deno.rename(file, newPath)
|
||||
|
27
clash-verge-rev/src-tauri/Cargo.lock
generated
27
clash-verge-rev/src-tauri/Cargo.lock
generated
@@ -1078,6 +1078,7 @@ dependencies = [
|
||||
"imageproc",
|
||||
"log",
|
||||
"log4rs",
|
||||
"mihomo_api",
|
||||
"mockito",
|
||||
"nanoid",
|
||||
"network-interface",
|
||||
@@ -3723,9 +3724,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3896,6 +3897,16 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mihomo_api"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -5996,9 +6007,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -6038,9 +6049,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6060,9 +6071,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa 1.0.14",
|
||||
"memchr",
|
||||
|
@@ -68,6 +68,7 @@ tokio-tungstenite = "0.26.1"
|
||||
futures = "0.3"
|
||||
sys-locale = "0.3.1"
|
||||
async-trait = "0.1.86"
|
||||
mihomo_api = { path = "./src/crate_mihomo_api" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
@@ -126,3 +127,8 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
env_logger = "0.11.0"
|
||||
mockito = "1.2.0"
|
||||
tempfile = "3.17.1"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"src/crate_mihomo_api"
|
||||
]
|
||||
|
@@ -1,9 +1,5 @@
|
||||
use crate::{
|
||||
utils::dirs,
|
||||
feat,
|
||||
wrap_err,
|
||||
};
|
||||
use super::CmdResult;
|
||||
use crate::{feat, utils::dirs, wrap_err};
|
||||
use tauri::Manager;
|
||||
|
||||
/// 打开应用程序所在目录
|
||||
@@ -93,26 +89,47 @@ pub async fn download_icon_cache(url: String, name: String) -> CmdResult<String>
|
||||
Ok(icon_path.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct IconInfo {
|
||||
name: String,
|
||||
previous_t: String,
|
||||
current_t: String,
|
||||
}
|
||||
|
||||
/// 复制图标文件
|
||||
#[tauri::command]
|
||||
pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
|
||||
let file_path = std::path::Path::new(&path);
|
||||
pub fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<String> {
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
let file_path = Path::new(&path);
|
||||
|
||||
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
|
||||
if !icon_dir.exists() {
|
||||
let _ = std::fs::create_dir_all(&icon_dir);
|
||||
let _ = fs::create_dir_all(&icon_dir);
|
||||
}
|
||||
let ext = match file_path.extension() {
|
||||
Some(e) => e.to_string_lossy().to_string(),
|
||||
None => "ico".to_string(),
|
||||
};
|
||||
|
||||
let png_dest_path = icon_dir.join(format!("{name}.png"));
|
||||
let ico_dest_path = icon_dir.join(format!("{name}.ico"));
|
||||
let dest_path = icon_dir.join(format!("{name}.{ext}"));
|
||||
let dest_path = icon_dir.join(format!(
|
||||
"{0}-{1}.{ext}",
|
||||
icon_info.name, icon_info.current_t
|
||||
));
|
||||
if file_path.exists() {
|
||||
std::fs::remove_file(png_dest_path).unwrap_or_default();
|
||||
std::fs::remove_file(ico_dest_path).unwrap_or_default();
|
||||
match std::fs::copy(file_path, &dest_path) {
|
||||
if icon_info.previous_t.trim() != "" {
|
||||
fs::remove_file(
|
||||
icon_dir.join(format!("{0}-{1}.png", icon_info.name, icon_info.previous_t)),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
fs::remove_file(
|
||||
icon_dir.join(format!("{0}-{1}.ico", icon_info.name, icon_info.previous_t)),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
}
|
||||
|
||||
match fs::copy(file_path, &dest_path) {
|
||||
Ok(_) => Ok(dest_path.to_string_lossy().to_string()),
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
|
@@ -1,35 +1,26 @@
|
||||
use super::CmdResult;
|
||||
use crate::module::mihomo::MihomoManager;
|
||||
use tauri::async_runtime;
|
||||
use crate::core;
|
||||
use mihomo_api;
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
|
||||
let proxies = async_runtime::spawn_blocking(|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let manager = MihomoManager::new();
|
||||
{
|
||||
let mut write_guard = manager.write();
|
||||
rt.block_on(write_guard.refresh_proxies());
|
||||
}
|
||||
let read_guard = manager.read();
|
||||
read_guard.fetch_proxies().clone()
|
||||
})
|
||||
.await.map_err(|e| e.to_string())?;
|
||||
Ok(proxies)
|
||||
let (mihomo_server, _) = core::clash_api::clash_client_info().unwrap();
|
||||
let mihomo = mihomo_api::MihomoManager::new(mihomo_server);
|
||||
Ok(mihomo
|
||||
.refresh_proxies()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_proxies())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
|
||||
let providers_proxies = async_runtime::spawn_blocking(|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let manager = MihomoManager::new();
|
||||
{
|
||||
let mut write_guard = manager.write();
|
||||
rt.block_on(write_guard.refresh_providers_proxies());
|
||||
}
|
||||
let read_guard = manager.read();
|
||||
read_guard.fetch_providers_proxies().clone()
|
||||
})
|
||||
.await.map_err(|e| e.to_string())?;
|
||||
Ok(providers_proxies)
|
||||
}
|
||||
let (mihomo_server, _) = core::clash_api::clash_client_info().unwrap();
|
||||
let mihomo = mihomo_api::MihomoManager::new(mihomo_server);
|
||||
Ok(mihomo
|
||||
.refresh_providers_proxies()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_providers_proxies())
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use super::CmdResult;
|
||||
use crate::{core::handle, model::sysinfo::PlatformSpecification};
|
||||
use crate::core::handle;
|
||||
use crate::module::sysinfo::PlatformSpecification;
|
||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||
use crate::{core::{self, CoreManager, service}, wrap_err};
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
pub const MIHOMO_URL: &str = concat!("http://", "127.0.0.1", ":", "9097");
|
@@ -1 +0,0 @@
|
||||
pub mod mihomo;
|
@@ -21,6 +21,3 @@ pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}
|
||||
"#;
|
||||
|
||||
|
||||
pub mod api;
|
@@ -76,7 +76,7 @@ pub async fn get_proxy_delay(
|
||||
}
|
||||
|
||||
/// 根据clash info获取clash服务地址和请求头
|
||||
fn clash_client_info() -> Result<(String, HeaderMap)> {
|
||||
pub fn clash_client_info() -> Result<(String, HeaderMap)> {
|
||||
let client = { Config::clash().data().get_client_info() };
|
||||
|
||||
let server = format!("http://{}", client.server);
|
||||
|
14
clash-verge-rev/src-tauri/src/crate_mihomo_api/Cargo.toml
Normal file
14
clash-verge-rev/src-tauri/src/crate_mihomo_api/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "mihomo_api"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
debug = []
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12.12", features = ["json"] }
|
||||
serde = { version = "1.0.218", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.43.0", features = ["rt", "macros"] }
|
76
clash-verge-rev/src-tauri/src/crate_mihomo_api/src/lib.rs
Normal file
76
clash-verge-rev/src-tauri/src/crate_mihomo_api/src/lib.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
pub mod model;
|
||||
pub use model::{MihomoData, MihomoManager};
|
||||
|
||||
impl MihomoManager {
|
||||
pub fn new(mihomo_server: String) -> Self {
|
||||
Self {
|
||||
mihomo_server,
|
||||
data: Arc::new(Mutex::new(MihomoData {
|
||||
proxies: serde_json::Value::Null,
|
||||
providers_proxies: serde_json::Value::Null,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_proxies(&self, proxies: serde_json::Value) {
|
||||
let mut data = self.data.lock().unwrap();
|
||||
data.proxies = proxies;
|
||||
}
|
||||
|
||||
fn update_providers_proxies(&self, providers_proxies: serde_json::Value) {
|
||||
let mut data = self.data.lock().unwrap();
|
||||
data.providers_proxies = providers_proxies;
|
||||
}
|
||||
|
||||
pub fn get_proxies(&self) -> serde_json::Value {
|
||||
let data = self.data.lock().unwrap();
|
||||
data.proxies.clone()
|
||||
}
|
||||
|
||||
pub fn get_providers_proxies(&self) -> serde_json::Value {
|
||||
let data = self.data.lock().unwrap();
|
||||
data.providers_proxies.clone()
|
||||
}
|
||||
|
||||
pub async fn refresh_proxies(&self) -> Result<&Self, String> {
|
||||
let url = format!("{}/proxies", self.mihomo_server);
|
||||
let response = reqwest::ClientBuilder::new()
|
||||
.no_proxy()
|
||||
.timeout(Duration::from_secs(3))
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?
|
||||
.get(url)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.json::<serde_json::Value>()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let proxies = response;
|
||||
self.update_proxies(proxies);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub async fn refresh_providers_proxies(&self) -> Result<&Self, String> {
|
||||
let url = format!("{}/providers/proxies", self.mihomo_server);
|
||||
let response = reqwest::ClientBuilder::new()
|
||||
.no_proxy()
|
||||
.timeout(Duration::from_secs(3))
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?
|
||||
.get(url)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.json::<serde_json::Value>()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let proxies = response;
|
||||
self.update_providers_proxies(proxies);
|
||||
Ok(self)
|
||||
}
|
||||
}
|
27
clash-verge-rev/src-tauri/src/crate_mihomo_api/src/model.rs
Normal file
27
clash-verge-rev/src-tauri/src/crate_mihomo_api/src/model.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct MihomoData {
|
||||
pub(crate) proxies: serde_json::Value,
|
||||
pub(crate) providers_proxies: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MihomoManager {
|
||||
pub(crate) mihomo_server: String,
|
||||
pub(crate) data: Arc<Mutex<MihomoData>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Drop for MihomoData {
|
||||
fn drop(&mut self) {
|
||||
println!("Dropping MihomoData");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Drop for MihomoManager {
|
||||
fn drop(&mut self) {
|
||||
println!("Dropping MihomoManager");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
use mihomo_api;
|
||||
|
||||
#[test]
|
||||
fn test_mihomo_manager_init() {
|
||||
let manager = mihomo_api::MihomoManager::new("url".into());
|
||||
assert_eq!(manager.get_proxies(), serde_json::Value::Null);
|
||||
assert_eq!(manager.get_providers_proxies(), serde_json::Value::Null);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_proxies() {
|
||||
let manager = mihomo_api::MihomoManager::new("http://127.0.0.1:9097".into());
|
||||
let manager = manager.refresh_proxies().await.unwrap();
|
||||
let proxies = manager.get_proxies();
|
||||
let providers = manager.get_providers_proxies();
|
||||
assert_ne!(proxies, serde_json::Value::Null);
|
||||
assert_eq!(providers, serde_json::Value::Null);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_providers_proxies() {
|
||||
let manager = mihomo_api::MihomoManager::new("http://127.0.0.1:9097".into());
|
||||
let manager = manager.refresh_providers_proxies().await.unwrap();
|
||||
let proxies = manager.get_proxies();
|
||||
let providers = manager.get_providers_proxies();
|
||||
assert_eq!(proxies, serde_json::Value::Null);
|
||||
assert_ne!(providers, serde_json::Value::Null);
|
||||
}
|
@@ -4,7 +4,6 @@ mod core;
|
||||
mod enhance;
|
||||
mod feat;
|
||||
mod utils;
|
||||
mod model;
|
||||
mod module;
|
||||
use crate::core::hotkey;
|
||||
use crate::utils::{resolve, resolve::resolve_scheme, server};
|
||||
|
@@ -1,20 +0,0 @@
|
||||
use reqwest::Client;
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) struct ApiCaller<'a> {
|
||||
pub(crate) url: &'a str,
|
||||
pub(crate) client: Client,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_api_caller() {
|
||||
let _api_caller = ApiCaller {
|
||||
url: "https://example.com",
|
||||
client: Client::new(),
|
||||
};
|
||||
}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
use super::common::ApiCaller;
|
||||
|
||||
pub struct MihomoAPICaller {
|
||||
pub(crate) caller: ApiCaller<'static>,
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
pub mod common;
|
||||
pub mod mihomo;
|
@@ -1,2 +0,0 @@
|
||||
pub mod api;
|
||||
pub mod sysinfo;
|
@@ -1,18 +0,0 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
pub struct PlatformSpecification {
|
||||
pub system_name: String,
|
||||
pub system_version: String,
|
||||
pub system_kernel_version: String,
|
||||
pub system_arch: String,
|
||||
}
|
||||
|
||||
impl Debug for PlatformSpecification {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}",
|
||||
self.system_name, self.system_version, self.system_kernel_version, self.system_arch
|
||||
)
|
||||
}
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
use crate::model::api::common::ApiCaller;
|
||||
use async_trait::async_trait;
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderName, HeaderValue},
|
||||
RequestBuilder,
|
||||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
impl<'a> ApiCaller<'a> {
|
||||
pub async fn send_request(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
) -> Result<String, String> {
|
||||
let full_url = format!("{}{}", self.url, path); // 拼接完整 URL
|
||||
let mut request: RequestBuilder = match method {
|
||||
"GET" => self.client.get(&full_url),
|
||||
"POST" => self
|
||||
.client
|
||||
.post(&full_url)
|
||||
.body(body.unwrap_or("").to_string()),
|
||||
"PUT" => self
|
||||
.client
|
||||
.put(&full_url)
|
||||
.body(body.unwrap_or("").to_string()),
|
||||
"DELETE" => self.client.delete(&full_url),
|
||||
_ => return Err("Unsupported HTTP method".to_string()),
|
||||
};
|
||||
|
||||
// 处理 headers
|
||||
if let Some(hdrs) = headers {
|
||||
let mut header_map = HeaderMap::new();
|
||||
for (key, value) in hdrs {
|
||||
if let (Ok(header_name), Ok(header_value)) = (
|
||||
HeaderName::from_bytes(key.as_bytes()),
|
||||
HeaderValue::from_str(value),
|
||||
) {
|
||||
header_map.insert(header_name, header_value);
|
||||
}
|
||||
}
|
||||
request = request.headers(header_map);
|
||||
}
|
||||
|
||||
let response = request.send().await.map_err(|e| e.to_string())?;
|
||||
response.text().await.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[async_trait]
|
||||
pub trait ApiCallerTrait: Send + Sync {
|
||||
async fn call_api<T>(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>
|
||||
) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned + Send + Sync;
|
||||
|
||||
fn parse_json_response<T>(json_str: &str) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
serde_json::from_str(json_str).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
use super::common::ApiCallerTrait;
|
||||
use crate::config::api::mihomo::MIHOMO_URL;
|
||||
use crate::model::api::common::ApiCaller;
|
||||
use crate::model::api::mihomo::MihomoAPICaller;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use reqwest::Client;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl MihomoAPICaller {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
static INSTANCE: OnceCell<Arc<RwLock<MihomoAPICaller>>> = OnceCell::new();
|
||||
INSTANCE
|
||||
.get_or_init(|| {
|
||||
let client = Client::new();
|
||||
Arc::new(RwLock::new(MihomoAPICaller {
|
||||
caller: ApiCaller {
|
||||
url: MIHOMO_URL,
|
||||
client,
|
||||
},
|
||||
}))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ApiCallerTrait for MihomoAPICaller {
|
||||
async fn call_api<T>(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned + Send + Sync,
|
||||
{
|
||||
let response = self
|
||||
.caller
|
||||
.send_request(method, path, body, headers)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Self::parse_json_response::<T>(&response)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl MihomoAPICaller {
|
||||
pub async fn get_proxies() -> Result<serde_json::Value, String> {
|
||||
Self::new()
|
||||
.read()
|
||||
.call_api("GET", "/proxies", None, None)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_providers_proxies() -> Result<serde_json::Value, String> {
|
||||
Self::new()
|
||||
.read()
|
||||
.call_api("GET", "/providers/proxies", None, None)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_api_singleton() {
|
||||
let mihomo_api_caller1 = MihomoAPICaller::new();
|
||||
let mihomo_api_caller2 = MihomoAPICaller::new();
|
||||
assert!(Arc::ptr_eq(&mihomo_api_caller1, &mihomo_api_caller2));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_api_version() {
|
||||
let mihomo_caller = MihomoAPICaller::new();
|
||||
let response: Result<serde_json::Value, String> = mihomo_caller
|
||||
.read()
|
||||
.call_api("GET", "/version", None, None)
|
||||
.await;
|
||||
assert!(response.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_get_proxies() {
|
||||
let response = MihomoAPICaller::get_proxies().await;
|
||||
assert!(response.is_ok());
|
||||
if let Ok(proxies) = &response {
|
||||
assert!(!proxies.get("proxies").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_get_providers_proxies() {
|
||||
let response = MihomoAPICaller::get_providers_proxies().await;
|
||||
println!("{:?}", response);
|
||||
assert!(response.is_ok());
|
||||
if let Ok(providers_proxies) = &response {
|
||||
assert!(!providers_proxies.get("providers").is_none());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
pub mod common;
|
||||
pub mod mihomo;
|
@@ -1,158 +0,0 @@
|
||||
use crate::model::api::mihomo::MihomoAPICaller;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct MihomoManager {
|
||||
proxies: serde_json::Value,
|
||||
providers_proxies: serde_json::Value,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl MihomoManager {
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
static INSTANCE: OnceCell<Arc<RwLock<MihomoManager>>> = OnceCell::new();
|
||||
INSTANCE
|
||||
.get_or_init(|| {
|
||||
Arc::new(RwLock::new(MihomoManager {
|
||||
proxies: serde_json::Value::Null,
|
||||
providers_proxies: serde_json::Value::Null,
|
||||
}))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn fetch_proxies(&self) -> &serde_json::Value {
|
||||
&self.proxies
|
||||
}
|
||||
|
||||
pub fn fetch_providers_proxies(&self) -> &serde_json::Value {
|
||||
&self.providers_proxies
|
||||
}
|
||||
|
||||
pub async fn refresh_proxies(&mut self) {
|
||||
match MihomoAPICaller::get_proxies().await {
|
||||
Ok(proxies) => {
|
||||
self.proxies = proxies;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to get proxies: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh_providers_proxies(&mut self) {
|
||||
match MihomoAPICaller::get_providers_proxies().await {
|
||||
Ok(providers_proxies) => {
|
||||
self.providers_proxies = providers_proxies;
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to get providers proxies: {}", e);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_manager_singleton() {
|
||||
let manager1 = MihomoManager::new();
|
||||
let manager2 = MihomoManager::new();
|
||||
|
||||
assert!(
|
||||
Arc::ptr_eq(&manager1, &manager2),
|
||||
"Should return same instance"
|
||||
);
|
||||
|
||||
let manager = manager1.read();
|
||||
assert!(manager.proxies.is_null());
|
||||
assert!(manager.providers_proxies.is_null());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
assert!(data.proxies.is_null());
|
||||
}
|
||||
|
||||
// Test refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_proxies().await;
|
||||
// Note: Since this depends on external API call,
|
||||
// we can only verify that the refresh call completes
|
||||
// without panicking. For more thorough testing,
|
||||
// we would need to mock the API caller.
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_providers_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
assert!(data.providers_proxies.is_null());
|
||||
}
|
||||
|
||||
// Test refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_providers_proxies().await;
|
||||
// Note: Since this depends on external API call,
|
||||
// we can only verify that the refresh call completes
|
||||
// without panicking. For more thorough testing,
|
||||
// we would need to mock the API caller.
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
let proxies = data.fetch_proxies();
|
||||
assert!(proxies.is_null());
|
||||
}
|
||||
|
||||
// Test after refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_proxies().await;
|
||||
let _proxies = data.fetch_proxies();
|
||||
// Can only verify the method returns without panicking
|
||||
// Would need API mocking for more thorough testing
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_providers_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
let providers_proxies = data.fetch_providers_proxies();
|
||||
assert!(providers_proxies.is_null());
|
||||
}
|
||||
|
||||
// Test after refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_providers_proxies().await;
|
||||
let _providers_proxies = data.fetch_providers_proxies();
|
||||
// Can only verify the method returns without panicking
|
||||
// Would need API mocking for more thorough testing
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +1 @@
|
||||
pub mod api;
|
||||
pub mod sysinfo;
|
||||
pub mod mihomo;
|
||||
pub mod sysinfo;
|
@@ -1,7 +1,26 @@
|
||||
use crate::model::sysinfo::PlatformSpecification;
|
||||
|
||||
use crate::core::{handle, CoreManager};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use sysinfo::System;
|
||||
|
||||
pub struct PlatformSpecification {
|
||||
system_name: String,
|
||||
system_version: String,
|
||||
system_kernel_version: String,
|
||||
system_arch: String,
|
||||
verge_version: String,
|
||||
running_mode: String,
|
||||
}
|
||||
|
||||
impl Debug for PlatformSpecification {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"System Name: {}\nSystem Version: {}\nSystem kernel Version: {}\nSystem Arch: {}\nVerge Version: {}\nRunning Mode: {}",
|
||||
self.system_name, self.system_version, self.system_kernel_version, self.system_arch, self.verge_version, self.running_mode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformSpecification {
|
||||
pub fn new() -> Self {
|
||||
let system_name = System::name().unwrap_or("Null".into());
|
||||
@@ -9,11 +28,29 @@ impl PlatformSpecification {
|
||||
let system_kernel_version = System::kernel_version().unwrap_or("Null".into());
|
||||
let system_arch = std::env::consts::ARCH.to_string();
|
||||
|
||||
let handler = handle::Handle::global().app_handle().unwrap();
|
||||
let config = handler.config();
|
||||
let verge_version = config.version.clone().unwrap_or("Null".into());
|
||||
|
||||
// Get running mode asynchronously
|
||||
let running_mode = tokio::task::block_in_place(|| {
|
||||
tokio::runtime::Handle::current().block_on(async {
|
||||
match CoreManager::global().get_running_mode().await {
|
||||
crate::core::RunningMode::Service => "Service".to_string(),
|
||||
crate::core::RunningMode::Sidecar => "Sidecar".to_string(),
|
||||
crate::core::RunningMode::NotRunning => "Not Running".to_string(),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Self {
|
||||
system_name,
|
||||
system_version,
|
||||
system_kernel_version,
|
||||
system_arch
|
||||
system_arch,
|
||||
verge_version,
|
||||
running_mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,18 @@ import getSystem from "@/utils/get-system";
|
||||
|
||||
const OS = getSystem();
|
||||
|
||||
const getIcons = async (icon_dir: string, name: string) => {
|
||||
const updateTime = localStorage.getItem(`icon_${name}_update_time`) || "";
|
||||
|
||||
const icon_png = await join(icon_dir, `${name}-${updateTime}.png`);
|
||||
const icon_ico = await join(icon_dir, `${name}-${updateTime}.ico`);
|
||||
|
||||
return {
|
||||
icon_png,
|
||||
icon_ico,
|
||||
};
|
||||
};
|
||||
|
||||
export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
@@ -37,13 +49,20 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
async function initIconPath() {
|
||||
const appDir = await getAppDir();
|
||||
|
||||
const icon_dir = await join(appDir, "icons");
|
||||
const common_icon_png = await join(icon_dir, "common.png");
|
||||
const common_icon_ico = await join(icon_dir, "common.ico");
|
||||
const sysproxy_icon_png = await join(icon_dir, "sysproxy.png");
|
||||
const sysproxy_icon_ico = await join(icon_dir, "sysproxy.ico");
|
||||
const tun_icon_png = await join(icon_dir, "tun.png");
|
||||
const tun_icon_ico = await join(icon_dir, "tun.ico");
|
||||
|
||||
const { icon_png: common_icon_png, icon_ico: common_icon_ico } =
|
||||
await getIcons(icon_dir, "common");
|
||||
|
||||
const { icon_png: sysproxy_icon_png, icon_ico: sysproxy_icon_ico } =
|
||||
await getIcons(icon_dir, "sysproxy");
|
||||
|
||||
const { icon_png: tun_icon_png, icon_ico: tun_icon_ico } = await getIcons(
|
||||
icon_dir,
|
||||
"tun",
|
||||
);
|
||||
|
||||
if (await exists(common_icon_ico)) {
|
||||
setCommonIcon(common_icon_ico);
|
||||
} else {
|
||||
@@ -212,11 +231,13 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (selected) {
|
||||
await copyIconFile(`${selected}`, "common");
|
||||
await initIconPath();
|
||||
onChangeData({ common_tray_icon: true });
|
||||
patchVerge({ common_tray_icon: true });
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
@@ -54,10 +54,6 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
proxy_auto_config,
|
||||
} = verge ?? {};
|
||||
|
||||
const isProxyEnabled = proxy_auto_config
|
||||
? autoproxy?.enable
|
||||
: sysproxy?.enable;
|
||||
|
||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||
const onChangeData = (patch: Partial<IVergeConfig>) => {
|
||||
mutateVerge({ ...verge, ...patch }, false);
|
||||
@@ -149,7 +145,13 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
icon={SettingsRounded}
|
||||
onClick={() => sysproxyRef.current?.open()}
|
||||
/>
|
||||
{isProxyEnabled ? (
|
||||
{proxy_auto_config ? (
|
||||
autoproxy?.enable ? (
|
||||
<PlayArrowRounded sx={{ color: "success.main", mr: 1 }} />
|
||||
) : (
|
||||
<PauseRounded sx={{ color: "error.main", mr: 1 }} />
|
||||
)
|
||||
) : sysproxy?.enable ? (
|
||||
<PlayArrowRounded sx={{ color: "success.main", mr: 1 }} />
|
||||
) : (
|
||||
<PauseRounded sx={{ color: "error.main", mr: 1 }} />
|
||||
|
@@ -166,9 +166,12 @@ const Layout = () => {
|
||||
}),
|
||||
|
||||
// verge 配置更新监听
|
||||
addListener("verge://refresh-verge-config", () =>
|
||||
mutate("getVergeConfig"),
|
||||
),
|
||||
addListener("verge://refresh-verge-config", () => {
|
||||
mutate("getVergeConfig");
|
||||
// 添加对系统代理状态的刷新
|
||||
mutate("getSystemProxy");
|
||||
mutate("getAutotemProxy");
|
||||
}),
|
||||
|
||||
// 通知消息监听
|
||||
addListener("verge://notice-message", ({ payload }) =>
|
||||
|
@@ -199,7 +199,19 @@ export async function copyIconFile(
|
||||
path: string,
|
||||
name: "common" | "sysproxy" | "tun",
|
||||
) {
|
||||
return invoke<void>("copy_icon_file", { path, name });
|
||||
const key = `icon_${name}_update_time`;
|
||||
const previousTime = localStorage.getItem(key) || "";
|
||||
|
||||
const currentTime = String(Date.now());
|
||||
localStorage.setItem(key, currentTime);
|
||||
|
||||
const iconInfo = {
|
||||
name,
|
||||
previous_t: previousTime,
|
||||
current_t: currentTime,
|
||||
};
|
||||
|
||||
return invoke<void>("copy_icon_file", { path, iconInfo });
|
||||
}
|
||||
|
||||
export async function downloadIconCache(url: string, name: string) {
|
||||
|
@@ -1219,7 +1219,8 @@
|
||||
};
|
||||
|
||||
sdhci: mmc@ffbf0000 {
|
||||
compatible = "rockchip,rk3528-dwcmshc";
|
||||
compatible = "rockchip,rk3528-dwcmshc",
|
||||
"rockchip,rk3588-dwcmshc";
|
||||
reg = <0x0 0xffbf0000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
|
||||
assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>, <&cru CCLK_SRC_EMMC>;
|
||||
|
@@ -28,12 +28,15 @@
|
||||
#phy-cells = <1>;
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
|
||||
@@ -299,7 +299,7 @@ static int rockchip_combphy_parse_dt(str
|
||||
@@ -299,7 +299,10 @@ static int rockchip_combphy_parse_dt(str
|
||||
|
||||
priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk");
|
||||
|
||||
- priv->phy_rst = devm_reset_control_array_get_exclusive(dev);
|
||||
+ priv->phy_rst = devm_reset_control_get(dev, "phy");
|
||||
- priv->phy_rst = devm_reset_control_get(dev, "phy");
|
||||
+ priv->phy_rst = devm_reset_control_get_exclusive(dev, "phy");
|
||||
+ /* fallback to old behaviour */
|
||||
+ if (PTR_ERR(priv->phy_rst) == -ENOENT)
|
||||
+ priv->phy_rst = devm_reset_control_array_get_exclusive(dev);
|
||||
if (IS_ERR(priv->phy_rst))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->phy_rst), "failed to get phy reset\n");
|
||||
|
||||
|
@@ -1,100 +1,3 @@
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -295,19 +295,20 @@ static void dwcmshc_rk3568_set_clock(str
|
||||
0x3 << 19; /* post-change delay */
|
||||
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||
|
||||
- if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
|
||||
- host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
|
||||
txclk_tapnum = priv->txclk_tapnum;
|
||||
|
||||
- if ((priv->devtype == DWCMSHC_RK3588) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
|
||||
|
||||
- extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
- DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
- DWCMSHC_EMMC_DLL_DLYENA |
|
||||
- DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
- DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
- sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ if (priv->devtype != DWCMSHC_RK3568) {
|
||||
+ extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
+ DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
+ DWCMSHC_EMMC_DLL_DLYENA |
|
||||
+ DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
+ DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
+ sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ }
|
||||
}
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
@@ -355,6 +356,15 @@ static const struct sdhci_ops sdhci_dwcm
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
};
|
||||
|
||||
+static const struct sdhci_ops sdhci_dwcmshc_rk3528_ops = {
|
||||
+ .set_clock = dwcmshc_rk3568_set_clock,
|
||||
+ .set_bus_width = sdhci_set_bus_width,
|
||||
+ .set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
+ .reset = rk35xx_sdhci_reset,
|
||||
+ .adma_write_desc = dwcmshc_adma_write_desc,
|
||||
+};
|
||||
+
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.ops = &sdhci_dwcmshc_ops,
|
||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||
@@ -378,6 +388,14 @@ static const struct sdhci_pltfm_data sdh
|
||||
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
};
|
||||
|
||||
+static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3528_pdata = {
|
||||
+ .ops = &sdhci_dwcmshc_rk3528_ops,
|
||||
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
+};
|
||||
+
|
||||
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
{
|
||||
int err;
|
||||
@@ -443,6 +461,10 @@ static const struct of_device_id sdhci_d
|
||||
.data = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
},
|
||||
{
|
||||
+ .compatible = "rockchip,rk3528-dwcmshc",
|
||||
+ .data = &sdhci_dwcmshc_rk3528_pdata,
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &sdhci_dwcmshc_pdata,
|
||||
},
|
||||
@@ -521,17 +543,18 @@ static int dwcmshc_probe(struct platform
|
||||
host->mmc_host_ops.request = dwcmshc_request;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
|
||||
|
||||
- if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
|
||||
+ if ((pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) ||
|
||||
+ (pltfm_data == &sdhci_dwcmshc_rk3528_pdata)) {
|
||||
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
|
||||
if (!rk_priv) {
|
||||
err = -ENOMEM;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
- if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc"))
|
||||
- rk_priv->devtype = DWCMSHC_RK3588;
|
||||
- else
|
||||
+ if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3568-dwcmshc"))
|
||||
rk_priv->devtype = DWCMSHC_RK3568;
|
||||
+ else
|
||||
+ rk_priv->devtype = DWCMSHC_RK3588;
|
||||
|
||||
priv->priv = rk_priv;
|
||||
|
||||
--- a/drivers/pci/controller/dwc/Makefile
|
||||
+++ b/drivers/pci/controller/dwc/Makefile
|
||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_PCIE_QCOM_EP) += pcie-qcom-
|
||||
|
@@ -1,3 +1,16 @@
|
||||
From 7c24d9902e1dab659e020798f0d682e0cd650a88 Mon Sep 17 00:00:00 2001
|
||||
From: Jianwei Zheng <jianwei.zheng@rock-chips.com>
|
||||
Date: Sun, 9 Oct 2022 11:22:44 +0800
|
||||
Subject: [PATCH] phy: rockchip: inno-usb2: add usb2 phy support for rk3528
|
||||
|
||||
This patch add usb2 phy support for rk3528.
|
||||
|
||||
Signed-off-by: Jianwei Zheng <jianwei.zheng@rock-chips.com>
|
||||
Change-Id: Ia4a861bccd6a37db4e1ba42cede66a6b07947b5d
|
||||
---
|
||||
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 51 ++++++++++++++++
|
||||
1 file changed, 51 insertions(+)
|
||||
|
||||
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
|
||||
@@ -1905,6 +1905,56 @@ static const struct rockchip_usb2phy_cfg
|
||||
@@ -11,10 +24,10 @@
|
||||
+ .clkout_ctl = { 0x041c, 7, 2, 0, 0x27 },
|
||||
+ .port_cfgs = {
|
||||
+ [USB2PHY_PORT_OTG] = {
|
||||
+ .phy_sus = { 0x6004c, 15, 0, 0, 0x1d1 },
|
||||
+ .bvalid_det_en = { 0x60074, 3, 2, 0, 3 },
|
||||
+ .bvalid_det_st = { 0x60078, 3, 2, 0, 3 },
|
||||
+ .bvalid_det_clr = { 0x6007c, 3, 2, 0, 3 },
|
||||
+ .phy_sus = { 0x6004c, 8, 0, 0, 0x1d1 },
|
||||
+ .bvalid_det_en = { 0x60074, 2, 2, 0, 1 },
|
||||
+ .bvalid_det_st = { 0x60078, 2, 2, 0, 1 },
|
||||
+ .bvalid_det_clr = { 0x6007c, 2, 2, 0, 1 },
|
||||
+ .idfall_det_en = { 0x60074, 5, 5, 0, 1 },
|
||||
+ .idfall_det_st = { 0x60078, 5, 5, 0, 1 },
|
||||
+ .idfall_det_clr = { 0x6007c, 5, 5, 0, 1 },
|
||||
@@ -30,7 +43,7 @@
|
||||
+ .utmi_ls = { 0x6006c, 5, 4, 0, 1 },
|
||||
+ },
|
||||
+ [USB2PHY_PORT_HOST] = {
|
||||
+ .phy_sus = { 0x6005c, 15, 0, 0x1d2, 0x1d1 },
|
||||
+ .phy_sus = { 0x6005c, 8, 0, 0x1d2, 0x1d1 },
|
||||
+ .ls_det_en = { 0x60090, 0, 0, 0, 1 },
|
||||
+ .ls_det_st = { 0x60094, 0, 0, 0, 1 },
|
||||
+ .ls_det_clr = { 0x60098, 0, 0, 0, 1 },
|
||||
|
@@ -1,96 +1,3 @@
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -688,19 +688,20 @@ static void dwcmshc_rk3568_set_clock(str
|
||||
0x3 << 19; /* post-change delay */
|
||||
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||
|
||||
- if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
|
||||
- host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
|
||||
txclk_tapnum = priv->txclk_tapnum;
|
||||
|
||||
- if ((priv->devtype == DWCMSHC_RK3588) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
|
||||
|
||||
- extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
- DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
- DWCMSHC_EMMC_DLL_DLYENA |
|
||||
- DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
- DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
- sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ if (priv->devtype != DWCMSHC_RK3568) {
|
||||
+ extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
+ DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
+ DWCMSHC_EMMC_DLL_DLYENA |
|
||||
+ DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
+ DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
+ sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ }
|
||||
}
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
@@ -741,10 +742,10 @@ static int dwcmshc_rk35xx_init(struct de
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
- if (of_device_is_compatible(dev->of_node, "rockchip,rk3588-dwcmshc"))
|
||||
- priv->devtype = DWCMSHC_RK3588;
|
||||
- else
|
||||
+ if (of_device_is_compatible(dev->of_node, "rockchip,rk3568-dwcmshc"))
|
||||
priv->devtype = DWCMSHC_RK3568;
|
||||
+ else
|
||||
+ priv->devtype = DWCMSHC_RK3588;
|
||||
|
||||
priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc));
|
||||
if (IS_ERR(priv->reset)) {
|
||||
@@ -1156,6 +1157,16 @@ static const struct sdhci_ops sdhci_dwcm
|
||||
.irq = dwcmshc_cqe_irq_handler,
|
||||
};
|
||||
|
||||
+static const struct sdhci_ops sdhci_dwcmshc_rk3528_ops = {
|
||||
+ .set_clock = dwcmshc_rk3568_set_clock,
|
||||
+ .set_bus_width = sdhci_set_bus_width,
|
||||
+ .set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
+ .reset = rk35xx_sdhci_reset,
|
||||
+ .adma_write_desc = dwcmshc_adma_write_desc,
|
||||
+ .irq = dwcmshc_cqe_irq_handler,
|
||||
+};
|
||||
+
|
||||
static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
@@ -1218,6 +1229,18 @@ static const struct dwcmshc_pltfm_data s
|
||||
.postinit = dwcmshc_rk35xx_postinit,
|
||||
};
|
||||
|
||||
+static const struct dwcmshc_pltfm_data sdhci_dwcmshc_rk3528_pdata = {
|
||||
+ .pdata = {
|
||||
+ .ops = &sdhci_dwcmshc_rk3528_ops,
|
||||
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
+ },
|
||||
+ .init = dwcmshc_rk35xx_init,
|
||||
+ .postinit = dwcmshc_rk35xx_postinit,
|
||||
+};
|
||||
+
|
||||
static const struct dwcmshc_pltfm_data sdhci_dwcmshc_th1520_pdata = {
|
||||
.pdata = {
|
||||
.ops = &sdhci_dwcmshc_th1520_ops,
|
||||
@@ -1320,6 +1343,10 @@ static const struct of_device_id sdhci_d
|
||||
.compatible = "rockchip,rk3568-dwcmshc",
|
||||
.data = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
},
|
||||
+ {
|
||||
+ .compatible = "rockchip,rk3528-dwcmshc",
|
||||
+ .data = &sdhci_dwcmshc_rk3528_pdata,
|
||||
+ },
|
||||
{
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &sdhci_dwcmshc_pdata,
|
||||
--- a/drivers/pci/controller/dwc/Makefile
|
||||
+++ b/drivers/pci/controller/dwc/Makefile
|
||||
@@ -18,6 +18,7 @@ obj-$(CONFIG_PCIE_QCOM_EP) += pcie-qcom-
|
||||
|
@@ -1,100 +1,3 @@
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -296,19 +296,20 @@ static void dwcmshc_rk3568_set_clock(str
|
||||
0x3 << 19; /* post-change delay */
|
||||
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||
|
||||
- if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
|
||||
- host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
|
||||
txclk_tapnum = priv->txclk_tapnum;
|
||||
|
||||
- if ((priv->devtype == DWCMSHC_RK3588) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
|
||||
|
||||
- extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
- DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
- DWCMSHC_EMMC_DLL_DLYENA |
|
||||
- DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
- DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
- sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ if (priv->devtype != DWCMSHC_RK3568) {
|
||||
+ extra = DLL_CMDOUT_SRC_CLK_NEG |
|
||||
+ DLL_CMDOUT_EN_SRC_CLK_NEG |
|
||||
+ DWCMSHC_EMMC_DLL_DLYENA |
|
||||
+ DLL_CMDOUT_TAPNUM_90_DEGREES |
|
||||
+ DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
+ sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
+ }
|
||||
}
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
@@ -356,6 +357,15 @@ static const struct sdhci_ops sdhci_dwcm
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
};
|
||||
|
||||
+static const struct sdhci_ops sdhci_dwcmshc_rk3528_ops = {
|
||||
+ .set_clock = dwcmshc_rk3568_set_clock,
|
||||
+ .set_bus_width = sdhci_set_bus_width,
|
||||
+ .set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
+ .reset = rk35xx_sdhci_reset,
|
||||
+ .adma_write_desc = dwcmshc_adma_write_desc,
|
||||
+};
|
||||
+
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.ops = &sdhci_dwcmshc_ops,
|
||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||
@@ -379,6 +389,14 @@ static const struct sdhci_pltfm_data sdh
|
||||
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
};
|
||||
|
||||
+static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3528_pdata = {
|
||||
+ .ops = &sdhci_dwcmshc_rk3528_ops,
|
||||
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
+};
|
||||
+
|
||||
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
{
|
||||
int err;
|
||||
@@ -444,6 +462,10 @@ static const struct of_device_id sdhci_d
|
||||
.data = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
},
|
||||
{
|
||||
+ .compatible = "rockchip,rk3528-dwcmshc",
|
||||
+ .data = &sdhci_dwcmshc_rk3528_pdata,
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &sdhci_dwcmshc_pdata,
|
||||
},
|
||||
@@ -523,17 +545,18 @@ static int dwcmshc_probe(struct platform
|
||||
host->mmc_host_ops.request = dwcmshc_request;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
|
||||
|
||||
- if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
|
||||
+ if ((pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) ||
|
||||
+ (pltfm_data == &sdhci_dwcmshc_rk3528_pdata)) {
|
||||
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
|
||||
if (!rk_priv) {
|
||||
err = -ENOMEM;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
- if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc"))
|
||||
- rk_priv->devtype = DWCMSHC_RK3588;
|
||||
- else
|
||||
+ if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3568-dwcmshc"))
|
||||
rk_priv->devtype = DWCMSHC_RK3568;
|
||||
+ else
|
||||
+ rk_priv->devtype = DWCMSHC_RK3588;
|
||||
|
||||
priv->priv = rk_priv;
|
||||
|
||||
--- a/drivers/pci/controller/dwc/Makefile
|
||||
+++ b/drivers/pci/controller/dwc/Makefile
|
||||
@@ -17,6 +17,7 @@ obj-$(CONFIG_PCIE_QCOM_EP) += pcie-qcom-
|
||||
|
@@ -25,6 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
appctl.RecordAppStartTime()
|
||||
appctl.SetAppType(appctl.CLIENT_APP)
|
||||
debug.SetGCPercent(90)
|
||||
cli.RegisterClientCommands()
|
||||
|
@@ -25,6 +25,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
appctl.RecordAppStartTime()
|
||||
appctl.SetAppType(appctl.SERVER_APP)
|
||||
debug.SetGCPercent(90)
|
||||
cli.RegisterServerCommands()
|
||||
|
43
mieru/pkg/appctl/apptime.go
Normal file
43
mieru/pkg/appctl/apptime.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2025 mieru authors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package appctl
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
appStartTime time.Time
|
||||
appStartTimeOnce sync.Once
|
||||
)
|
||||
|
||||
// RecordAppStartTime record the app start time.
|
||||
// This function does nothing after the first use.
|
||||
func RecordAppStartTime() {
|
||||
appStartTimeOnce.Do(func() {
|
||||
appStartTime = time.Now()
|
||||
})
|
||||
}
|
||||
|
||||
// Elapsed returns the how long the app has been started.
|
||||
// It panics if the start time is not recorded.
|
||||
func Elapsed() time.Duration {
|
||||
if appStartTime.IsZero() {
|
||||
panic("app start time is not recorded")
|
||||
}
|
||||
return time.Since(appStartTime).Truncate(time.Microsecond)
|
||||
}
|
@@ -682,6 +682,7 @@ var clientRunFunc = func(s []string) error {
|
||||
metrics.EnableLogging()
|
||||
|
||||
appctl.SetAppStatus(appctlpb.AppStatus_RUNNING)
|
||||
log.Debugf("Started proxy after %v", appctl.Elapsed())
|
||||
wg.Wait()
|
||||
|
||||
// Stop CPU profiling, if previously started.
|
||||
|
@@ -474,8 +474,10 @@ var serverRunFunc = func(s []string) error {
|
||||
initProxyTasks.Wait()
|
||||
metrics.EnableLogging()
|
||||
appctl.SetAppStatus(appctlpb.AppStatus_RUNNING)
|
||||
log.Debugf("Started proxy after %v", appctl.Elapsed())
|
||||
proxyTasks.Wait()
|
||||
}
|
||||
|
||||
// If fails to validate server configuration, do nothing.
|
||||
// Most likely the server configuration is empty.
|
||||
// It will be set by new RPC calls.
|
||||
|
@@ -293,7 +293,6 @@ jobs:
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall=m" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_Iptables_Transparent_Proxy=y" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_Nftables_Transparent_Proxy=y" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Geoview=y" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Haproxy=y" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_INCLUDE_Hysteria=y" >> .config
|
||||
echo "CONFIG_PACKAGE_luci-app-passwall_INCLUDE_NaiveProxy=y" >> .config
|
||||
|
@@ -45,7 +45,34 @@ o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/chi
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/apple-cn.txt", translate("Loyalsoldier/apple-cn"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/google-cn.txt", translate("Loyalsoldier/google-cn"))
|
||||
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
if has_xray or has_singbox then
|
||||
o = s:option(ListValue, "geoip_url", translate("GeoIP Update URL"))
|
||||
o:value("https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest", translate("Loyalsoldier/geoip"))
|
||||
o:value("https://api.github.com/repos/MetaCubeX/meta-rules-dat/releases/latest", translate("MetaCubeX/geoip"))
|
||||
o.default = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
|
||||
o = s:option(ListValue, "geosite_url", translate("Geosite Update URL"))
|
||||
o:value("https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest", translate("Loyalsoldier/geosite"))
|
||||
o:value("https://api.github.com/repos/MetaCubeX/meta-rules-dat/releases/latest", translate("MetaCubeX/geosite"))
|
||||
o.default = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
|
||||
o = s:option(Value, "v2ray_location_asset", translate("Location of Geo rule files"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
|
||||
o.default = "/usr/share/v2ray/"
|
||||
o.placeholder = "/usr/share/v2ray/"
|
||||
o.rmempty = false
|
||||
|
||||
if api.is_finded("geoview") then
|
||||
o = s:option(Flag, "enable_geoview", translate("Enable Geo Data Parsing"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
o.description = "<ul>"
|
||||
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
||||
.. "<li>" .. "1." .. translate("Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray.") .. "</li>"
|
||||
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
||||
.. "<li>" .. translate("Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes.") .. "</li>"
|
||||
.. "</ul>"
|
||||
end
|
||||
end
|
||||
|
||||
---- Auto Update
|
||||
o = s:option(Flag, "auto_update", translate("Enable auto update rules"))
|
||||
@@ -88,23 +115,9 @@ o.default = 2
|
||||
o:depends("week_update", "8")
|
||||
o.rmempty = true
|
||||
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
|
||||
if has_xray or has_singbox then
|
||||
o = s:option(Value, "v2ray_location_asset", translate("Location of V2ray/Xray asset"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
|
||||
o.default = "/usr/share/v2ray/"
|
||||
o.rmempty = false
|
||||
|
||||
if api.is_finded("geoview") then
|
||||
o = s:option(Flag, "enable_geoview", translate("Enable Geo Data Parsing"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
o.description = "<ul>"
|
||||
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
||||
.. "<li>" .. "1." .. translate("Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray.") .. "</li>"
|
||||
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
||||
.. "<li>" .. translate("Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes.") .. "</li>"
|
||||
.. "</ul>"
|
||||
end
|
||||
|
||||
s = m:section(TypedSection, "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
|
||||
s.template = "cbi/tblsection"
|
||||
s.anonymous = false
|
||||
|
@@ -937,8 +937,14 @@ msgstr "小时"
|
||||
msgid "Hour"
|
||||
msgstr "小时"
|
||||
|
||||
msgid "Location of V2ray/Xray asset"
|
||||
msgstr "V2ray/Xray 资源文件目录"
|
||||
msgid "GeoIP Update URL"
|
||||
msgstr "GeoIP 更新URL"
|
||||
|
||||
msgid "Geosite Update URL"
|
||||
msgstr "Geosite 更新URL"
|
||||
|
||||
msgid "Location of Geo rule files"
|
||||
msgstr "Geo 规则文件目录"
|
||||
|
||||
msgid "This variable specifies a directory where geoip.dat and geosite.dat files are."
|
||||
msgstr "此变量指定 geoip.dat 和 geosite.dat 文件所在的目录。"
|
||||
|
@@ -72,6 +72,8 @@ config global_rules
|
||||
list chnlist_url 'https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf'
|
||||
list chnlist_url 'https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf'
|
||||
option v2ray_location_asset '/usr/share/v2ray/'
|
||||
option geoip_url 'https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest'
|
||||
option geosite_url 'https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest'
|
||||
|
||||
config global_app
|
||||
option singbox_file '/usr/bin/sing-box'
|
||||
|
@@ -350,8 +350,7 @@ parse_doh() {
|
||||
get_geoip() {
|
||||
local geoip_code="$1"
|
||||
local geoip_type_flag=""
|
||||
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
geoip_path="${geoip_path%*/}/geoip.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
[ -s "$geoip_path" ] || { echo ""; return 1; }
|
||||
case "$2" in
|
||||
"ipv4") geoip_type_flag="-ipv6=false" ;;
|
||||
@@ -777,9 +776,8 @@ run_redir() {
|
||||
sing-box)
|
||||
local protocol=$(config_n_get $node protocol)
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,UDP Sing-Box分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -789,9 +787,8 @@ run_redir() {
|
||||
xray)
|
||||
local protocol=$(config_n_get $node protocol)
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,UDP Xray分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -896,9 +893,8 @@ run_redir() {
|
||||
}
|
||||
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,TCP Sing-Box分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -983,9 +979,8 @@ run_redir() {
|
||||
}
|
||||
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,TCP Xray分流节点无法正常使用!"
|
||||
fi
|
||||
|
@@ -88,7 +88,7 @@ local function insert_array_after(array1, array2, target) --将array2插入到ar
|
||||
end
|
||||
|
||||
local function get_geosite(list_arg, out_path)
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset")
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
geosite_path = geosite_path:match("^(.*)/") .. "/geosite.dat"
|
||||
if not is_file_nonzero(geosite_path) then return 1 end
|
||||
if api.is_finded("geoview") and list_arg and out_path then
|
||||
|
@@ -92,7 +92,7 @@ local function insert_array_after(array1, array2, target) --将array2插入到ar
|
||||
end
|
||||
|
||||
local function get_geosite(list_arg, out_path)
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset")
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
geosite_path = geosite_path:match("^(.*)/") .. "/geosite.dat"
|
||||
if not is_file_nonzero(geosite_path) then return 1 end
|
||||
if api.is_finded("geoview") and list_arg and out_path then
|
||||
|
@@ -33,8 +33,8 @@ local gfwlist_url = uci:get(name, "@global_rules[0]", "gfwlist_url") or {"https:
|
||||
local chnroute_url = uci:get(name, "@global_rules[0]", "chnroute_url") or {"https://ispip.clang.cn/all_cn.txt"}
|
||||
local chnroute6_url = uci:get(name, "@global_rules[0]", "chnroute6_url") or {"https://ispip.clang.cn/all_cn_ipv6.txt"}
|
||||
local chnlist_url = uci:get(name, "@global_rules[0]", "chnlist_url") or {"https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf","https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf","https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/google.china.conf"}
|
||||
local geoip_api = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geosite_api = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geoip_api = uci:get(name, "@global_rules[0]", "geoip_url") or "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geosite_api = uci:get(name, "@global_rules[0]", "geosite_url") or "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local asset_location = uci:get(name, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
local use_nft = uci:get(name, "@global_forwarding[0]", "use_nft") or "0"
|
||||
|
||||
|
12
shadowsocks-rust/Cargo.lock
generated
12
shadowsocks-rust/Cargo.lock
generated
@@ -1471,9 +1471,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.0"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
@@ -2412,18 +2412,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.9"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d"
|
||||
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.9"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67"
|
||||
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=1.20.0
|
||||
PKG_VERSION:=1.20.1
|
||||
|
||||
LUCI_TITLE:=LuCI Support for nikki
|
||||
LUCI_DEPENDS:=+luci-base +nikki
|
||||
|
@@ -114,7 +114,7 @@ return baseclass.extend({
|
||||
openDashboard: async function () {
|
||||
const uiName = uci.get('nikki', 'mixin', 'ui_name');
|
||||
const apiListen = uci.get('nikki', 'mixin', 'api_listen');
|
||||
const apiSecret = encodeURIComponent(uci.get('nikki', 'mixin', 'api_secret') ?? '');
|
||||
const apiSecret = uci.get('nikki', 'mixin', 'api_secret') ?? '';
|
||||
const apiPort = apiListen.substring(apiListen.lastIndexOf(':') + 1);
|
||||
const params = {
|
||||
host: window.location.hostname,
|
||||
|
@@ -12,7 +12,6 @@ PKG_RELEASE:=1
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Geoview \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
|
||||
@@ -36,7 +35,7 @@ LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
|
||||
+chinadns-ng +dns2socks +dnsmasq-full +ip-full \
|
||||
+libuci-lua +lua +luci-compat +luci-lib-jsonc \
|
||||
+microsocks +resolveip +tcping
|
||||
+microsocks +resolveip +tcping +geoview
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
menu "Configuration"
|
||||
@@ -64,11 +63,6 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
|
||||
select PACKAGE_kmod-nft-nat
|
||||
default y if PACKAGE_firewall4
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Geoview
|
||||
bool "Include Geoview"
|
||||
select PACKAGE_geoview
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
|
||||
bool "Include Haproxy"
|
||||
select PACKAGE_haproxy
|
||||
|
@@ -242,42 +242,6 @@ if has_singbox then
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
o.description = translate("Override the connection destination address with the sniffed domain.<br />When enabled, traffic will match only by domain, ignoring IP rules.<br />If using shunt nodes, configure the domain shunt rules correctly.")
|
||||
|
||||
o = s:option(Value, "geoip_path", translate("Custom geoip Path"))
|
||||
o.default = "/usr/share/singbox/geoip.db"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geoip_url", translate("Custom geoip URL"))
|
||||
o.default = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db"
|
||||
o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db")
|
||||
o:value("https://github.com/1715173329/sing-geoip/releases/latest/download/geoip.db")
|
||||
o:value("https://github.com/lyc8503/sing-box-rules/releases/latest/download/geoip.db")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geosite_path", translate("Custom geosite Path"))
|
||||
o.default = "/usr/share/singbox/geosite.db"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geosite_url", translate("Custom geosite URL"))
|
||||
o.default = "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db"
|
||||
o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db")
|
||||
o:value("https://github.com/1715173329/sing-geosite/releases/latest/download/geosite.db")
|
||||
o:value("https://github.com/lyc8503/sing-box-rules/releases/latest/download/geosite.db")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Button, "_remove_resource", translate("Remove resource files"))
|
||||
o.description = translate("Sing-Box will automatically download resource files when starting, you can use this feature achieve upgrade resource files.")
|
||||
o.inputstyle = "remove"
|
||||
function o.write(self, section, value)
|
||||
local geoip_path = s.fields["geoip_path"] and s.fields["geoip_path"]:formvalue(section) or nil
|
||||
if geoip_path then
|
||||
os.remove(geoip_path)
|
||||
end
|
||||
local geosite_path = s.fields["geosite_path"] and s.fields["geosite_path"]:formvalue(section) or nil
|
||||
if geosite_path then
|
||||
os.remove(geosite_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
|
@@ -45,7 +45,34 @@ o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/chi
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/apple-cn.txt", translate("Loyalsoldier/apple-cn"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/google-cn.txt", translate("Loyalsoldier/google-cn"))
|
||||
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
if has_xray or has_singbox then
|
||||
o = s:option(ListValue, "geoip_url", translate("GeoIP Update URL"))
|
||||
o:value("https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest", translate("Loyalsoldier/geoip"))
|
||||
o:value("https://api.github.com/repos/MetaCubeX/meta-rules-dat/releases/latest", translate("MetaCubeX/geoip"))
|
||||
o.default = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
|
||||
o = s:option(ListValue, "geosite_url", translate("Geosite Update URL"))
|
||||
o:value("https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest", translate("Loyalsoldier/geosite"))
|
||||
o:value("https://api.github.com/repos/MetaCubeX/meta-rules-dat/releases/latest", translate("MetaCubeX/geosite"))
|
||||
o.default = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
|
||||
o = s:option(Value, "v2ray_location_asset", translate("Location of Geo rule files"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
|
||||
o.default = "/usr/share/v2ray/"
|
||||
o.placeholder = "/usr/share/v2ray/"
|
||||
o.rmempty = false
|
||||
|
||||
if api.is_finded("geoview") then
|
||||
o = s:option(Flag, "enable_geoview", translate("Enable Geo Data Parsing"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
o.description = "<ul>"
|
||||
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
||||
.. "<li>" .. "1." .. translate("Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray.") .. "</li>"
|
||||
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
||||
.. "<li>" .. translate("Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes.") .. "</li>"
|
||||
.. "</ul>"
|
||||
end
|
||||
end
|
||||
|
||||
---- Auto Update
|
||||
o = s:option(Flag, "auto_update", translate("Enable auto update rules"))
|
||||
@@ -88,23 +115,9 @@ o.default = 2
|
||||
o:depends("week_update", "8")
|
||||
o.rmempty = true
|
||||
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
|
||||
if has_xray or has_singbox then
|
||||
o = s:option(Value, "v2ray_location_asset", translate("Location of V2ray/Xray asset"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
|
||||
o.default = "/usr/share/v2ray/"
|
||||
o.rmempty = false
|
||||
|
||||
if api.is_finded("geoview") then
|
||||
o = s:option(Flag, "enable_geoview", translate("Enable Geo Data Parsing"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
o.description = "<ul>"
|
||||
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
||||
.. "<li>" .. "1." .. translate("Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray.") .. "</li>"
|
||||
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
||||
.. "<li>" .. translate("Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes.") .. "</li>"
|
||||
.. "</ul>"
|
||||
end
|
||||
|
||||
s = m:section(TypedSection, "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
|
||||
s.template = "cbi/tblsection"
|
||||
s.anonymous = false
|
||||
|
@@ -10,6 +10,41 @@ local split = api.split
|
||||
local local_version = api.get_app_version("singbox")
|
||||
local version_ge_1_11_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.11.0")
|
||||
|
||||
local geosite_all_tag = {}
|
||||
local geoip_all_tag = {}
|
||||
local srss_path = "/tmp/etc/" .. appname .."/srss/"
|
||||
|
||||
local function convert_geofile()
|
||||
local geo_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
local geosite_path = geo_path:match("^(.*)/") .. "/geosite.dat"
|
||||
local geoip_path = geo_path:match("^(.*)/") .. "/geoip.dat"
|
||||
if not api.is_finded("geoview") then
|
||||
api.log("* 注意:缺少 geoview 组件,Sing-Box 分流将无法启用!")
|
||||
return
|
||||
end
|
||||
if not fs.access(srss_path) then
|
||||
fs.mkdir(srss_path)
|
||||
end
|
||||
if next(geosite_all_tag) and fs.access(geosite_path) then
|
||||
for k,v in pairs(geosite_all_tag) do
|
||||
local srs_file = srss_path .. "geosite-" .. k ..".srs"
|
||||
if not fs.access(srs_file) then
|
||||
sys.exec("geoview -type geosite -action convert -input " .. geosite_path .. " -list '" .. k .. "' -output " .. srs_file .. " -lowmem=true")
|
||||
--api.log("* 转换geosite:" .. k .. " 到 Sing-Box 规则集二进制文件")
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(geoip_all_tag) and fs.access(geoip_path) then
|
||||
for k,v in pairs(geoip_all_tag) do
|
||||
local srs_file = srss_path .. "geoip-" .. k ..".srs"
|
||||
if not fs.access(srs_file) then
|
||||
sys.exec("geoview -type geoip -action convert -input " .. geoip_path .. " -list '" .. k .. "' -output " .. srs_file .. " -lowmem=true")
|
||||
--api.log("* 转换geoip:" .. k .. " 到 Sing-Box 规则集二进制文件")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local new_port
|
||||
|
||||
local function get_new_port()
|
||||
@@ -802,17 +837,7 @@ function gen_config(var)
|
||||
local singbox_settings = uci:get_all(appname, "@global_singbox[0]") or {}
|
||||
|
||||
local route = {
|
||||
rules = {},
|
||||
geoip = {
|
||||
path = singbox_settings.geoip_path or "/usr/share/singbox/geoip.db",
|
||||
download_url = singbox_settings.geoip_url or nil,
|
||||
download_detour = nil,
|
||||
},
|
||||
geosite = {
|
||||
path = singbox_settings.geosite_path or "/usr/share/singbox/geosite.db",
|
||||
download_url = singbox_settings.geosite_url or nil,
|
||||
download_detour = nil,
|
||||
},
|
||||
rules = {}
|
||||
}
|
||||
|
||||
local experimental = nil
|
||||
@@ -1183,17 +1208,21 @@ function gen_config(var)
|
||||
end
|
||||
|
||||
if e.source then
|
||||
local source_geoip = {}
|
||||
local source_ip_cidr = {}
|
||||
local is_private = false
|
||||
string.gsub(e.source, '[^' .. " " .. ']+', function(w)
|
||||
if w:find("geoip") == 1 then
|
||||
table.insert(source_geoip, w)
|
||||
local _geoip = w:sub(1 + #"geoip:") --适配srs
|
||||
if _geoip == "private" then
|
||||
is_private = true
|
||||
end
|
||||
else
|
||||
table.insert(source_ip_cidr, w)
|
||||
end
|
||||
end)
|
||||
rule.source_geoip = #source_geoip > 0 and source_geoip or nil
|
||||
rule.source_ip_is_private = is_private and true or nil
|
||||
rule.source_ip_cidr = #source_ip_cidr > 0 and source_ip_cidr or nil
|
||||
if is_private or #source_ip_cidr > 0 then rule.rule_set_ip_cidr_match_source = true end
|
||||
end
|
||||
|
||||
if e.sourcePort then
|
||||
@@ -1224,6 +1253,8 @@ function gen_config(var)
|
||||
rule.port_range = #port_range > 0 and port_range or nil
|
||||
end
|
||||
|
||||
local rule_set_tag = {}
|
||||
|
||||
if e.domain_list then
|
||||
local domain_table = {
|
||||
outboundTag = outboundTag,
|
||||
@@ -1231,12 +1262,15 @@ function gen_config(var)
|
||||
domain_suffix = {},
|
||||
domain_keyword = {},
|
||||
domain_regex = {},
|
||||
geosite = {},
|
||||
rule_set = {},
|
||||
}
|
||||
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
if w:find("#") == 1 then return end
|
||||
if w:find("geosite:") == 1 then
|
||||
table.insert(domain_table.geosite, w:sub(1 + #"geosite:"))
|
||||
local _geosite = w:sub(1 + #"geosite:") --适配srs
|
||||
geosite_all_tag[_geosite] = true
|
||||
table.insert(rule_set_tag, "geosite-" .. _geosite)
|
||||
table.insert(domain_table.rule_set, "geosite-" .. _geosite)
|
||||
elseif w:find("regexp:") == 1 then
|
||||
table.insert(domain_table.domain_regex, w:sub(1 + #"regexp:"))
|
||||
elseif w:find("full:") == 1 then
|
||||
@@ -1251,7 +1285,6 @@ function gen_config(var)
|
||||
rule.domain_suffix = #domain_table.domain_suffix > 0 and domain_table.domain_suffix or nil
|
||||
rule.domain_keyword = #domain_table.domain_keyword > 0 and domain_table.domain_keyword or nil
|
||||
rule.domain_regex = #domain_table.domain_regex > 0 and domain_table.domain_regex or nil
|
||||
rule.geosite = #domain_table.geosite > 0 and domain_table.geosite or nil
|
||||
|
||||
if outboundTag then
|
||||
table.insert(dns_domain_rules, api.clone(domain_table))
|
||||
@@ -1260,20 +1293,28 @@ function gen_config(var)
|
||||
|
||||
if e.ip_list then
|
||||
local ip_cidr = {}
|
||||
local geoip = {}
|
||||
local is_private = false
|
||||
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
if w:find("#") == 1 then return end
|
||||
if w:find("geoip:") == 1 then
|
||||
table.insert(geoip, w:sub(1 + #"geoip:"))
|
||||
local _geoip = w:sub(1 + #"geoip:") --适配srs
|
||||
if _geoip == "private" then
|
||||
is_private = true
|
||||
else
|
||||
geoip_all_tag[_geoip] = true
|
||||
table.insert(rule_set_tag, "geoip-" .. _geoip)
|
||||
end
|
||||
else
|
||||
table.insert(ip_cidr, w)
|
||||
end
|
||||
end)
|
||||
|
||||
rule.ip_is_private = is_private and true or nil
|
||||
rule.ip_cidr = #ip_cidr > 0 and ip_cidr or nil
|
||||
rule.geoip = #geoip > 0 and geoip or nil
|
||||
end
|
||||
|
||||
rule.rule_set = #rule_set_tag > 0 and rule_set_tag or nil --适配srs
|
||||
|
||||
table.insert(rules, rule)
|
||||
end
|
||||
end)
|
||||
@@ -1281,6 +1322,34 @@ function gen_config(var)
|
||||
for index, value in ipairs(rules) do
|
||||
table.insert(route.rules, rules[index])
|
||||
end
|
||||
|
||||
local rule_set = {} --适配srs
|
||||
if next(geosite_all_tag) then
|
||||
for k,v in pairs(geosite_all_tag) do
|
||||
local srs_file = srss_path .. "geosite-" .. k ..".srs"
|
||||
local _rule_set = {
|
||||
tag = "geosite-" .. k,
|
||||
type = "local",
|
||||
format = "binary",
|
||||
path = srs_file
|
||||
}
|
||||
table.insert(rule_set, _rule_set)
|
||||
end
|
||||
end
|
||||
if next(geoip_all_tag) then
|
||||
for k,v in pairs(geoip_all_tag) do
|
||||
local srs_file = srss_path .. "geoip-" .. k ..".srs"
|
||||
local _rule_set = {
|
||||
tag = "geoip-" .. k,
|
||||
type = "local",
|
||||
format = "binary",
|
||||
path = srs_file
|
||||
}
|
||||
table.insert(rule_set, _rule_set)
|
||||
end
|
||||
end
|
||||
route.rule_set = #rule_set >0 and rule_set or nil
|
||||
|
||||
elseif node.protocol == "_urltest" then
|
||||
if node.urltest_node then
|
||||
COMMON.default_outbound_tag = gen_urltest(node)
|
||||
@@ -1470,14 +1539,14 @@ function gen_config(var)
|
||||
--按分流顺序DNS
|
||||
if dns_domain_rules and #dns_domain_rules > 0 then
|
||||
for index, value in ipairs(dns_domain_rules) do
|
||||
if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.geosite) then
|
||||
if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.rule_set) then
|
||||
local dns_rule = {
|
||||
server = value.outboundTag,
|
||||
domain = (value.domain and #value.domain > 0) and value.domain or nil,
|
||||
domain_suffix = (value.domain_suffix and #value.domain_suffix > 0) and value.domain_suffix or nil,
|
||||
domain_keyword = (value.domain_keyword and #value.domain_keyword > 0) and value.domain_keyword or nil,
|
||||
domain_regex = (value.domain_regex and #value.domain_regex > 0) and value.domain_regex or nil,
|
||||
geosite = (value.geosite and #value.geosite > 0) and value.geosite or nil,
|
||||
rule_set = (value.rule_set and #value.rule_set > 0) and value.rule_set or nil, --适配srs
|
||||
disable_cache = false,
|
||||
}
|
||||
if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then
|
||||
@@ -1737,5 +1806,8 @@ if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
if next(geosite_all_tag) or next(geoip_all_tag) then
|
||||
convert_geofile()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -937,8 +937,14 @@ msgstr "小时"
|
||||
msgid "Hour"
|
||||
msgstr "小时"
|
||||
|
||||
msgid "Location of V2ray/Xray asset"
|
||||
msgstr "V2ray/Xray 资源文件目录"
|
||||
msgid "GeoIP Update URL"
|
||||
msgstr "GeoIP 更新URL"
|
||||
|
||||
msgid "Geosite Update URL"
|
||||
msgstr "Geosite 更新URL"
|
||||
|
||||
msgid "Location of Geo rule files"
|
||||
msgstr "Geo 规则文件目录"
|
||||
|
||||
msgid "This variable specifies a directory where geoip.dat and geosite.dat files are."
|
||||
msgstr "此变量指定 geoip.dat 和 geosite.dat 文件所在的目录。"
|
||||
@@ -1633,24 +1639,6 @@ msgstr "端口跳跃额外端口"
|
||||
msgid "HeartbeatPeriod(second)"
|
||||
msgstr "心跳周期(单位:秒)"
|
||||
|
||||
msgid "Custom geoip Path"
|
||||
msgstr "自定义 geoip 文件路径"
|
||||
|
||||
msgid "Custom geoip URL"
|
||||
msgstr "自定义 geoip 文件更新链接"
|
||||
|
||||
msgid "Custom geosite Path"
|
||||
msgstr "自定义 geosite 文件路径"
|
||||
|
||||
msgid "Custom geosite URL"
|
||||
msgstr "自定义 geosite 文件更新链接"
|
||||
|
||||
msgid "Remove resource files"
|
||||
msgstr "删除资源文件"
|
||||
|
||||
msgid "Sing-Box will automatically download resource files when starting, you can use this feature achieve upgrade resource files."
|
||||
msgstr "Sing-Box 会在启动时自动下载资源文件,您可以使用此功能实现升级资源文件。"
|
||||
|
||||
msgid "Override the connection destination address"
|
||||
msgstr "覆盖连接目标地址"
|
||||
|
||||
|
@@ -51,10 +51,6 @@ config global_xray
|
||||
|
||||
config global_singbox
|
||||
option sniff_override_destination '0'
|
||||
option geoip_path '/usr/share/singbox/geoip.db'
|
||||
option geoip_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.db'
|
||||
option geosite_path '/usr/share/singbox/geosite.db'
|
||||
option geosite_url 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.db'
|
||||
|
||||
config global_other
|
||||
option auto_detection_time 'tcping'
|
||||
@@ -76,6 +72,8 @@ config global_rules
|
||||
list chnlist_url 'https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf'
|
||||
list chnlist_url 'https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf'
|
||||
option v2ray_location_asset '/usr/share/v2ray/'
|
||||
option geoip_url 'https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest'
|
||||
option geosite_url 'https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest'
|
||||
|
||||
config global_app
|
||||
option singbox_file '/usr/bin/sing-box'
|
||||
|
@@ -350,8 +350,7 @@ parse_doh() {
|
||||
get_geoip() {
|
||||
local geoip_code="$1"
|
||||
local geoip_type_flag=""
|
||||
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
geoip_path="${geoip_path%*/}/geoip.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
[ -s "$geoip_path" ] || { echo ""; return 1; }
|
||||
case "$2" in
|
||||
"ipv4") geoip_type_flag="-ipv6=false" ;;
|
||||
@@ -777,8 +776,8 @@ run_redir() {
|
||||
sing-box)
|
||||
local protocol=$(config_n_get $node protocol)
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geoip_path="$(config_t_get global_singbox geoip_path)"
|
||||
local geosite_path="$(config_t_get global_singbox geosite_path)"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,UDP Sing-Box分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -788,9 +787,8 @@ run_redir() {
|
||||
xray)
|
||||
local protocol=$(config_n_get $node protocol)
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,UDP Xray分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -895,8 +893,8 @@ run_redir() {
|
||||
}
|
||||
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geoip_path="$(config_t_get global_singbox geoip_path)"
|
||||
local geosite_path="$(config_t_get global_singbox geosite_path)"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,TCP Sing-Box分流节点无法正常使用!"
|
||||
fi
|
||||
@@ -981,9 +979,8 @@ run_redir() {
|
||||
}
|
||||
|
||||
[ "$protocol" = "_shunt" ] && {
|
||||
local geo_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
local geoip_path="${geo_path%*/}/geoip.dat"
|
||||
local geosite_path="${geo_path%*/}/geosite.dat"
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geosite_path="${V2RAY_LOCATION_ASSET%*/}/geosite.dat"
|
||||
if [ ! -s "$geoip_path" ] || [ ! -s "$geosite_path" ]; then
|
||||
echolog "* 缺少Geo规则文件,TCP Xray分流节点无法正常使用!"
|
||||
fi
|
||||
|
@@ -88,7 +88,7 @@ local function insert_array_after(array1, array2, target) --将array2插入到ar
|
||||
end
|
||||
|
||||
local function get_geosite(list_arg, out_path)
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset")
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
geosite_path = geosite_path:match("^(.*)/") .. "/geosite.dat"
|
||||
if not is_file_nonzero(geosite_path) then return 1 end
|
||||
if api.is_finded("geoview") and list_arg and out_path then
|
||||
|
@@ -92,7 +92,7 @@ local function insert_array_after(array1, array2, target) --将array2插入到ar
|
||||
end
|
||||
|
||||
local function get_geosite(list_arg, out_path)
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset")
|
||||
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
geosite_path = geosite_path:match("^(.*)/") .. "/geosite.dat"
|
||||
if not is_file_nonzero(geosite_path) then return 1 end
|
||||
if api.is_finded("geoview") and list_arg and out_path then
|
||||
|
@@ -33,8 +33,8 @@ local gfwlist_url = uci:get(name, "@global_rules[0]", "gfwlist_url") or {"https:
|
||||
local chnroute_url = uci:get(name, "@global_rules[0]", "chnroute_url") or {"https://ispip.clang.cn/all_cn.txt"}
|
||||
local chnroute6_url = uci:get(name, "@global_rules[0]", "chnroute6_url") or {"https://ispip.clang.cn/all_cn_ipv6.txt"}
|
||||
local chnlist_url = uci:get(name, "@global_rules[0]", "chnlist_url") or {"https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf","https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf","https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/google.china.conf"}
|
||||
local geoip_api = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geosite_api = "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geoip_api = uci:get(name, "@global_rules[0]", "geoip_url") or "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local geosite_api = uci:get(name, "@global_rules[0]", "geosite_url") or "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest"
|
||||
local asset_location = uci:get(name, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
local use_nft = uci:get(name, "@global_forwarding[0]", "use_nft") or "0"
|
||||
|
||||
|
@@ -7,33 +7,20 @@ namespace AmazTool
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
Utils.WriteLine(Resx.Resource.Guidelines);
|
||||
Utils.Waiting(5);
|
||||
Console.WriteLine(Resx.Resource.Guidelines);
|
||||
Thread.Sleep(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||
if (argData.Equals("rebootas"))
|
||||
{
|
||||
Utils.Waiting(1);
|
||||
Thread.Sleep(1000);
|
||||
Utils.StartV2RayN();
|
||||
return;
|
||||
}
|
||||
|
||||
var tryTimes = 0;
|
||||
UpgradeApp.Init();
|
||||
while (tryTimes++ < 3)
|
||||
{
|
||||
if (!UpgradeApp.Upgrade(argData))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Utils.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Utils.Waiting(3);
|
||||
Utils.StartV2RayN();
|
||||
break;
|
||||
}
|
||||
UpgradeApp.Upgrade(argData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,99 +6,19 @@ namespace AmazTool
|
||||
{
|
||||
internal class UpgradeApp
|
||||
{
|
||||
public static bool Upgrade(string fileName)
|
||||
public static void Upgrade(string fileName)
|
||||
{
|
||||
Utils.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
Utils.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||
return false;
|
||||
}
|
||||
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||
|
||||
Utils.Waiting(5);
|
||||
|
||||
KillV2rayN();
|
||||
|
||||
Utils.WriteLine(Resx.Resource.StartUnzipping);
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
var splitKey = "/";
|
||||
|
||||
using var archive = ZipFile.OpenRead(fileName);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Utils.WriteLine(entry.FullName);
|
||||
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
var entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
//In the bin folder, if the file already exists, it will be skipped
|
||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
Utils.WriteLine(entryOutputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(ex.Message);
|
||||
sb.Append(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sb.Length <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Utils.WriteLine(sb.ToString());
|
||||
Utils.WriteLine(Resx.Resource.FailedUpgrade);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
//Process temporary files generated by the last update
|
||||
var files = Directory.GetFiles(Utils.GetPath(""), "*.tmp");
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.Contains(Utils.AmazTool))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
var destFileName = $"{Utils.GetExePath()}{Guid.NewGuid().ToString("N")[..8]}.tmp";
|
||||
File.Move(Utils.GetExePath(), destFileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool KillV2rayN()
|
||||
{
|
||||
Utils.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||
try
|
||||
{
|
||||
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
||||
@@ -115,10 +35,83 @@ namespace AmazTool
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Access may be denied without admin right. The user may not be an administrator.
|
||||
Utils.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||
}
|
||||
|
||||
return true;
|
||||
Console.WriteLine(Resx.Resource.StartUnzipping);
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
{
|
||||
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||
File.Delete(thisAppOldFile);
|
||||
var splitKey = "/";
|
||||
|
||||
using var archive = ZipFile.OpenRead(fileName);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine(entry.FullName);
|
||||
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
|
||||
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.Move(Utils.GetExePath(), thisAppOldFile);
|
||||
}
|
||||
|
||||
var entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
//In the bin folder, if the file already exists, it will be skipped
|
||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
}
|
||||
|
||||
Console.WriteLine(entryOutputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||
//return;
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
|
||||
//return;
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Utils.Waiting(2);
|
||||
|
||||
Utils.StartV2RayN();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ namespace AmazTool
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
public static string GetPath(string? fileName)
|
||||
public static string GetPath(string fileName)
|
||||
{
|
||||
var startupPath = StartupPath();
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
@@ -25,7 +25,6 @@ namespace AmazTool
|
||||
}
|
||||
|
||||
public static string V2rayN => "v2rayN";
|
||||
public static string AmazTool => "AmazTool";
|
||||
|
||||
public static void StartV2RayN()
|
||||
{
|
||||
@@ -45,14 +44,9 @@ namespace AmazTool
|
||||
{
|
||||
for (var i = second; i > 0; i--)
|
||||
{
|
||||
Utils.WriteLine(i);
|
||||
Console.WriteLine(i);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteLine(object obj)
|
||||
{
|
||||
Console.WriteLine(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.10.1</Version>
|
||||
<Version>7.10.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
@@ -265,7 +265,8 @@ namespace ServiceLib
|
||||
"utp",
|
||||
"wechat-video",
|
||||
"dtls",
|
||||
"wireguard"
|
||||
"wireguard",
|
||||
"dns"
|
||||
];
|
||||
|
||||
public static readonly List<string> CoreTypes =
|
||||
|
@@ -109,7 +109,7 @@ namespace ServiceLib.Handler
|
||||
task.Settings.RunOnlyIfIdle = false;
|
||||
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(20) });
|
||||
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
|
||||
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
|
||||
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
||||
|
||||
|
@@ -291,6 +291,8 @@ namespace ServiceLib.Models
|
||||
public object request { get; set; }
|
||||
|
||||
public object response { get; set; }
|
||||
|
||||
public string? domain { get; set; }
|
||||
}
|
||||
|
||||
public class KcpSettings4Ray
|
||||
|
@@ -915,7 +915,8 @@ namespace ServiceLib.Services.CoreConfig
|
||||
kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize;
|
||||
kcpSettings.header = new Header4Ray
|
||||
{
|
||||
type = node.HeaderType
|
||||
type = node.HeaderType,
|
||||
domain = host.IsNullOrEmpty() ? null : host
|
||||
};
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@ module github.com/2dust/AndroidLibXrayLite
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/xtls/xray-core v1.8.25-0.20250221075831-be43f66b63d5
|
||||
github.com/xtls/xray-core v1.8.25-0.20250303153022-e15dff94b5bd
|
||||
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3
|
||||
golang.org/x/sys v0.30.0
|
||||
)
|
||||
@@ -36,7 +36,7 @@ require (
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
@@ -51,5 +51,5 @@ require (
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20250215002057-313350f3e697 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
lukechampine.com/blake3 v1.4.0 // indirect
|
||||
)
|
||||
|
@@ -24,8 +24,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -75,8 +75,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
||||
github.com/xtls/xray-core v1.8.25-0.20250221075831-be43f66b63d5 h1:x4pNCiwk/x/zS/dpZl8fdNzC0YP8NBIOVZOAA1in/Zo=
|
||||
github.com/xtls/xray-core v1.8.25-0.20250221075831-be43f66b63d5/go.mod h1:bPLUPQGZ8ADeL1CANo0nIUNchY+SuhZCT+ItgprlPf4=
|
||||
github.com/xtls/xray-core v1.8.25-0.20250303153022-e15dff94b5bd h1:xzZCYhdr1pL1kZe7GysAMuVNtlzXqsQKTFbc1xvR+bI=
|
||||
github.com/xtls/xray-core v1.8.25-0.20250303153022-e15dff94b5bd/go.mod h1:0n4A2nJD1yZlxuXexV5rJODKcJJo8zpbTFcESVg8fgM=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||
@@ -93,8 +93,8 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3 h1:0V/7Y1FEaFdAzb9DkVDh4QFp4vL4yYCiJ5cjk80lZyA=
|
||||
@@ -136,5 +136,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20250215002057-313350f3e697 h1:3xb9C+AmVuRnDDAwJGJ8ZVAmcIourUD9DwHaAd5Ldyk=
|
||||
gvisor.dev/gvisor v0.0.0-20250215002057-313350f3e697/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
||||
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
||||
|
@@ -12,8 +12,8 @@ android {
|
||||
applicationId = "com.v2ray.ang"
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
versionCode = 634
|
||||
versionName = "1.9.37"
|
||||
versionCode = 635
|
||||
versionName = "1.9.38"
|
||||
multiDexEnabled = true
|
||||
|
||||
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
||||
@@ -157,9 +157,8 @@ dependencies {
|
||||
implementation(libs.gson)
|
||||
|
||||
// Reactive and Utility Libraries
|
||||
implementation(libs.rxjava)
|
||||
implementation(libs.rxandroid)
|
||||
implementation(libs.rxpermissions)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
||||
// Language and Processing Libraries
|
||||
implementation(libs.language.base)
|
||||
|
@@ -31,10 +31,11 @@ import com.v2ray.ang.util.MessageUtil
|
||||
import com.v2ray.ang.util.PluginUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import go.Seq
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import libv2ray.Libv2ray
|
||||
import libv2ray.V2RayPoint
|
||||
@@ -62,7 +63,7 @@ object V2RayServiceManager {
|
||||
|
||||
private var lastQueryTime = 0L
|
||||
private var mBuilder: NotificationCompat.Builder? = null
|
||||
private var mDisposable: Disposable? = null
|
||||
private var speedNotificationJob: Job? = null
|
||||
private var mNotificationManager: NotificationManager? = null
|
||||
|
||||
fun startV2Ray(context: Context) {
|
||||
@@ -365,8 +366,8 @@ object V2RayServiceManager {
|
||||
}
|
||||
|
||||
mBuilder = null
|
||||
mDisposable?.dispose()
|
||||
mDisposable = null
|
||||
speedNotificationJob?.cancel()
|
||||
speedNotificationJob = null
|
||||
}
|
||||
|
||||
private fun updateNotification(contentText: String?, proxyTraffic: Long, directTraffic: Long) {
|
||||
@@ -393,7 +394,7 @@ object V2RayServiceManager {
|
||||
}
|
||||
|
||||
private fun startSpeedNotification() {
|
||||
if (mDisposable == null &&
|
||||
if (speedNotificationJob == null &&
|
||||
v2rayPoint.isRunning &&
|
||||
MmkvManager.decodeSettingsBool(AppConfig.PREF_SPEED_ENABLED) == true
|
||||
) {
|
||||
@@ -401,8 +402,8 @@ object V2RayServiceManager {
|
||||
val outboundTags = currentConfig?.getAllOutboundTags()
|
||||
outboundTags?.remove(TAG_DIRECT)
|
||||
|
||||
mDisposable = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.subscribe {
|
||||
speedNotificationJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
while (isActive) {
|
||||
val queryTime = System.currentTimeMillis()
|
||||
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
|
||||
var proxyTotal = 0L
|
||||
@@ -430,7 +431,9 @@ object V2RayServiceManager {
|
||||
}
|
||||
lastZeroSpeed = zeroSpeed
|
||||
lastQueryTime = queryTime
|
||||
delay(3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,11 +448,10 @@ object V2RayServiceManager {
|
||||
}
|
||||
|
||||
private fun stopSpeedNotification() {
|
||||
mDisposable?.let {
|
||||
it.dispose() //stop queryStats
|
||||
mDisposable = null
|
||||
speedNotificationJob?.let {
|
||||
it.cancel()
|
||||
speedNotificationJob = null
|
||||
updateNotification(currentConfig?.remarks, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,15 +5,16 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityAboutBinding
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.util.SpeedtestUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.ZipUtil
|
||||
@@ -21,11 +22,24 @@ import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
class AboutActivity : BaseActivity() {
|
||||
|
||||
private val binding by lazy { ActivityAboutBinding.inflate(layoutInflater) }
|
||||
private val extDir by lazy { File(Utils.backupPath(this)) }
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (isGranted) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
@@ -33,6 +47,7 @@ class AboutActivity : BaseActivity() {
|
||||
title = getString(R.string.title_about)
|
||||
|
||||
binding.tvBackupSummary.text = this.getString(R.string.summary_configuration_backup, extDir)
|
||||
|
||||
binding.layoutBackup.setOnClickListener {
|
||||
val ret = backupConfiguration(extDir.absolutePath)
|
||||
if (ret.first) {
|
||||
@@ -50,7 +65,8 @@ class AboutActivity : BaseActivity() {
|
||||
Intent(Intent.ACTION_SEND).setType("application/zip")
|
||||
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
.putExtra(
|
||||
Intent.EXTRA_STREAM, FileProvider.getUriForFile(
|
||||
Intent.EXTRA_STREAM,
|
||||
FileProvider.getUriForFile(
|
||||
this, BuildConfig.APPLICATION_ID + ".cache", File(ret.second)
|
||||
)
|
||||
), getString(R.string.title_configuration_share)
|
||||
@@ -62,23 +78,22 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
binding.layoutRestore.setOnClickListener {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
RxPermissions(this)
|
||||
.request(permission)
|
||||
.subscribe {
|
||||
if (it) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else
|
||||
toast(R.string.toast_permission_denied)
|
||||
val permission =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
}
|
||||
|
||||
binding.layoutSoureCcode.setOnClickListener {
|
||||
@@ -88,13 +103,15 @@ class AboutActivity : BaseActivity() {
|
||||
binding.layoutFeedback.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.v2rayNGIssues)
|
||||
}
|
||||
binding.layoutOssLicenses.setOnClickListener{
|
||||
|
||||
binding.layoutOssLicenses.setOnClickListener {
|
||||
val webView = android.webkit.WebView(this);
|
||||
webView.loadUrl("file:///android_asset/open_source_licenses.html");
|
||||
webView.loadUrl("file:///android_asset/open_source_licenses.html")
|
||||
android.app.AlertDialog.Builder(this)
|
||||
.setTitle("Open source licenses")
|
||||
.setView(webView)
|
||||
.setPositiveButton("OK", android.content.DialogInterface.OnClickListener { dialog, whichButton -> dialog.dismiss() }).show()
|
||||
.setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
binding.layoutTgChannel.setOnClickListener {
|
||||
@@ -157,9 +174,9 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private val chooseFile =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
val uri = result.data?.data
|
||||
if (result.resultCode == RESULT_OK && uri != null) {
|
||||
try {
|
||||
val targetFile =
|
||||
File(this.cacheDir.absolutePath, "${System.currentTimeMillis()}.zip")
|
||||
@@ -180,4 +197,7 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun toast(messageResId: Int) {
|
||||
Toast.makeText(this, getString(messageResId), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@ package com.v2ray.ang.ui
|
||||
import android.Manifest
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.net.Uri
|
||||
import android.net.VpnService
|
||||
@@ -27,7 +28,6 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.VPN
|
||||
import com.v2ray.ang.R
|
||||
@@ -41,8 +41,6 @@ import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
|
||||
import com.v2ray.ang.service.V2RayServiceManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.MainViewModel
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -81,6 +79,60 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
private var mItemTouchHelper: ItemTouchHelper? = null
|
||||
val mainViewModel: MainViewModel by viewModels()
|
||||
|
||||
// register activity result for requesting permission
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
when (pendingAction) {
|
||||
Action.IMPORT_QR_CODE_CONFIG ->
|
||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
Action.IMPORT_QR_CODE_URL ->
|
||||
scanQRCodeForUrlToCustomConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
Action.READ_CONTENT_FROM_URI ->
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
type = "*/*"
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
}, getString(R.string.title_file_chooser)))
|
||||
Action.POST_NOTIFICATIONS -> {}
|
||||
else -> {}
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
pendingAction = Action.NONE
|
||||
}
|
||||
|
||||
private var pendingAction: Action = Action.NONE
|
||||
|
||||
enum class Action {
|
||||
NONE,
|
||||
IMPORT_QR_CODE_CONFIG,
|
||||
IMPORT_QR_CODE_URL,
|
||||
READ_CONTENT_FROM_URI,
|
||||
POST_NOTIFICATIONS
|
||||
}
|
||||
|
||||
private val chooseFileForCustomConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
readContentFromUri(uri)
|
||||
}
|
||||
}
|
||||
|
||||
private val scanQRCodeForConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"))
|
||||
}
|
||||
}
|
||||
|
||||
private val scanQRCodeForUrlToCustomConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
importConfigCustomUrl(it.data?.getStringExtra("SCAN_RESULT"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
@@ -129,12 +181,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
migrateLegacy()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
RxPermissions(this)
|
||||
.request(Manifest.permission.POST_NOTIFICATIONS)
|
||||
.subscribe {
|
||||
if (!it)
|
||||
toast(R.string.toast_permission_denied_notification)
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
pendingAction = Action.POST_NOTIFICATIONS
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
@@ -226,11 +276,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
if (mainViewModel.isRunning.value == true) {
|
||||
Utils.stopVService(this)
|
||||
}
|
||||
Observable.timer(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
startV2Ray()
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
delay(500)
|
||||
startV2Ray()
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
@@ -462,38 +511,20 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
* import config from qrcode
|
||||
*/
|
||||
private fun importQRcode(forConfig: Boolean): Boolean {
|
||||
// try {
|
||||
// startActivityForResult(Intent("com.google.zxing.client.android.SCAN")
|
||||
// .addCategory(Intent.CATEGORY_DEFAULT)
|
||||
// .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), requestCode)
|
||||
// } catch (e: Exception) {
|
||||
RxPermissions(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.subscribe {
|
||||
if (it)
|
||||
if (forConfig)
|
||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
else
|
||||
scanQRCodeForUrlToCustomConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
else
|
||||
toast(R.string.toast_permission_denied)
|
||||
val permission = Manifest.permission.CAMERA
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (forConfig) {
|
||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
scanQRCodeForUrlToCustomConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
}
|
||||
// }
|
||||
} else {
|
||||
pendingAction = if (forConfig) Action.IMPORT_QR_CODE_CONFIG else Action.IMPORT_QR_CODE_URL
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private val scanQRCodeForConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"))
|
||||
}
|
||||
}
|
||||
|
||||
private val scanQRCodeForUrlToCustomConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
importConfigCustomUrl(it.data?.getStringExtra("SCAN_RESULT"))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* import config from clipboard
|
||||
*/
|
||||
@@ -614,10 +645,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
* import config from sub
|
||||
*/
|
||||
private fun importConfigViaSub(): Boolean {
|
||||
// val dialog = AlertDialog.Builder(this)
|
||||
// .setView(LayoutProgressBinding.inflate(layoutInflater).root)
|
||||
// .setCancelable(false)
|
||||
// .show()
|
||||
binding.pbWaiting.show()
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
@@ -630,7 +657,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
//dialog.dismiss()
|
||||
binding.pbWaiting.hide()
|
||||
}
|
||||
}
|
||||
@@ -645,17 +671,17 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
}
|
||||
|
||||
private val chooseFileForCustomConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
readContentFromUri(uri)
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
pendingAction = Action.READ_CONTENT_FROM_URI
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,20 +694,18 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
RxPermissions(this)
|
||||
.request(permission)
|
||||
.subscribe {
|
||||
if (it) {
|
||||
try {
|
||||
contentResolver.openInputStream(uri).use { input ->
|
||||
importCustomizeConfig(input?.bufferedReader()?.readText())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else
|
||||
toast(R.string.toast_permission_denied)
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
try {
|
||||
contentResolver.openInputStream(uri).use { input ->
|
||||
importCustomizeConfig(input?.bufferedReader()?.readText())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -763,4 +787,4 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.v2ray.ang.AngApplication.Companion.application
|
||||
import com.v2ray.ang.AppConfig
|
||||
@@ -23,9 +24,9 @@ import com.v2ray.ang.helper.ItemTouchHelperAdapter
|
||||
import com.v2ray.ang.helper.ItemTouchHelperViewHolder
|
||||
import com.v2ray.ang.service.V2RayServiceManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>(), ItemTouchHelperAdapter {
|
||||
companion object {
|
||||
@@ -165,11 +166,14 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
|
||||
if (isRunning) {
|
||||
Utils.stopVService(mActivity)
|
||||
Observable.timer(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
mActivity.lifecycleScope.launch {
|
||||
try {
|
||||
delay(500)
|
||||
V2RayServiceManager.startV2Ray(mActivity)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,4 +250,4 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
|
||||
override fun onItemDismiss(position: Int) {
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,10 +20,9 @@ import com.v2ray.ang.extension.v2RayApplication
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.util.AppManagerUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.text.Collator
|
||||
|
||||
class PerAppProxyActivity : BaseActivity() {
|
||||
@@ -43,93 +42,39 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
|
||||
val blacklist = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||
|
||||
AppManagerUtil.rxLoadNetworkAppList(this)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map {
|
||||
if (blacklist != null) {
|
||||
it.forEach { one ->
|
||||
if (blacklist.contains(one.packageName)) {
|
||||
one.isSelected = 1
|
||||
} else {
|
||||
one.isSelected = 0
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
binding.pbWaiting.visibility = View.VISIBLE
|
||||
val blacklist = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||
val apps = withContext(Dispatchers.IO) {
|
||||
val appsList = AppManagerUtil.loadNetworkAppList(this@PerAppProxyActivity)
|
||||
|
||||
if (blacklist != null) {
|
||||
appsList.forEach { app ->
|
||||
app.isSelected = if (blacklist.contains(app.packageName)) 1 else 0
|
||||
}
|
||||
}
|
||||
val comparator = Comparator<AppInfo> { p1, p2 ->
|
||||
when {
|
||||
p1.isSelected > p2.isSelected -> -1
|
||||
p1.isSelected == p2.isSelected -> 0
|
||||
else -> 1
|
||||
}
|
||||
}
|
||||
it.sortedWith(comparator)
|
||||
} else {
|
||||
val comparator = object : Comparator<AppInfo> {
|
||||
appsList.sortedWith(Comparator { p1, p2 ->
|
||||
when {
|
||||
p1.isSelected > p2.isSelected -> -1
|
||||
p1.isSelected == p2.isSelected -> 0
|
||||
else -> 1
|
||||
}
|
||||
})
|
||||
} else {
|
||||
val collator = Collator.getInstance()
|
||||
override fun compare(o1: AppInfo, o2: AppInfo) = collator.compare(o1.appName, o2.appName)
|
||||
appsList.sortedWith(compareBy(collator) { it.appName })
|
||||
}
|
||||
it.sortedWith(comparator)
|
||||
}
|
||||
}
|
||||
// .map {
|
||||
// val comparator = object : Comparator<AppInfo> {
|
||||
// val collator = Collator.getInstance()
|
||||
// override fun compare(o1: AppInfo, o2: AppInfo) = collator.compare(o1.appName, o2.appName)
|
||||
// }
|
||||
// it.sortedWith(comparator)
|
||||
// }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
appsAll = it
|
||||
adapter = PerAppProxyAdapter(this, it, blacklist)
|
||||
|
||||
appsAll = apps
|
||||
adapter = PerAppProxyAdapter(this@PerAppProxyActivity, apps, blacklist)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.pbWaiting.visibility = View.GONE
|
||||
} catch (e: Exception) {
|
||||
binding.pbWaiting.visibility = View.GONE
|
||||
Log.e(ANG_PACKAGE, "Error loading apps", e)
|
||||
}
|
||||
/***
|
||||
recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
var dst = 0
|
||||
val threshold = resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 2
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
dst += dy
|
||||
if (dst > threshold) {
|
||||
header_view.hide()
|
||||
dst = 0
|
||||
} else if (dst < -20) {
|
||||
header_view.show()
|
||||
dst = 0
|
||||
}
|
||||
}
|
||||
|
||||
var hiding = false
|
||||
fun View.hide() {
|
||||
val target = -height.toFloat()
|
||||
if (hiding || translationY == target) return
|
||||
animate()
|
||||
.translationY(target)
|
||||
.setInterpolator(AccelerateInterpolator(2F))
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
hiding = false
|
||||
}
|
||||
})
|
||||
hiding = true
|
||||
}
|
||||
|
||||
var showing = false
|
||||
fun View.show() {
|
||||
val target = 0f
|
||||
if (showing || translationY == target) return
|
||||
animate()
|
||||
.translationY(target)
|
||||
.setInterpolator(DecelerateInterpolator(2F))
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
showing = false
|
||||
}
|
||||
})
|
||||
showing = true
|
||||
}
|
||||
})
|
||||
***/
|
||||
|
||||
binding.switchPerAppProxy.setOnCheckedChangeListener { _, isChecked ->
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_PER_APP_PROXY, isChecked)
|
||||
@@ -140,36 +85,6 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_BYPASS_APPS, isChecked)
|
||||
}
|
||||
binding.switchBypassApps.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS, false)
|
||||
|
||||
/***
|
||||
et_search.setOnEditorActionListener { v, actionId, event ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
//hide
|
||||
var imm: InputMethodManager = v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
|
||||
|
||||
val key = v.text.toString().toUpperCase()
|
||||
val apps = ArrayList<AppInfo>()
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
appsAll?.forEach {
|
||||
apps.add(it)
|
||||
}
|
||||
} else {
|
||||
appsAll?.forEach {
|
||||
if (it.appName.toUpperCase().indexOf(key) >= 0) {
|
||||
apps.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
adapter = PerAppProxyAdapter(this, apps, adapter?.blacklist)
|
||||
recycler_view.adapter = adapter
|
||||
adapter?.notifyDataSetChanged()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
***/
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@@ -12,7 +12,6 @@ import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityRoutingSettingBinding
|
||||
@@ -39,6 +38,16 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
private val preset_rulesets: Array<out String> by lazy {
|
||||
resources.getStringArray(R.array.preset_rulesets)
|
||||
}
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRcodeForRulesets.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -102,11 +111,9 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}.show()
|
||||
|
||||
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
//do noting
|
||||
//do nothing
|
||||
}
|
||||
.show()
|
||||
true
|
||||
@@ -142,18 +149,10 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
R.id.import_rulesets_from_qrcode -> {
|
||||
RxPermissions(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.subscribe {
|
||||
if (it)
|
||||
scanQRcodeForRulesets.launch(Intent(this, ScannerActivity::class.java))
|
||||
else
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
R.id.export_rulesets_to_clipboard -> {
|
||||
val rulesetList = MmkvManager.decodeRoutingRulesets()
|
||||
if (rulesetList.isNullOrEmpty()) {
|
||||
@@ -201,5 +200,4 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
rulesets.addAll(MmkvManager.decodeRoutingRulesets() ?: mutableListOf())
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -4,13 +4,23 @@ import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.handler.AngConfigManager
|
||||
|
||||
class ScScannerActivity : BaseActivity() {
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRCode.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_none)
|
||||
@@ -18,19 +28,10 @@ class ScScannerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
fun importQRcode(): Boolean {
|
||||
RxPermissions(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.subscribe { granted ->
|
||||
if (granted) {
|
||||
scanQRCode.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private val scanQRCode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
val scanResult = it.data?.getStringExtra("SCAN_RESULT").orEmpty()
|
||||
@@ -46,5 +47,4 @@ class ScScannerActivity : BaseActivity() {
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -2,13 +2,15 @@ package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.toast
|
||||
@@ -21,6 +23,37 @@ import io.github.g00fy2.quickie.config.ScannerConfig
|
||||
class ScannerActivity : BaseActivity() {
|
||||
|
||||
private val scanQrCode = registerForActivityResult(ScanCustomCode(), ::handleResult)
|
||||
private val chooseFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
|
||||
val text = QRCodeDecoder.syncDecodeQRCode(bitmap)
|
||||
if (text.isNullOrEmpty()) {
|
||||
toast(R.string.toast_decoding_failed)
|
||||
} else {
|
||||
finished(text)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toast(R.string.toast_decoding_failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
showFileChooser()
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -72,15 +105,12 @@ class ScannerActivity : BaseActivity() {
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
RxPermissions(this)
|
||||
.request(permission)
|
||||
.subscribe { granted ->
|
||||
if (granted) {
|
||||
showFileChooser()
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
showFileChooser()
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
@@ -100,26 +130,4 @@ class ScannerActivity : BaseActivity() {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
}
|
||||
|
||||
private val chooseFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
|
||||
val text = QRCodeDecoder.syncDecodeQRCode(bitmap)
|
||||
if (text.isNullOrEmpty()) {
|
||||
toast(R.string.toast_decoding_failed)
|
||||
} else {
|
||||
finished(text)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toast(R.string.toast_decoding_failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -19,7 +19,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tbruyelle.rxpermissions3.RxPermissions
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.LOOPBACK
|
||||
import com.v2ray.ang.R
|
||||
@@ -50,6 +49,38 @@ class UserAssetActivity : BaseActivity() {
|
||||
val extDir by lazy { File(Utils.userAssetPath(this)) }
|
||||
val builtInGeoFiles = arrayOf("geosite.dat", "geoip.dat")
|
||||
|
||||
private val requestStoragePermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFile.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.title_file_chooser)
|
||||
)
|
||||
)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRCodeForAssetURL.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -86,27 +117,7 @@ class UserAssetActivity : BaseActivity() {
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
RxPermissions(this)
|
||||
.request(permission)
|
||||
.subscribe {
|
||||
if (it) {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFile.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.title_file_chooser)
|
||||
)
|
||||
)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
} else
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
requestStoragePermissionLauncher.launch(permission)
|
||||
}
|
||||
|
||||
val chooseFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
@@ -158,14 +169,7 @@ class UserAssetActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun importAssetFromQRcode(): Boolean {
|
||||
RxPermissions(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.subscribe {
|
||||
if (it)
|
||||
scanQRCodeForAssetURL.launch(Intent(this, ScannerActivity::class.java))
|
||||
else
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -349,4 +353,4 @@ class UserAssetActivity : BaseActivity() {
|
||||
|
||||
class UserAssetViewHolder(val itemUserAssetBinding: ItemRecyclerUserAssetBinding) :
|
||||
RecyclerView.ViewHolder(itemUserAssetBinding.root)
|
||||
}
|
||||
}
|
@@ -4,36 +4,27 @@ import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import com.v2ray.ang.dto.AppInfo
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
object AppManagerUtil {
|
||||
private fun loadNetworkAppList(ctx: Context): ArrayList<AppInfo> {
|
||||
val packageManager = ctx.packageManager
|
||||
val packages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)
|
||||
val apps = ArrayList<AppInfo>()
|
||||
suspend fun loadNetworkAppList(context: Context): ArrayList<AppInfo> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val packageManager = context.packageManager
|
||||
val packages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)
|
||||
val apps = ArrayList<AppInfo>()
|
||||
|
||||
for (pkg in packages) {
|
||||
val applicationInfo = pkg.applicationInfo ?: continue
|
||||
for (pkg in packages) {
|
||||
val applicationInfo = pkg.applicationInfo ?: continue
|
||||
|
||||
val appName = applicationInfo.loadLabel(packageManager).toString()
|
||||
val appIcon = applicationInfo.loadIcon(packageManager) ?: continue
|
||||
val isSystemApp = (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) > 0
|
||||
val appName = applicationInfo.loadLabel(packageManager).toString()
|
||||
val appIcon = applicationInfo.loadIcon(packageManager) ?: continue
|
||||
val isSystemApp = (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) > 0
|
||||
|
||||
val appInfo = AppInfo(appName, pkg.packageName, appIcon, isSystemApp, 0)
|
||||
apps.add(appInfo)
|
||||
val appInfo = AppInfo(appName, pkg.packageName, appIcon, isSystemApp, 0)
|
||||
apps.add(appInfo)
|
||||
}
|
||||
|
||||
return@withContext apps
|
||||
}
|
||||
|
||||
return apps
|
||||
}
|
||||
|
||||
fun rxLoadNetworkAppList(ctx: Context): Observable<ArrayList<AppInfo>> =
|
||||
Observable.unsafeCreate {
|
||||
it.onNext(loadNetworkAppList(ctx))
|
||||
}
|
||||
|
||||
// val PackageInfo.hasInternetPermission: Boolean
|
||||
// get() {
|
||||
// val permissions = requestedPermissions
|
||||
// return permissions?.any { it == Manifest.permission.INTERNET } ?: false
|
||||
// }
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
agp = "8.8.1"
|
||||
desugar_jdk_libs = "2.1.4"
|
||||
agp = "8.8.2"
|
||||
desugar_jdk_libs = "2.1.5"
|
||||
gradleLicensePlugin = "0.9.8"
|
||||
kotlin = "2.1.10"
|
||||
coreKtx = "1.15.0"
|
||||
@@ -9,14 +9,13 @@ junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
activity = "1.10.0"
|
||||
constraintlayout = "2.2.0"
|
||||
mmkvStatic = "1.3.11"
|
||||
activity = "1.10.1"
|
||||
constraintlayout = "2.2.1"
|
||||
mmkvStatic = "1.3.12"
|
||||
gson = "2.11.0"
|
||||
quickieFoss = "1.13.1"
|
||||
rxjava = "3.1.10"
|
||||
rxandroid = "3.0.2"
|
||||
rxpermissions = "0.12"
|
||||
kotlinx-coroutines-android = "1.10.1"
|
||||
kotlinx-coroutines-core = "1.10.1"
|
||||
swiperefreshlayout = "1.1.0"
|
||||
toastcompat = "1.1.0"
|
||||
editorkit = "2.9.0"
|
||||
@@ -43,9 +42,8 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const
|
||||
mmkv-static = { module = "com.tencent:mmkv-static", version.ref = "mmkvStatic" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
quickie-foss = { module = "com.github.T8RIN.QuickieExtended:quickie-foss", version.ref = "quickieFoss" }
|
||||
rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
|
||||
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
|
||||
rxpermissions = { module = "com.github.tbruyelle:rxpermissions", version.ref = "rxpermissions" }
|
||||
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version = "kotlinx-coroutines-android" }
|
||||
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version = "kotlinx-coroutines-core" }
|
||||
toastcompat = { module = "me.drakeet.support:toastcompat", version.ref = "toastcompat" }
|
||||
editorkit = { module = "com.blacksquircle.ui:editorkit", version.ref = "editorkit" }
|
||||
language-base = { module = "com.blacksquircle.ui:language-base", version.ref = "editorkit" }
|
||||
|
@@ -324,6 +324,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
if w.sniffingConfig != nil {
|
||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
|
||||
}
|
||||
|
@@ -120,7 +120,7 @@ func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.Bu
|
||||
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||
// deep-clone outbounds because it is going to be mutated concurrently
|
||||
// (Target and OriginalTarget)
|
||||
ctx = session.ContextCloneOutbounds(ctx)
|
||||
ctx = session.ContextCloneOutboundsAndContent(ctx)
|
||||
errors.LogInfo(ctx, "received request for ", meta.Target)
|
||||
{
|
||||
msg := &log.AccessMessage{
|
||||
|
@@ -63,7 +63,7 @@ func SniffHTTP(b []byte, c context.Context) (*SniffHeader, error) {
|
||||
ShouldSniffAttr := true
|
||||
// If content.Attributes have information, that means it comes from HTTP inbound PlainHTTP mode.
|
||||
// It will set attributes, so skip it.
|
||||
if content == nil || content.AttributeLen() != 0 {
|
||||
if content == nil || len(content.Attributes) != 0 {
|
||||
ShouldSniffAttr = false
|
||||
}
|
||||
if err := beginWithHTTPMethod(b); err != nil {
|
||||
|
@@ -42,7 +42,7 @@ func ContextWithOutbounds(ctx context.Context, outbounds []*Outbound) context.Co
|
||||
return context.WithValue(ctx, outboundSessionKey, outbounds)
|
||||
}
|
||||
|
||||
func ContextCloneOutbounds(ctx context.Context) context.Context {
|
||||
func ContextCloneOutboundsAndContent(ctx context.Context) context.Context {
|
||||
outbounds := OutboundsFromContext(ctx)
|
||||
newOutbounds := make([]*Outbound, len(outbounds))
|
||||
for i, ob := range outbounds {
|
||||
@@ -55,7 +55,15 @@ func ContextCloneOutbounds(ctx context.Context) context.Context {
|
||||
newOutbounds[i] = &v
|
||||
}
|
||||
|
||||
return ContextWithOutbounds(ctx, newOutbounds)
|
||||
content := ContentFromContext(ctx)
|
||||
newContent := Content{}
|
||||
if content != nil {
|
||||
newContent = *content
|
||||
if content.Attributes != nil {
|
||||
panic("content.Attributes != nil")
|
||||
}
|
||||
}
|
||||
return ContextWithContent(ContextWithOutbounds(ctx, newOutbounds), &newContent)
|
||||
}
|
||||
|
||||
func OutboundsFromContext(ctx context.Context) []*Outbound {
|
||||
|
@@ -4,7 +4,6 @@ package session // import "github.com/xtls/xray-core/common/session"
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync"
|
||||
|
||||
c "github.com/xtls/xray-core/common/ctx"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
@@ -75,8 +74,8 @@ type Outbound struct {
|
||||
|
||||
// SniffingRequest controls the behavior of content sniffing.
|
||||
type SniffingRequest struct {
|
||||
ExcludeForDomain []string
|
||||
OverrideDestinationForProtocol []string
|
||||
ExcludeForDomain []string // read-only once set
|
||||
OverrideDestinationForProtocol []string // read-only once set
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
RouteOnly bool
|
||||
@@ -92,10 +91,6 @@ type Content struct {
|
||||
Attributes map[string]string
|
||||
|
||||
SkipDNSResolve bool
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
isLocked bool
|
||||
}
|
||||
|
||||
// Sockopt is the settings for socket connection.
|
||||
@@ -104,22 +99,8 @@ type Sockopt struct {
|
||||
Mark int32
|
||||
}
|
||||
|
||||
// Some how when using mux, there will be a same ctx between different requests
|
||||
// This will cause problem as it's designed for single request, like concurrent map writes
|
||||
// Add a Mutex as a temp solution
|
||||
|
||||
// SetAttribute attaches additional string attributes to content.
|
||||
func (c *Content) SetAttribute(name string, value string) {
|
||||
if c.isLocked {
|
||||
errors.LogError(context.Background(), "Multiple goroutines are tring to access one routing content, tring to write ", name, ":", value)
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
|
||||
if c.Attributes == nil {
|
||||
c.Attributes = make(map[string]string)
|
||||
}
|
||||
@@ -128,24 +109,8 @@ func (c *Content) SetAttribute(name string, value string) {
|
||||
|
||||
// Attribute retrieves additional string attributes from content.
|
||||
func (c *Content) Attribute(name string) string {
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
if c.Attributes == nil {
|
||||
return ""
|
||||
}
|
||||
return c.Attributes[name]
|
||||
}
|
||||
|
||||
func (c *Content) AttributeLen() int {
|
||||
c.mu.Lock()
|
||||
c.isLocked = true
|
||||
defer func() {
|
||||
c.isLocked = false
|
||||
c.mu.Unlock()
|
||||
}()
|
||||
return len(c.Attributes)
|
||||
}
|
||||
|
@@ -502,6 +502,7 @@ type REALITYConfig struct {
|
||||
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
ServerName string `json:"serverName"`
|
||||
Password string `json:"password"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
ShortId string `json:"shortId"`
|
||||
SpiderX string `json:"spiderX"`
|
||||
@@ -610,11 +611,14 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
||||
if len(c.ServerNames) != 0 {
|
||||
return nil, errors.New(`non-empty "serverNames", please use "serverName" instead`)
|
||||
}
|
||||
if c.Password != "" {
|
||||
c.PublicKey = c.Password
|
||||
}
|
||||
if c.PublicKey == "" {
|
||||
return nil, errors.New(`empty "publicKey"`)
|
||||
return nil, errors.New(`empty "password"`)
|
||||
}
|
||||
if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
|
||||
return nil, errors.New(`invalid "publicKey": `, c.PublicKey)
|
||||
return nil, errors.New(`invalid "password": `, c.PublicKey)
|
||||
}
|
||||
if len(c.ShortIds) != 0 {
|
||||
return nil, errors.New(`non-empty "shortIds", please use "shortId" instead`)
|
||||
|
@@ -2224,6 +2224,7 @@ from .tvplay import (
|
||||
TVPlayIE,
|
||||
)
|
||||
from .tvplayer import TVPlayerIE
|
||||
from .tvw import TvwIE
|
||||
from .tweakers import TweakersIE
|
||||
from .twentymin import TwentyMinutenIE
|
||||
from .twentythreevideo import TwentyThreeVideoIE
|
||||
|
@@ -1,35 +1,36 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import parse_age_limit, parse_duration, traverse_obj
|
||||
from ..utils import parse_age_limit, parse_duration, url_or_none
|
||||
from ..utils.traversal import traverse_obj
|
||||
|
||||
|
||||
class MagellanTVIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?magellantv\.com/(?:watch|video)/(?P<id>[\w-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.magellantv.com/watch/my-dads-on-death-row?type=v',
|
||||
'url': 'https://www.magellantv.com/watch/incas-the-new-story?type=v',
|
||||
'info_dict': {
|
||||
'id': 'my-dads-on-death-row',
|
||||
'id': 'incas-the-new-story',
|
||||
'ext': 'mp4',
|
||||
'title': 'My Dad\'s On Death Row',
|
||||
'description': 'md5:33ba23b9f0651fc4537ed19b1d5b0d7a',
|
||||
'duration': 3780.0,
|
||||
'title': 'Incas: The New Story',
|
||||
'description': 'md5:936c7f6d711c02dfb9db22a067b586fe',
|
||||
'age_limit': 14,
|
||||
'tags': ['Justice', 'Reality', 'United States', 'True Crime'],
|
||||
'duration': 3060.0,
|
||||
'tags': ['Ancient History', 'Archaeology', 'Anthropology'],
|
||||
},
|
||||
'params': {'skip_download': 'm3u8'},
|
||||
}, {
|
||||
'url': 'https://www.magellantv.com/video/james-bulger-the-new-revelations',
|
||||
'url': 'https://www.magellantv.com/video/tortured-to-death-murdering-the-nanny',
|
||||
'info_dict': {
|
||||
'id': 'james-bulger-the-new-revelations',
|
||||
'id': 'tortured-to-death-murdering-the-nanny',
|
||||
'ext': 'mp4',
|
||||
'title': 'James Bulger: The New Revelations',
|
||||
'description': 'md5:7b97922038bad1d0fe8d0470d8a189f2',
|
||||
'title': 'Tortured to Death: Murdering the Nanny',
|
||||
'description': 'md5:d87033594fa218af2b1a8b49f52511e5',
|
||||
'age_limit': 14,
|
||||
'duration': 2640.0,
|
||||
'age_limit': 0,
|
||||
'tags': ['Investigation', 'True Crime', 'Justice', 'Europe'],
|
||||
'tags': ['True Crime', 'Murder'],
|
||||
},
|
||||
'params': {'skip_download': 'm3u8'},
|
||||
}, {
|
||||
'url': 'https://www.magellantv.com/watch/celebration-nation',
|
||||
'url': 'https://www.magellantv.com/watch/celebration-nation?type=s',
|
||||
'info_dict': {
|
||||
'id': 'celebration-nation',
|
||||
'ext': 'mp4',
|
||||
@@ -43,10 +44,19 @@ class MagellanTVIE(InfoExtractor):
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
data = traverse_obj(self._search_nextjs_data(webpage, video_id), (
|
||||
'props', 'pageProps', 'reactContext',
|
||||
(('video', 'detail'), ('series', 'currentEpisode')), {dict}), get_all=False)
|
||||
formats, subtitles = self._extract_m3u8_formats_and_subtitles(data['jwpVideoUrl'], video_id)
|
||||
context = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['reactContext']
|
||||
data = traverse_obj(context, ((('video', 'detail'), ('series', 'currentEpisode')), {dict}, any))
|
||||
|
||||
formats, subtitles = [], {}
|
||||
for m3u8_url in set(traverse_obj(data, ((('manifests', ..., 'hls'), 'jwp_video_url'), {url_or_none}))):
|
||||
fmts, subs = self._extract_m3u8_formats_and_subtitles(
|
||||
m3u8_url, video_id, 'mp4', m3u8_id='hls', fatal=False)
|
||||
formats.extend(fmts)
|
||||
self._merge_subtitles(subs, target=subtitles)
|
||||
if not formats and (error := traverse_obj(context, ('errorDetailPage', 'errorMessage', {str}))):
|
||||
if 'available in your country' in error:
|
||||
self.raise_geo_restricted(msg=error)
|
||||
self.raise_no_formats(f'{self.IE_NAME} said: {error}', expected=True)
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
|
@@ -4,7 +4,9 @@ from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
extract_attributes,
|
||||
unified_timestamp,
|
||||
url_or_none,
|
||||
)
|
||||
from ..utils.traversal import traverse_obj
|
||||
|
||||
|
||||
class N1InfoAssetIE(InfoExtractor):
|
||||
@@ -35,9 +37,9 @@ class N1InfoIIE(InfoExtractor):
|
||||
IE_NAME = 'N1Info:article'
|
||||
_VALID_URL = r'https?://(?:(?:\w+\.)?n1info\.\w+|nova\.rs)/(?:[^/?#]+/){1,2}(?P<id>[^/?#]+)'
|
||||
_TESTS = [{
|
||||
# Youtube embedded
|
||||
# YouTube embedded
|
||||
'url': 'https://rs.n1info.com/sport-klub/tenis/kako-je-djokovic-propustio-istorijsku-priliku-video/',
|
||||
'md5': '01ddb6646d0fd9c4c7d990aa77fe1c5a',
|
||||
'md5': '987ce6fd72acfecc453281e066b87973',
|
||||
'info_dict': {
|
||||
'id': 'L5Hd4hQVUpk',
|
||||
'ext': 'mp4',
|
||||
@@ -45,7 +47,26 @@ class N1InfoIIE(InfoExtractor):
|
||||
'title': 'Ozmo i USO21, ep. 13: Novak Đoković – Danil Medvedev | Ključevi Poraza, Budućnost | SPORT KLUB TENIS',
|
||||
'description': 'md5:467f330af1effedd2e290f10dc31bb8e',
|
||||
'uploader': 'Sport Klub',
|
||||
'uploader_id': 'sportklub',
|
||||
'uploader_id': '@sportklub',
|
||||
'uploader_url': 'https://www.youtube.com/@sportklub',
|
||||
'channel': 'Sport Klub',
|
||||
'channel_id': 'UChpzBje9Ro6CComXe3BgNaw',
|
||||
'channel_url': 'https://www.youtube.com/channel/UChpzBje9Ro6CComXe3BgNaw',
|
||||
'channel_is_verified': True,
|
||||
'channel_follower_count': int,
|
||||
'comment_count': int,
|
||||
'view_count': int,
|
||||
'like_count': int,
|
||||
'age_limit': 0,
|
||||
'duration': 1049,
|
||||
'thumbnail': 'https://i.ytimg.com/vi/L5Hd4hQVUpk/maxresdefault.jpg',
|
||||
'chapters': 'count:9',
|
||||
'categories': ['Sports'],
|
||||
'tags': 'count:10',
|
||||
'timestamp': 1631522787,
|
||||
'playable_in_embed': True,
|
||||
'availability': 'public',
|
||||
'live_status': 'not_live',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://rs.n1info.com/vesti/djilas-los-plan-za-metro-nece-resiti-nijedan-saobracajni-problem/',
|
||||
@@ -55,6 +76,7 @@ class N1InfoIIE(InfoExtractor):
|
||||
'title': 'Đilas: Predlog izgradnje metroa besmislen; SNS odbacuje navode',
|
||||
'upload_date': '20210924',
|
||||
'timestamp': 1632481347,
|
||||
'thumbnail': 'http://n1info.rs/wp-content/themes/ucnewsportal-n1/dist/assets/images/placeholder-image-video.jpg',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
@@ -67,6 +89,7 @@ class N1InfoIIE(InfoExtractor):
|
||||
'title': 'Zadnji dnevi na kopališču Ilirija: “Ilirija ni umrla, ubili so jo”',
|
||||
'timestamp': 1632567630,
|
||||
'upload_date': '20210925',
|
||||
'thumbnail': 'https://n1info.si/wp-content/uploads/2021/09/06/1630945843-tomaz3.png',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
@@ -81,6 +104,14 @@ class N1InfoIIE(InfoExtractor):
|
||||
'upload_date': '20210924',
|
||||
'timestamp': 1632448649.0,
|
||||
'uploader': 'YouLotWhatDontStop',
|
||||
'display_id': 'pu9wbx',
|
||||
'channel_id': 'serbia',
|
||||
'comment_count': int,
|
||||
'like_count': int,
|
||||
'dislike_count': int,
|
||||
'age_limit': 0,
|
||||
'duration': 134,
|
||||
'thumbnail': 'https://external-preview.redd.it/5nmmawSeGx60miQM3Iq-ueC9oyCLTLjjqX-qqY8uRsc.png?format=pjpg&auto=webp&s=2f973400b04d23f871b608b178e47fc01f9b8f1d',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
@@ -93,6 +124,7 @@ class N1InfoIIE(InfoExtractor):
|
||||
'title': 'Žaklina Tatalović Ani Brnabić: Pričate laži (VIDEO)',
|
||||
'upload_date': '20211102',
|
||||
'timestamp': 1635861677,
|
||||
'thumbnail': 'https://nova.rs/wp-content/uploads/2021/11/02/1635860298-TNJG_Ana_Brnabic_i_Zaklina_Tatalovic_100_dana_Vlade_GP.jpg',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://n1info.rs/vesti/cuta-biti-u-kosovskoj-mitrovici-znaci-da-te-docekaju-eksplozivnim-napravama/',
|
||||
@@ -104,6 +136,16 @@ class N1InfoIIE(InfoExtractor):
|
||||
'timestamp': 1687290536,
|
||||
'thumbnail': 'https://cdn.brid.tv/live/partners/26827/snapshot/1332368_th_6492013a8356f_1687290170.jpg',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://n1info.rs/vesti/vuciceva-turneja-po-srbiji-najavljuje-kontrarevoluciju-preti-svom-narodu-vredja-novinare/',
|
||||
'info_dict': {
|
||||
'id': '2025974',
|
||||
'ext': 'mp4',
|
||||
'title': 'Vučićeva turneja po Srbiji: Najavljuje kontrarevoluciju, preti svom narodu, vređa novinare',
|
||||
'thumbnail': 'https://cdn-uc.brid.tv/live/partners/26827/snapshot/2025974_fhd_67c4a23280a81_1740939826.jpg',
|
||||
'timestamp': 1740939936,
|
||||
'upload_date': '20250302',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://hr.n1info.com/vijesti/pravobraniteljica-o-ubojstvu-u-zagrebu-radi-se-o-doista-nezapamcenoj-situaciji/',
|
||||
'only_matching': True,
|
||||
@@ -115,11 +157,11 @@ class N1InfoIIE(InfoExtractor):
|
||||
|
||||
title = self._html_search_regex(r'<h1[^>]+>(.+?)</h1>', webpage, 'title')
|
||||
timestamp = unified_timestamp(self._html_search_meta('article:published_time', webpage))
|
||||
plugin_data = self._html_search_meta('BridPlugin', webpage)
|
||||
plugin_data = re.findall(r'\$bp\("(?:Brid|TargetVideo)_\d+",\s(.+)\);', webpage)
|
||||
entries = []
|
||||
if plugin_data:
|
||||
site_id = self._html_search_regex(r'site:(\d+)', webpage, 'site id')
|
||||
for video_data in re.findall(r'\$bp\("Brid_\d+", (.+)\);', webpage):
|
||||
for video_data in plugin_data:
|
||||
video_id = self._parse_json(video_data, title)['video']
|
||||
entries.append({
|
||||
'id': video_id,
|
||||
@@ -140,7 +182,7 @@ class N1InfoIIE(InfoExtractor):
|
||||
'url': video_data.get('data-url'),
|
||||
'id': video_data.get('id'),
|
||||
'title': title,
|
||||
'thumbnail': video_data.get('data-thumbnail'),
|
||||
'thumbnail': traverse_obj(video_data, (('data-thumbnail', 'data-default_thumbnail'), {url_or_none}, any)),
|
||||
'timestamp': timestamp,
|
||||
'ie_key': 'N1InfoAsset',
|
||||
})
|
||||
@@ -152,7 +194,7 @@ class N1InfoIIE(InfoExtractor):
|
||||
if url.startswith('https://www.youtube.com'):
|
||||
entries.append(self.url_result(url, ie='Youtube'))
|
||||
elif url.startswith('https://www.redditmedia.com'):
|
||||
entries.append(self.url_result(url, ie='RedditR'))
|
||||
entries.append(self.url_result(url, ie='Reddit'))
|
||||
|
||||
return {
|
||||
'_type': 'playlist',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user