Update On Sat Jan 25 19:31:17 CET 2025

This commit is contained in:
github-action[bot]
2025-01-25 19:31:17 +01:00
parent ab89d29845
commit 4d5a9cd310
37 changed files with 789 additions and 684 deletions

1
.github/update.log vendored
View File

@@ -893,3 +893,4 @@ Update On Tue Jan 21 19:34:05 CET 2025
Update On Wed Jan 22 19:34:22 CET 2025
Update On Thu Jan 23 19:35:00 CET 2025
Update On Fri Jan 24 19:33:49 CET 2025
Update On Sat Jan 25 19:31:08 CET 2025

View File

@@ -1,322 +0,0 @@
// 大陆域名用 Bypass DNS 来解析, 注意与 bypass_china_domain_a.tengo 区分. 这是一个包含主流的精小样本.
// generated by: https://bash.ooo/china.js
// The script limits the stack size 2048. If your array or map exceeds max stack size, try splitting it into multiple. The memory occupied by a dictionary is approximately twice that of an array with same elements.
modules = append(modules, {
dnsquery: func(m) {
text := import("text")
f := func(domain, l){
ss := text.split(text.to_lower(domain), ".")
s := ""
for i := len(ss) - 1; i >= 0; i-- {
if s == "" {
s = ss[i]
} else {
s = ss[i] + "." + s
}
if l[s] {
return { bypass: true }
}
}
}
l := {
"wxcloudrun.com": true,
"alibabadns.com": true,
"10010.com": true,
"115.com": true,
"126.net": true,
"127.net": true,
"163.com": true,
"163jiasu.com": true,
"163yun.com": true,
"1905.com": true,
"21cn.com": true,
"300hu.com": true,
"321fenx.com": true,
"360buyimg.com": true,
"365dmp.com": true,
"71edge.com": true,
"95516.com": true,
"adkwai.com": true,
"adukwai.com": true,
"aggrx.com": true,
"ali-health.com": true,
"aliapp.org": true,
"alibaba-inc.com": true,
"alibaba.com": true,
"alibabausercontent.com": true,
"alicdn.com": true,
"alipay.com": true,
"alipayobjects.com": true,
"aliyun.com": true,
"aliyuncs.com": true,
"amap.com": true,
"amemv.com": true,
"baidu.com": true,
"baidubce.com": true,
"baidupcs.com": true,
"baidustatic.com": true,
"baifubao.com": true,
"baishan.com": true,
"baizhanlive.com": true,
"bcebos.com": true,
"bcelive.com": true,
"bdimg.com": true,
"bdstatic.com": true,
"bdurl.net": true,
"bdxiguastatic.com": true,
"bdxiguavod.com": true,
"bigda.com": true,
"biliapi.com": true,
"biliapi.net": true,
"bilibili.com": true,
"biligame.com": true,
"biligame.net": true,
"bilivideo.com": true,
"bjshcw.com": true,
"bosszhipin.com": true,
"bytedance.com": true,
"byteeffecttos.com": true,
"bytegecko.com": true,
"bytegoofy.com": true,
"byteimg.com": true,
"bytemaimg.com": true,
"bytemastatic.com": true,
"bytescm.com": true,
"bytetos.com": true,
"c-ctrip.com": true,
"calorietech.com": true,
"cdnhwc2.com": true,
"cdntips.net": true,
"chinanetcenter.com": true,
"cibntv.net": true,
"cl2009.com": true,
"cmbchina.com": true,
"cmbimg.com": true,
"cmpassport.com": true,
"cn": true,
"cnzz.com": true,
"cpatrk.net": true,
"ctfile.com": true,
"ctobsnssdk.com": true,
"dbankcloud.com": true,
"dewu.com": true,
"dewucdn.com": true,
"dianping.com": true,
"douyincdn.com": true,
"douyinliving.com": true,
"douyinstatic.com": true,
"douyinvod.com": true,
"douyu.com": true,
"dpfile.com": true,
"dutils.com": true,
"duxiaoman.com": true,
"duxiaomanfintech.com": true,
"dxmpay.com": true,
"easytomessage.com": true,
"eckwai.com": true,
"ecukwai.com": true,
"effirst.com": true,
"etoote.com": true,
"fengkongcloud.com": true,
"fun.tv": true,
"funshion.com": true,
"funshion.net": true,
"gdtimg.com": true,
"geetest.com": true,
"gepush.com": true,
"getui.com": true,
"getui.net": true,
"gifshow.com": true,
"gotokeep.com": true,
"gridsumdissector.com": true,
"gtimg.com": true,
"hc-cdn.com": true,
"hdslb.com": true,
"hicloud.com": true,
"hitv.com": true,
"httpdns.pro": true,
"huanqiu.com": true,
"huaweicloud.com": true,
"hunantv.com": true,
"huoshan.com": true,
"huoshanlive.com": true,
"huoshanstatic.com": true,
"huoshanvod.com": true,
"id6.me": true,
"idqqimg.com": true,
"igexin.com": true,
"ihuoshanlive.com": true,
"imtmp.net": true,
"inkuai.com": true,
"ip6.arpa": true,
"ipaddr.host": true,
"ipv4only.arpa": true,
"iqiyi.com": true,
"iqiyipic.com": true,
"irs01.com": true,
"itoutiaostatic.com": true,
"ixigua.com": true,
"jd.com": true,
"jdcloud.com": true,
"jinhuahuolong.com": true,
"jomoxc.com": true,
"joying.com": true,
"jpush.io": true,
"keepcdn.com": true,
"ksapisrv.com": true,
"kskwai.com": true,
"ksord.com": true,
"ksosoft.com": true,
"kspkg.com": true,
"ksyun.com": true,
"ksyungslb.com": true,
"kuaishou.com": true,
"kuaishouzt.com": true,
"kuiniuca.com": true,
"kwai.com": true,
"kwaicdn.com": true,
"kwaizt.com": true,
"kwimgs.com": true,
"laiqukankan.com": true,
"le.com": true,
"letv.com": true,
"letvimg.com": true,
"leyingtt.com": true,
"lnk0.com": true,
"m1905.com": true,
"maoyan.com": true,
"meipai.com": true,
"meitu.com": true,
"meituan.com": true,
"meituan.net": true,
"meitudata.com": true,
"meitustat.com": true,
"meizu.com": true,
"mgtv.com": true,
"miaozhen.com": true,
"migucloud.com": true,
"miguvideo.com": true,
"mmstat.com": true,
"mob.com": true,
"myapp.com": true,
"myqcloud.com": true,
"myzhiniu.com": true,
"mzstatic.com": true,
"netease.com": true,
"netease.im": true,
"nintyinc.com": true,
"novelfm.com": true,
"novelfmstatic.com": true,
"onethingpcs.com": true,
"onewsvod.com": true,
"oskwai.com": true,
"pangolin-dsp-toutiao.com": true,
"pangolin-sdk-toutiao-b.com": true,
"pangolin-sdk-toutiao.com": true,
"pddpic.com": true,
"pddugc.com": true,
"pglstatp-toutiao.com": true,
"pinduoduo.com": true,
"pinduoduo.net": true,
"poizon.com": true,
"ppsimg.com": true,
"pstatp.com": true,
"qcloud.com": true,
"qingting.fm": true,
"qiniup.com": true,
"qiyi.com": true,
"qiyukf.com": true,
"qmail.com": true,
"qnqcdn.net": true,
"qq.com": true,
"qqmail.com": true,
"qy.net": true,
"rr.tv": true,
"sankuai.com": true,
"servicewechat.com": true,
"shuqireader.com": true,
"smtcdns.net": true,
"snssdk.com": true,
"sohu.com": true,
"sohucs.com": true,
"szbdyd.com": true,
"tamaegis.com": true,
"tanx.com": true,
"taobao.com": true,
"tdatamaster.com": true,
"tencent-cloud.com": true,
"tencent-cloud.net": true,
"tencent.com": true,
"tencentmusic.com": true,
"tenpay.com": true,
"tfogc.com": true,
"tingyun.com": true,
"tmall.com": true,
"toutiao.com": true,
"toutiaoapi.com": true,
"toutiaostatic.com": true,
"toutiaovod.com": true,
"tudou.com": true,
"tv002.com": true,
"ucweb.com": true,
"ugdtimg.com": true,
"ulikecam.com": true,
"umeng.com": true,
"umengcloud.com": true,
"umsns.com": true,
"unionpay.com": true,
"upqzfile.com": true,
"vemarsdev.com": true,
"vemarsstatic.com": true,
"vlabvod.com": true,
"volceapplog.com": true,
"volces.com": true,
"vzuu.com": true,
"wanzjhb.com": true,
"weibo.com": true,
"weibocdn.com": true,
"weiyun.com": true,
"wnsqzonebk.com": true,
"xhscdn.com": true,
"xiaodutv.com": true,
"xiaohongshu.com": true,
"xiaomi.com": true,
"xiaomi.net": true,
"ximalaya.com": true,
"xiuxiustatic.com": true,
"xmcdn.com": true,
"xxpkg.com": true,
"xycdn.com": true,
"yangkeduo.com": true,
"ykimg.com": true,
"youku.com": true,
"yqkk.link": true,
"yximgs.com": true,
"yy.com": true,
"yystatic.com": true,
"zhihu.com": true,
"zhimg.com": true,
"zhipin.com": true,
"zhuanzfx.com": true,
"zijieapi.com": true
}
r := f(m.domain, l)
if r != undefined {
return r
}
l = {
"ip138.com": true,
"ipchaxun.net": true,
// cname
"lxdns.com": true,
"wsglb0.com": true,
"wswebpic.com": true
}
r = f(m.domain, l)
if r != undefined {
return r
}
}
})

View File

