mirror of
https://github.com/bolucat/Archive.git
synced 2025-10-26 01:31:31 +08:00
Update On Fri May 23 20:34:58 CEST 2025
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -1007,3 +1007,4 @@ Update On Mon May 19 20:37:08 CEST 2025
|
||||
Update On Tue May 20 20:37:19 CEST 2025
|
||||
Update On Wed May 21 20:37:50 CEST 2025
|
||||
Update On Thu May 22 20:37:12 CEST 2025
|
||||
Update On Fri May 23 20:34:50 CEST 2025
|
||||
|
||||
@@ -84,7 +84,14 @@ func getCache() (*ifaceCache, error) {
|
||||
continue // interface down
|
||||
}
|
||||
for _, prefix := range ipNets {
|
||||
cache.ifTable.Insert(prefix, ifaceObj)
|
||||
if _, ok := cache.ifTable.Get(prefix); ok {
|
||||
// maybe two interfaces have the same prefix but different address,
|
||||
// so we add a special /32(ipv4) or /128(ipv6) item to let ResolveInterfaceByAddr
|
||||
// could find the correct interface
|
||||
cache.ifTable.Insert(netip.PrefixFrom(prefix.Addr(), prefix.Addr().BitLen()), ifaceObj)
|
||||
} else {
|
||||
cache.ifTable.Insert(prefix, ifaceObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ require (
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
|
||||
github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639
|
||||
github.com/metacubex/randv2 v0.2.0
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7
|
||||
github.com/metacubex/sing v0.5.3
|
||||
github.com/metacubex/sing-mux v0.3.2
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7
|
||||
github.com/metacubex/sing-vmess v0.2.1
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
|
||||
@@ -116,20 +116,20 @@ github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639/go.mod h1:Kc6
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7 h1:m4nSxvw46JEgxMzzmnXams+ebwabcry4Ydep/zNiesQ=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3 h1:QWdN16WFKMk06x4nzkc8SvZ7y2x+TLQrpkPoHs+WSVM=
|
||||
github.com/metacubex/sing v0.5.3/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
|
||||
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a h1:Ho73vGiB94LmtK5T+tKVwtCNEi/YiHmPjlqpHSAmAVs=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f h1:mP3vIm+9hRFI0C0Vl3pE0NESF/L85FDbuB0tGgUii6I=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9 h1:2e++13WNN7EGjGtvrGLUzW1xrCdQbW2gIFpgw5GEw00=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9/go.mod h1:CJSEGO4FWQAWe+ZiLZxCweGdjRR60A61SIoVjdjQeBA=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3 h1:v3rNS/5Ywh0NIZ6VU/NmdERQIN5RePzyxCFeQsU4Cx0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3/go.mod h1:/WNy/Q8ahLCoPRriWuFZFD0Jy+JNp1MEQl28Zw6SaF8=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6 h1:TAwL91XPa6x1QK55CRm+VTzPvLPUfEr/uFDnOZArqEU=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7 h1:vxkBCkZocH2de2tqeeCZxWvT1VjSJPFkE/8hGqvcLCQ=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-vmess v0.2.1 h1:I6gM3VUjtvJ15D805EUbNH+SRBuqzJeFnuIbKYUsWZ0=
|
||||
github.com/metacubex/sing-vmess v0.2.1/go.mod h1:DsODWItJtOMZNna8Qhheg8r3tUivrcO3vWgaTYKnfTo=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"build": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "5.76.1",
|
||||
"@tanstack/react-query": "5.76.2",
|
||||
"@tauri-apps/api": "2.5.0",
|
||||
"ahooks": "3.8.5",
|
||||
"dayjs": "1.11.13",
|
||||
|
||||
@@ -55,12 +55,12 @@
|
||||
"@csstools/normalize.css": "12.1.1",
|
||||
"@emotion/babel-plugin": "11.13.5",
|
||||
"@emotion/react": "11.14.0",
|
||||
"@iconify/json": "2.2.340",
|
||||
"@iconify/json": "2.2.341",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@tanstack/react-query": "5.76.1",
|
||||
"@tanstack/react-router": "1.120.5",
|
||||
"@tanstack/react-router-devtools": "1.120.6",
|
||||
"@tanstack/router-plugin": "1.120.5",
|
||||
"@tanstack/react-query": "5.76.2",
|
||||
"@tanstack/react-router": "1.120.7",
|
||||
"@tanstack/react-router-devtools": "1.120.7",
|
||||
"@tanstack/router-plugin": "1.120.7",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
|
||||
"@tauri-apps/plugin-dialog": "2.2.1",
|
||||
"@tauri-apps/plugin-fs": "2.2.1",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.19.8",
|
||||
"mihomo_alpha": "alpha-fd959fe",
|
||||
"mihomo": "v1.19.9",
|
||||
"mihomo_alpha": "alpha-b1d12a1",
|
||||
"clash_rs": "v0.7.8",
|
||||
"clash_premium": "2023-09-05-gdcc8d87",
|
||||
"clash_rs_alpha": "0.7.8-alpha+sha.dbd16f0"
|
||||
"clash_rs_alpha": "0.7.8-alpha+sha.5e5a732"
|
||||
},
|
||||
"arch_template": {
|
||||
"mihomo": {
|
||||
@@ -69,5 +69,5 @@
|
||||
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
||||
}
|
||||
},
|
||||
"updated_at": "2025-05-21T22:21:11.677Z"
|
||||
"updated_at": "2025-05-22T22:21:09.549Z"
|
||||
}
|
||||
|
||||
110
clash-nyanpasu/pnpm-lock.yaml
generated
110
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -173,8 +173,8 @@ importers:
|
||||
frontend/interface:
|
||||
dependencies:
|
||||
'@tanstack/react-query':
|
||||
specifier: 5.76.1
|
||||
version: 5.76.1(react@19.1.0)
|
||||
specifier: 5.76.2
|
||||
version: 5.76.2(react@19.1.0)
|
||||
'@tauri-apps/api':
|
||||
specifier: 2.5.0
|
||||
version: 2.5.0
|
||||
@@ -247,7 +247,7 @@ importers:
|
||||
version: 4.1.7
|
||||
'@tanstack/router-zod-adapter':
|
||||
specifier: 1.81.5
|
||||
version: 1.81.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(zod@3.24.4)
|
||||
version: 1.81.5(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(zod@3.24.4)
|
||||
'@tauri-apps/api':
|
||||
specifier: 2.5.0
|
||||
version: 2.5.0
|
||||
@@ -337,23 +337,23 @@ importers:
|
||||
specifier: 11.14.0
|
||||
version: 11.14.0(@types/react@19.1.4)(react@19.1.0)
|
||||
'@iconify/json':
|
||||
specifier: 2.2.340
|
||||
version: 2.2.340
|
||||
specifier: 2.2.341
|
||||
version: 2.2.341
|
||||
'@monaco-editor/react':
|
||||
specifier: 4.7.0
|
||||
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-query':
|
||||
specifier: 5.76.1
|
||||
version: 5.76.1(react@19.1.0)
|
||||
specifier: 5.76.2
|
||||
version: 5.76.2(react@19.1.0)
|
||||
'@tanstack/react-router':
|
||||
specifier: 1.120.5
|
||||
version: 1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
specifier: 1.120.7
|
||||
version: 1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-router-devtools':
|
||||
specifier: 1.120.6
|
||||
version: 1.120.6(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.120.5)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
|
||||
specifier: 1.120.7
|
||||
version: 1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.120.7)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
|
||||
'@tanstack/router-plugin':
|
||||
specifier: 1.120.5
|
||||
version: 1.120.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.8.0))
|
||||
specifier: 1.120.7
|
||||
version: 1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.8.0))
|
||||
'@tauri-apps/plugin-clipboard-manager':
|
||||
specifier: 2.2.2
|
||||
version: 2.2.2
|
||||
@@ -1666,8 +1666,8 @@ packages:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
|
||||
'@iconify/json@2.2.340':
|
||||
resolution: {integrity: sha512-pr5oueoKCYmLce5ukSrKihnLDW0CEuQVPIWtrlw8qgx5RBzSxg/aIsuv6Me35ZXrCkBUKxK8h1XLqCLlMB7L6g==}
|
||||
'@iconify/json@2.2.341':
|
||||
resolution: {integrity: sha512-IwH6m5hbVRtjBcmcI7xI6/H3VV3Tt0rqzWO4UxV1L82Cv32CsnvwpykLe9a2DgC06/gnrCmp3vgEzPsEHzndqg==}
|
||||
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
@@ -2686,24 +2686,24 @@ packages:
|
||||
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tanstack/query-core@5.76.0':
|
||||
resolution: {integrity: sha512-FN375hb8ctzfNAlex5gHI6+WDXTNpe0nbxp/d2YJtnP+IBM6OUm7zcaoCW6T63BawGOYZBbKC0iPvr41TteNVg==}
|
||||
'@tanstack/query-core@5.76.2':
|
||||
resolution: {integrity: sha512-PFGwWh5ss9cJQ67l6bZ7hqXbisX2gy13G2jP+VGY1bgdbCfOMWh6UBVnN62QbFXro6CCoX9hYzTnZHr6Rz00YQ==}
|
||||
|
||||
'@tanstack/react-query@5.76.1':
|
||||
resolution: {integrity: sha512-YxdLZVGN4QkT5YT1HKZQWiIlcgauIXEIsMOTSjvyD5wLYK8YVvKZUPAysMqossFJJfDpJW3pFn7WNZuPOqq+fw==}
|
||||
'@tanstack/react-query@5.76.2':
|
||||
resolution: {integrity: sha512-rGkWberCrFdIxMdvSAJM/UOKeu0O/JVTbMmfhQoJpiU9Uq0EDx2EMCadnNuJWbXR4smDA2t7DY3NKkYFmDVS5A==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tanstack/react-router-devtools@1.120.6':
|
||||
resolution: {integrity: sha512-EKK0+s10S7/00lGh881dDMvP7ySlCTRNKvrHx0wlO9JnGZ+WuNMyNgRRiQdZrSLVZ96se45cTbc4HeImAZN9BA==}
|
||||
'@tanstack/react-router-devtools@1.120.7':
|
||||
resolution: {integrity: sha512-0CsgRHYZhFHvHxexBBMAWi88+QFZzQLYVnezO6BrIcL5Y8FmMK2Ww+hSdVbOzUAZZHFPR/LkUduCoUBsYEMQMA==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@tanstack/react-router': ^1.120.5
|
||||
'@tanstack/react-router': ^1.120.7
|
||||
react: '>=18.0.0 || >=19.0.0'
|
||||
react-dom: '>=18.0.0 || >=19.0.0'
|
||||
|
||||
'@tanstack/react-router@1.120.5':
|
||||
resolution: {integrity: sha512-A+YRftGwAeFBxa8DF5ujNYqkSEbjCa1KjxDNYr+jWj16jjTxrz/XqgOJCv5ZfbAqqqOa3yLYoQbWa7OGz5jHuA==}
|
||||
'@tanstack/react-router@1.120.7':
|
||||
resolution: {integrity: sha512-fKzZXYC0mIY6/deHXvHqUuWrZ9fWOkdXB7IOofLDCBuIyi8eeSAoB6qlUbHnI4adZZVaDVuDqkiXp+1Yp4FBgA==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0 || >=19.0.0'
|
||||
@@ -2728,15 +2728,15 @@ packages:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@tanstack/router-core@1.120.5':
|
||||
resolution: {integrity: sha512-IXLNv3j7rpTL/YNCWHijZgrnxFuvD4Nz/nUiGSak4x5BKzlnuZEso81xFcIuczVrEW72NxZv8IfzpR5M5Tuc0A==}
|
||||
'@tanstack/router-core@1.120.7':
|
||||
resolution: {integrity: sha512-CAoRZtDJv5XIn4dBNsg/JqCfG1/ioMJjPR+G71ZhwUgPOBt7gmAGEAwdXD0gwdcBoOupL4//6/NPArNdMJj7yg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tanstack/router-devtools-core@1.120.6':
|
||||
resolution: {integrity: sha512-+E0WjRDTgwLRxH2NN/NCIyRxRCu3/iYFEeegWCvCjKFa1Tm34dulI3mX8YNjfwQVjo++XLjRRtUKjqVVpF1X6Q==}
|
||||
'@tanstack/router-devtools-core@1.120.7':
|
||||
resolution: {integrity: sha512-ijBs21+DdLx5llm+wHJgZ/qBF1m4QLq+b2C0/aA54NGvjSdenWPg+TYnjyUK/34LoDYUw+poIal1aSynaVribw==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@tanstack/router-core': ^1.120.5
|
||||
'@tanstack/router-core': ^1.120.7
|
||||
csstype: ^3.0.10
|
||||
solid-js: '>=1.9.5'
|
||||
tiny-invariant: ^1.3.3
|
||||
@@ -2744,21 +2744,21 @@ packages:
|
||||
csstype:
|
||||
optional: true
|
||||
|
||||
'@tanstack/router-generator@1.120.5':
|
||||
resolution: {integrity: sha512-09YWjEXqrJE+j89gKBGSbt0ca3CYwo0QUlsDlCQ1WSI4e3GuQLvSROjq97nMjaPtrnWiROxgnw5S18BlcVVvfA==}
|
||||
'@tanstack/router-generator@1.120.7':
|
||||
resolution: {integrity: sha512-vMXzEuNDQBmMwJ96VPzfhxpxm4SkL1Dn/iDjPv/LVXSLbIgZT4szln2qUq5B4VchSFTnVUZdPG9rXdnR/YeRzw==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@tanstack/react-router': ^1.120.5
|
||||
'@tanstack/react-router': ^1.120.7
|
||||
peerDependenciesMeta:
|
||||
'@tanstack/react-router':
|
||||
optional: true
|
||||
|
||||
'@tanstack/router-plugin@1.120.5':
|
||||
resolution: {integrity: sha512-5w6vW7g5LgGZ1IM1D2HPInRmJHqK5jSa2REr7QFwKVDvbVHfzOAcqfAIw1kiPRRqIh/r6YSsrGyMV5MVbrJSCA==}
|
||||
'@tanstack/router-plugin@1.120.7':
|
||||
resolution: {integrity: sha512-dk/Td/0vunav1UmViIqtGdnP/6MYAnf78UHgy+o8CwtelxAT6B2l0IQ6YAHlRL5EuWcYGlQ0BT7BFY7eCIUNvA==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@rsbuild/core': '>=1.0.2'
|
||||
'@tanstack/react-router': ^1.120.5
|
||||
'@tanstack/react-router': ^1.120.7
|
||||
vite: '>=5.0.0 || >=6.0.0'
|
||||
vite-plugin-solid: ^2.11.2
|
||||
webpack: '>=5.92.0'
|
||||
@@ -9488,7 +9488,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@iconify/json@2.2.340':
|
||||
'@iconify/json@2.2.341':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
pathe: 1.1.2
|
||||
@@ -10483,17 +10483,17 @@ snapshots:
|
||||
dependencies:
|
||||
remove-accents: 0.5.0
|
||||
|
||||
'@tanstack/query-core@5.76.0': {}
|
||||
'@tanstack/query-core@5.76.2': {}
|
||||
|
||||
'@tanstack/react-query@5.76.1(react@19.1.0)':
|
||||
'@tanstack/react-query@5.76.2(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.76.0
|
||||
'@tanstack/query-core': 5.76.2
|
||||
react: 19.1.0
|
||||
|
||||
'@tanstack/react-router-devtools@1.120.6(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.120.5)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
|
||||
'@tanstack/react-router-devtools@1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.120.7)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
|
||||
dependencies:
|
||||
'@tanstack/react-router': 1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/router-devtools-core': 1.120.6(@tanstack/router-core@1.120.5)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
|
||||
'@tanstack/react-router': 1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/router-devtools-core': 1.120.7(@tanstack/router-core@1.120.7)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
solid-js: 1.9.5
|
||||
@@ -10502,11 +10502,11 @@ snapshots:
|
||||
- csstype
|
||||
- tiny-invariant
|
||||
|
||||
'@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
'@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@tanstack/history': 1.115.0
|
||||
'@tanstack/react-store': 0.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/router-core': 1.120.5
|
||||
'@tanstack/router-core': 1.120.7
|
||||
jsesc: 3.1.0
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
@@ -10532,15 +10532,15 @@ snapshots:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
'@tanstack/router-core@1.120.5':
|
||||
'@tanstack/router-core@1.120.7':
|
||||
dependencies:
|
||||
'@tanstack/history': 1.115.0
|
||||
'@tanstack/store': 0.7.0
|
||||
tiny-invariant: 1.3.3
|
||||
|
||||
'@tanstack/router-devtools-core@1.120.6(@tanstack/router-core@1.120.5)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
|
||||
'@tanstack/router-devtools-core@1.120.7(@tanstack/router-core@1.120.7)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
|
||||
dependencies:
|
||||
'@tanstack/router-core': 1.120.5
|
||||
'@tanstack/router-core': 1.120.7
|
||||
clsx: 2.1.1
|
||||
goober: 2.1.16(csstype@3.1.3)
|
||||
solid-js: 1.9.5
|
||||
@@ -10548,16 +10548,16 @@ snapshots:
|
||||
optionalDependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
'@tanstack/router-generator@1.120.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
|
||||
'@tanstack/router-generator@1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
|
||||
dependencies:
|
||||
'@tanstack/virtual-file-routes': 1.115.0
|
||||
prettier: 3.5.3
|
||||
tsx: 4.19.4
|
||||
zod: 3.24.4
|
||||
optionalDependencies:
|
||||
'@tanstack/react-router': 1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-router': 1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
|
||||
'@tanstack/router-plugin@1.120.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.8.0))':
|
||||
'@tanstack/router-plugin@1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.8.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.26.10
|
||||
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10)
|
||||
@@ -10565,8 +10565,8 @@ snapshots:
|
||||
'@babel/template': 7.27.0
|
||||
'@babel/traverse': 7.27.0
|
||||
'@babel/types': 7.27.0
|
||||
'@tanstack/router-core': 1.120.5
|
||||
'@tanstack/router-generator': 1.120.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
||||
'@tanstack/router-core': 1.120.7
|
||||
'@tanstack/router-generator': 1.120.7(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
||||
'@tanstack/router-utils': 1.115.0
|
||||
'@tanstack/virtual-file-routes': 1.115.0
|
||||
'@types/babel__core': 7.20.5
|
||||
@@ -10577,7 +10577,7 @@ snapshots:
|
||||
unplugin: 2.3.2
|
||||
zod: 3.24.4
|
||||
optionalDependencies:
|
||||
'@tanstack/react-router': 1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-router': 1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
vite: 6.3.5(@types/node@22.15.18)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.88.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.4)(yaml@2.8.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -10589,9 +10589,9 @@ snapshots:
|
||||
ansis: 3.12.0
|
||||
diff: 7.0.0
|
||||
|
||||
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(zod@3.24.4)':
|
||||
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@tanstack/react-router': 1.120.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@tanstack/react-router': 1.120.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
zod: 3.24.4
|
||||
|
||||
'@tanstack/store@0.7.0': {}
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
- 使用操作系统默认的窗口管理器
|
||||
- 切换、升级、重启内核的状态管理
|
||||
- 更精细化控制自动日志清理,新增1天选项。
|
||||
- 简化了随机API端口和密钥(重启即可刷新)
|
||||
|
||||
#### 优化了:
|
||||
- 系统代理 Bypass 设置
|
||||
@@ -83,6 +82,8 @@
|
||||
- 优化端口设置退出和保存机制!
|
||||
- 强制为 Mihomo 配置补全并覆盖 external-controller-cors 字段,默认不允许跨域和仅本地请求,提升 cors 安全性,升级配置时自动覆盖。
|
||||
- 优化了 随机API端口和密钥刷新按钮
|
||||
- 简化了 随机API端口和密钥(重启即可刷新)
|
||||
- 增强了 随机API端口和密钥的安全生成
|
||||
|
||||
## v2.2.3
|
||||
|
||||
|
||||
1
clash-verge-rev/src-tauri/Cargo.lock
generated
1
clash-verge-rev/src-tauri/Cargo.lock
generated
@@ -1076,6 +1076,7 @@ dependencies = [
|
||||
"port_scanner",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest_dav",
|
||||
|
||||
@@ -82,6 +82,7 @@ sha2 = "0.10.9"
|
||||
hex = "0.4.3"
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3.1"
|
||||
rand_core = "0.6.4"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::utils::{dirs, help};
|
||||
use anyhow::Result;
|
||||
use rand::{rngs::OsRng, Rng};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use rand_core::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::{Mapping, Value};
|
||||
use std::{
|
||||
@@ -61,6 +63,9 @@ impl IClashTemp {
|
||||
"tauri://localhost",
|
||||
"http://tauri.localhost",
|
||||
"http://localhost:3000",
|
||||
"https://yacd.metacubex.one",
|
||||
"https://metacubex.github.io",
|
||||
"https://board.zash.run.place",
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
@@ -72,21 +77,30 @@ impl IClashTemp {
|
||||
|
||||
// 生成随机端口(动态端口范围:1111-65535)
|
||||
fn generate_random_port() -> u16 {
|
||||
let mut rng = OsRng;
|
||||
let seed = Self::generate_seed();
|
||||
let mut rng = ChaCha8Rng::from_seed(seed);
|
||||
rng.gen_range(1111..=65535)
|
||||
}
|
||||
|
||||
// 生成32位强密码(包含大小写字母、数字、特殊符号)
|
||||
// 生成64位强密码(包含大小写字母、数字、特殊符号)
|
||||
fn generate_secret() -> String {
|
||||
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;':\",.<>/?`~";
|
||||
let mut rng = OsRng;
|
||||
(0..32)
|
||||
let seed = Self::generate_seed();
|
||||
let mut rng = ChaCha8Rng::from_seed(seed);
|
||||
(0..64)
|
||||
.map(|_| CHARS[rng.gen_range(0..CHARS.len())] as char)
|
||||
.collect()
|
||||
}
|
||||
|
||||
// 生成加密安全的随机种子
|
||||
fn generate_seed() -> [u8; 32] {
|
||||
let mut seed = [0u8; 32];
|
||||
OsRng.fill(&mut seed as &mut [u8]);
|
||||
seed
|
||||
}
|
||||
|
||||
fn guard(mut config: Mapping) -> Mapping {
|
||||
// 生成随机控制器端口和密钥
|
||||
// 填入随机控制器端口和密钥
|
||||
let ctrl_port = Self::generate_random_port();
|
||||
let ctrl_addr = format!("127.0.0.1:{}", ctrl_port);
|
||||
let secret = Self::generate_secret();
|
||||
@@ -99,7 +113,7 @@ impl IClashTemp {
|
||||
let socks_port = Self::guard_socks_port(&config);
|
||||
let port = Self::guard_port(&config);
|
||||
|
||||
// 注入随机值
|
||||
// 加注随机值
|
||||
config.insert("external-controller".into(), Value::String(ctrl_addr));
|
||||
config.insert("secret".into(), Value::String(secret));
|
||||
|
||||
@@ -120,6 +134,9 @@ impl IClashTemp {
|
||||
"tauri://localhost",
|
||||
"http://tauri.localhost",
|
||||
"http://localhost:3000",
|
||||
"https://yacd.metacubex.one",
|
||||
"https://metacubex.github.io",
|
||||
"https://board.zash.run.place",
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useVerge } from "@/hooks/use-verge";
|
||||
import { showNotice } from "@/services/noticeService";
|
||||
import {
|
||||
ContentCopy,
|
||||
RefreshRounded,
|
||||
} from "@mui/icons-material";
|
||||
import {
|
||||
Alert,
|
||||
@@ -22,23 +21,6 @@ import { useLockFn } from "ahooks";
|
||||
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
// 随机端口和密码生成
|
||||
const generateRandomPort = (): number => {
|
||||
return Math.floor(Math.random() * (65535 - 1024 + 1)) + 1024;
|
||||
};
|
||||
|
||||
const generateRandomPassword = (length: number = 64): string => {
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let password = "";
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * charset.length);
|
||||
password += charset.charAt(randomIndex);
|
||||
}
|
||||
|
||||
return password;
|
||||
};
|
||||
|
||||
export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -111,23 +93,6 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 生成随机端口
|
||||
const handleGeneratePort = useLockFn(async () => {
|
||||
const port = generateRandomPort();
|
||||
const host = controller.split(':')[0] || '127.0.0.1';
|
||||
setController(`${host}:${port}`);
|
||||
showNotice('success', t("Random port generated"), 1000);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
// 生成随机 Secret
|
||||
const handleGenerateSecret = useLockFn(async () => {
|
||||
const password = generateRandomPassword();
|
||||
setSecret(password);
|
||||
showNotice('success', t("Random secret generated"), 1000);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
// 复制到剪贴板
|
||||
const handleCopyToClipboard = useLockFn(async (text: string, type: string) => {
|
||||
try {
|
||||
@@ -172,19 +137,7 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px", display: "flex", justifyContent: "space-between" }}>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<ListItemText primary={t("External Controller")} />
|
||||
<Tooltip title={t("Generate Random Port")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={handleGeneratePort}
|
||||
color="primary"
|
||||
disabled={isSaving || isRestarting}
|
||||
>
|
||||
<RefreshRounded fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<ListItemText primary={t("External Controller")} />
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -193,14 +146,13 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
value={controller}
|
||||
placeholder="Required"
|
||||
onChange={(e) => setController(e.target.value)}
|
||||
disabled={isSaving || isRestarting}
|
||||
disabled={true}
|
||||
/>
|
||||
<Tooltip title={t("Copy to clipboard")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleCopyToClipboard(controller, "controller")}
|
||||
color="primary"
|
||||
disabled={isSaving || isRestarting}
|
||||
>
|
||||
<ContentCopy fontSize="small" />
|
||||
</IconButton>
|
||||
@@ -209,19 +161,7 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px", display: "flex", justifyContent: "space-between" }}>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<ListItemText primary={t("Core Secret")} />
|
||||
<Tooltip title={t("Generate Random Secret")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={handleGenerateSecret}
|
||||
color="primary"
|
||||
disabled={isSaving || isRestarting}
|
||||
>
|
||||
<RefreshRounded fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<ListItemText primary={t("Core Secret")} />
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -229,17 +169,14 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
sx={{ width: 175 }}
|
||||
value={secret}
|
||||
placeholder={t("Recommended")}
|
||||
onChange={(e) =>
|
||||
setSecret(e.target.value?.replace(/[^\x00-\x7F]/g, ""))
|
||||
}
|
||||
disabled={isSaving || isRestarting}
|
||||
onChange={(e) => setSecret(e.target.value)}
|
||||
disabled={true}
|
||||
/>
|
||||
<Tooltip title={t("Copy to clipboard")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleCopyToClipboard(secret, "secret")}
|
||||
color="primary"
|
||||
disabled={isSaving || isRestarting}
|
||||
>
|
||||
<ContentCopy fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
@@ -93,6 +93,7 @@ $(curdir)/automake/compile := $(curdir)/autoconf/compile $(curdir)/pkgconf/compi
|
||||
$(curdir)/b43-tools/compile := $(curdir)/bison/compile
|
||||
$(curdir)/bc/compile := $(curdir)/bison/compile $(curdir)/libtool/compile
|
||||
$(curdir)/bison/compile := $(curdir)/flex/compile
|
||||
$(curdir)/bzip2/compile := $(curdir)/cmake/compile
|
||||
$(curdir)/cbootimage/compile += $(curdir)/automake/compile
|
||||
$(curdir)/cmake/compile += $(curdir)/libressl/compile $(curdir)/ninja/compile $(curdir)/expat/compile $(curdir)/xz/compile $(curdir)/zlib/compile $(curdir)/zstd/compile
|
||||
$(curdir)/dosfstools/compile := $(curdir)/automake/compile
|
||||
|
||||
@@ -84,7 +84,14 @@ func getCache() (*ifaceCache, error) {
|
||||
continue // interface down
|
||||
}
|
||||
for _, prefix := range ipNets {
|
||||
cache.ifTable.Insert(prefix, ifaceObj)
|
||||
if _, ok := cache.ifTable.Get(prefix); ok {
|
||||
// maybe two interfaces have the same prefix but different address,
|
||||
// so we add a special /32(ipv4) or /128(ipv6) item to let ResolveInterfaceByAddr
|
||||
// could find the correct interface
|
||||
cache.ifTable.Insert(netip.PrefixFrom(prefix.Addr(), prefix.Addr().BitLen()), ifaceObj)
|
||||
} else {
|
||||
cache.ifTable.Insert(prefix, ifaceObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ require (
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
|
||||
github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639
|
||||
github.com/metacubex/randv2 v0.2.0
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7
|
||||
github.com/metacubex/sing v0.5.3
|
||||
github.com/metacubex/sing-mux v0.3.2
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7
|
||||
github.com/metacubex/sing-vmess v0.2.1
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
|
||||
@@ -116,20 +116,20 @@ github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639/go.mod h1:Kc6
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7 h1:m4nSxvw46JEgxMzzmnXams+ebwabcry4Ydep/zNiesQ=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3 h1:QWdN16WFKMk06x4nzkc8SvZ7y2x+TLQrpkPoHs+WSVM=
|
||||
github.com/metacubex/sing v0.5.3/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
|
||||
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a h1:Ho73vGiB94LmtK5T+tKVwtCNEi/YiHmPjlqpHSAmAVs=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250520025433-6e556a6bef7a/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f h1:mP3vIm+9hRFI0C0Vl3pE0NESF/L85FDbuB0tGgUii6I=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9 h1:2e++13WNN7EGjGtvrGLUzW1xrCdQbW2gIFpgw5GEw00=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9/go.mod h1:CJSEGO4FWQAWe+ZiLZxCweGdjRR60A61SIoVjdjQeBA=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3 h1:v3rNS/5Ywh0NIZ6VU/NmdERQIN5RePzyxCFeQsU4Cx0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3/go.mod h1:/WNy/Q8ahLCoPRriWuFZFD0Jy+JNp1MEQl28Zw6SaF8=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6 h1:TAwL91XPa6x1QK55CRm+VTzPvLPUfEr/uFDnOZArqEU=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7 h1:vxkBCkZocH2de2tqeeCZxWvT1VjSJPFkE/8hGqvcLCQ=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250523121712-972bc1c2b1e7/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-vmess v0.2.1 h1:I6gM3VUjtvJ15D805EUbNH+SRBuqzJeFnuIbKYUsWZ0=
|
||||
github.com/metacubex/sing-vmess v0.2.1/go.mod h1:DsODWItJtOMZNna8Qhheg8r3tUivrcO3vWgaTYKnfTo=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
|
||||
@@ -2176,7 +2176,7 @@ component("base") {
|
||||
"process/set_process_title_linux.h",
|
||||
"system/sys_info_linux.cc",
|
||||
]
|
||||
if (!is_cronet_build) {
|
||||
if (!is_android) {
|
||||
# These dependencies are not required on Android.
|
||||
sources += [
|
||||
"nix/mime_util_xdg.cc",
|
||||
|
||||
@@ -390,19 +390,19 @@ class TracedArray;
|
||||
class TracedDictionary;
|
||||
class EventContext;
|
||||
|
||||
class StaticString {
|
||||
class BASE_EXPORT StaticString {
|
||||
public:
|
||||
template <typename T>
|
||||
StaticString(T) {}
|
||||
};
|
||||
|
||||
class DynamicString {
|
||||
class BASE_EXPORT DynamicString {
|
||||
public:
|
||||
template <typename T>
|
||||
explicit DynamicString(T) {}
|
||||
};
|
||||
|
||||
class TracedValue {
|
||||
class BASE_EXPORT TracedValue {
|
||||
public:
|
||||
void WriteInt64(int64_t) && {}
|
||||
void WriteUInt64(uint64_t) && {}
|
||||
@@ -417,7 +417,7 @@ class TracedValue {
|
||||
TracedArray WriteArray() &&;
|
||||
};
|
||||
|
||||
class TracedDictionary {
|
||||
class BASE_EXPORT TracedDictionary {
|
||||
public:
|
||||
TracedValue AddItem(StaticString) { return TracedValue(); }
|
||||
TracedValue AddItem(DynamicString) { return TracedValue(); }
|
||||
@@ -433,7 +433,7 @@ class TracedDictionary {
|
||||
TracedArray AddArray(DynamicString);
|
||||
};
|
||||
|
||||
class TracedArray {
|
||||
class BASE_EXPORT TracedArray {
|
||||
public:
|
||||
TracedValue AppendItem() { return TracedValue(); }
|
||||
|
||||
@@ -447,16 +447,16 @@ class TracedArray {
|
||||
template <class T>
|
||||
void WriteIntoTracedValue(TracedValue, T&&) {}
|
||||
|
||||
struct Track {
|
||||
struct BASE_EXPORT Track {
|
||||
explicit Track(uint64_t id) {}
|
||||
};
|
||||
|
||||
struct NamedTrack {
|
||||
struct BASE_EXPORT NamedTrack {
|
||||
template <class T>
|
||||
explicit NamedTrack(T name, uint64_t id = 0, Track parent = Track{0}) {}
|
||||
};
|
||||
|
||||
struct Flow {
|
||||
struct BASE_EXPORT Flow {
|
||||
static inline Flow ProcessScoped(uint64_t flow_id) { return Flow(); }
|
||||
static inline Flow FromPointer(void* ptr) { return Flow(); }
|
||||
static inline Flow Global(uint64_t flow_id) { return Flow(); }
|
||||
|
||||
@@ -8,6 +8,7 @@ mkdir -p "$TMPDIR"
|
||||
if [ "$1" = debug ]; then
|
||||
out=out/Debug
|
||||
flags="
|
||||
chrome_pgo_phase=0
|
||||
is_debug=true
|
||||
is_component_build=true"
|
||||
else
|
||||
@@ -16,6 +17,7 @@ else
|
||||
is_official_build=true
|
||||
exclude_unwind_tables=true
|
||||
enable_resource_allowlist_generation=false
|
||||
chrome_pgo_phase=2
|
||||
symbol_level=0"
|
||||
fi
|
||||
|
||||
@@ -51,7 +53,6 @@ flags="$flags"'
|
||||
treat_warnings_as_errors=false
|
||||
|
||||
is_cronet_build=true
|
||||
chrome_pgo_phase=2
|
||||
|
||||
enable_base_tracing=false
|
||||
use_udev=false
|
||||
|
||||
@@ -628,7 +628,7 @@ config("compiler") {
|
||||
|
||||
# Enable ELF CREL (see crbug.com/357878242) for all platforms that use ELF
|
||||
# (excluding toolchains that use an older version of LLVM).
|
||||
if (is_linux && !llvm_android_mainline &&
|
||||
if (is_linux && !llvm_android_mainline && current_cpu != "arm" &&
|
||||
current_cpu != "mipsel" && current_cpu != "mips64el" &&
|
||||
default_toolchain != "//build/toolchain/cros:target") {
|
||||
cflags += [ "-Wa,--crel,--allow-experimental-crel" ]
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "net/base/features.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/net_export.h"
|
||||
#include "net/base/proxy_chain.h"
|
||||
#include "net/base/proxy_server.h"
|
||||
#include "net/dns/public/secure_dns_policy.h"
|
||||
@@ -207,7 +208,7 @@ base::TimeDelta ClientSocketPoolManager::unused_idle_socket_timeout(
|
||||
return base::Seconds(kPreconnectIntervalSec);
|
||||
}
|
||||
|
||||
int InitSocketHandleForHttpRequest(
|
||||
int NET_EXPORT InitSocketHandleForHttpRequest(
|
||||
url::SchemeHostPort endpoint,
|
||||
int request_load_flags,
|
||||
RequestPriority request_priority,
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.12.0-beta.16
|
||||
#### 1.12.0-beta.17
|
||||
|
||||
* Update quic-go to v0.52.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.0-beta.15
|
||||
|
||||
@@ -27,10 +27,10 @@ require (
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gomobile v0.1.6
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||
github.com/sagernet/quic-go v0.51.0-beta.5
|
||||
github.com/sagernet/sing v0.6.10-0.20250521033217-30d675ea099b
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b
|
||||
github.com/sagernet/sing-mux v0.3.2
|
||||
github.com/sagernet/sing-quic v0.4.1-0.20250511050139-d459f561c9c3
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.1
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
|
||||
@@ -167,13 +167,17 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.51.0-beta.5 h1:/mME3sJvQ8k/JKP0oC/9XoWrm0znO7hWXviB5yiipJY=
|
||||
github.com/sagernet/quic-go v0.51.0-beta.5/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.6.10-0.20250521033217-30d675ea099b h1:E9zgBma90grCIC1Rber6UgGw3CzbpeizJdavNu1Fy8M=
|
||||
github.com/sagernet/sing v0.6.10-0.20250521033217-30d675ea099b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b h1:ZjTCYPb5f7aHdf1UpUvE22dVmf7BL8eQ/zLZhjgh7Wo=
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
||||
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.4.1-0.20250511050139-d459f561c9c3 h1:1J+s1yyZ8+YAYaClI+az8YuFgV9NGXUUCZnriKmos6w=
|
||||
github.com/sagernet/sing-quic v0.4.1-0.20250511050139-d459f561c9c3/go.mod h1:Mv7CdSyLepmqoLT8rd88Qn3QMv5AbsgjEm3DvEhDVNE=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.1 h1:nC0i/s8LhlZB8ev6laZCXF/uiwAE4kRdT4PcDdE4rI4=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.1/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
|
||||
@@ -3,7 +3,6 @@ package route
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -314,14 +313,10 @@ func (r *NetworkManager) AutoDetectInterfaceFunc() control.Func {
|
||||
return nil
|
||||
}
|
||||
bindFunc := control.BindToInterfaceFunc(r.interfaceFinder, func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
|
||||
for _, iif := range r.interfaceFinder.Interfaces() {
|
||||
r.logger.Warn("iif ", iif.Name, ": ", fmt.Sprint(iif.Addresses))
|
||||
}
|
||||
remoteAddr := M.ParseSocksaddr(address).Addr
|
||||
if remoteAddr.IsValid() {
|
||||
iif, err := r.interfaceFinder.ByAddr(remoteAddr)
|
||||
if err == nil {
|
||||
r.logger.Warn("bind to interface ", iif.Name, " (", iif.Index, "): ", remoteAddr)
|
||||
return iif.Name, iif.Index, nil
|
||||
}
|
||||
}
|
||||
@@ -329,7 +324,6 @@ func (r *NetworkManager) AutoDetectInterfaceFunc() control.Func {
|
||||
if defaultInterface == nil {
|
||||
return "", -1, tun.ErrNoRoute
|
||||
}
|
||||
r.logger.Warn("bind to default interface ", defaultInterface.Name, " (", defaultInterface.Index, "): ", remoteAddr)
|
||||
return defaultInterface.Name, defaultInterface.Index, nil
|
||||
})
|
||||
return func(network, address string, conn syscall.RawConn) error {
|
||||
|
||||
@@ -598,7 +598,7 @@ return view.extend({
|
||||
|
||||
so = ss.option(form.DynamicList, 'external_controller_cors_allow_origins', _('CORS Allow origins'),
|
||||
_('CORS allowed origins, <code>*</code> will be used if empty.'));
|
||||
so.placeholder = 'https://yacd.metacubex.one';
|
||||
so.placeholder = 'https://board.zash.run.place';
|
||||
|
||||
so = ss.option(form.Flag, 'external_controller_cors_allow_private_network', _('CORS Allow private network'),
|
||||
_('Allow access from private network.</br>' +
|
||||
@@ -680,6 +680,9 @@ return view.extend({
|
||||
o = s.taboption('experimental', form.SectionValue, '_experimental', form.NamedSection, 'experimental', 'fchomo', null);
|
||||
ss = o.subsection;
|
||||
|
||||
so = ss.option(form.Flag, 'skip_safe_path_check', _('Disable safe path check'));
|
||||
so.default = so.disabled;
|
||||
|
||||
so = ss.option(form.Flag, 'quic_go_disable_gso', _('Disable GSO of quic-go'));
|
||||
so.default = so.disabled;
|
||||
|
||||
|
||||
@@ -539,6 +539,10 @@ msgstr ""
|
||||
msgid "Disable UDP"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:683
|
||||
msgid "Disable safe path check"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:750
|
||||
msgid ""
|
||||
"Do not resolve the domain connection to IP for this match.</br>Only works "
|
||||
|
||||
@@ -547,6 +547,10 @@ msgstr "禁用 SNI"
|
||||
msgid "Disable UDP"
|
||||
msgstr "禁用 UDP"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:683
|
||||
msgid "Disable safe path check"
|
||||
msgstr "禁用安全路径检查"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:750
|
||||
msgid ""
|
||||
"Do not resolve the domain connection to IP for this match.</br>Only works "
|
||||
|
||||
@@ -547,6 +547,10 @@ msgstr "停用 SNI"
|
||||
msgid "Disable UDP"
|
||||
msgstr "停用 UDP"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:683
|
||||
msgid "Disable safe path check"
|
||||
msgstr "禁用安全路徑檢查"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:750
|
||||
msgid ""
|
||||
"Do not resolve the domain connection to IP for this match.</br>Only works "
|
||||
|
||||
@@ -110,11 +110,13 @@ start_service() {
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
|
||||
# Global ENV variables
|
||||
config_get_bool SKIP_SAFE_PATH_CHECK "experimental" "skip_safe_path_check" "0"
|
||||
export SKIP_SAFE_PATH_CHECK=$([ "$SKIP_SAFE_PATH_CHECK" = "1" ] && echo true || echo false)
|
||||
|
||||
# Client
|
||||
if [ "$client_enabled" = "1" ]; then
|
||||
if [ -z "$1" -o "$1" = "mihomo-c" ]; then
|
||||
# Env variables
|
||||
export SAFE_PATHS="$RUN_DIR/"
|
||||
|
||||
# Generate/Validate client config
|
||||
ucode -S "$SDL_DIR/generate_client.uc" 2>>"$LOG_PATH" | yq -Poy | yq \
|
||||
@@ -131,9 +133,20 @@ start_service() {
|
||||
if [ ! -e "$RUN_DIR/mihomo-c.yaml" ]; then
|
||||
log "Error: failed to generate client configuration."
|
||||
return 1
|
||||
elif ! "$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-c.yaml" >/dev/null 2>>"$LOG_PATH"; then
|
||||
log "Error: wrong client configuration detected."
|
||||
return 1
|
||||
else
|
||||
# Set ENV variables for Client
|
||||
export SAFE_PATHS="$RUN_DIR$(
|
||||
yq 'with(.tls; .[] |= sub("(/[^/]+$)", ""))
|
||||
| [.external-ui, .tls.certificate, .tls.private-key] | unique
|
||||
| .[] | sub("(^)", ":")' \
|
||||
"$RUN_DIR/mihomo-c.yaml" | tr -d '\n'
|
||||
)"
|
||||
|
||||
if ! "$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-c.yaml" >/dev/null; then
|
||||
log "Error: wrong client configuration detected."
|
||||
"$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-c.yaml" >>"$LOG_PATH"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
echo > "$RUN_DIR/mihomo-c.log"
|
||||
|
||||
@@ -251,7 +264,7 @@ start_service() {
|
||||
|
||||
procd_set_param command /bin/sh
|
||||
procd_append_param command -c "'$PROG' -d '$HM_DIR' -f '$RUN_DIR/mihomo-c.yaml' >> '$RUN_DIR/mihomo-c.log' 2>&1"
|
||||
procd_set_param env SAFE_PATHS="$RUN_DIR:/etc/ssl" SKIP_SAFE_PATH_CHECK=true # The syntax of this environment variable is the same as the PATH environment variable parsing rules of this operating system (i.e., semicolon-separated under Windows and colon-separated under other systems)
|
||||
procd_set_param env SAFE_PATHS="$SAFE_PATHS" SKIP_SAFE_PATH_CHECK="$SKIP_SAFE_PATH_CHECK" # The syntax of this environment variable is the same as the PATH environment variable parsing rules of this operating system (i.e., semicolon-separated under Windows and colon-separated under other systems)
|
||||
|
||||
# Only supports `Global`` and does not support `Proxy Group` and `Proxy Node`
|
||||
local bind_ifname
|
||||
@@ -288,9 +301,20 @@ start_service() {
|
||||
if [ ! -e "$RUN_DIR/mihomo-s.yaml" ]; then
|
||||
log "Error: failed to generate server configuration."
|
||||
return 1
|
||||
elif ! "$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-s.yaml" >/dev/null 2>>"$LOG_PATH"; then
|
||||
log "Error: wrong server configuration detected."
|
||||
return 1
|
||||
else
|
||||
# Set ENV variables for Server
|
||||
export SAFE_PATHS="$RUN_DIR$(
|
||||
yq '[.listeners[] | select(.certificate // .private-key) | [.certificate, .private-key][]]
|
||||
| .[] |= sub("(/[^/]+$)", "") | unique
|
||||
| .[] | sub("(^)", ":")' \
|
||||
"$RUN_DIR/mihomo-s.yaml" | tr -d '\n'
|
||||
)"
|
||||
|
||||
if ! "$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-s.yaml" >/dev/null; then
|
||||
log "Error: wrong server configuration detected."
|
||||
"$PROG" -t -d "$HM_DIR" -f "$RUN_DIR/mihomo-s.yaml" >>"$LOG_PATH"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
echo > "$RUN_DIR/mihomo-s.log"
|
||||
|
||||
@@ -299,6 +323,7 @@ start_service() {
|
||||
|
||||
procd_set_param command /bin/sh
|
||||
procd_append_param command -c "'$PROG' -d '$HM_DIR' -f '$RUN_DIR/mihomo-s.yaml' >> '$RUN_DIR/mihomo-s.log' 2>&1"
|
||||
procd_set_param env SAFE_PATHS="$SAFE_PATHS" SKIP_SAFE_PATH_CHECK="$SKIP_SAFE_PATH_CHECK" # The syntax of this environment variable is the same as the PATH environment variable parsing rules of this operating system (i.e., semicolon-separated under Windows and colon-separated under other systems)
|
||||
|
||||
#procd_set_param capabilities "/etc/capabilities/fchomo.json"
|
||||
#procd_set_param user mihomo
|
||||
|
||||
@@ -38,7 +38,7 @@ LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:= \
|
||||
+coreutils +coreutils-base64 +dns2tcp +dnsmasq-full +@PACKAGE_dnsmasq_full_ipset +ipset +kmod-ipt-nat +jq \
|
||||
+ip-full +iptables +iptables-mod-tproxy +lua +lua-neturl +libuci-lua +microsocks \
|
||||
+tcping +resolveip +shadowsocksr-libev-ssr-check +wget-ssl \
|
||||
+tcping +resolveip +shadowsocksr-libev-ssr-check +curl \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:curl \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray-core \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:curl \
|
||||
|
||||
@@ -95,7 +95,7 @@ get_host_ip() {
|
||||
if [ -z "$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")" ]; then
|
||||
if [ "$host" == "${host#*:[0-9a-fA-F]}" ]; then
|
||||
ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}')
|
||||
[ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$host | awk -F ';' '{print $1}')
|
||||
[ -z "$ip" ] && ip=$(curl -sSL "http://119.29.29.29/d?dn=$host" | awk -F ';' '{print $1}')
|
||||
fi
|
||||
fi
|
||||
[ -z "$ip" ] || uci_set_by_name $1 ip $ip
|
||||
|
||||
@@ -419,6 +419,7 @@ local function processData(szType, content)
|
||||
elseif szType == "sip008" then
|
||||
result.type = v2_ss
|
||||
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
|
||||
result.has_ss_type = has_ss_type
|
||||
result.server = content.server
|
||||
result.server_port = content.server_port
|
||||
result.password = content.password
|
||||
@@ -432,6 +433,7 @@ local function processData(szType, content)
|
||||
elseif szType == "ssd" then
|
||||
result.type = v2_ss
|
||||
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
|
||||
result.has_ss_type = has_ss_type
|
||||
result.server = content.server
|
||||
result.server_port = content.port
|
||||
result.password = content.password
|
||||
@@ -680,12 +682,12 @@ local function processData(szType, content)
|
||||
result.switch_enable = switch_enable
|
||||
return result
|
||||
end
|
||||
-- wget
|
||||
local function wget(url)
|
||||
-- curl
|
||||
local function curl(url)
|
||||
-- 清理URL中的隐藏字符
|
||||
url = url:gsub("%s+$", ""):gsub("^%s+", ""):gsub("%z", "")
|
||||
|
||||
local stdout = luci.sys.exec('wget-ssl --timeout=20 --tries=3 -q --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --no-check-certificate -O- "' .. url .. '"')
|
||||
local stdout = luci.sys.exec('curl -sSL --connect-timeout 20 --max-time 30 --retry 3 -A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --insecure --location "' .. url .. '"')
|
||||
return trim(stdout)
|
||||
end
|
||||
|
||||
@@ -739,7 +741,7 @@ local execute = function()
|
||||
luci.sys.init.stop(name)
|
||||
end
|
||||
for k, url in ipairs(subscribe_url) do
|
||||
local raw = wget(url)
|
||||
local raw = curl(url)
|
||||
if #raw > 0 then
|
||||
local nodes, szType
|
||||
local groupHash = md5(url)
|
||||
|
||||
@@ -150,7 +150,7 @@ end
|
||||
|
||||
local function update(url, file, type, file2)
|
||||
local Num = 1
|
||||
local refresh_cmd = "wget --no-check-certificate -q -O /tmp/ssr-update." .. type .. " " .. url
|
||||
local refresh_cmd = "curl -sSL --insecure -o /tmp/ssr-update." .. type .. " " .. url
|
||||
local sret = luci.sys.call(refresh_cmd)
|
||||
if sret == 0 then
|
||||
if type == "gfw_data" then
|
||||
|
||||
@@ -21,22 +21,22 @@ define Download/geoip
|
||||
HASH:=8023379316bca4713dcfa5ba4ea2fe7f4c127fff64a0cb7859d4756142b2c4dc
|
||||
endef
|
||||
|
||||
GEOSITE_VER:=20250521095120
|
||||
GEOSITE_VER:=20250523074055
|
||||
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
|
||||
define Download/geosite
|
||||
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
|
||||
URL_FILE:=dlc.dat
|
||||
FILE:=$(GEOSITE_FILE)
|
||||
HASH:=54049654ec3ded40d0ba8e6c00b7f2efb908275b57cd6b0d8ed78b9f5a639105
|
||||
HASH:=02479c2a08974893a97dfac39c33e32e72b5181ffb669b13ce351de9195e9c47
|
||||
endef
|
||||
|
||||
GEOSITE_IRAN_VER:=202505120041
|
||||
GEOSITE_IRAN_VER:=202505230820
|
||||
GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER)
|
||||
define Download/geosite-ir
|
||||
URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/
|
||||
URL_FILE:=iran.dat
|
||||
FILE:=$(GEOSITE_IRAN_FILE)
|
||||
HASH:=1797aec3ef7cf7f9a34fef2e056fd4faa04458bb468b0a6ff4e8b2440bb6ed29
|
||||
HASH:=063852d8eb2df6a4541bdbaf38b422b8cfadbb6315cc2098f0eb6c9437bbb8b6
|
||||
endef
|
||||
|
||||
define Package/v2ray-geodata/template
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core)
|
||||
|
||||
[](https://developer.android.com/about/versions/lollipop)
|
||||
[](https://kotlinlang.org)
|
||||
[](https://kotlinlang.org)
|
||||
[](https://github.com/2dust/v2rayNG/commits/master)
|
||||
[](https://www.codefactor.io/repository/github/2dust/v2rayng)
|
||||
[](https://github.com/2dust/v2rayNG/releases)
|
||||
|
||||
@@ -144,6 +144,9 @@
|
||||
<data android:host="install-sub" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.CheckUpdateActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.AboutActivity"
|
||||
android:exported="false" />
|
||||
|
||||
@@ -5,28 +5,21 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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.dto.CheckUpdateResult
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.toastError
|
||||
import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SpeedtestManager
|
||||
import com.v2ray.ang.handler.UpdateCheckerManager
|
||||
import com.v2ray.ang.util.AppManagerUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.ZipUtil
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
@@ -105,23 +98,6 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
//If it is the Google Play version, not be displayed within 1 days after update
|
||||
// if (Utils.isGoogleFlavor()) {
|
||||
// val lastUpdateTime = AppManagerUtil.getLastUpdateTime(this)
|
||||
// val currentTime = System.currentTimeMillis()
|
||||
// if ((currentTime - lastUpdateTime) < 1 * 24 * 60 * 60 * 1000L) {
|
||||
// binding.layoutCheckUpdate.visibility = View.GONE
|
||||
// }
|
||||
// }
|
||||
binding.layoutCheckUpdate.setOnClickListener {
|
||||
checkForUpdates(binding.checkPreRelease.isChecked)
|
||||
}
|
||||
|
||||
binding.checkPreRelease.setOnCheckedChangeListener { _, isChecked ->
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_CHECK_UPDATE_PRE_RELEASE, isChecked)
|
||||
}
|
||||
binding.checkPreRelease.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_CHECK_UPDATE_PRE_RELEASE, false)
|
||||
|
||||
binding.layoutSoureCcode.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.APP_URL)
|
||||
}
|
||||
@@ -222,28 +198,4 @@ class AboutActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkForUpdates(includePreRelease: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
val result = UpdateCheckerManager.checkForUpdate(includePreRelease)
|
||||
if (result.hasUpdate) {
|
||||
showUpdateDialog(result)
|
||||
} else {
|
||||
toast(R.string.update_already_latest_version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdateDialog(result: CheckUpdateResult) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.update_new_version_found, result.latestVersion))
|
||||
.setMessage(result.releaseNotes)
|
||||
.setPositiveButton(R.string.update_now) { _, _ ->
|
||||
result.downloadUrl?.let {
|
||||
Utils.openUri(this, it)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityCheckUpdateBinding
|
||||
import com.v2ray.ang.dto.CheckUpdateResult
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SpeedtestManager
|
||||
import com.v2ray.ang.handler.UpdateCheckerManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CheckUpdateActivity : BaseActivity() {
|
||||
|
||||
private val binding by lazy { ActivityCheckUpdateBinding.inflate(layoutInflater) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
|
||||
title = getString(R.string.update_check_for_update)
|
||||
|
||||
binding.layoutCheckUpdate.setOnClickListener {
|
||||
checkForUpdates(binding.checkPreRelease.isChecked)
|
||||
}
|
||||
|
||||
binding.checkPreRelease.setOnCheckedChangeListener { _, isChecked ->
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_CHECK_UPDATE_PRE_RELEASE, isChecked)
|
||||
}
|
||||
binding.checkPreRelease.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_CHECK_UPDATE_PRE_RELEASE, false)
|
||||
|
||||
"v${BuildConfig.VERSION_NAME} (${SpeedtestManager.getLibVersion()})".also {
|
||||
binding.tvVersion.text = it
|
||||
}
|
||||
|
||||
checkForUpdates(binding.checkPreRelease.isChecked)
|
||||
}
|
||||
|
||||
private fun checkForUpdates(includePreRelease: Boolean) {
|
||||
toast(R.string.update_checking_for_update)
|
||||
|
||||
lifecycleScope.launch {
|
||||
val result = UpdateCheckerManager.checkForUpdate(includePreRelease)
|
||||
if (result.hasUpdate) {
|
||||
showUpdateDialog(result)
|
||||
} else {
|
||||
toastSuccess(R.string.update_already_latest_version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdateDialog(result: CheckUpdateResult) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.update_new_version_found, result.latestVersion))
|
||||
.setMessage(result.releaseNotes)
|
||||
.setPositiveButton(R.string.update_now) { _, _ ->
|
||||
result.downloadUrl?.let {
|
||||
Utils.openUri(this, it)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
@@ -685,6 +685,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
|
||||
R.id.promotion -> Utils.openUri(this, "${Utils.decode(AppConfig.APP_PROMOTION_URL)}?t=${System.currentTimeMillis()}")
|
||||
R.id.logcat -> startActivity(Intent(this, LogcatActivity::class.java))
|
||||
R.id.check_for_update -> startActivity(Intent(this, CheckUpdateActivity::class.java))
|
||||
R.id.about -> startActivity(Intent(this, AboutActivity::class.java))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivitySubEditBinding
|
||||
import com.v2ray.ang.dto.SubscriptionItem
|
||||
@@ -109,19 +110,28 @@ class SubEditActivity : BaseActivity() {
|
||||
*/
|
||||
private fun deleteServer(): Boolean {
|
||||
if (editSubId.isNotEmpty()) {
|
||||
AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
MmkvManager.removeSubscription(editSubId)
|
||||
launch(Dispatchers.Main) {
|
||||
finish()
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE) == true) {
|
||||
AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
MmkvManager.removeSubscription(editSubId)
|
||||
launch(Dispatchers.Main) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
MmkvManager.removeSubscription(editSubId)
|
||||
launch(Dispatchers.Main) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
@@ -20,6 +21,8 @@ import com.v2ray.ang.helper.ItemTouchHelperAdapter
|
||||
import com.v2ray.ang.helper.ItemTouchHelperViewHolder
|
||||
import com.v2ray.ang.util.QRCodeDecoder
|
||||
import com.v2ray.ang.util.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView.Adapter<SubSettingRecyclerAdapter.MainViewHolder>(), ItemTouchHelperAdapter {
|
||||
|
||||
@@ -46,6 +49,10 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
|
||||
)
|
||||
}
|
||||
|
||||
holder.itemSubSettingBinding.layoutRemove.setOnClickListener {
|
||||
removeSubscription(subId, position)
|
||||
}
|
||||
|
||||
holder.itemSubSettingBinding.chkEnable.setOnCheckedChangeListener { it, isChecked ->
|
||||
if (!it.isPressed) return@setOnCheckedChangeListener
|
||||
subItem.enabled = isChecked
|
||||
@@ -54,9 +61,11 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(subItem.url)) {
|
||||
holder.itemSubSettingBinding.layoutUrl.visibility = View.GONE
|
||||
holder.itemSubSettingBinding.layoutShare.visibility = View.INVISIBLE
|
||||
holder.itemSubSettingBinding.chkEnable.visibility = View.INVISIBLE
|
||||
} else {
|
||||
holder.itemSubSettingBinding.layoutUrl.visibility = View.VISIBLE
|
||||
holder.itemSubSettingBinding.layoutShare.visibility = View.VISIBLE
|
||||
holder.itemSubSettingBinding.chkEnable.visibility = View.VISIBLE
|
||||
holder.itemSubSettingBinding.layoutShare.setOnClickListener {
|
||||
@@ -90,6 +99,32 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeSubscription(subId: String, position: Int) {
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE) == true) {
|
||||
AlertDialog.Builder(mActivity).setMessage(R.string.del_config_comfirm)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
removeSubscriptionSub(subId, position)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
//do noting
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
removeSubscriptionSub(subId, position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeSubscriptionSub(subId: String, position: Int) {
|
||||
mActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||
MmkvManager.removeSubscription(subId)
|
||||
launch(Dispatchers.Main) {
|
||||
notifyItemRemoved(position)
|
||||
notifyItemRangeChanged(position, mActivity.subscriptions.size)
|
||||
mActivity.refreshData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
|
||||
return MainViewHolder(
|
||||
ItemRecyclerSubSettingBinding.inflate(
|
||||
|
||||
@@ -111,49 +111,6 @@
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/padding_spacing_dp16">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_check_update"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_spacing_dp16">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_check_update_24dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/padding_spacing_dp16">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/update_check_for_update"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/check_pre_release"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/padding_spacing_dp16"
|
||||
android:maxLines="1"
|
||||
android:text="@string/update_check_pre_release"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorAccent"
|
||||
app:theme="@style/BrandedSwitch" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_soure_ccode"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_spacing_dp16">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_source_code_24dp" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/check_pre_release"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
||||
android:text="@string/update_check_pre_release"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorAccent"
|
||||
app:theme="@style/BrandedSwitch" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_check_update"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_spacing_dp16">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_check_update_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/padding_spacing_dp16"
|
||||
android:text="@string/update_check_for_update"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_spacing_dp16">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_about"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -15,97 +15,144 @@
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:nextFocusRight="@+id/layout_edit"
|
||||
android:nextFocusRight="@+id/layout_share"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_url"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
||||
android:lines="2"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
android:paddingStart="@dimen/padding_spacing_dp8">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_share_24dp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:minLines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:nextFocusLeft="@+id/info_container"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_share"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:nextFocusLeft="@+id/info_container"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_share_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_spacing_dp8">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_delete_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/image_size_dp24"
|
||||
android:layout_height="@dimen/image_size_dp24"
|
||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/layout_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/padding_spacing_dp8"
|
||||
android:paddingEnd="@dimen/padding_spacing_dp8">
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/chk_enable"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="@dimen/padding_spacing_dp8">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_url"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="2"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:theme="@style/BrandedSwitch" />
|
||||
android:layout_marginTop="@dimen/padding_spacing_dp8"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/chk_enable"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:theme="@style/BrandedSwitch" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -35,6 +35,10 @@
|
||||
android:id="@+id/logcat"
|
||||
android:icon="@drawable/ic_logcat_24dp"
|
||||
android:title="@string/title_logcat" />
|
||||
<item
|
||||
android:id="@+id/check_for_update"
|
||||
android:icon="@drawable/ic_check_update_24dp"
|
||||
android:title="@string/update_check_for_update" />
|
||||
<item
|
||||
android:id="@+id/about"
|
||||
android:icon="@drawable/ic_about_24dp"
|
||||
|
||||
@@ -316,6 +316,7 @@
|
||||
<string name="update_new_version_found">New version found: %s</string>
|
||||
<string name="update_now">Update now</string>
|
||||
<string name="update_check_pre_release">Check Pre-release</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>رمز استجابة سريعة (QRcode)</item>
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<string name="update_new_version_found">New version found: %s</string>
|
||||
<string name="update_now">Update now</string>
|
||||
<string name="update_check_pre_release">Check Pre-release</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QR কোড</item>
|
||||
|
||||
@@ -324,6 +324,7 @@
|
||||
<string name="update_new_version_found">نوسخه نۊ ن جوست: %s</string>
|
||||
<string name="update_now">سکو ورۊ رسۊوی کۊنین</string>
|
||||
<string name="update_check_pre_release">واجۊری نوسخه یل پؽش ز تیجنیڌن</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QRcode</item>
|
||||
|
||||
@@ -321,6 +321,7 @@
|
||||
<string name="update_new_version_found">نسخه جدید پیدا شد: %s</string>
|
||||
<string name="update_now">اکنون به روز رسانی کنید</string>
|
||||
<string name="update_check_pre_release">بررسی نسخه پیش از انتشار</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QRcode</item>
|
||||
|
||||
@@ -323,6 +323,7 @@
|
||||
<string name="update_new_version_found">Найдена новая версия: %s</string>
|
||||
<string name="update_now">Обновить</string>
|
||||
<string name="update_check_pre_release">Искать предварительный выпуск</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QR-код</item>
|
||||
|
||||
@@ -317,6 +317,7 @@
|
||||
<string name="update_new_version_found">New version found: %s</string>
|
||||
<string name="update_now">Update now</string>
|
||||
<string name="update_check_pre_release">Check Pre-release</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>Xuất ra mã QR (Chụp màn hình để lưu)</item>
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<string name="update_new_version_found">发现新版本: %s</string>
|
||||
<string name="update_now">立即更新</string>
|
||||
<string name="update_check_pre_release">检查 Pre-release</string>
|
||||
<string name="update_checking_for_update">正在检查更新中…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>二维码</item>
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<string name="update_new_version_found">發現新版本: %s</string>
|
||||
<string name="update_now">立即更新</string>
|
||||
<string name="update_check_pre_release">檢查 Pre-release</string>
|
||||
<string name="update_checking_for_update">正在檢查更新中…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QR Code</item>
|
||||
|
||||
@@ -325,6 +325,7 @@
|
||||
<string name="update_new_version_found">New version found: %s</string>
|
||||
<string name="update_now">Update now</string>
|
||||
<string name="update_check_pre_release">Check Pre-release</string>
|
||||
<string name="update_checking_for_update">Checking for update…</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QRcode</item>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
agp = "8.9.3"
|
||||
desugarJdkLibs = "2.1.5"
|
||||
gradleLicensePlugin = "0.9.8"
|
||||
kotlin = "2.1.20"
|
||||
kotlin = "2.1.21"
|
||||
coreKtx = "1.16.0"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
|
||||
@@ -2147,6 +2147,7 @@ from .toggle import (
|
||||
from .toggo import ToggoIE
|
||||
from .tonline import TOnlineIE
|
||||
from .toongoggles import ToonGogglesIE
|
||||
from .toutiao import ToutiaoIE
|
||||
from .toutv import TouTvIE
|
||||
from .toypics import (
|
||||
ToypicsIE,
|
||||
|
||||
@@ -340,8 +340,9 @@ class PatreonIE(PatreonBaseIE):
|
||||
'channel_follower_count': ('attributes', 'patron_count', {int_or_none}),
|
||||
}))
|
||||
|
||||
# all-lowercase 'referer' so we can smuggle it to Generic, SproutVideo, Vimeo
|
||||
headers = {'referer': 'https://patreon.com/'}
|
||||
# Must be all-lowercase 'referer' so we can smuggle it to Generic, SproutVideo, and Vimeo.
|
||||
# patreon.com URLs redirect to www.patreon.com; this matters when requesting mux.com m3u8s
|
||||
headers = {'referer': 'https://www.patreon.com/'}
|
||||
|
||||
# handle Vimeo embeds
|
||||
if traverse_obj(attributes, ('embed', 'provider')) == 'Vimeo':
|
||||
@@ -352,7 +353,7 @@ class PatreonIE(PatreonBaseIE):
|
||||
v_url, video_id, 'Checking Vimeo embed URL', headers=headers,
|
||||
fatal=False, errnote=False, expected_status=429): # 429 is TLS fingerprint rejection
|
||||
entries.append(self.url_result(
|
||||
VimeoIE._smuggle_referrer(v_url, 'https://patreon.com/'),
|
||||
VimeoIE._smuggle_referrer(v_url, headers['referer']),
|
||||
VimeoIE, url_transparent=True))
|
||||
|
||||
embed_url = traverse_obj(attributes, ('embed', 'url', {url_or_none}))
|
||||
@@ -379,11 +380,13 @@ class PatreonIE(PatreonBaseIE):
|
||||
'url': post_file['url'],
|
||||
})
|
||||
elif name == 'video' or determine_ext(post_file.get('url')) == 'm3u8':
|
||||
formats, subtitles = self._extract_m3u8_formats_and_subtitles(post_file['url'], video_id)
|
||||
formats, subtitles = self._extract_m3u8_formats_and_subtitles(
|
||||
post_file['url'], video_id, headers=headers)
|
||||
entries.append({
|
||||
'id': video_id,
|
||||
'formats': formats,
|
||||
'subtitles': subtitles,
|
||||
'http_headers': headers,
|
||||
})
|
||||
|
||||
can_view_post = traverse_obj(attributes, 'current_user_can_view')
|
||||
|
||||
@@ -5,11 +5,13 @@ from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
OnDemandPagedList,
|
||||
float_or_none,
|
||||
int_or_none,
|
||||
orderedSet,
|
||||
str_or_none,
|
||||
str_to_int,
|
||||
traverse_obj,
|
||||
unified_timestamp,
|
||||
url_or_none,
|
||||
)
|
||||
from ..utils.traversal import require, traverse_obj
|
||||
|
||||
|
||||
class PodchaserIE(InfoExtractor):
|
||||
@@ -21,24 +23,25 @@ class PodchaserIE(InfoExtractor):
|
||||
'id': '104365585',
|
||||
'title': 'Ep. 285 – freeze me off',
|
||||
'description': 'cam ahn',
|
||||
'thumbnail': r're:^https?://.*\.jpg$',
|
||||
'thumbnail': r're:https?://.+/.+\.jpg',
|
||||
'ext': 'mp3',
|
||||
'categories': ['Comedy'],
|
||||
'categories': ['Comedy', 'News', 'Politics', 'Arts'],
|
||||
'tags': ['comedy', 'dark humor'],
|
||||
'series': 'Cum Town',
|
||||
'series': 'The Adam Friedland Show Podcast',
|
||||
'duration': 3708,
|
||||
'timestamp': 1636531259,
|
||||
'upload_date': '20211110',
|
||||
'average_rating': 4.0,
|
||||
'series_id': '36924',
|
||||
},
|
||||
}, {
|
||||
'url': 'https://www.podchaser.com/podcasts/the-bone-zone-28853',
|
||||
'info_dict': {
|
||||
'id': '28853',
|
||||
'title': 'The Bone Zone',
|
||||
'description': 'Podcast by The Bone Zone',
|
||||
'description': r're:The official home of the Bone Zone podcast.+',
|
||||
},
|
||||
'playlist_count': 275,
|
||||
'playlist_mincount': 275,
|
||||
}, {
|
||||
'url': 'https://www.podchaser.com/podcasts/sean-carrolls-mindscape-scienc-699349/episodes',
|
||||
'info_dict': {
|
||||
@@ -51,19 +54,33 @@ class PodchaserIE(InfoExtractor):
|
||||
|
||||
@staticmethod
|
||||
def _parse_episode(episode, podcast):
|
||||
return {
|
||||
'id': str(episode.get('id')),
|
||||
'title': episode.get('title'),
|
||||
'description': episode.get('description'),
|
||||
'url': episode.get('audio_url'),
|
||||
'thumbnail': episode.get('image_url'),
|
||||
'duration': str_to_int(episode.get('length')),
|
||||
'timestamp': unified_timestamp(episode.get('air_date')),
|
||||
'average_rating': float_or_none(episode.get('rating')),
|
||||
'categories': list(set(traverse_obj(podcast, (('summary', None), 'categories', ..., 'text')))),
|
||||
'tags': traverse_obj(podcast, ('tags', ..., 'text')),
|
||||
'series': podcast.get('title'),
|
||||
}
|
||||
info = traverse_obj(episode, {
|
||||
'id': ('id', {int}, {str_or_none}, {require('episode ID')}),
|
||||
'title': ('title', {str}),
|
||||
'description': ('description', {str}),
|
||||
'url': ('audio_url', {url_or_none}),
|
||||
'thumbnail': ('image_url', {url_or_none}),
|
||||
'duration': ('length', {int_or_none}),
|
||||
'timestamp': ('air_date', {unified_timestamp}),
|
||||
'average_rating': ('rating', {float_or_none}),
|
||||
})
|
||||
info.update(traverse_obj(podcast, {
|
||||
'series': ('title', {str}),
|
||||
'series_id': ('id', {int}, {str_or_none}),
|
||||
'categories': (('summary', None), 'categories', ..., 'text', {str}, filter, all, {orderedSet}),
|
||||
'tags': ('tags', ..., 'text', {str}),
|
||||
}))
|
||||
info['vcodec'] = 'none'
|
||||
|
||||
if info.get('series_id'):
|
||||
podcast_slug = traverse_obj(podcast, ('slug', {str})) or 'podcast'
|
||||
episode_slug = traverse_obj(episode, ('slug', {str})) or 'episode'
|
||||
info['webpage_url'] = '/'.join((
|
||||
'https://www.podchaser.com/podcasts',
|
||||
'-'.join((podcast_slug[:30].rstrip('-'), info['series_id'])),
|
||||
'-'.join((episode_slug[:30].rstrip('-'), info['id']))))
|
||||
|
||||
return info
|
||||
|
||||
def _call_api(self, path, *args, **kwargs):
|
||||
return self._download_json(f'https://api.podchaser.com/{path}', *args, **kwargs)
|
||||
@@ -93,5 +110,5 @@ class PodchaserIE(InfoExtractor):
|
||||
OnDemandPagedList(functools.partial(self._fetch_page, podcast_id, podcast), self._PAGE_SIZE),
|
||||
str_or_none(podcast.get('id')), podcast.get('title'), podcast.get('description'))
|
||||
|
||||
episode = self._call_api(f'episodes/{episode_id}', episode_id)
|
||||
episode = self._call_api(f'podcasts/{podcast_id}/episodes/{episode_id}/player_ids', episode_id)
|
||||
return self._parse_episode(episode, podcast)
|
||||
|
||||
121
yt-dlp/yt_dlp/extractor/toutiao.py
Normal file
121
yt-dlp/yt_dlp/extractor/toutiao.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
float_or_none,
|
||||
int_or_none,
|
||||
str_or_none,
|
||||
try_call,
|
||||
url_or_none,
|
||||
)
|
||||
from ..utils.traversal import find_element, traverse_obj
|
||||
|
||||
|
||||
class ToutiaoIE(InfoExtractor):
|
||||
IE_NAME = 'toutiao'
|
||||
IE_DESC = '今日头条'
|
||||
|
||||
_VALID_URL = r'https?://www\.toutiao\.com/video/(?P<id>\d+)/?(?:[?#]|$)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.toutiao.com/video/7505382061495176511/',
|
||||
'info_dict': {
|
||||
'id': '7505382061495176511',
|
||||
'ext': 'mp4',
|
||||
'title': '新疆多地现不明飞行物,目击者称和月亮一样亮,几秒内突然加速消失,气象部门回应',
|
||||
'comment_count': int,
|
||||
'duration': 9.753,
|
||||
'like_count': int,
|
||||
'release_date': '20250517',
|
||||
'release_timestamp': 1747483344,
|
||||
'thumbnail': r're:https?://p\d+-sign\.toutiaoimg\.com/.+$',
|
||||
'uploader': '极目新闻',
|
||||
'uploader_id': 'MS4wLjABAAAAeateBb9Su8I3MJOZozmvyzWktmba5LMlliRDz1KffnM',
|
||||
'view_count': int,
|
||||
},
|
||||
}, {
|
||||
'url': 'https://www.toutiao.com/video/7479446610359878153/',
|
||||
'info_dict': {
|
||||
'id': '7479446610359878153',
|
||||
'ext': 'mp4',
|
||||
'title': '小伙竟然利用两块磁铁制作成磁力减震器,简直太有创意了!',
|
||||
'comment_count': int,
|
||||
'duration': 118.374,
|
||||
'like_count': int,
|
||||
'release_date': '20250308',
|
||||
'release_timestamp': 1741444368,
|
||||
'thumbnail': r're:https?://p\d+-sign\.toutiaoimg\.com/.+$',
|
||||
'uploader': '小莉创意发明',
|
||||
'uploader_id': 'MS4wLjABAAAA4f7d4mwtApALtHIiq-QM20dwXqe32NUz0DeWF7wbHKw',
|
||||
'view_count': int,
|
||||
},
|
||||
}]
|
||||
|
||||
def _real_initialize(self):
|
||||
if self._get_cookies('https://www.toutiao.com').get('ttwid'):
|
||||
return
|
||||
|
||||
urlh = self._request_webpage(
|
||||
'https://ttwid.bytedance.com/ttwid/union/register/', None,
|
||||
'Fetching ttwid', 'Unable to fetch ttwid', headers={
|
||||
'Content-Type': 'application/json',
|
||||
}, data=json.dumps({
|
||||
'aid': 24,
|
||||
'needFid': False,
|
||||
'region': 'cn',
|
||||
'service': 'www.toutiao.com',
|
||||
'union': True,
|
||||
}).encode(),
|
||||
)
|
||||
|
||||
if ttwid := try_call(lambda: self._get_cookies(urlh.url)['ttwid'].value):
|
||||
self._set_cookie('.toutiao.com', 'ttwid', ttwid)
|
||||
return
|
||||
|
||||
self.raise_login_required()
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
video_data = traverse_obj(webpage, (
|
||||
{find_element(tag='script', id='RENDER_DATA')},
|
||||
{urllib.parse.unquote}, {json.loads}, 'data', 'initialVideo',
|
||||
))
|
||||
|
||||
formats = []
|
||||
for video in traverse_obj(video_data, (
|
||||
'videoPlayInfo', 'video_list', lambda _, v: v['main_url'],
|
||||
)):
|
||||
formats.append({
|
||||
'url': video['main_url'],
|
||||
**traverse_obj(video, ('video_meta', {
|
||||
'acodec': ('audio_profile', {str}),
|
||||
'asr': ('audio_sample_rate', {int_or_none}),
|
||||
'audio_channels': ('audio_channels', {float_or_none}, {int_or_none}),
|
||||
'ext': ('vtype', {str}),
|
||||
'filesize': ('size', {int_or_none}),
|
||||
'format_id': ('definition', {str}),
|
||||
'fps': ('fps', {int_or_none}),
|
||||
'height': ('vheight', {int_or_none}),
|
||||
'tbr': ('real_bitrate', {float_or_none(scale=1000)}),
|
||||
'vcodec': ('codec_type', {str}),
|
||||
'width': ('vwidth', {int_or_none}),
|
||||
})),
|
||||
})
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'formats': formats,
|
||||
**traverse_obj(video_data, {
|
||||
'comment_count': ('commentCount', {int_or_none}),
|
||||
'duration': ('videoPlayInfo', 'video_duration', {float_or_none}),
|
||||
'like_count': ('repinCount', {int_or_none}),
|
||||
'release_timestamp': ('publishTime', {int_or_none}),
|
||||
'thumbnail': (('poster', 'coverUrl'), {url_or_none}, any),
|
||||
'title': ('title', {str}),
|
||||
'uploader': ('userInfo', 'name', {str}),
|
||||
'uploader_id': ('userInfo', 'userId', {str_or_none}),
|
||||
'view_count': ('playCount', {int_or_none}),
|
||||
'webpage_url': ('detailUrl', {url_or_none}),
|
||||
}),
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import itertools
|
||||
import re
|
||||
|
||||
@@ -16,6 +17,7 @@ from ..utils import (
|
||||
str_to_int,
|
||||
try_get,
|
||||
unified_timestamp,
|
||||
update_url_query,
|
||||
url_or_none,
|
||||
urlencode_postdata,
|
||||
urljoin,
|
||||
@@ -171,6 +173,10 @@ class TwitCastingIE(InfoExtractor):
|
||||
'player': 'pc_web',
|
||||
})
|
||||
|
||||
password_params = {
|
||||
'word': hashlib.md5(video_password.encode()).hexdigest(),
|
||||
} if video_password else None
|
||||
|
||||
formats = []
|
||||
# low: 640x360, medium: 1280x720, high: 1920x1080
|
||||
qq = qualities(['low', 'medium', 'high'])
|
||||
@@ -178,7 +184,7 @@ class TwitCastingIE(InfoExtractor):
|
||||
'tc-hls', 'streams', {dict.items}, lambda _, v: url_or_none(v[1]),
|
||||
)):
|
||||
formats.append({
|
||||
'url': m3u8_url,
|
||||
'url': update_url_query(m3u8_url, password_params),
|
||||
'format_id': f'hls-{quality}',
|
||||
'ext': 'mp4',
|
||||
'quality': qq(quality),
|
||||
@@ -192,7 +198,7 @@ class TwitCastingIE(InfoExtractor):
|
||||
'llfmp4', 'streams', {dict.items}, lambda _, v: url_or_none(v[1]),
|
||||
)):
|
||||
formats.append({
|
||||
'url': ws_url,
|
||||
'url': update_url_query(ws_url, password_params),
|
||||
'format_id': f'ws-{mode}',
|
||||
'ext': 'mp4',
|
||||
'quality': qq(mode),
|
||||
|
||||
@@ -3950,19 +3950,23 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
||||
|
||||
subtitles = {}
|
||||
skipped_subs_clients = set()
|
||||
prs = traverse_obj(player_responses, (
|
||||
# Filter out initial_pr which does not have streamingData (smuggled client context)
|
||||
lambda _, v: v['streamingData'] and v['captions']['playerCaptionsTracklistRenderer']))
|
||||
|
||||
pctrs = traverse_obj(prs, (..., 'captions', 'playerCaptionsTracklistRenderer', {dict}))
|
||||
# Only web/mweb clients provide translationLanguages, so include initial_pr in the traversal
|
||||
translation_languages = {
|
||||
lang.get('languageCode'): self._get_text(lang.get('languageName'), max_runs=1)
|
||||
for lang in traverse_obj(pctrs, (..., 'translationLanguages', ..., {dict}))}
|
||||
lang['languageCode']: self._get_text(lang['languageName'], max_runs=1)
|
||||
for lang in traverse_obj(player_responses, (
|
||||
..., 'captions', 'playerCaptionsTracklistRenderer', 'translationLanguages',
|
||||
lambda _, v: v['languageCode'] and v['languageName']))
|
||||
}
|
||||
# NB: Constructing the full subtitle dictionary is slow
|
||||
get_translated_subs = 'translated_subs' not in self._configuration_arg('skip') and (
|
||||
self.get_param('writeautomaticsub', False) or self.get_param('listsubtitles'))
|
||||
|
||||
all_captions = traverse_obj(pctrs, (..., 'captionTracks', ..., {dict}))
|
||||
# Filter out initial_pr which does not have streamingData (smuggled client context)
|
||||
prs = traverse_obj(player_responses, (
|
||||
lambda _, v: v['streamingData'] and v['captions']['playerCaptionsTracklistRenderer']))
|
||||
all_captions = traverse_obj(prs, (
|
||||
..., 'captions', 'playerCaptionsTracklistRenderer', 'captionTracks', ..., {dict}))
|
||||
need_subs_langs = {get_lang_code(sub) for sub in all_captions if sub.get('kind') != 'asr'}
|
||||
need_caps_langs = {
|
||||
remove_start(get_lang_code(sub), 'a-')
|
||||
|
||||
Reference in New Issue
Block a user