[TMP] Plugins system.

This commit is contained in:
Sakamoto Shiina
2025-03-05 23:22:22 +09:00
parent a2cc69b8ee
commit 22ada89fa6
21 changed files with 990 additions and 7 deletions

91
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"name": "tauri-app", "name": "tauri-app",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@babel/standalone": "^7.26.9",
"@emotion/react": "11.14.0", "@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0", "@emotion/styled": "11.14.0",
"@mui/material": "6.2.0", "@mui/material": "6.2.0",
@@ -20,6 +21,7 @@
"jotai": "2.10.3", "jotai": "2.10.3",
"js-base64": "3.7.7", "js-base64": "3.7.7",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jszip": "^3.10.1",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-i18next": "15.2.0", "react-i18next": "15.2.0",
@@ -271,6 +273,14 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/standalone": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.26.9.tgz",
"integrity": "sha512-UTeQKy0kzJwWRe55kT1uK4G9H6D0lS6G4207hCU/bDaOhA5t2aC0qHN6GmID0Axv3OFLNXm27NdqcWp+BXcGtA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
@@ -2330,6 +2340,11 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
}, },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cosmiconfig": { "node_modules/cosmiconfig": {
"version": "7.1.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -3424,6 +3439,11 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
},
"node_modules/immutable": { "node_modules/immutable": {
"version": "4.3.7", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
@@ -3933,6 +3953,17 @@
"node": ">=4.0" "node": ">=4.0"
} }
}, },
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -3953,6 +3984,14 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lines-and-columns": { "node_modules/lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -4364,6 +4403,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/parent-module": { "node_modules/parent-module": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -4510,6 +4554,11 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -4659,6 +4708,25 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/readable-stream/node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
@@ -4836,6 +4904,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/safe-regex-test": { "node_modules/safe-regex-test": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
@@ -4919,6 +4992,11 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -5022,6 +5100,14 @@
"integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==",
"dev": true "dev": true
}, },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/string.prototype.matchall": { "node_modules/string.prototype.matchall": {
"version": "4.0.11", "version": "4.0.11",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
@@ -5338,6 +5424,11 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/validate-npm-package-license": { "node_modules/validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",

View File

@@ -23,6 +23,7 @@
"release-all": "npm run release && npm run release-cuda" "release-all": "npm run release && npm run release-cuda"
}, },
"dependencies": { "dependencies": {
"@babel/standalone": "^7.26.9",
"@emotion/react": "11.14.0", "@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0", "@emotion/styled": "11.14.0",
"@mui/material": "6.2.0", "@mui/material": "6.2.0",
@@ -35,6 +36,7 @@
"jotai": "2.10.3", "jotai": "2.10.3",
"js-base64": "3.7.7", "js-base64": "3.7.7",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"jszip": "^3.10.1",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-i18next": "15.2.0", "react-i18next": "15.2.0",

507
src-tauri/Cargo.lock generated
View File

@@ -6,7 +6,9 @@ version = 3
name = "VRCT" name = "VRCT"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"base64 0.22.1",
"font-kit", "font-kit",
"reqwest",
"serde", "serde",
"serde_json", "serde_json",
"tauri", "tauri",
@@ -218,6 +220,9 @@ name = "bytes"
version = "1.9.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "cairo-rs" name = "cairo-rs"
@@ -729,7 +734,7 @@ dependencies = [
"rustc_version", "rustc_version",
"toml 0.8.19", "toml 0.8.19",
"vswhom", "vswhom",
"winreg", "winreg 0.52.0",
] ]
[[package]] [[package]]
@@ -971,6 +976,12 @@ dependencies = [
"syn 2.0.94", "syn 2.0.94",
] ]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.31" version = "0.3.31"
@@ -984,8 +995,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io",
"futures-macro", "futures-macro",
"futures-sink",
"futures-task", "futures-task",
"memchr",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab", "slab",
@@ -1297,6 +1311,25 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "h2"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap 2.7.0",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@@ -1361,12 +1394,86 @@ dependencies = [
"itoa 1.0.14", "itoa 1.0.14",
] ]
[[package]]
name = "http-body"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]] [[package]]
name = "http-range" name = "http-range"
version = "0.1.5" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]]
name = "httparse"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa 1.0.14",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [
"futures-util",
"http",
"hyper",
"rustls",
"tokio",
"tokio-rustls",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.61" version = "0.1.61"
@@ -1613,6 +1720,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "ipnet"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.8" version = "0.4.8"
@@ -1849,6 +1962,12 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.2" version = "0.8.2"
@@ -1859,6 +1978,34 @@ dependencies = [
"simd-adler32", "simd-adler32",
] ]
[[package]]
name = "mio"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
[[package]]
name = "native-tls"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "ndk" name = "ndk"
version = "0.6.0" version = "0.6.0"
@@ -1998,6 +2145,50 @@ dependencies = [
"windows-sys 0.42.0", "windows-sys 0.42.0",
] ]
[[package]]
name = "openssl"
version = "0.10.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"foreign-types 0.3.2",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.94",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "option-ext" name = "option-ext"
version = "0.2.0" version = "0.2.0"
@@ -2516,6 +2707,67 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-rustls",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots",
"winreg 0.50.0",
]
[[package]]
name = "ring"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"libc",
"spin",
"untrusted",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.24" version = "0.1.24"
@@ -2544,6 +2796,37 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "rustls"
version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring",
"rustls-webpki",
"sct",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
"base64 0.21.7",
]
[[package]]
name = "rustls-webpki"
version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.19" version = "1.0.19"
@@ -2565,6 +2848,15 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "schannel"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "scoped-tls" name = "scoped-tls"
version = "1.0.1" version = "1.0.1"
@@ -2577,6 +2869,39 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.6.0",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "selectors" name = "selectors"
version = "0.22.0" version = "0.22.0"
@@ -2659,6 +2984,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa 1.0.14",
"ryu",
"serde",
]
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.12.0" version = "3.12.0"
@@ -2784,6 +3121,16 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "soup2" name = "soup2"
version = "0.2.1" version = "0.2.1"
@@ -2812,6 +3159,12 @@ dependencies = [
"system-deps 5.0.0", "system-deps 5.0.0",
] ]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@@ -2881,6 +3234,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.13.1" version = "0.13.1"
@@ -2892,6 +3251,27 @@ dependencies = [
"syn 2.0.94", "syn 2.0.94",
] ]
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "5.0.0" version = "5.0.0"
@@ -3000,6 +3380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf327e247698d3f39af8aa99401c9708384290d1f5c544bf5d251d44c2fea22" checksum = "1bf327e247698d3f39af8aa99401c9708384290d1f5c544bf5d251d44c2fea22"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes",
"cocoa 0.24.1", "cocoa 0.24.1",
"dirs-next", "dirs-next",
"dunce", "dunce",
@@ -3014,6 +3395,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"http", "http",
"ignore", "ignore",
"indexmap 1.9.3",
"log", "log",
"objc", "objc",
"once_cell", "once_cell",
@@ -3024,6 +3406,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"raw-window-handle", "raw-window-handle",
"regex", "regex",
"reqwest",
"semver", "semver",
"serde", "serde",
"serde_json", "serde_json",
@@ -3296,7 +3679,44 @@ checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
"libc",
"mio",
"pin-project-lite", "pin-project-lite",
"socket2",
"windows-sys 0.52.0",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
] ]
[[package]] [[package]]
@@ -3367,6 +3787,12 @@ dependencies = [
"winnow 0.6.22", "winnow 0.6.22",
] ]
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.41" version = "0.1.41"
@@ -3428,6 +3854,12 @@ dependencies = [
"tracing-log", "tracing-log",
] ]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"
@@ -3446,6 +3878,12 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "url" name = "url"
version = "2.5.4" version = "2.5.4"
@@ -3491,6 +3929,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.0.11" version = "0.0.11"
@@ -3539,6 +3983,15 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.9.0+wasi-snapshot-preview1" version = "0.9.0+wasi-snapshot-preview1"
@@ -3576,6 +4029,19 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.99" version = "0.2.99"
@@ -3605,6 +4071,29 @@ version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
[[package]]
name = "wasm-streams"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "web-sys"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "webkit2gtk" name = "webkit2gtk"
version = "0.18.2" version = "0.18.2"
@@ -3652,6 +4141,12 @@ dependencies = [
"system-deps 6.2.2", "system-deps 6.2.2",
] ]
[[package]]
name = "webpki-roots"
version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]] [[package]]
name = "webview2-com" name = "webview2-com"
version = "0.19.1" version = "0.19.1"
@@ -4058,6 +4553,16 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.52.0" version = "0.52.0"

View File

@@ -11,11 +11,13 @@ edition = "2021"
tauri-build = { version = "1", features = [] } tauri-build = { version = "1", features = [] }
[dependencies] [dependencies]
tauri = { version = "1", features = [ "window-hide", "window-set-focus", "global-shortcut-all", "window-set-size", "window-set-position", "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] } tauri = { version = "1", features = [ "fs-read-file", "fs-create-dir", "fs-write-file", "fs-exists", "http-request", "fs-read-dir", "window-hide", "window-set-focus", "global-shortcut-all", "window-set-size", "window-set-position", "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
font-kit = "0.14.2" font-kit = "0.14.2"
window-shadows = { git = "https://github.com/tauri-apps/window-shadows.git" } window-shadows = { git = "https://github.com/tauri-apps/window-shadows.git" }
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
base64 = "0.22.1"
[features] [features]

View File

@@ -0,0 +1,22 @@
import React from "react";
import { MainContainer } from "./main_container/MainContainer";
export const init = (plugin_context) => {
const { useHook: useStore_CountPluginState } = plugin_context.createAtomWithHook({ count: 6 }, "CountPluginState");
const EntryComponents = () => {
return (
<MainContainer useStore_CountPluginState={useStore_CountPluginState}/>
);
};
// UI の"main_section"拡張ポイントにコンポーネントを登録
plugin_context.registerComponent({
plugin_id: "dev_vrct_plugin_example_1",
location: "main_section",
component: EntryComponents,
});
};

View File

@@ -0,0 +1,19 @@
export const MainContainer = ({useStore_CountPluginState}) => {
const { updateCountPluginState, currentCountPluginState } = useStore_CountPluginState();
const incrementCount = () => {
updateCountPluginState((prev_value) => {
return { count: prev_value.data.count + 1 }
});
};
return (
<div>
<p>Dev Plugin Count: {currentCountPluginState?.data?.count}</p>
<button onClick={incrementCount}>
Increment Plugin Count
</button>
</div>
);
};

View File

@@ -22,7 +22,7 @@ fn main() {
event.window().set_size(tauri::Size::Physical(*new_inner_size)).unwrap(); event.window().set_size(tauri::Size::Physical(*new_inner_size)).unwrap();
} }
}) })
.invoke_handler(tauri::generate_handler![get_font_list]) .invoke_handler(tauri::generate_handler![get_font_list, download_zip_asset])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
} }
@@ -46,3 +46,22 @@ async fn get_font_list() -> Vec<String> {
font_families.into_iter().collect() font_families.into_iter().collect()
} }
#[tauri::command]
async fn download_zip_asset(url: String) -> Result<String, String> {
use reqwest;
// reqwest のクライアントを作成
let client = reqwest::Client::new();
// GET リクエストを送信(リダイレクトも自動追従します)
let resp = client.get(&url)
.header("Accept", "application/octet-stream")
.send()
.await.map_err(|e| format!("Request error: {}", e))?;
if !resp.status().is_success() {
return Err(format!("HTTP error: {}", resp.status()));
}
// レスポンスのバイナリデータを取得
let bytes = resp.bytes().await.map_err(|e| format!("Reading bytes error: {}", e))?;
// バイナリデータを base64 エンコードして返す
Ok(base64::encode(&bytes))
}

View File

@@ -30,6 +30,18 @@
"globalShortcut": { "globalShortcut": {
"all": true "all": true
}, },
"fs": {
"readDir": true,
"readFile": true,
"exists": true,
"writeFile": true,
"createDir": true,
"scope": ["$RESOURCE/**", "**/src-tauri/target/debug/plugins/**"]
},
"http": {
"request": true,
"scope": ["https://api.github.com/repos/**", "https://github.com/**"]
},
"shell": { "shell": {
"all": false, "all": false,
"open": true, "open": true,
@@ -74,7 +86,8 @@
"bin/VRCT-sidecar" "bin/VRCT-sidecar"
], ],
"resources":{ "resources":{
"bin/_internal": "_internal" "bin/_internal": "_internal",
"plugins": "plugins"
}, },
"windows": { "windows": {
"nsis": { "nsis": {

View File

@@ -9,6 +9,7 @@ import {
UiSizeController, UiSizeController,
FontFamilyController, FontFamilyController,
TransparencyController, TransparencyController,
PluginsController,
} from "./_app_controllers/index.js"; } from "./_app_controllers/index.js";
import { WindowTitleBar } from "./window_title_bar/WindowTitleBar"; import { WindowTitleBar } from "./window_title_bar/WindowTitleBar";
@@ -40,6 +41,7 @@ export const App = () => {
<FontFamilyController /> <FontFamilyController />
<TransparencyController /> <TransparencyController />
<WindowGeometryController /> <WindowGeometryController />
<PluginsController />
{(currentIsBackendReady.data === false || currentIsVrctAvailable.data === false) {(currentIsBackendReady.data === false || currentIsVrctAvailable.data === false)
? <SplashComponent /> ? <SplashComponent />

View File

@@ -0,0 +1,17 @@
import { useEffect } from "react";
import { usePlugins } from "@logics_configs";
// ホスト側でReactやjotaiをグローバル変数として提供
import ReactModule from "react";
if (typeof window !== "undefined") {
window.React = ReactModule;
}
export const PluginsController = () => {
const { loadAllPlugins } = usePlugins();
useEffect(() => {
loadAllPlugins();
}, []);
return null;
};

View File

@@ -6,3 +6,4 @@ export { ConfigPageCloseTriggerController } from "./ConfigPageCloseTriggerContro
export { UiSizeController } from "./UiSizeController"; export { UiSizeController } from "./UiSizeController";
export { FontFamilyController } from "./FontFamilyController"; export { FontFamilyController } from "./FontFamilyController";
export { TransparencyController } from "./TransparencyController"; export { TransparencyController } from "./TransparencyController";
export { PluginsController } from "./PluginsController";

View File

@@ -9,6 +9,7 @@ import {
AdvancedSettings, AdvancedSettings,
Vr, Vr,
Hotkeys, Hotkeys,
Plugins,
Supporters, Supporters,
AboutVrct, AboutVrct,
} from "@setting_box"; } from "@setting_box";
@@ -32,6 +33,8 @@ export const SettingBox = () => {
return <Hotkeys />; return <Hotkeys />;
case "advanced_settings": case "advanced_settings":
return <AdvancedSettings />; return <AdvancedSettings />;
case "plugins":
return <Plugins />;
case "supporters": case "supporters":
return <Supporters />; return <Supporters />;
case "about_vrct": case "about_vrct":

View File

@@ -6,5 +6,6 @@ export { Others, VrcMicMuteSyncContainer } from "./others/Others";
export { AdvancedSettings } from "./advanced_settings/AdvancedSettings"; export { AdvancedSettings } from "./advanced_settings/AdvancedSettings";
export { Vr } from "./vr/Vr"; export { Vr } from "./vr/Vr";
export { Hotkeys } from "./hotkeys/Hotkeys"; export { Hotkeys } from "./hotkeys/Hotkeys";
export { Plugins } from "./plugins/Plugins";
export { AboutVrct } from "./about_vrct/AboutVrct"; export { AboutVrct } from "./about_vrct/AboutVrct";
export { Supporters } from "./supporters/Supporters"; export { Supporters } from "./supporters/Supporters";

View File

@@ -0,0 +1,60 @@
import React, { useState, useEffect } from "react";
import { usePlugins } from "@logics_configs";
import styles from "./Plugins.module.scss";
export const Plugins = () => {
return (
<div className={styles.container}>
<PluginDownloadContainer />
</div>
);
};
const PluginDownloadContainer = () => {
const [plugin_list, set_plugin_list] = useState([]);
const [download_progress, set_download_progress] = useState({});
const { downloadAndExtractPlugin } = usePlugins();
useEffect(() => {
// GitHub上のJSONファイルからプラグインリストを取得
const fetchPluginList = async () => {
try {
const response = await fetch(
"https://raw.githubusercontent.com/ShiinaSakamoto/vrct_plugins_list/main/vrct_plugins_list.json"
);
if (!response.ok) {
throw new Error("Failed to fetch plugin list");
}
const data = await response.json();
set_plugin_list(data);
} catch (error) {
console.error("Error fetching plugin list:", error);
}
};
fetchPluginList();
}, []);
const handleDownload = async (plugin) => {
await downloadAndExtractPlugin(plugin);
};
return (
<div>
{plugin_list.map((plugin) => (
<div key={plugin.plugin_id}>
<h3>{plugin.title}</h3>
<button onClick={() => handleDownload(plugin)}>
Download and Load Plugin
</button>
{download_progress[plugin.plugin_id] !== undefined && (
<div>
Download Progress: {download_progress[plugin.plugin_id].toFixed(0)}%
</div>
)}
</div>
))}
</div>
);
};

View File

@@ -0,0 +1,5 @@
.container {
display: flex;
gap: 6.4rem;
flex-direction: column;
}

View File

@@ -12,6 +12,7 @@ export const SidebarSection = () => {
<Tab tab_id="vr" /> <Tab tab_id="vr" />
<Tab tab_id="others" /> <Tab tab_id="others" />
<Tab tab_id="hotkeys" /> <Tab tab_id="hotkeys" />
<Tab tab_id="plugins" />
<Tab tab_id="advanced_settings" /> <Tab tab_id="advanced_settings" />
</div> </div>
<div className={styles.separated_tabs_wrapper}> <div className={styles.separated_tabs_wrapper}>

View File

@@ -9,12 +9,16 @@ import { useStore_IsOpenedLanguageSelector } from "@store";
import { useLanguageSettings } from "@logics_main"; import { useLanguageSettings } from "@logics_main";
import { useEffect } from "react"; import { useEffect } from "react";
import { SubtitleSystemContainer } from "./subtitle_system_container/SubtitleSystemContainer"; import { SubtitleSystemContainer } from "./subtitle_system_container/SubtitleSystemContainer";
import { PluginHost } from "./PluginHost";
export const MainSection = () => { export const MainSection = () => {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<TopBar /> <TopBar />
<SubtitleSystemContainer /> {/* <SubtitleSystemContainer /> */}
<PluginHost />
{/* <MessageContainer /> */} {/* <MessageContainer /> */}
<HandleLanguageSelector /> <HandleLanguageSelector />
</div> </div>

View File

@@ -0,0 +1,20 @@
// PluginHost.jsx
import React from "react";
import { useStore_LoadedPluginsList } from "@store";
// export const PluginHost = ({ location }) => {
export const PluginHost = () => {
const { currentLoadedPluginsList } = useStore_LoadedPluginsList();
console.log(currentLoadedPluginsList.data);
return (
<div>
{currentLoadedPluginsList.data
.filter((plugin) => plugin.location === "main_section")
.map((plugin, index) => {
const PluginComponent = plugin.component;
return PluginComponent ? <PluginComponent key={index} /> : null;
})}
</div>
);
};

View File

@@ -60,6 +60,8 @@ export { useOscPort } from "./advanced_settings/useOscPort";
export { useSupporters } from "./supporters/useSupporters"; export { useSupporters } from "./supporters/useSupporters";
export { usePlugins } from "./plugins/usePlugins";
export { useSettingBoxScrollPosition } from "./useSettingBoxScrollPosition"; export { useSettingBoxScrollPosition } from "./useSettingBoxScrollPosition";
export { useSoftwareVersion } from "./useSoftwareVersion"; export { useSoftwareVersion } from "./useSoftwareVersion";

View File

@@ -0,0 +1,190 @@
import { invoke } from '@tauri-apps/api/tauri';
import { createAtomWithHook, useStore_LoadedPluginsList } from "@store";
import { transform } from "@babel/standalone";
import { writeFile, createDir, exists, readDir, BaseDirectory, readTextFile } from "@tauri-apps/api/fs";
const dev_plugin_mapping = import.meta.glob("/src-tauri/plugins/**/index.jsx", { eager: true });
import JSZip from "jszip";
import { fetch as tauriFetch, ResponseType } from "@tauri-apps/api/http";
export const usePlugins = () => {
const { updateLoadedPluginsList } = useStore_LoadedPluginsList();
const plugin_context = {
registerComponent: ({ plugin_id, location, component }) => {
if (!plugin_id || !location || !component) {
return console.error("An invalid plugin was detected.", plugin_id, location, component);
}
updateLoadedPluginsList((prev) => {
const filtered = prev.data.filter(item => item.plugin_id !== plugin_id);
return [...filtered, { plugin_id, location, component }];
});
},
createAtomWithHook: (...args) => createAtomWithHook(...args)
};
const asyncLoadPlugin = async (plugin_relative_path) => {
plugin_relative_path = "plugins/" + plugin_relative_path;
console.log("plugin_relative_path",plugin_relative_path);
try {
const plugin_code = await readTextFile(plugin_relative_path, { dir: BaseDirectory.Resource, recursive: true });
const cleanedCode = removeImportStatements(plugin_code);
const transpiled_code = transform(cleanedCode, {
presets: [
["env", { modules: false }],
"react"
],
sourceType: "module"
}).code;
const blob = new Blob([transpiled_code], { type: "text/javascript" });
const blob_url = URL.createObjectURL(blob);
const plugin_module = await import(/* @vite-ignore */ blob_url);
URL.revokeObjectURL(blob_url);
if (plugin_module && plugin_module.init) {
plugin_module.init(plugin_context);
}
} catch (error) {
console.error("Failed to load plugin from", plugin_relative_path, error);
}
};
const loadAllPlugins = async () => {
if (import.meta.env.DEV) {
// ホットリロード対応 src-tauri以下にあるpluginsディレクトリから直接読み込み開発用
Object.entries(dev_plugin_mapping).forEach(([key, plugin_module]) => {
console.log(plugin_module);
if (plugin_module && plugin_module.init) {
plugin_module.init(plugin_context);
}
});
} else {
try {
const plugin_files = await readDir("plugins", { dir: BaseDirectory.Resource, recursive: true });
for (const target_dir of plugin_files) {
console.log(target_dir);
const target_path = target_dir.name + "\\index.jsx";
await asyncLoadPlugin(target_path, plugin_context);
}
} catch (error) {
console.error("Error loading plugins:", error);
}
}
};
const downloadAndExtractPlugin = async (plugin) => {
try {
const plugin_zip_url = await fetchLatestPluginZipUrl(plugin);
console.log("Latest plugin zip URL:", plugin_zip_url);
// Rust コマンド経由で zip をダウンロード
const base64Zip = await invoke("download_zip_asset", { url: plugin_zip_url });
// base64Zip は文字列なので、デコードして Uint8Array に変換
const binaryString = atob(base64Zip);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
// JSZip で zip を解凍
const zip = await JSZip.loadAsync(bytes);
// const plugin_dir_exists = await exists("plugins", { dir: BaseDirectory.Resource, recursive: true });
await createDir("plugins/" + plugin.asset_name.replace(".zip", ""), { dir: BaseDirectory.Resource, recursive: true });
// if (!plugin_dir_exists) {
// }
const target_plugin_path = "plugins/" + plugin.asset_name.replace(".zip", "");
const filePromises = [];
zip.forEach((relativePath, zipEntry) => {
// .git 以下のファイルはスキップ
if (relativePath.startsWith(".git") || relativePath.includes("/.git/")) {
// console.log("Skipping .git file: " + relativePath);
return;
}
const filePath = target_plugin_path + "/" + relativePath;
if (zipEntry.dir) {
// フォルダの場合、ディレクトリを作成
filePromises.push(
createDir(filePath, { dir: BaseDirectory.Resource, recursive: true }).catch((err) => {
console.log(err);
if (!err.message?.includes("already exists")) {
console.error("Failed to create directory:", filePath, err);
}
})
);
} else {
// ファイルの場合、ディレクトリを作成してから書き込む
const dirPath = filePath.substring(0, filePath.lastIndexOf("/")); // 親ディレクトリのパス
const promise = createDir(dirPath, { dir: BaseDirectory.Resource, recursive: true })
.catch((err) => {
if (!err.message?.includes("already exists")) {
console.error("Failed to create parent directory:", dirPath, err);
}
})
.then(() => zipEntry.async("text"))
.then(async (fileData) => {
await writeFile(filePath, fileData, { dir: BaseDirectory.Resource, recursive: true });
});
filePromises.push(promise);
}
});
await Promise.all(filePromises);
console.log("Plugin downloaded successfully.");
const index_file_relative_path = plugin.asset_name.replace(".zip", "") + "/" + "index.jsx"
console.log("index_file_relative_path", index_file_relative_path);
await asyncLoadPlugin(index_file_relative_path);
console.log("Plugin loaded successfully.");
} catch (error) {
console.error("Error downloading and extracting plugin:", error);
}
};
// JSON内のURLから GitHub API を使って最新リリース情報を取得し、
// assets 配列から plugin.asset_name に一致するアセットの browser_download_url を返す
const fetchLatestPluginZipUrl = async (plugin) => {
const api_url = plugin.url;
const response = await tauriFetch(api_url, {
method: "GET",
responseType: ResponseType.Json,
headers: {
"Accept": "application/vnd.github+json",
"User-Agent": "VRCTPluginApp"
}
});
if (response.status !== 200) {
throw new Error("Failed to fetch latest release info, status: " + response.status);
}
const release_info = response.data;
const asset = release_info.assets.find((a) => a.name === plugin.asset_name);
if (!asset) {
throw new Error(`Asset ${plugin.asset_name} not found in the latest release`);
}
return asset.browser_download_url;
};
return {
loadAllPlugins,
downloadAndExtractPlugin,
};
};
const removeImportStatements = (code) => {
return code
.split("\n")
.filter(line => !line.match(/^import\s+.*['"]react['"]/))
.join("\n");
};

View File

@@ -34,7 +34,7 @@ const generatePropertyNames = (base_name) => ({
}); });
const createAtomWithHook = (initialValue, base_name, options) => { export const createAtomWithHook = (initialValue, base_name, options) => {
const property_names = generatePropertyNames(base_name); const property_names = generatePropertyNames(base_name);
const atomInstance = atom({ const atomInstance = atom({
state: (options?.is_state_ok) ? "ok" : "pending", state: (options?.is_state_ok) ? "ok" : "pending",
@@ -274,6 +274,10 @@ export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createA
toggle_transcription_receive: null, toggle_transcription_receive: null,
}, "Hotkeys"); }, "Hotkeys");
// Plugins
export const { atomInstance: Atom_InstalledPluginsPath, useHook: useStore_InstalledPluginsPath } = createAtomWithHook([], "InstalledPluginsPath");
export const { atomInstance: Atom_LoadedPluginsList, useHook: useStore_LoadedPluginsList } = createAtomWithHook([], "LoadedPluginsList");
// Advanced Settings // Advanced Settings
export const { atomInstance: Atom_OscIpAddress, useHook: useStore_OscIpAddress } = createAtomWithHook("127.0.0.1", "OscIpAddress"); export const { atomInstance: Atom_OscIpAddress, useHook: useStore_OscIpAddress } = createAtomWithHook("127.0.0.1", "OscIpAddress");
export const { atomInstance: Atom_OscPort, useHook: useStore_OscPort } = createAtomWithHook("9000", "OscPort"); export const { atomInstance: Atom_OscPort, useHook: useStore_OscPort } = createAtomWithHook("9000", "OscPort");