@@ -1,5 +1,5 @@
// 大陆域名用 Bypass DNS 来解析 A 并直连, 注意与 bypass_china_domain.tengo 区分. 这是一个包含主流的精小样本.
// generated by: https://bash.ooo/china.js
// 大陆域名用 Bypass DNS 来解析 A 并直连
// 注意:这是一个包含主流的精小样本. 你可以自己生成自用的模块https://www.txthinking.com/talks/articles/china-list.article
// The script limits the stack size 2048. If your array or map exceeds max stack size, try splitting it into multiple. The memory occupied by a dictionary is approximately twice that of an array with same elements.
modules = append(modules, {
address: func(m) {

View File

@@ -1667,7 +1667,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -2334,17 +2334,18 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "display-info"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0d5fb296340ffc0419a6032d03a253b89aaa0c52ec5e4847da1f76ad2412fe3"
checksum = "1bae989b257338ef815f8a807d35836d94d790bc273549b303d8feee7ce2e9c9"
dependencies = [
"anyhow",
"core-graphics 0.23.2",
"core-graphics 0.24.0",
"fxhash",
"log",
"scopeguard",
"smithay-client-toolkit 0.18.1",
"thiserror 2.0.11",
"widestring 1.1.0",
"windows 0.56.0",
"windows 0.59.0",
"xcb",
]
@@ -4712,7 +4713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.52.6",
]
[[package]]
@@ -5957,9 +5958,9 @@ dependencies = [
[[package]]
name = "oxc_allocator"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f5b38027b943889e914774968782a2b67df6ba50f6d4e265eaa7a933a8e3075"
checksum = "41fdbb3186e88af51e863d150f8f3b96c96b9d9e5bc02030f14b66be2814f32f"
dependencies = [
"allocator-api2",
"bumpalo",
@@ -5970,9 +5971,9 @@ dependencies = [
[[package]]
name = "oxc_ast"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb78951e98af99dfdac1e530f5a36af114d9d8a03e967b5ea68be271509183da"
checksum = "a5297b74b56d814f7bd92bb06b77b9e7022790b14e943553e53867bd735b917d"
dependencies = [
"bitflags 2.6.0",
"cow-utils",
@@ -5988,9 +5989,9 @@ dependencies = [
[[package]]
name = "oxc_ast_macros"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f17b1dc89732a6969c6dcb274035c737db46fe1f378ce86fb6c4674db201f5ca"
checksum = "ebd4278ab760c1c3341914f18bef52e03e6ccc1decb26162f096d2eb5cfb82ec"
dependencies = [
"proc-macro2",
"quote",
@@ -5999,18 +6000,18 @@ dependencies = [
[[package]]
name = "oxc_diagnostics"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5f7392025441f29ae145b21bc0e656530f2443fb197195b6ba39ac0d613b8b"
checksum = "11eed5a9db1823b1b0e30a03e11f614271a191fb440298e6fb39ed206927109e"
dependencies = [
"oxc-miette",
]
[[package]]
name = "oxc_ecmascript"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5993579c5c04491bfcfc9a675c9939caa9f8f5faceecc5e4d281c432bbfd4c6e"
checksum = "47529b18e85f7daea78fcba566e0e29ab172d95134f1f992980e2f82ec781a45"
dependencies = [
"num-bigint",
"num-traits",
@@ -6021,9 +6022,9 @@ dependencies = [
[[package]]
name = "oxc_estree"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b216e48759b14e08652c925aa024f6b2d318a795793bbe51482718829ac9bc4"
checksum = "96c551c306b1cd5bf0dfa5fc317c8fe446c0f9483be83c925d7549545cdb64cf"
[[package]]
name = "oxc_index"
@@ -6033,9 +6034,9 @@ checksum = "5eca5d9726cd0a6e433debe003b7bc88b2ecad0bb6109f0cef7c55e692139a34"
[[package]]
name = "oxc_parser"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08e83d2a08991efc1a79c3b42fcc77344f3de58d27c53cd9b184d17b1ed4ace3"
checksum = "1460e8763b17ae35534ff791a56a6c3410601ae9e23dd3495b0ea7053787d2d0"
dependencies = [
"assert-unchecked",
"bitflags 2.6.0",
@@ -6056,9 +6057,9 @@ dependencies = [
[[package]]
name = "oxc_regular_expression"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d495804e1bf588e5e1a2d6fe760ff1ba53ece5cbf04e4dce531da64014869fea"
checksum = "7c98aff8db7094d7f5e30e0dcbd5b57d031470c13e0526768feb2380a4877e84"
dependencies = [
"oxc_allocator",
"oxc_ast_macros",
@@ -6072,9 +6073,9 @@ dependencies = [
[[package]]
name = "oxc_span"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a50160bfd66b0ef0acff1181c6860c61cf59d6c0d5bf05b589f1fc6dcdbafc2"
checksum = "19ac361139f6df3b4ce7ca0a6876a2a898d5744f5b5c92f3232d78e2f9cd9364"
dependencies = [
"compact_str",
"oxc-miette",
@@ -6085,9 +6086,9 @@ dependencies = [
[[package]]
name = "oxc_syntax"
version = "0.47.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aa0a2543f375feb387b0b94a6d72ec5b0cc6a2349518d48704189b23d6c4070"
checksum = "00abdcf60bd01719cb94832ca3de3247962472676141def7bffaafaa4736e9af"
dependencies = [
"assert-unchecked",
"bitflags 2.6.0",
@@ -10458,7 +10459,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]

View File

@@ -149,11 +149,11 @@ display-info = "0.5.0" # should be removed after upgrading to tauri v2
# OXC (The Oxidation Compiler)
# We use it to parse and transpile the old script profile to esm based script profile
oxc_parser = "0.47"
oxc_allocator = "0.47"
oxc_span = "0.47"
oxc_ast = "0.47"
oxc_syntax = "0.47"
oxc_parser = "0.48"
oxc_allocator = "0.48"
oxc_span = "0.48"
oxc_ast = "0.48"
oxc_syntax = "0.48"
# Lua Integration
mlua = { version = "0.10", features = [

View File

@@ -55,9 +55,9 @@
"@iconify/json": "2.2.299",
"@monaco-editor/react": "4.6.0",
"@tanstack/react-query": "5.64.2",
"@tanstack/react-router": "1.97.14",
"@tanstack/router-devtools": "1.97.14",
"@tanstack/router-plugin": "1.97.14",
"@tanstack/react-router": "1.97.17",
"@tanstack/router-devtools": "1.97.17",
"@tanstack/router-plugin": "1.97.17",
"@tauri-apps/plugin-clipboard-manager": "2.2.0",
"@tauri-apps/plugin-dialog": "2.2.0",
"@tauri-apps/plugin-fs": "2.2.0",

View File

@@ -71,7 +71,7 @@
"conventional-changelog-conventionalcommits": "8.0.0",
"cross-env": "7.0.3",
"dedent": "1.5.3",
"eslint": "9.18.0",
"eslint": "9.19.0",
"eslint-config-prettier": "9.1.0",
"eslint-config-standard": "17.1.0",
"eslint-import-resolver-alias": "1.1.2",

View File

@@ -26,7 +26,7 @@ importers:
version: 19.6.0
'@eslint/compat':
specifier: 1.2.5
version: 1.2.5(eslint@9.18.0(jiti@2.4.2))
version: 1.2.5(eslint@9.19.0(jiti@2.4.2))
'@ianvs/prettier-plugin-sort-imports':
specifier: 4.4.1
version: 4.4.1(prettier@3.4.2)
@@ -44,10 +44,10 @@ importers:
version: 22.10.10
'@typescript-eslint/eslint-plugin':
specifier: 8.21.0
version: 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
version: 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/parser':
specifier: 8.21.0
version: 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
version: 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
autoprefixer:
specifier: 10.4.20
version: 10.4.20(postcss@8.5.1)
@@ -61,41 +61,41 @@ importers:
specifier: 1.5.3
version: 1.5.3(babel-plugin-macros@3.1.0)
eslint:
specifier: 9.18.0
version: 9.18.0(jiti@2.4.2)
specifier: 9.19.0
version: 9.19.0(jiti@2.4.2)
eslint-config-prettier:
specifier: 9.1.0
version: 9.1.0(eslint@9.18.0(jiti@2.4.2))
version: 9.1.0(eslint@9.19.0(jiti@2.4.2))
eslint-config-standard:
specifier: 17.1.0
version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint-plugin-n@17.15.1(eslint@9.18.0(jiti@2.4.2)))(eslint-plugin-promise@7.2.1(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))
version: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint-plugin-n@17.15.1(eslint@9.19.0(jiti@2.4.2)))(eslint-plugin-promise@7.2.1(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))
eslint-import-resolver-alias:
specifier: 1.1.2
version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))
version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))
eslint-plugin-html:
specifier: 8.1.2
version: 8.1.2
eslint-plugin-import:
specifier: 2.31.0
version: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))
version: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-n:
specifier: 17.15.1
version: 17.15.1(eslint@9.18.0(jiti@2.4.2))
version: 17.15.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-prettier:
specifier: 5.2.3
version: 5.2.3(eslint-config-prettier@9.1.0(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))(prettier@3.4.2)
version: 5.2.3(eslint-config-prettier@9.1.0(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))(prettier@3.4.2)
eslint-plugin-promise:
specifier: 7.2.1
version: 7.2.1(eslint@9.18.0(jiti@2.4.2))
version: 7.2.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-react:
specifier: 7.37.4
version: 7.37.4(eslint@9.18.0(jiti@2.4.2))
version: 7.37.4(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-react-compiler:
specifier: 19.0.0-beta-e552027-20250112
version: 19.0.0-beta-e552027-20250112(eslint@9.18.0(jiti@2.4.2))
version: 19.0.0-beta-e552027-20250112(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-react-hooks:
specifier: 5.1.0
version: 5.1.0(eslint@9.18.0(jiti@2.4.2))
version: 5.1.0(eslint@9.19.0(jiti@2.4.2))
globals:
specifier: 15.14.0
version: 15.14.0
@@ -107,7 +107,7 @@ importers:
version: 15.4.2
neostandard:
specifier: 0.12.0
version: 0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
version: 0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
npm-run-all2:
specifier: 7.0.2
version: 7.0.2
@@ -167,7 +167,7 @@ importers:
version: 5.7.3
typescript-eslint:
specifier: 8.21.0
version: 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
version: 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
frontend/interface:
dependencies:
@@ -228,7 +228,7 @@ importers:
version: link:../ui
'@tanstack/router-zod-adapter':
specifier: 1.81.5
version: 1.81.5(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.1)
version: 1.81.5(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.1)
'@tauri-apps/api':
specifier: 2.2.0
version: 2.2.0
@@ -324,14 +324,14 @@ importers:
specifier: 5.64.2
version: 5.64.2(react@19.0.0)
'@tanstack/react-router':
specifier: 1.97.14
version: 1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: 1.97.17
version: 1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-devtools':
specifier: 1.97.14
version: 1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: 1.97.17
version: 1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-plugin':
specifier: 1.97.14
version: 1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.0)(sass-embedded@1.83.4)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.7.0))
specifier: 1.97.17
version: 1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.0)(sass-embedded@1.83.4)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.7.0))
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.2.0
version: 2.2.0
@@ -1683,8 +1683,8 @@ packages:
resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.18.0':
resolution: {integrity: sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==}
'@eslint/js@9.19.0':
resolution: {integrity: sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.5':
@@ -2741,8 +2741,8 @@ packages:
peerDependencies:
react: ^18 || ^19
'@tanstack/react-router@1.97.14':
resolution: {integrity: sha512-FQi/Mg8dmpPeLH0Tu7mwoIHhea2WY9DAp5retATxf++y1nv8H6eL0P11RMpL/fMDpr8eoX4OHNY59Zph74q1bA==}
'@tanstack/react-router@1.97.17':
resolution: {integrity: sha512-xcEWyA16k9vnzc8f2djXN2HtoKEEUTL9yu4JB93wXwW+Ni9+wIXPWZoS+Q6TSjVsvpZHwt+jN1i7BndOhPx/4w==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18'
@@ -2767,25 +2767,25 @@ 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-devtools@1.97.14':
resolution: {integrity: sha512-dU1kvvq3ClnU7lz6Kc5PQAK6gIbdYkcihKNaCh4f/8K0RT+8C80ySeq4f+uRED+YLv+IFHdSMQYjOoFh48Q/4w==}
'@tanstack/router-devtools@1.97.17':
resolution: {integrity: sha512-2CQsy9Ry4Bx4cL+fN/DCQQgy2NFXlUFHvgUvdwuO1KHyO2VsBlqCTs7JUyxMAgPVISK68KE4LanVFZbLLBYIFQ==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.97.14
'@tanstack/react-router': ^1.97.17
react: '>=18'
react-dom: '>=18'
'@tanstack/router-generator@1.97.14':
resolution: {integrity: sha512-hNICcT3AsNYJT4bwppwgQTB8pFY5Mvob69TDyDLI28rRg95BtP2gPUzistFGdAxpyQXg+AVNnehpemgdon+FMQ==}
'@tanstack/router-generator@1.97.17':
resolution: {integrity: sha512-NyJA2wfWn1FohyA1dvQzlyOxVGyq4pbxxxtn1RLqn4BzuUkbYsIN9wYu3ZYbt3aQOn6MKuK++BMICA8m+0I2uw==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.97.14
'@tanstack/react-router': ^1.97.17
peerDependenciesMeta:
'@tanstack/react-router':
optional: true
'@tanstack/router-plugin@1.97.14':
resolution: {integrity: sha512-ZcX6xNJcvfbd5pr9yYfG8LKGY6f8xoiwPOx4O1aVUeBAV3EUOmrpcGwd0jLM5QmrT7YuEUe29O0IRVrP8ABG3g==}
'@tanstack/router-plugin@1.97.17':
resolution: {integrity: sha512-yc4SFQJmRDYa8QNIhYvuTBbfA+EUn/UtU5ufXWZSDQ8eHhREgYQ363DusrVlKqMxi0JNyyxt0vxPVhB9LBUnoA==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
@@ -4610,8 +4610,8 @@ packages:
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.18.0:
resolution: {integrity: sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==}
eslint@9.19.0:
resolution: {integrity: sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
peerDependencies:
@@ -4769,9 +4769,6 @@ packages:
flat-cache@6.1.5:
resolution: {integrity: sha512-QR+2kN38f8nMfiIQ1LHYjuDEmZNZVjxuxY+HufbS3BW0EX01Q5OnH7iduOYRutmgiXb797HAKcXUeXrvRjjgSQ==}
flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
flatted@3.3.2:
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
@@ -9428,16 +9425,16 @@ snapshots:
'@esbuild/win32-x64@0.24.2':
optional: true
'@eslint-community/eslint-utils@4.4.1(eslint@9.18.0(jiti@2.4.2))':
'@eslint-community/eslint-utils@4.4.1(eslint@9.19.0(jiti@2.4.2))':
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
'@eslint/compat@1.2.5(eslint@9.18.0(jiti@2.4.2))':
'@eslint/compat@1.2.5(eslint@9.19.0(jiti@2.4.2))':
optionalDependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
'@eslint/config-array@0.19.1':
dependencies:
@@ -9465,7 +9462,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@eslint/js@9.18.0': {}
'@eslint/js@9.19.0': {}
'@eslint/object-schema@2.1.5': {}
@@ -10348,10 +10345,10 @@ snapshots:
ignore: 5.3.2
p-map: 4.0.0
'@stylistic/eslint-plugin@2.11.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@stylistic/eslint-plugin@2.11.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/utils': 8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
'@typescript-eslint/utils': 8.20.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.2)
eslint-visitor-keys: 4.2.0
espree: 10.3.0
estraverse: 5.3.0
@@ -10499,7 +10496,7 @@ snapshots:
'@tanstack/query-core': 5.64.2
react: 19.0.0
'@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@tanstack/history': 1.97.8
'@tanstack/react-store': 0.7.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -10528,9 +10525,9 @@ snapshots:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
'@tanstack/router-devtools@1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@tanstack/router-devtools@1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(csstype@3.1.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@tanstack/react-router': 1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
react: 19.0.0
@@ -10538,16 +10535,16 @@ snapshots:
transitivePeerDependencies:
- csstype
'@tanstack/router-generator@1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))':
'@tanstack/router-generator@1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))':
dependencies:
'@tanstack/virtual-file-routes': 1.97.8
prettier: 3.4.2
tsx: 4.19.2
zod: 3.24.1
optionalDependencies:
'@tanstack/react-router': 1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/router-plugin@1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.0)(sass-embedded@1.83.4)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.7.0))':
'@tanstack/router-plugin@1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(vite@6.0.11(@types/node@22.10.10)(jiti@2.4.2)(less@4.2.0)(sass-embedded@1.83.4)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.2)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.0
'@babel/generator': 7.26.3
@@ -10557,7 +10554,7 @@ snapshots:
'@babel/template': 7.25.9
'@babel/traverse': 7.26.4
'@babel/types': 7.26.3
'@tanstack/router-generator': 1.97.14(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@tanstack/router-generator': 1.97.17(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
'@tanstack/virtual-file-routes': 1.97.8
'@types/babel__core': 7.20.5
'@types/babel__generator': 7.6.8
@@ -10576,9 +10573,9 @@ snapshots:
- '@tanstack/react-router'
- supports-color
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.1)':
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(zod@3.24.1)':
dependencies:
'@tanstack/react-router': 1.97.14(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@tanstack/react-router': 1.97.17(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
zod: 3.24.1
'@tanstack/store@0.7.0': {}
@@ -10948,15 +10945,15 @@ snapshots:
'@types/node': 22.10.10
optional: true
'@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/type-utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/type-utils': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.21.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
@@ -10965,14 +10962,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.21.0
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
@@ -10987,12 +10984,12 @@ snapshots:
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/visitor-keys': 8.21.0
'@typescript-eslint/type-utils@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@typescript-eslint/type-utils@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
ts-api-utils: 2.0.0(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies:
@@ -11030,24 +11027,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@typescript-eslint/utils@8.20.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
'@typescript-eslint/scope-manager': 8.20.0
'@typescript-eslint/types': 8.20.0
'@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)':
'@typescript-eslint/utils@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
@@ -12549,25 +12546,25 @@ snapshots:
escape-string-regexp@5.0.0: {}
eslint-compat-utils@0.5.1(eslint@9.18.0(jiti@2.4.2)):
eslint-compat-utils@0.5.1(eslint@9.19.0(jiti@2.4.2)):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
semver: 7.6.3
eslint-config-prettier@9.1.0(eslint@9.18.0(jiti@2.4.2)):
eslint-config-prettier@9.1.0(eslint@9.19.0(jiti@2.4.2)):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint-plugin-n@17.15.1(eslint@9.18.0(jiti@2.4.2)))(eslint-plugin-promise@7.2.1(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2)):
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint-plugin-n@17.15.1(eslint@9.19.0(jiti@2.4.2)))(eslint-plugin-promise@7.2.1(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-n: 17.15.1(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-promise: 7.2.1(eslint@9.18.0(jiti@2.4.2))
eslint: 9.19.0(jiti@2.4.2)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-n: 17.15.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-promise: 7.2.1(eslint@9.19.0(jiti@2.4.2))
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))):
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))):
dependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))
eslint-import-resolver-node@0.3.9:
dependencies:
@@ -12577,51 +12574,51 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2)):
eslint-import-resolver-typescript@3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.0
enhanced-resolve: 5.18.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
fast-glob: 3.3.3
get-tsconfig: 4.8.1
is-bun-module: 1.3.0
is-glob: 4.0.3
stable-hash: 0.0.4
optionalDependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-import-x: 4.5.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-import-x: 4.5.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.18.0(jiti@2.4.2)):
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.19.0(jiti@2.4.2)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
'@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
eslint-plugin-es-x@7.8.0(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-es-x@7.8.0(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
'@eslint-community/regexpp': 4.12.1
eslint: 9.18.0(jiti@2.4.2)
eslint-compat-utils: 0.5.1(eslint@9.18.0(jiti@2.4.2))
eslint: 9.19.0(jiti@2.4.2)
eslint-compat-utils: 0.5.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-html@8.1.2:
dependencies:
htmlparser2: 9.1.0
eslint-plugin-import-x@4.5.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3):
eslint-plugin-import-x@4.5.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3):
dependencies:
'@typescript-eslint/scope-manager': 8.20.0
'@typescript-eslint/utils': 8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.20.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
debug: 4.4.0
doctrine: 3.0.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
get-tsconfig: 4.8.1
is-glob: 4.0.3
@@ -12633,7 +12630,7 @@ snapshots:
- supports-color
- typescript
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -12642,9 +12639,9 @@ snapshots:
array.prototype.flatmap: 1.3.2
debug: 3.2.7
doctrine: 2.1.0
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.18.0(jiti@2.4.2))
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.19.0(jiti@2.4.2))
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -12656,55 +12653,55 @@ snapshots:
string.prototype.trimend: 1.0.8
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
eslint-plugin-n@17.15.1(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-n@17.15.1(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
enhanced-resolve: 5.17.1
eslint: 9.18.0(jiti@2.4.2)
eslint-plugin-es-x: 7.8.0(eslint@9.18.0(jiti@2.4.2))
eslint: 9.19.0(jiti@2.4.2)
eslint-plugin-es-x: 7.8.0(eslint@9.19.0(jiti@2.4.2))
get-tsconfig: 4.8.1
globals: 15.14.0
ignore: 5.3.2
minimatch: 9.0.5
semver: 7.6.3
eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))(prettier@3.4.2):
eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))(prettier@3.4.2):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
prettier: 3.4.2
prettier-linter-helpers: 1.0.0
synckit: 0.9.1
optionalDependencies:
eslint-config-prettier: 9.1.0(eslint@9.18.0(jiti@2.4.2))
eslint-config-prettier: 9.1.0(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-promise@7.2.1(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-promise@7.2.1(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
eslint: 9.18.0(jiti@2.4.2)
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
eslint: 9.19.0(jiti@2.4.2)
eslint-plugin-react-compiler@19.0.0-beta-e552027-20250112(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-react-compiler@19.0.0-beta-e552027-20250112(eslint@9.19.0(jiti@2.4.2)):
dependencies:
'@babel/core': 7.26.0
'@babel/parser': 7.26.3
'@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.0)
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
hermes-parser: 0.25.1
zod: 3.24.1
zod-validation-error: 3.3.1(zod@3.24.1)
transitivePeerDependencies:
- supports-color
eslint-plugin-react-hooks@5.1.0(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-react-hooks@5.1.0(eslint@9.19.0(jiti@2.4.2)):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
eslint-plugin-react@7.37.4(eslint@9.18.0(jiti@2.4.2)):
eslint-plugin-react@7.37.4(eslint@9.19.0(jiti@2.4.2)):
dependencies:
array-includes: 3.1.8
array.prototype.findlast: 1.2.5
@@ -12712,7 +12709,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.2.1
eslint: 9.18.0(jiti@2.4.2)
eslint: 9.19.0(jiti@2.4.2)
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
@@ -12735,14 +12732,14 @@ snapshots:
eslint-visitor-keys@4.2.0: {}
eslint@9.18.0(jiti@2.4.2):
eslint@9.19.0(jiti@2.4.2):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
'@eslint-community/regexpp': 4.12.1
'@eslint/config-array': 0.19.1
'@eslint/core': 0.10.0
'@eslint/eslintrc': 3.2.0
'@eslint/js': 9.18.0
'@eslint/js': 9.19.0
'@eslint/plugin-kit': 0.2.5
'@humanfs/node': 0.16.6
'@humanwhocodes/module-importer': 1.0.1
@@ -12948,7 +12945,7 @@ snapshots:
flat-cache@4.0.1:
dependencies:
flatted: 3.3.1
flatted: 3.3.2
keyv: 4.5.4
flat-cache@6.1.5:
@@ -12957,8 +12954,6 @@ snapshots:
flatted: 3.3.2
hookified: 1.6.0
flatted@3.3.1: {}
flatted@3.3.2: {}
for-each@0.3.3:
@@ -14387,20 +14382,20 @@ snapshots:
sax: 1.3.0
optional: true
neostandard@0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3):
neostandard@0.12.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3):
dependencies:
'@humanwhocodes/gitignore-to-minimatch': 1.0.2
'@stylistic/eslint-plugin': 2.11.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-import-x: 4.5.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint-plugin-n: 17.15.1(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-promise: 7.2.1(eslint@9.18.0(jiti@2.4.2))
eslint-plugin-react: 7.37.4(eslint@9.18.0(jiti@2.4.2))
'@stylistic/eslint-plugin': 2.11.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.2)
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import-x@4.5.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-import-x: 4.5.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
eslint-plugin-n: 17.15.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-promise: 7.2.1(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-react: 7.37.4(eslint@9.19.0(jiti@2.4.2))
find-up: 5.0.0
globals: 15.14.0
peowly: 1.3.2
typescript-eslint: 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
typescript-eslint: 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
transitivePeerDependencies:
- eslint-plugin-import
- supports-color
@@ -16176,12 +16171,12 @@ snapshots:
dependencies:
is-typedarray: 1.0.0
typescript-eslint@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3):
typescript-eslint@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.2)
'@typescript-eslint/eslint-plugin': 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/parser': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.2)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color

View File

@@ -11,6 +11,7 @@ PKG_NAME:=autocore
PKG_RELEASE:=$(COMMITCOUNT)
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/target.mk
define Package/autocore-arm
TITLE:=Arm auto core loadbalance script.
@@ -49,7 +50,9 @@ define Package/autocore-arm/install
$(INSTALL_BIN) ./files/arm/sbin/cpuinfo $(1)/sbin/cpuinfo
$(INSTALL_BIN) ./files/arm/sbin/ethinfo $(1)/sbin/ethinfo
$(INSTALL_BIN) ./files/arm/sbin/usage $(1)/sbin/usage
ifneq ($(filter ipq% %filogic qualcommax%, $(TARGETID)),)
$(INSTALL_BIN) ./files/arm/sbin/tempinfo $(1)/sbin/tempinfo
endif
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(CP) ./files/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/
endef

View File

@@ -17,6 +17,9 @@ rm -f /usr/lib/lua/luci/view/admin_status/index/upnp.htm
rm -f /usr/lib/lua/luci/view/admin_status/index/ddns.htm
rm -f /usr/lib/lua/luci/view/admin_status/index/minidlna.htm
rm -f /www/luci-static/resources/view/status/include/70_ddns.js
rm -f /www/luci-static/resources/view/status/include/80_upnp.js
sed -i 's/\"services\"/\"nas\"/g' /usr/lib/lua/luci/controller/aria2.lua
sed -i 's/services/nas/g' /usr/lib/lua/luci/view/aria2/overview_status.htm
sed -i 's/\"services\"/\"nas\"/g' /usr/lib/lua/luci/controller/hd_idle.lua

View File

@@ -16,7 +16,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-amlogic
PKG_VERSION:=3.1.248
PKG_VERSION:=3.1.249
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0 License

View File

@@ -31,7 +31,7 @@ mydevice.rmempty = false
--2.Set OpenWrt Firmware Repository
firmware_repo = o:option(Value, "amlogic_firmware_repo", translate("Download repository of OpenWrt:"))
firmware_repo.description = translate("Set the download repository of the OpenWrt files on github.com in [Online Download Update].")
firmware_repo.default = "https://github.com/breakings/OpenWrt"
firmware_repo.default = "https://github.com/breakingbadboy/OpenWrt"
firmware_repo.rmempty = false
--3.Set OpenWrt Releases's Tag Keywords
@@ -53,9 +53,9 @@ firmware_suffix.rmempty = false
--5.Set OpenWrt Kernel DownLoad Path
kernel_path = o:option(Value, "amlogic_kernel_path", translate("Download path of OpenWrt kernel:"))
kernel_path.description = translate("Set the download path of the kernel in the github.com repository in [Online Download Update].")
kernel_path:value("https://github.com/breakings/OpenWrt")
kernel_path:value("https://github.com/breakingbadboy/OpenWrt")
kernel_path:value("https://github.com/ophub/kernel")
kernel_path.default = "https://github.com/breakings/OpenWrt"
kernel_path.default = "https://github.com/breakingbadboy/OpenWrt"
kernel_path.rmempty = false
--6.Set kernel version branch

View File

@@ -29,9 +29,19 @@ table td, .table .td {
color: red !important;
}
._now_use_bg {
background: #5e72e445 !important;
}
.ping a:hover{
text-decoration : underline;
}
@media (prefers-color-scheme: dark) {
._now_use_bg {
background: #4a90e2 !important;
}
}
</style>
<script type="text/javascript">
@@ -212,6 +222,7 @@ table td, .table .td {
var dom = document.getElementById("cbi-passwall-" + id);
if (dom) {
dom.title = "当前使用的 TCP 节点";
dom.classList.add("_now_use_bg");
//var v = "<a style='color: red'>当前TCP节点</a>" + document.getElementById("cbid.passwall." + id + ".remarks").value;
//document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v;
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
@@ -229,6 +240,7 @@ table td, .table .td {
} else {
dom.title = "当前使用的 UDP 节点";
}
dom.classList.add("_now_use_bg");
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
if (dom_remarks) {
dom_remarks.classList.add("_now_use");

View File

@@ -29,9 +29,19 @@ table td, .table .td {
color: red !important;
}
._now_use_bg {
background: #5e72e445 !important;
}
.ping a:hover{
text-decoration : underline;
}
@media (prefers-color-scheme: dark) {
._now_use_bg {
background: #4a90e2 !important;
}
}
</style>
<script type="text/javascript">
@@ -212,6 +222,7 @@ table td, .table .td {
var dom = document.getElementById("cbi-passwall-" + id);
if (dom) {
dom.title = "当前使用的 TCP 节点";
dom.classList.add("_now_use_bg");
//var v = "<a style='color: red'>当前TCP节点</a>" + document.getElementById("cbid.passwall." + id + ".remarks").value;
//document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v;
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
@@ -229,6 +240,7 @@ table td, .table .td {
} else {
dom.title = "当前使用的 UDP 节点";
}
dom.classList.add("_now_use_bg");
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
if (dom_remarks) {
dom_remarks.classList.add("_now_use");

View File

@@ -1,5 +1,5 @@
# v2rayN
A GUI client for Windows, Linux and macOS, support [Xray core](https://github.com/XTLS/Xray-core) and [sing-box-core](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core) and [sing-box](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)
@@ -9,26 +9,8 @@ A GUI client for Windows, Linux and macOS, support [Xray core](https://github.co
## How to use
Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-files-introduction) and select the version you need to download
### Windows
- Run `v2rayN.exe`
### Linux
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
```
Debian 9+
Ubuntu 16.04+
Fedora 30+
```
### macOS
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
```
macOS 11+
```
## Requirements
- [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
## Telegram Channel
[github_2dust](https://t.me/github_2dust)

View File

@@ -7,6 +7,7 @@
xmlns:semi="https://irihi.tech/semi"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
x:DataType="vms:StatusBarViewModel"
Name="v2rayN"
RequestedThemeVariant="Default">
<Application.Styles>
<semi:SemiTheme />

View File

@@ -12,8 +12,8 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 628
versionName = "1.9.32"
versionCode = 629
versionName = "1.9.33"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')

View File

@@ -120,8 +120,8 @@
<string name="server_lab_port_hop">پورت گوم (درگا سرورن ز نۊ هؽل اکونه)</string>
<string name="server_lab_port_hop_interval">فاسله پورت گوم (سانیه)</string>
<string name="server_lab_stream_pinsha256">pinSHA256</string>
<string name="server_lab_bandwidth_down">Bandwidth down (units)</string>
<string name="server_lab_bandwidth_up">Bandwidth up (units)</string>
<string name="server_lab_bandwidth_down">ب لم ٱووڌن پئنا باند (واهڌ)</string>
<string name="server_lab_bandwidth_up">وا روء رئڌن پئنا باند (واهڌ)</string>
<string name="server_lab_xhttp_mode">هالت XHTTP</string>
<string name="server_lab_xhttp_extra">XHTTP Extra خام JSON، قالوو: { XHTTPObject }</string>
@@ -191,11 +191,11 @@
<string name="summary_pref_delay_test_url">نشۊوی اینترنتی</string>
<string name="title_pref_proxy_sharing_enabled">هشتن منپیزا ز شبکه مهلی</string>
<string name="summary_pref_proxy_sharing_enabled">پوی دسگایل ترن وا آدرس IP ایسا، ز ر socks/http و پروکسی منپیز بۊن، تینا من شبکه قابل اعتماد فعال بۊ تا ز منپیز ؛یر موجاز جلو گری بۊ.</string>
<string name="summary_pref_proxy_sharing_enabled">پوی دسگایل ترن وا آدرس IP ایسا، ز ر socks/http و پروکسی منپیز بۊن، تینا من شبکه قابل اعتماد فعال بۊ تا ز منپیز غیر موجاز جلو گری بۊ.</string>
<string name="toast_warning_pref_proxysharing_short">منپیزا ز شبکه مهلی ن موجار کۊنین، موتمعن بۊین ک من ی شبکه قابل ائتماڌ هڌین.</string>
<string name="title_pref_allow_insecure">اجازه نا ٱمن</string>
<string name="summary_pref_allow_insecure">مجال و کار بردن TLS ب تۉر پؽش فرز، موجوز نا ٱمن فعال هڌ.</string>
<string name="summary_pref_allow_insecure">مجال و کار بوردن TLS ب تۉر پؽش فرز، موجوز نا ٱمن فعال هڌ.</string>
<string name="title_pref_socks_port">پورت پروکسی مهلی</string>
<string name="summary_pref_socks_port">پورت پروکسی مهلی</string>
@@ -348,4 +348,4 @@
<item>دور زیڌه نبۊ</item>
</string-array>
</resources>
</resources>

View File

@@ -7,7 +7,7 @@
<string name="navigation_drawer_close">Закрыть панель навигации</string>
<string name="migration_success">Успешный перенос данных!</string>
<string name="migration_fail">Перенос данных не выполнен!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<string name="pull_down_to_refresh">Потяните вниз для обновления!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Остановить</string>
@@ -119,8 +119,8 @@
<string name="server_lab_port_hop">Смена портов (переопределяет порт)</string>
<string name="server_lab_port_hop_interval">Интервал смены портов</string>
<string name="server_lab_stream_pinsha256">pinSHA256</string>
<string name="server_lab_bandwidth_down">Bandwidth down (units)</string>
<string name="server_lab_bandwidth_up">Bandwidth up (units)</string>
<string name="server_lab_bandwidth_down">Входящая пропускная способность (единицы)</string>
<string name="server_lab_bandwidth_up">Исходящая пропускная способность (единицы)</string>
<string name="server_lab_xhttp_mode">Режим XHTTP</string>
<string name="server_lab_xhttp_extra">Необработанный JSON XHTTP Extra, формат: { XHTTPObject }</string>

View File

@@ -1,5 +1,5 @@
[versions]
agp = "8.7.3"
agp = "8.8.0"
desugar_jdk_libs = "2.1.4"
gradleLicensePlugin = "0.9.8"
kotlin = "2.1.0"
@@ -9,12 +9,12 @@ junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
material = "1.12.0"
activity = "1.9.3"
activity = "1.10.0"
constraintlayout = "2.2.0"
mmkvStatic = "1.3.11"
gson = "2.11.0"
quickieFoss = "1.13.1"
rxjava = "3.1.9"
rxjava = "3.1.10"
rxandroid = "3.0.2"
rxpermissions = "0.12"
swiperefreshlayout = "1.1.0"
@@ -27,7 +27,7 @@ multidex = "2.0.1"
mockitoMockitoInline = "4.0.0"
flexbox = "3.0.0"
preferenceKtx = "1.2.1"
recyclerview = "1.3.2"
recyclerview = "1.4.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" }
@@ -66,4 +66,3 @@ preference-ktx = { module = "androidx.preference:preference-ktx", version.ref =
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }

View File

@@ -1,6 +1,6 @@
#Thu Nov 14 12:42:51 BDT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -44,9 +44,11 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
switch {
case strings.EqualFold(u.String(), "localhost"):
return NewLocalNameServer(queryStrategy), nil
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
return NewDoHNameServer(u, dispatcher, queryStrategy)
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
case strings.EqualFold(u.Scheme, "https"): // DNS-over-HTTPS Remote mode
return NewDoHNameServer(u, dispatcher, queryStrategy, false)
case strings.EqualFold(u.Scheme, "h2c"): // DNS-over-HTTPS h2c Remote mode
return NewDoHNameServer(u, dispatcher, queryStrategy, true)
case strings.EqualFold(u.Scheme, "https+local"): // DNS-over-HTTPS Local mode
return NewDoHLocalNameServer(u, queryStrategy), nil
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
return NewQUICNameServer(u, queryStrategy)

View File

@@ -3,6 +3,7 @@ package dns
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"net/http"
@@ -23,6 +24,7 @@ import (
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet"
"golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http2"
)
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
@@ -41,49 +43,59 @@ type DoHNameServer struct {
}
// NewDoHNameServer creates DOH server object for remote resolving.
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
errors.LogInfo(context.Background(), "DNS: created Remote DOH client for ", url.String())
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy, h2c bool) (*DoHNameServer, error) {
url.Scheme = "https"
errors.LogInfo(context.Background(), "DNS: created Remote DNS-over-HTTPS client for ", url.String(), ", with h2c ", h2c)
s := baseDOHNameServer(url, "DOH", queryStrategy)
s.dispatcher = dispatcher
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := s.dispatcher.Dispatch(toDnsContext(ctx, s.dohURL), dest)
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := s.dispatcher.Dispatch(toDnsContext(ctx, s.dohURL), dest)
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
if err != nil {
return nil, err
}
}
if err != nil {
return nil, err
}
cc := common.ChainedClosable{}
if cw, ok := link.Writer.(common.Closable); ok {
cc = append(cc, cw)
}
if cr, ok := link.Reader.(common.Closable); ok {
cc = append(cc, cr)
}
return cnc.NewConnection(
cnc.ConnectionInputMulti(link.Writer),
cnc.ConnectionOutputMulti(link.Reader),
cnc.ConnectionOnClose(cc),
), nil
cc := common.ChainedClosable{}
if cw, ok := link.Writer.(common.Closable); ok {
cc = append(cc, cw)
}
if cr, ok := link.Reader.(common.Closable); ok {
cc = append(cc, cr)
}
return cnc.NewConnection(
cnc.ConnectionInputMulti(link.Writer),
cnc.ConnectionOutputMulti(link.Reader),
cnc.ConnectionOnClose(cc),
), nil
}
s.httpClient = &http.Client{
Timeout: time.Second * 180,
Transport: &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: dialContext,
},
}
s.httpClient = &http.Client{
Timeout: time.Second * 180,
Transport: tr,
if h2c {
s.httpClient.Transport = &http2.Transport{
IdleConnTimeout: 90 * time.Second,
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
return dialContext(ctx, network, addr)
},
}
}
return s, nil
@@ -118,7 +130,7 @@ func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameSe
Timeout: time.Second * 180,
Transport: tr,
}
errors.LogInfo(context.Background(), "DNS: created Local DOH client for ", url.String())
errors.LogInfo(context.Background(), "DNS: created Local DNS-over-HTTPS client for ", url.String())
return s
}

View File

@@ -146,7 +146,7 @@ func (w *fileLogWriter) Close() error {
func CreateStdoutLogWriter() WriterCreator {
return func() Writer {
return &consoleLogWriter{
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime),
logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lmicroseconds),
}
}
}
@@ -155,7 +155,7 @@ func CreateStdoutLogWriter() WriterCreator {
func CreateStderrLogWriter() WriterCreator {
return func() Writer {
return &consoleLogWriter{
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime),
logger: log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lmicroseconds),
}
}
}
@@ -174,7 +174,7 @@ func CreateFileLogWriter(path string) (WriterCreator, error) {
}
return &fileLogWriter{
file: file,
logger: log.New(file, "", log.Ldate|log.Ltime),
logger: log.New(file, "", log.Ldate|log.Ltime|log.Lmicroseconds),
}
}, nil
}

View File

@@ -410,6 +410,7 @@ type TLSConfig struct {
PinnedPeerCertificatePublicKeySha256 *[]string `json:"pinnedPeerCertificatePublicKeySha256"`
CurvePreferences *StringList `json:"curvePreferences"`
MasterKeyLog string `json:"masterKeyLog"`
ServerNameToVerify string `json:"serverNameToVerify"`
}
// Build implements Buildable.
@@ -468,6 +469,10 @@ func (c *TLSConfig) Build() (proto.Message, error) {
}
config.MasterKeyLog = c.MasterKeyLog
config.ServerNameToVerify = c.ServerNameToVerify
if config.ServerNameToVerify != "" && config.Fingerprint == "unsafe" {
return nil, errors.New(`serverNameToVerify only works with uTLS for now`)
}
return config, nil
}

View File

@@ -24,8 +24,14 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
conn = tls.UClient(conn, tlsConfig, fingerprint)
if err := conn.(*tls.UConn).HandshakeContext(ctx); err != nil {
return nil, err
if len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "http/1.1" {
if err := conn.(*tls.UConn).WebsocketHandshakeContext(ctx); err != nil {
return nil, err
}
} else {
if err := conn.(*tls.UConn).HandshakeContext(ctx); err != nil {
return nil, err
}
}
} else {
conn = tls.Client(conn, tlsConfig)

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"crypto/hmac"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"encoding/base64"
@@ -303,6 +304,14 @@ func (c *Config) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Cert
return nil
}
type RandCarrier struct {
ServerNameToVerify string
}
func (r *RandCarrier) Read(p []byte) (n int, err error) {
return rand.Read(p)
}
// GetTLSConfig converts this Config into tls.Config.
func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
root, err := c.getCertPool()
@@ -321,6 +330,9 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
}
config := &tls.Config{
Rand: &RandCarrier{
ServerNameToVerify: c.ServerNameToVerify,
},
ClientSessionCache: globalSessionCache,
RootCAs: root,
InsecureSkipVerify: c.AllowInsecure,

View File

@@ -214,7 +214,8 @@ type Config struct {
PinnedPeerCertificatePublicKeySha256 [][]byte `protobuf:"bytes,14,rep,name=pinned_peer_certificate_public_key_sha256,json=pinnedPeerCertificatePublicKeySha256,proto3" json:"pinned_peer_certificate_public_key_sha256,omitempty"`
MasterKeyLog string `protobuf:"bytes,15,opt,name=master_key_log,json=masterKeyLog,proto3" json:"master_key_log,omitempty"`
// Lists of string as CurvePreferences values.
CurvePreferences []string `protobuf:"bytes,16,rep,name=curve_preferences,json=curvePreferences,proto3" json:"curve_preferences,omitempty"`
CurvePreferences []string `protobuf:"bytes,16,rep,name=curve_preferences,json=curvePreferences,proto3" json:"curve_preferences,omitempty"`
ServerNameToVerify string `protobuf:"bytes,17,opt,name=server_name_to_verify,json=serverNameToVerify,proto3" json:"server_name_to_verify,omitempty"`
}
func (x *Config) Reset() {
@@ -352,6 +353,13 @@ func (x *Config) GetCurvePreferences() []string {
return nil
}
func (x *Config) GetServerNameToVerify() string {
if x != nil {
return x.ServerNameToVerify
}
return ""
}
var File_transport_internet_tls_config_proto protoreflect.FileDescriptor
var file_transport_internet_tls_config_proto_rawDesc = []byte{
@@ -383,7 +391,7 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a,
0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46,
0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59,
0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xe0, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0x93, 0x06, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73,
0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c,
0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65,
@@ -429,15 +437,18 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x52, 0x0c, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x12, 0x2b,
0x0a, 0x11, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x75, 0x72, 0x76, 0x65,
0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x42, 0x73, 0x0a, 0x1f, 0x63,
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01,
0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74,
0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x6c, 0x73,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x76, 0x65,
0x72, 0x69, 0x66, 0x79, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x54, 0x6f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x42, 0x73,
0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c,
0x73, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x54, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -87,4 +87,6 @@ message Config {
// Lists of string as CurvePreferences values.
repeated string curve_preferences = 16;
string server_name_to_verify = 17;
}

View File

@@ -134,12 +134,17 @@ func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) ne
}
func copyConfig(c *tls.Config) *utls.Config {
serverNameToVerify := ""
if r, ok := c.Rand.(*RandCarrier); ok {
serverNameToVerify = r.ServerNameToVerify
}
return &utls.Config{
RootCAs: c.RootCAs,
ServerName: c.ServerName,
InsecureSkipVerify: c.InsecureSkipVerify,
VerifyPeerCertificate: c.VerifyPeerCertificate,
KeyLogWriter: c.KeyLogWriter,
RootCAs: c.RootCAs,
ServerName: c.ServerName,
InsecureSkipVerify: c.InsecureSkipVerify,
VerifyPeerCertificate: c.VerifyPeerCertificate,
KeyLogWriter: c.KeyLogWriter,
InsecureServerNameToVerify: serverNameToVerify,
}
}

View File

@@ -1769,7 +1769,7 @@ The following extractors use this feature:
#### youtube
* `lang`: Prefer translated metadata (`title`, `description` etc) of this language code (case-sensitive). By default, the video primary language metadata is preferred, with a fallback to `en` translated. See [youtube.py](https://github.com/yt-dlp/yt-dlp/blob/c26f9b991a0681fd3ea548d535919cec1fbbd430/yt_dlp/extractor/youtube.py#L381-L390) for list of supported content language codes
* `skip`: One or more of `hls`, `dash` or `translated_subs` to skip extraction of the m3u8 manifests, dash manifests and [auto-translated subtitles](https://github.com/yt-dlp/yt-dlp/issues/4090#issuecomment-1158102032) respectively
* `player_client`: Clients to extract video data from. The main clients are `web`, `ios` and `android`, with variants `_music` and `_creator` (e.g. `ios_creator`); and `mweb`, `android_vr`, `web_safari`, `web_embedded`, `tv` and `tv_embedded` with no variants. By default, `tv,ios,web` is used, or `tv,web` is used when authenticating with cookies. The `_music` variants may be added for `music.youtube.com` URLs. Some clients, such as `web` and `android`, require a `po_token` for their formats to be downloadable. Some clients, such as the `_creator` variants, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
* `player_client`: Clients to extract video data from. The main clients are `web`, `ios` and `android`, with variants `_music` and `_creator` (e.g. `ios_creator`); and `mweb`, `android_vr`, `web_safari`, `web_embedded`, `tv` and `tv_embedded` with no variants. By default, `tv,ios,web` is used, or `tv,web` is used when authenticating with cookies. The `web_music` client is added for `music.youtube.com` URLs when logged-in cookies are used. The `tv_embedded` and `web_creator` clients are added for age-restricted videos if account age-verification is required. Some clients, such as `web` and `web_music`, require a `po_token` for their formats to be downloadable. Some clients, such as the `_creator` variants, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
* `player_skip`: Skip some network requests that are generally needed for robust extraction. One or more of `configs` (skip client configs), `webpage` (skip initial webpage), `js` (skip js player). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause some issues. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) for more details
* `player_params`: YouTube player parameters to use for player requests. Will overwrite any default ones set by yt-dlp.
* `comment_sort`: `top` or `new` (default) - choose comment sorting mode (on YouTube's side)
@@ -1781,7 +1781,7 @@ The following extractors use this feature:
* `raise_incomplete_data`: `Incomplete Data Received` raises an error instead of reporting a warning
* `data_sync_id`: Overrides the account Data Sync ID used in Innertube API requests. This may be needed if you are using an account with `youtube:player_skip=webpage,configs` or `youtubetab:skip=webpage`
* `visitor_data`: Overrides the Visitor Data used in Innertube API requests. This should be used with `player_skip=webpage,configs` and without cookies. Note: this may have adverse effects if used improperly. If a session from a browser is wanted, you should pass cookies instead (which contain the Visitor ID)
* `po_token`: Proof of Origin (PO) Token(s) to use for requesting video playback. Comma seperated list of PO Tokens in the format `CLIENT+PO_TOKEN`, e.g. `youtube:po_token=web+XXX,android+YYY`
* `po_token`: Proof of Origin (PO) Token(s) to use. Comma seperated list of PO Tokens in the format `CLIENT.CONTEXT+PO_TOKEN`, e.g. `youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY`. Context can be either `gvs` (Google Video Server URLs) or `player` (Innertube player request)
#### youtubetab (YouTube playlists, channels, feeds, etc.)
* `skip`: One or more of `webpage` (skip initial webpage download), `authcheck` (allow the download of playlists requiring authentication when no initial webpage is downloaded. This may cause unwanted behavior, see [#1122](https://github.com/yt-dlp/yt-dlp/pull/1122) for more details)

View File

@@ -1996,6 +1996,10 @@ from .streetvoice import StreetVoiceIE
from .stretchinternet import StretchInternetIE
from .stripchat import StripchatIE
from .stv import STVPlayerIE
from .subsplash import (
SubsplashIE,
SubsplashPlaylistIE,
)
from .substack import SubstackIE
from .sunporno import SunPornoIE
from .sverigesradio import (

View File

@@ -1,40 +1,48 @@
from .common import InfoExtractor
from ..utils import (
clean_html,
int_or_none,
str_or_none,
traverse_obj,
url_or_none,
)
class GoodGameIE(InfoExtractor):
IE_NAME = 'goodgame:stream'
_VALID_URL = r'https?://goodgame\.ru/channel/(?P<id>\w+)'
_VALID_URL = r'https?://goodgame\.ru/(?!channel/)(?P<id>[\w.*-]+)'
_TESTS = [{
'url': 'https://goodgame.ru/channel/Pomi/#autoplay',
'url': 'https://goodgame.ru/TGW#autoplay',
'info_dict': {
'id': 'pomi',
'id': '7998',
'ext': 'mp4',
'title': r're:Reynor vs Special \(1/2,bo3\) Wardi Spring EU \- playoff \(финальный день\) \d{4}-\d{2}-\d{2} \d{2}:\d{2}$',
'channel_id': '1644',
'channel': 'Pomi',
'channel_url': 'https://goodgame.ru/channel/Pomi/',
'description': 'md5:4a87b775ee7b2b57bdccebe285bbe171',
'thumbnail': r're:^https?://.*\.jpg$',
'channel_id': '7998',
'title': r're:шоуматч Happy \(NE\) vs Fortitude \(UD\), потом ладдер и дс \d{4}-\d{2}-\d{2} \d{2}:\d{2}$',
'channel_url': 'https://goodgame.ru/TGW',
'thumbnail': 'https://hls.goodgame.ru/previews/7998_240.jpg',
'uploader': 'TGW',
'channel': 'JosephStalin',
'live_status': 'is_live',
'view_count': int,
'age_limit': 18,
'channel_follower_count': int,
'uploader_id': '2899',
'concurrent_view_count': int,
},
'params': {'skip_download': 'm3u8'},
'skip': 'May not be online',
}, {
'url': 'https://goodgame.ru/Mr.Gray',
'only_matching': True,
}, {
'url': 'https://goodgame.ru/HeDoPa3yMeHue*',
'only_matching': True,
}]
def _real_extract(self, url):
channel_name = self._match_id(url)
response = self._download_json(f'https://api2.goodgame.ru/v2/streams/{channel_name}', channel_name)
player_id = response['channel']['gg_player_src']
response = self._download_json(f'https://goodgame.ru/api/4/users/{channel_name}/stream', channel_name)
player_id = response['streamkey']
formats, subtitles = [], {}
if response.get('status') == 'Live':
if response.get('status'):
formats, subtitles = self._extract_m3u8_formats_and_subtitles(
f'https://hls.goodgame.ru/manifest/{player_id}_master.m3u8',
channel_name, 'mp4', live=True)
@@ -45,13 +53,17 @@ class GoodGameIE(InfoExtractor):
'id': player_id,
'formats': formats,
'subtitles': subtitles,
'title': traverse_obj(response, ('channel', 'title')),
'channel': channel_name,
'channel_id': str_or_none(traverse_obj(response, ('channel', 'id'))),
'channel_url': response.get('url'),
'description': clean_html(traverse_obj(response, ('channel', 'description'))),
'thumbnail': traverse_obj(response, ('channel', 'thumb')),
'is_live': bool(formats),
'view_count': int_or_none(response.get('viewers')),
'age_limit': 18 if traverse_obj(response, ('channel', 'adult')) else None,
**traverse_obj(response, {
'title': ('title', {str}),
'channel': ('channelkey', {str}),
'channel_id': ('id', {str_or_none}),
'channel_url': ('link', {url_or_none}),
'uploader': ('streamer', 'username', {str}),
'uploader_id': ('streamer', 'id', {str_or_none}),
'thumbnail': ('preview', {url_or_none}, {self._proto_relative_url}),
'concurrent_view_count': ('viewers', {int_or_none}),
'channel_follower_count': ('followers', {int_or_none}),
'age_limit': ('adult', {bool}, {lambda x: 18 if x else None}),
}),
}

View File

@@ -28,6 +28,12 @@ class NRKBaseIE(InfoExtractor):
)/'''
def _extract_nrk_formats(self, asset_url, video_id):
asset_url = update_url_query(asset_url, {
# Remove 'adap' to return all streams (known values are: small, large, small_h265, large_h265)
'adap': [],
# Disable subtitles since they are fetched separately
's': 0,
})
if re.match(r'https?://[^/]+\.akamaihd\.net/i/', asset_url):
return self._extract_akamai_formats(asset_url, video_id)
asset_url = re.sub(r'(?:bw_(?:low|high)=\d+|no_audio_only)&?', '', asset_url)
@@ -59,7 +65,10 @@ class NRKBaseIE(InfoExtractor):
return self._download_json(
urljoin('https://psapi.nrk.no/', path),
video_id, note or f'Downloading {item} JSON',
fatal=fatal, query=query)
fatal=fatal, query=query, headers={
# Needed for working stream URLs, see https://github.com/yt-dlp/yt-dlp/issues/12192
'Accept': 'application/vnd.nrk.psapi+json; version=9; player=tv-player; device=player-core',
})
class NRKIE(NRKBaseIE):
@@ -78,13 +87,17 @@ class NRKIE(NRKBaseIE):
_TESTS = [{
# video
'url': 'http://www.nrk.no/video/PS*150533',
'md5': 'f46be075326e23ad0e524edfcb06aeb6',
'md5': '2b88a652ad2e275591e61cf550887eec',
'info_dict': {
'id': '150533',
'ext': 'mp4',
'title': 'Dompap og andre fugler i Piip-Show',
'description': 'md5:d9261ba34c43b61c812cb6b0269a5c8f',
'duration': 262,
'upload_date': '20140325',
'thumbnail': r're:^https?://gfx\.nrk\.no/.*$',
'timestamp': 1395751833,
'alt_title': 'md5:d9261ba34c43b61c812cb6b0269a5c8f',
},
}, {
# audio
@@ -96,6 +109,10 @@ class NRKIE(NRKBaseIE):
'title': 'Slik høres internett ut når du er blind',
'description': 'md5:a621f5cc1bd75c8d5104cb048c6b8568',
'duration': 20,
'timestamp': 1398429565,
'alt_title': 'Cathrine Lie Wathne er blind, og bruker hurtigtaster for å navigere seg rundt på ulike nettsider.',
'thumbnail': 'https://gfx.nrk.no/urxQMSXF-WnbfjBH5ke2igLGyN27EdJVWZ6FOsEAclhA',
'upload_date': '20140425',
},
}, {
'url': 'nrk:ecc1b952-96dc-4a98-81b9-5296dc7a98d9',
@@ -153,7 +170,7 @@ class NRKIE(NRKBaseIE):
return self._call_api(f'playback/{item}/{video_id}', video_id, item, query=query)
raise
# known values for preferredCdn: akamai, iponly, minicdn and telenor
# known values for preferredCdn: akamai, globalconnect and telenor
manifest = call_playback_api('manifest', {'preferredCdn': 'akamai'})
video_id = try_get(manifest, lambda x: x['id'], str) or video_id
@@ -172,8 +189,6 @@ class NRKIE(NRKBaseIE):
format_url = url_or_none(asset.get('url'))
if not format_url:
continue
# Remove the 'adap' query parameter
format_url = update_url_query(format_url, {'adap': []})
asset_format = (asset.get('format') or '').lower()
if asset_format == 'hls' or determine_ext(format_url) == 'm3u8':
formats.extend(self._extract_nrk_formats(format_url, video_id))
@@ -310,6 +325,13 @@ class NRKTVIE(InfoExtractor):
'ext': 'vtt',
}],
},
'upload_date': '20170627',
'timestamp': 1498591822,
'thumbnail': 'https://gfx.nrk.no/myRSc4vuFlahB60P3n6swwRTQUZI1LqJZl9B7icZFgzA',
'alt_title': 'md5:46923a6e6510eefcce23d5ef2a58f2ce',
},
'params': {
'skip_download': True,
},
}, {
'url': 'https://tv.nrk.no/serie/20-spoersmaal-tv/MUHH48000314/23-05-2014',
@@ -324,6 +346,13 @@ class NRKTVIE(InfoExtractor):
'series': '20 spørsmål',
'episode': '23. mai 2014',
'age_limit': 0,
'timestamp': 1584593700,
'thumbnail': 'https://gfx.nrk.no/u7uCe79SEfPVGRAGVp2_uAZnNc4mfz_kjXg6Bgek8lMQ',
'season_id': '126936',
'upload_date': '20200319',
'season': 'Season 2014',
'season_number': 2014,
'episode_number': 3,
},
}, {
'url': 'https://tv.nrk.no/program/mdfp15000514',

View File

@@ -393,7 +393,7 @@ class SoundcloudIE(SoundcloudBaseIE):
(?:(?:(?:www\.|m\.)?soundcloud\.com/
(?!stations/track)
(?P<uploader>[\w\d-]+)/
(?!(?:tracks|albums|sets(?:/.+?)?|reposts|likes|spotlight)/?(?:$|[?#]))
(?!(?:tracks|albums|sets(?:/.+?)?|reposts|likes|spotlight|comments)/?(?:$|[?#]))
(?P<title>[\w\d-]+)
(?:/(?P<token>(?!(?:albums|sets|recommended))[^?]+?))?
(?:[?].*)?$)
@@ -776,7 +776,7 @@ class SoundcloudUserIE(SoundcloudPagedPlaylistBaseIE):
(?:(?:www|m)\.)?soundcloud\.com/
(?P<user>[^/]+)
(?:/
(?P<rsrc>tracks|albums|sets|reposts|likes|spotlight)
(?P<rsrc>tracks|albums|sets|reposts|likes|spotlight|comments)
)?
/?(?:[?#].*)?$
'''
@@ -830,6 +830,13 @@ class SoundcloudUserIE(SoundcloudPagedPlaylistBaseIE):
'title': 'Grynpyret (Spotlight)',
},
'playlist_mincount': 1,
}, {
'url': 'https://soundcloud.com/one-thousand-and-one/comments',
'info_dict': {
'id': '992430331',
'title': '7x11x13-testing (Comments)',
},
'playlist_mincount': 1,
}]
_BASE_URL_MAP = {
@@ -840,6 +847,7 @@ class SoundcloudUserIE(SoundcloudPagedPlaylistBaseIE):
'reposts': 'stream/users/%s/reposts',
'likes': 'users/%s/likes',
'spotlight': 'users/%s/spotlight',
'comments': 'users/%s/comments',
}
def _real_extract(self, url):

View File

@@ -0,0 +1,199 @@
import functools
import math
from .common import InfoExtractor
from ..utils import (
InAdvancePagedList,
int_or_none,
parse_iso8601,
try_call,
url_or_none,
)
from ..utils.traversal import traverse_obj
class SubsplashBaseIE(InfoExtractor):
def _get_headers(self, url, display_id):
token = try_call(lambda: self._get_cookies(url)['ss-token-guest'].value)
if not token:
webpage, urlh = self._download_webpage_handle(url, display_id)
token = (
try_call(lambda: self._get_cookies(url)['ss-token-guest'].value)
or urlh.get_header('x-api-token')
or self._search_json(
r'<script[^>]+\bid="shoebox-tokens"[^>]*>', webpage, 'shoebox tokens',
display_id, default={}).get('apiToken')
or self._search_regex(r'\\"tokens\\":{\\"guest\\":\\"([A-Za-z0-9._-]+)\\"', webpage, 'token', default=None))
if not token:
self.report_warning('Unable to extract auth token')
return None
return {'Authorization': f'Bearer {token}'}
def _extract_video(self, data, video_id):
formats = []
video_data = traverse_obj(data, ('_embedded', 'video', '_embedded', {dict}))
m3u8_url = traverse_obj(video_data, ('playlists', 0, '_links', 'related', 'href', {url_or_none}))
if m3u8_url:
formats.extend(self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', m3u8_id='hls', fatal=False))
mp4_entry = traverse_obj(video_data, ('video-outputs', lambda _, v: url_or_none(v['_links']['related']['href']), any))
if mp4_entry:
formats.append({
'url': mp4_entry['_links']['related']['href'],
'format_id': 'direct',
'quality': 1,
**traverse_obj(mp4_entry, {
'height': ('height', {int_or_none}),
'width': ('width', {int_or_none}),
'filesize': ('file_size', {int_or_none}),
}),
})
return {
'id': video_id,
'formats': formats,
**traverse_obj(data, {
'title': ('title', {str}),
'description': ('summary_text', {str}),
'thumbnail': ('_embedded', 'images', 0, '_links', 'related', 'href', {url_or_none}),
'duration': ('_embedded', 'video', 'duration', {int_or_none(scale=1000)}),
'timestamp': ('date', {parse_iso8601}),
'release_timestamp': ('published_at', {parse_iso8601}),
'modified_timestamp': ('updated_at', {parse_iso8601}),
}),
}
class SubsplashIE(SubsplashBaseIE):
_VALID_URL = [
r'https?://(?:www\.)?subsplash\.com/(?:u/)?[^/?#]+/[^/?#]+/(?:d/|mi/\+)(?P<id>\w+)',
r'https?://(?:\w+\.)?subspla\.sh/(?P<id>\w+)',
]
_TESTS = [{
'url': 'https://subsplash.com/u/skywatchtv/media/d/5whnx5s-the-grand-delusion-taking-place-right-now',
'md5': 'd468729814e533cec86f1da505dec82d',
'info_dict': {
'id': '5whnx5s',
'ext': 'mp4',
'title': 'THE GRAND DELUSION TAKING PLACE RIGHT NOW!',
'description': 'md5:220a630865c3697b0ec9dcb3a70cbc33',
'upload_date': '20240901',
'duration': 1710,
'thumbnail': r're:https?://.*\.(?:jpg|png)$',
'modified_date': '20240901',
'release_date': '20240901',
'release_timestamp': 1725195600,
'timestamp': 1725148800,
'modified_timestamp': 1725195657,
},
}, {
'url': 'https://subsplash.com/u/prophecywatchers/media/d/n4dr8b2-the-transhumanist-plan-for-humanity-billy-crone',
'md5': '01982d58021af81c969958459bd81f13',
'info_dict': {
'id': 'n4dr8b2',
'ext': 'mp4',
'title': 'The Transhumanist Plan for Humanity | Billy Crone',
'upload_date': '20240903',
'duration': 1709,
'thumbnail': r're:https?://.*\.(?:jpg|png)$',
'timestamp': 1725321600,
'modified_date': '20241010',
'release_date': '20240903',
'release_timestamp': 1725379200,
'modified_timestamp': 1728577804,
},
}, {
'url': 'https://subsplash.com/laiglesiadelcentro/vid/mi/+ecb6a6b?autoplay=true',
'md5': '013c9b1e391dd4b34d8612439445deef',
'info_dict': {
'id': 'ecb6a6b',
'ext': 'mp4',
'thumbnail': r're:https?://.*\.(?:jpg|png)$',
'release_timestamp': 1477095852,
'title': 'En el Principio Era el Verbo | EVANGELIO DE JUAN | Ps. Gadiel Ríos',
'timestamp': 1425772800,
'upload_date': '20150308',
'description': 'md5:f368221de93176654989ba66bb564798',
'modified_timestamp': 1730258864,
'modified_date': '20241030',
'release_date': '20161022',
},
}, {
'url': 'https://prophecywatchers.subspla.sh/8gps8cx',
'only_matching': True,
}]
def _real_extract(self, url):
video_id = self._match_id(url)
data = self._download_json(
'https://core.subsplash.com/media/v1/media-items',
video_id, headers=self._get_headers(url, video_id),
query={
'filter[short_code]': video_id,
'include': 'images,audio.audio-outputs,audio.video,video.video-outputs,video.playlists,document,broadcast',
})
return self._extract_video(traverse_obj(data, ('_embedded', 'media-items', 0)), video_id)
class SubsplashPlaylistIE(SubsplashBaseIE):
IE_NAME = 'subsplash:playlist'
_VALID_URL = r'https?://(?:www\.)?subsplash\.com/[^/?#]+/(?:our-videos|media)/ms/\+(?P<id>\w+)'
_PAGE_SIZE = 15
_TESTS = [{
'url': 'https://subsplash.com/skywatchtv/our-videos/ms/+dbyjzp8',
'info_dict': {
'id': 'dbyjzp8',
'title': 'Five in Ten',
},
'playlist_mincount': 11,
}, {
'url': 'https://subsplash.com/prophecywatchers/media/ms/+n42mr48',
'info_dict': {
'id': 'n42mr48',
'title': 'Road to Zion Series',
},
'playlist_mincount': 13,
}, {
'url': 'https://subsplash.com/prophecywatchers/media/ms/+918b9f6',
'only_matching': True,
}]
def _entries(self, series_id, headers, page):
data = self._download_json(
'https://core.subsplash.com/media/v1/media-items', series_id, headers=headers,
query={
'filter[broadcast.status|broadcast.status]': 'null|on-demand',
'filter[media_series]': series_id,
'filter[status]': 'published',
'include': 'images,audio.audio-outputs,audio.video,video.video-outputs,video.playlists,document',
'page[number]': page + 1,
'page[size]': self._PAGE_SIZE,
'sort': '-position',
}, note=f'Downloading page {page + 1}')
for entry in traverse_obj(data, ('_embedded', 'media-items', lambda _, v: v['short_code'])):
entry_id = entry['short_code']
info = self._extract_video(entry, entry_id)
yield {
**info,
'webpage_url': f'https://subspla.sh/{entry_id}',
'extractor_key': SubsplashIE.ie_key(),
'extractor': SubsplashIE.IE_NAME,
}
def _real_extract(self, url):
display_id = self._match_id(url)
headers = self._get_headers(url, display_id)
data = self._download_json(
'https://core.subsplash.com/media/v1/media-series', display_id, headers=headers,
query={'filter[short_code]': display_id})
series_data = traverse_obj(data, ('_embedded', 'media-series', 0, {
'id': ('id', {str}),
'title': ('title', {str}),
'count': ('media_items_count', {int}),
}))
total_pages = math.ceil(series_data['count'] / self._PAGE_SIZE)
return self.playlist_result(
InAdvancePagedList(functools.partial(self._entries, series_data['id'], headers), total_pages, self._PAGE_SIZE),
display_id, series_data['title'])

View File

@@ -1,4 +1,5 @@
import base64
import binascii
import calendar
import collections
import copy
@@ -69,7 +70,14 @@ from ..utils import (
)
STREAMING_DATA_CLIENT_NAME = '__yt_dlp_client'
STREAMING_DATA_PO_TOKEN = '__yt_dlp_po_token'
STREAMING_DATA_INITIAL_PO_TOKEN = '__yt_dlp_po_token'
PO_TOKEN_GUIDE_URL = 'https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide'
class _PoTokenContext(enum.Enum):
PLAYER = 'player'
GVS = 'gvs'
# any clients starting with _ cannot be explicitly requested by the user
INNERTUBE_CLIENTS = {
@@ -81,7 +89,7 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 1,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'SUPPORTS_COOKIES': True,
},
# Safari UA returns pre-merged video+audio 144p/240p/360p/720p/1080p HLS formats
@@ -94,7 +102,7 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 1,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'SUPPORTS_COOKIES': True,
},
'web_embedded': {
@@ -116,7 +124,7 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 67,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'SUPPORTS_COOKIES': True,
},
# This client now requires sign-in for every video
@@ -128,7 +136,7 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 62,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_AUTH': True,
'SUPPORTS_COOKIES': True,
},
@@ -145,7 +153,7 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 3,
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
},
# This client now requires sign-in for every video
'android_music': {
@@ -161,7 +169,7 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 21,
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_AUTH': True,
},
# This client now requires sign-in for every video
@@ -178,7 +186,7 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 14,
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_AUTH': True,
},
# YouTube Kids videos aren't returned on this client for some reason
@@ -213,8 +221,8 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 5,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
},
# This client now requires sign-in for every video
'ios_music': {
@@ -231,7 +239,7 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 26,
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_AUTH': True,
},
# This client now requires sign-in for every video
@@ -249,7 +257,7 @@ INNERTUBE_CLIENTS = {
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 15,
'REQUIRE_JS_PLAYER': False,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'REQUIRE_AUTH': True,
},
# mweb has 'ultralow' formats
@@ -264,7 +272,7 @@ INNERTUBE_CLIENTS = {
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 2,
'REQUIRE_PO_TOKEN': True,
'PO_TOKEN_REQUIRED_CONTEXTS': [_PoTokenContext.GVS],
'SUPPORTS_COOKIES': True,
},
'tv': {
@@ -318,7 +326,7 @@ def build_innertube_clients():
for client, ytcfg in tuple(INNERTUBE_CLIENTS.items()):
ytcfg.setdefault('INNERTUBE_HOST', 'www.youtube.com')
ytcfg.setdefault('REQUIRE_JS_PLAYER', True)
ytcfg.setdefault('REQUIRE_PO_TOKEN', False)
ytcfg.setdefault('PO_TOKEN_REQUIRED_CONTEXTS', [])
ytcfg.setdefault('REQUIRE_AUTH', False)
ytcfg.setdefault('SUPPORTS_COOKIES', False)
ytcfg.setdefault('PLAYER_PARAMS', None)
@@ -3842,53 +3850,105 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
**cls._get_checkok_params(),
}
def _get_config_po_token(self, client):
def _get_config_po_token(self, client: str, context: _PoTokenContext):
po_token_strs = self._configuration_arg('po_token', [], ie_key=YoutubeIE, casesense=True)
for token_str in po_token_strs:
po_token_client, sep, po_token = token_str.partition('+')
po_token_meta, sep, po_token = token_str.partition('+')
if not sep:
self.report_warning(
f'Invalid po_token configuration format. Expected "client+po_token", got "{token_str}"', only_once=True)
f'Invalid po_token configuration format. '
f'Expected "CLIENT.CONTEXT+PO_TOKEN", got "{token_str}"', only_once=True)
continue
if po_token_client == client:
return po_token
def fetch_po_token(self, client='web', visitor_data=None, data_sync_id=None, player_url=None, **kwargs):
# PO Token is bound to visitor_data / Visitor ID when logged out. Must have visitor_data for it to function.
if not visitor_data and not self.is_authenticated and player_url:
po_token_client, sep, po_token_context = po_token_meta.partition('.')
if po_token_client.lower() != client:
continue
if not sep:
# TODO(future): deprecate the old format?
self.write_debug(
f'po_token configuration for {client} client is missing a context; assuming GVS. '
'You can provide a context with the format "CLIENT.CONTEXT+PO_TOKEN"',
only_once=True)
po_token_context = _PoTokenContext.GVS.value
if po_token_context.lower() != context.value:
continue
# Clean and validate the PO Token. This will strip invalid characters off
# (e.g. additional url params the user may accidentally include)
try:
return base64.urlsafe_b64encode(base64.urlsafe_b64decode(urllib.parse.unquote(po_token))).decode()
except (binascii.Error, ValueError):
self.report_warning(
f'Invalid po_token configuration for {client} client: '
f'{po_token_context} PO Token should be a base64url-encoded string.',
only_once=True)
continue
def fetch_po_token(self, client='web', context=_PoTokenContext.GVS, ytcfg=None, visitor_data=None,
data_sync_id=None, session_index=None, player_url=None, video_id=None, **kwargs):
"""
Fetch a PO Token for a given client and context. This function will validate required parameters for a given context and client.
EXPERIMENTAL: This method is unstable and may change or be removed without notice.
@param client: The client to fetch the PO Token for.
@param context: The context in which the PO Token is used.
@param ytcfg: The ytcfg for the client.
@param visitor_data: visitor data.
@param data_sync_id: data sync ID.
@param session_index: session index.
@param player_url: player URL.
@param video_id: video ID.
@param kwargs: Additional arguments to pass down. May be more added in the future.
@return: The fetched PO Token. None if it could not be fetched.
"""
# GVS WebPO Token is bound to visitor_data / Visitor ID when logged out.
# Must have visitor_data for it to function.
if player_url and context == _PoTokenContext.GVS and not visitor_data and not self.is_authenticated:
self.report_warning(
f'Unable to fetch PO Token for {client} client: Missing required Visitor Data. '
f'Unable to fetch GVS PO Token for {client} client: Missing required Visitor Data. '
f'You may need to pass Visitor Data with --extractor-args "youtube:visitor_data=XXX"')
return
config_po_token = self._get_config_po_token(client)
if context == _PoTokenContext.PLAYER and not video_id:
self.report_warning(
f'Unable to fetch Player PO Token for {client} client: Missing required Video ID')
return
config_po_token = self._get_config_po_token(client, context)
if config_po_token:
# PO token is bound to data_sync_id / account Session ID when logged in. However, for the config po_token,
# if using first channel in an account then we don't need the data_sync_id anymore...
if not data_sync_id and self.is_authenticated and player_url:
# GVS WebPO token is bound to data_sync_id / account Session ID when logged in.
if player_url and context == _PoTokenContext.GVS and not data_sync_id and self.is_authenticated:
self.report_warning(
f'Got a PO Token for {client} client, but missing Data Sync ID for account. Formats may not work.'
f'Got a GVS PO Token for {client} client, but missing Data Sync ID for account. Formats may not work.'
f'You may need to pass a Data Sync ID with --extractor-args "youtube:data_sync_id=XXX"')
return config_po_token
# Require PO Token if logged in for external fetching
if not data_sync_id and self.is_authenticated and player_url:
# Require GVS WebPO Token if logged in for external fetching
if player_url and context == _PoTokenContext.GVS and not data_sync_id and self.is_authenticated:
self.report_warning(
f'Unable to fetch PO Token for {client} client: Missing required Data Sync ID for account. '
f'Unable to fetch GVS PO Token for {client} client: Missing required Data Sync ID for account. '
f'You may need to pass a Data Sync ID with --extractor-args "youtube:data_sync_id=XXX"')
return
return self._fetch_po_token(
client=client,
context=context.value,
ytcfg=ytcfg,
visitor_data=visitor_data,
data_sync_id=data_sync_id,
session_index=session_index,
player_url=player_url,
video_id=video_id,
**kwargs,
)
def _fetch_po_token(self, client, visitor_data=None, data_sync_id=None, player_url=None, **kwargs):
"""External PO Token fetch stub"""
def _fetch_po_token(self, client, **kwargs):
"""(Unstable) External PO Token fetch stub"""
@staticmethod
def _is_agegated(player_response):
@@ -3970,6 +4030,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
raise ExtractorError('No player clients have been requested', expected=True)
if self.is_authenticated:
if (smuggled_data.get('is_music_url') or self.is_music_url(url)) and 'web_music' not in requested_clients:
requested_clients.append('web_music')
unsupported_clients = [
client for client in requested_clients if not INNERTUBE_CLIENTS[client]['SUPPORTS_COOKIES']
]
@@ -4036,17 +4099,47 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
visitor_data = visitor_data or self._extract_visitor_data(master_ytcfg, initial_pr, player_ytcfg)
data_sync_id = data_sync_id or self._extract_data_sync_id(master_ytcfg, initial_pr, player_ytcfg)
po_token = self.fetch_po_token(
client=client, visitor_data=visitor_data,
data_sync_id=data_sync_id if self.is_authenticated else None,
player_url=player_url if require_js_player else None,
)
require_po_token = self._get_default_ytcfg(client).get('REQUIRE_PO_TOKEN')
if not po_token and require_po_token and 'missing_pot' in self._configuration_arg('formats'):
fetch_po_token_args = {
'client': client,
'visitor_data': visitor_data,
'video_id': video_id,
'data_sync_id': data_sync_id if self.is_authenticated else None,
'player_url': player_url if require_js_player else None,
'session_index': self._extract_session_index(master_ytcfg, player_ytcfg),
'ytcfg': player_ytcfg,
}
player_po_token = self.fetch_po_token(
context=_PoTokenContext.PLAYER, **fetch_po_token_args)
gvs_po_token = self.fetch_po_token(
context=_PoTokenContext.GVS, **fetch_po_token_args)
required_pot_contexts = self._get_default_ytcfg(client)['PO_TOKEN_REQUIRED_CONTEXTS']
if (
not player_po_token
and _PoTokenContext.PLAYER in required_pot_contexts
):
# TODO: may need to skip player response request. Unsure yet..
self.report_warning(
f'No PO Token provided for {client} client, '
f'which may be required for working {client} formats. This client will be deprioritized', only_once=True)
f'No Player PO Token provided for {client} client, '
f'which may be required for working {client} formats. This client will be deprioritized'
f'You can manually pass a Player PO Token for this client with --extractor-args "youtube:po_token={client}.player+XXX". '
f'For more information, refer to {PO_TOKEN_GUIDE_URL} .', only_once=True)
deprioritize_pr = True
if (
not gvs_po_token
and _PoTokenContext.GVS in required_pot_contexts
and 'missing_pot' in self._configuration_arg('formats')
):
# note: warning with help message is provided later during format processing
self.report_warning(
f'No GVS PO Token provided for {client} client, '
f'which may be required for working {client} formats. This client will be deprioritized',
only_once=True)
deprioritize_pr = True
pr = initial_pr if client == 'web' else None
@@ -4059,7 +4152,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
initial_pr=initial_pr,
visitor_data=visitor_data,
data_sync_id=data_sync_id,
po_token=po_token)
po_token=player_po_token)
except ExtractorError as e:
self.report_warning(e)
continue
@@ -4070,15 +4163,25 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
# Save client name for introspection later
sd = traverse_obj(pr, ('streamingData', {dict})) or {}
sd[STREAMING_DATA_CLIENT_NAME] = client
sd[STREAMING_DATA_PO_TOKEN] = po_token
sd[STREAMING_DATA_INITIAL_PO_TOKEN] = gvs_po_token
for f in traverse_obj(sd, (('formats', 'adaptiveFormats'), ..., {dict})):
f[STREAMING_DATA_CLIENT_NAME] = client
f[STREAMING_DATA_PO_TOKEN] = po_token
f[STREAMING_DATA_INITIAL_PO_TOKEN] = gvs_po_token
if deprioritize_pr:
deprioritized_prs.append(pr)
else:
prs.append(pr)
# EU countries require age-verification for accounts to access age-restricted videos
# If account is not age-verified, _is_agegated() will be truthy for non-embedded clients
if self.is_authenticated and self._is_agegated(pr):
self.to_screen(
f'{video_id}: This video is age-restricted and YouTube is requiring '
'account age-verification; some formats may be missing', only_once=True)
# tv_embedded can work around the age-verification requirement for embeddable videos
# web_creator may work around age-verification for all videos but requires PO token
append_client('tv_embedded', 'web_creator')
prs.extend(deprioritized_prs)
if skipped_clients:
@@ -4099,10 +4202,10 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
def _report_pot_format_skipped(self, video_id, client_name, proto):
msg = (
f'{video_id}: {client_name} client {proto} formats require a PO Token which was not provided. '
f'{video_id}: {client_name} client {proto} formats require a GVS PO Token which was not provided. '
'They will be skipped as they may yield HTTP Error 403. '
f'You can manually pass a PO Token for this client with --extractor-args "youtube:po_token={client_name}+XXX". '
'For more information, refer to https://github.com/yt-dlp/yt-dlp/wiki/Extractors#po-token-guide . '
f'You can manually pass a GVS PO Token for this client with --extractor-args "youtube:po_token={client_name}.gvs+XXX". '
f'For more information, refer to {PO_TOKEN_GUIDE_URL} . '
'To enable these broken formats anyway, pass --extractor-args "youtube:formats=missing_pot"')
# Only raise a warning for non-default clients, to not confuse users.
@@ -4232,13 +4335,17 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
f'{video_id}: Some formats are possibly damaged. They will be deprioritized', only_once=True)
client_name = fmt[STREAMING_DATA_CLIENT_NAME]
po_token = fmt.get(STREAMING_DATA_PO_TOKEN)
po_token = fmt.get(STREAMING_DATA_INITIAL_PO_TOKEN)
if po_token:
fmt_url = update_url_query(fmt_url, {'pot': po_token})
# Clients that require PO Token return videoplayback URLs that may return 403
require_po_token = (not po_token and self._get_default_ytcfg(client_name).get('REQUIRE_PO_TOKEN'))
require_po_token = (
not po_token
and _PoTokenContext.GVS in self._get_default_ytcfg(client_name)['PO_TOKEN_REQUIRED_CONTEXTS']
and itag not in ['18']) # these formats do not require PO Token
if require_po_token and 'missing_pot' not in self._configuration_arg('formats'):
self._report_pot_format_skipped(video_id, client_name, 'https')
continue
@@ -4327,7 +4434,11 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
# Clients that require PO Token return videoplayback URLs that may return 403
# hls does not currently require PO Token
if (not po_token and self._get_default_ytcfg(client_name).get('REQUIRE_PO_TOKEN')) and proto != 'hls':
if (
not po_token
and _PoTokenContext.GVS in self._get_default_ytcfg(client_name)['PO_TOKEN_REQUIRED_CONTEXTS']
and proto != 'hls'
):
if 'missing_pot' not in self._configuration_arg('formats'):
self._report_pot_format_skipped(video_id, client_name, proto)
return False
@@ -4368,7 +4479,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
subtitles = {}
for sd in streaming_data:
client_name = sd[STREAMING_DATA_CLIENT_NAME]
po_token = sd.get(STREAMING_DATA_PO_TOKEN)
po_token = sd.get(STREAMING_DATA_INITIAL_PO_TOKEN)
hls_manifest_url = 'hls' not in skip_manifests and sd.get('hlsManifestUrl')
if hls_manifest_url:
if po_token: