mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-22 01:47:39 -07:00
[backend] Remove nsfw detection / tensorflow
This commit is contained in:
parent
6b45b7019c
commit
5c7a663320
93 changed files with 73 additions and 2544 deletions
BIN
.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.9-7ef8e73557-1b9c4c87a6.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.9-7ef8e73557-1b9c4c87a6.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@nsfw-filter-gif-frames-npm-1.0.2-38d9beaa21-1da5be8751.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@nsfw-filter-gif-frames-npm-1.0.2-38d9beaa21-1da5be8751.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@nsfw-filter-save-pixels-npm-2.3.4-bc58c7088f-3d8f8ba370.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@nsfw-filter-save-pixels-npm-2.3.4-bc58c7088f-3d8f8ba370.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-backend-cpu-npm-3.21.0-3b1ad6ef49-0c2d7ae1ba.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-backend-cpu-npm-3.21.0-3b1ad6ef49-0c2d7ae1ba.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-backend-cpu-npm-4.9.0-b2c383ebb4-a85f21c132.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-backend-cpu-npm-4.9.0-b2c383ebb4-a85f21c132.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-backend-webgl-npm-3.21.0-1869be8b43-e857fcdb52.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-backend-webgl-npm-3.21.0-1869be8b43-e857fcdb52.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-backend-webgl-npm-4.9.0-20855a82df-a210885ffa.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-backend-webgl-npm-4.9.0-20855a82df-a210885ffa.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-converter-npm-3.21.0-d1a52c5cb8-b31e010f53.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-converter-npm-3.21.0-d1a52c5cb8-b31e010f53.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-converter-npm-4.9.0-53ae2c5e42-9685823165.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-converter-npm-4.9.0-53ae2c5e42-9685823165.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-core-npm-3.21.0-55e687f48d-58a6686662.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-core-npm-3.21.0-55e687f48d-58a6686662.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-core-npm-4.9.0-0230dde1f0-973d4f2193.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-core-npm-4.9.0-0230dde1f0-973d4f2193.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-data-npm-3.21.0-3dcd30b900-ac54f4e6f7.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-data-npm-3.21.0-3dcd30b900-ac54f4e6f7.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-data-npm-4.9.0-edf807b6e3-49420730c9.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-data-npm-4.9.0-edf807b6e3-49420730c9.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-layers-npm-3.21.0-2bd44d0d44-73d1e9dcb5.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-layers-npm-3.21.0-2bd44d0d44-73d1e9dcb5.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-layers-npm-4.9.0-caa8082ef7-186983b32b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-layers-npm-4.9.0-caa8082ef7-186983b32b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-node-npm-3.21.1-eddf4f4a47-39289653e0.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-node-npm-3.21.1-eddf4f4a47-39289653e0.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-npm-3.21.0-fc5d555cf7-712d0acb8a.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-npm-3.21.0-fc5d555cf7-712d0acb8a.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@tensorflow-tfjs-npm-4.9.0-99af600b5f-3f786ba433.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@tensorflow-tfjs-npm-4.9.0-99af600b5f-3f786ba433.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-long-npm-4.0.2-e7bdc00dd4-d16cde7240.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-long-npm-4.0.2-e7bdc00dd4-d16cde7240.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-node-fetch-npm-2.6.4-3e5a54c325-f3e1d881bb.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-node-fetch-npm-2.6.4-3e5a54c325-f3e1d881bb.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-offscreencanvas-npm-2019.3.0-5d5329705c-006361d170.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-offscreencanvas-npm-2019.3.0-5d5329705c-006361d170.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-offscreencanvas-npm-2019.7.0-c691495e16-018cfcd19e.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-offscreencanvas-npm-2019.7.0-c691495e16-018cfcd19e.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-seedrandom-npm-2.4.30-2dd47adb4c-1bcf634bb0.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-seedrandom-npm-2.4.30-2dd47adb4c-1bcf634bb0.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-webgl-ext-npm-0.0.30-198c76ab05-c98aa8af2d.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-webgl-ext-npm-0.0.30-198c76ab05-c98aa8af2d.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@types-webgl2-npm-0.0.6-1a6b507373-32a6ff4088.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@types-webgl2-npm-0.0.6-1a6b507373-32a6ff4088.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@webgpu-types-npm-0.1.16-58c22d069b-550732f427.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@webgpu-types-npm-0.1.16-58c22d069b-550732f427.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/@webgpu-types-npm-0.1.30-bbd4b8862a-c07516879c.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/@webgpu-types-npm-0.1.30-bbd4b8862a-c07516879c.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/agent-base-npm-4.3.0-48c7e81d60-0c10891060.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/agent-base-npm-4.3.0-48c7e81d60-0c10891060.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/core-js-npm-3.29.1-baa30db121-b38446dbfc.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/core-js-npm-3.29.1-baa30db121-b38446dbfc.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/cwise-compiler-npm-1.1.3-26ff483afd-6c8ed75ad5.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/cwise-compiler-npm-1.1.3-26ff483afd-6c8ed75ad5.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/data-uri-to-buffer-npm-0.0.3-b26974551a-c85bc1e278.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/data-uri-to-buffer-npm-0.0.3-b26974551a-c85bc1e278.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/es6-promise-npm-4.2.8-c9f5b11f66-95614a8887.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/es6-promise-npm-4.2.8-c9f5b11f66-95614a8887.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/es6-promisify-npm-5.0.0-3726550934-fbed9d7915.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/es6-promisify-npm-5.0.0-3726550934-fbed9d7915.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/fs-minipass-npm-1.2.7-0e18342ce1-40fd46a2b5.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/fs-minipass-npm-1.2.7-0e18342ce1-40fd46a2b5.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/get-pixels-frame-info-update-npm-3.3.2-9a479a0deb-d32e0772d1.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/get-pixels-frame-info-update-npm-3.3.2-9a479a0deb-d32e0772d1.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/gif-encoder-npm-0.4.1-e3fef33f8c-36dabe29f8.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/gif-encoder-npm-0.4.1-e3fef33f8c-36dabe29f8.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-3caa2e1e26.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-3caa2e1e26.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/har-schema-npm-2.0.0-3a318c0ca5-d8946348f3.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/har-schema-npm-2.0.0-3a318c0ca5-d8946348f3.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/har-validator-npm-5.1.5-bd9ac162f5-b998a7269c.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/har-validator-npm-5.1.5-bd9ac162f5-b998a7269c.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/http-signature-npm-1.2.0-ee92426f34-3324598712.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/http-signature-npm-1.2.0-ee92426f34-3324598712.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/https-proxy-agent-npm-2.2.4-8bb97bed48-5fa8eab256.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/https-proxy-agent-npm-2.2.4-8bb97bed48-5fa8eab256.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/iota-array-npm-1.0.0-d8061f3372-e537c236d9.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/iota-array-npm-1.0.0-d8061f3372-e537c236d9.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/isarray-npm-0.0.1-92e37e0a70-49191f1425.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/isarray-npm-0.0.1-92e37e0a70-49191f1425.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/jpeg-js-npm-0.3.7-fe3ece5658-85a1ab09fe.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/jpeg-js-npm-0.3.7-fe3ece5658-85a1ab09fe.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/long-npm-4.0.0-ecd96a31ed-16afbe8f74.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/long-npm-4.0.0-ecd96a31ed-16afbe8f74.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/minipass-npm-2.9.0-6335fbe4af-077b66f31b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/minipass-npm-2.9.0-6335fbe4af-077b66f31b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/minizlib-npm-1.3.3-b590e5bfb8-b0425c04d2.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/minizlib-npm-1.3.3-b590e5bfb8-b0425c04d2.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/multi-integer-range-npm-3.0.0-b72c939d45-ce4b57c060.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/multi-integer-range-npm-3.0.0-b72c939d45-ce4b57c060.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/ndarray-npm-1.0.18-0841bb9e2d-e4d442c9e8.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/ndarray-npm-1.0.18-0841bb9e2d-e4d442c9e8.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/ndarray-npm-1.0.19-d03b8fa8ef-2f8ac89f0b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/ndarray-npm-1.0.19-d03b8fa8ef-2f8ac89f0b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/ndarray-ops-npm-1.2.2-cd8205bd47-6d4f81bd37.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/ndarray-ops-npm-1.2.2-cd8205bd47-6d4f81bd37.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/ndarray-pack-npm-1.2.1-9765c7e13c-455030bebc.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/ndarray-pack-npm-1.2.1-9765c7e13c-455030bebc.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/node-bitmap-npm-0.0.1-df1ff3aae0-4e30bbd22e.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/node-bitmap-npm-0.0.1-df1ff3aae0-4e30bbd22e.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/nsfwjs-npm-2.4.2-5f987f8b7e-a66a78caaa.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/nsfwjs-npm-2.4.2-5f987f8b7e-a66a78caaa.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/oauth-sign-npm-0.9.0-7aa9422221-8f5497a127.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/oauth-sign-npm-0.9.0-7aa9422221-8f5497a127.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/omggif-npm-1.0.10-6ffa5bf343-15102e46b6.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/omggif-npm-1.0.10-6ffa5bf343-15102e46b6.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/parse-data-uri-npm-0.2.0-d70e3f0b43-6e8d76eb4b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/parse-data-uri-npm-0.2.0-d70e3f0b43-6e8d76eb4b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/pngjs-nozlib-npm-1.0.0-1c99b27261-63dd1425fe.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/pngjs-nozlib-npm-1.0.0-1c99b27261-63dd1425fe.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/progress-npm-2.0.3-d1f87e2ac6-f67403fe7b.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/progress-npm-2.0.3-d1f87e2ac6-f67403fe7b.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/qs-npm-6.5.3-90b2635484-6f20bf08ca.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/qs-npm-6.5.3-90b2635484-6f20bf08ca.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/readable-stream-npm-1.1.14-41e61d1768-17dfeae3e9.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/readable-stream-npm-1.1.14-41e61d1768-17dfeae3e9.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/request-npm-2.88.2-f4a57c72c4-4e112c087f.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/request-npm-2.88.2-f4a57c72c4-4e112c087f.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/rimraf-npm-2.7.1-9a71f3cc37-cdc7f6eacb.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/rimraf-npm-2.7.1-9a71f3cc37-cdc7f6eacb.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/string_decoder-npm-0.10.31-851f3f7302-fe00f8e303.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/string_decoder-npm-0.10.31-851f3f7302-fe00f8e303.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/tar-npm-4.4.19-5f8e81b87e-423c8259b1.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/tar-npm-4.4.19-5f8e81b87e-423c8259b1.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/through-npm-2.3.4-eb93babff1-bab392560a.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/through-npm-2.3.4-eb93babff1-bab392560a.zip
(Stored with Git LFS)
vendored
Binary file not shown.
BIN
.yarn/cache/uuid-npm-3.4.0-4fd8ef88ad-58de2feed6.zip
(Stored with Git LFS)
vendored
BIN
.yarn/cache/uuid-npm-3.4.0-4fd8ef88ad-58de2feed6.zip
(Stored with Git LFS)
vendored
Binary file not shown.
|
@ -44,7 +44,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/api": "5.6.0",
|
"@bull-board/api": "5.6.0",
|
||||||
"@bull-board/ui": "5.6.0",
|
"@bull-board/ui": "5.6.0",
|
||||||
"@tensorflow/tfjs": "^3.21.0",
|
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"seedrandom": "^3.0.5"
|
"seedrandom": "^3.0.5"
|
||||||
},
|
},
|
||||||
|
|
BIN
packages/backend/nsfw-model/group1-shard1of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard1of6
(Stored with Git LFS)
Binary file not shown.
BIN
packages/backend/nsfw-model/group1-shard2of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard2of6
(Stored with Git LFS)
Binary file not shown.
BIN
packages/backend/nsfw-model/group1-shard3of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard3of6
(Stored with Git LFS)
Binary file not shown.
BIN
packages/backend/nsfw-model/group1-shard4of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard4of6
(Stored with Git LFS)
Binary file not shown.
BIN
packages/backend/nsfw-model/group1-shard5of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard5of6
(Stored with Git LFS)
Binary file not shown.
BIN
packages/backend/nsfw-model/group1-shard6of6
(Stored with Git LFS)
BIN
packages/backend/nsfw-model/group1-shard6of6
(Stored with Git LFS)
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -19,7 +19,6 @@
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@tensorflow/tfjs-node": "3.21.1",
|
|
||||||
"@types/formidable": "^2.0.5"
|
"@types/formidable": "^2.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -36,9 +35,6 @@
|
||||||
"@redocly/openapi-core": "1.0.0-beta.131",
|
"@redocly/openapi-core": "1.0.0-beta.131",
|
||||||
"@sinonjs/fake-timers": "9.1.2",
|
"@sinonjs/fake-timers": "9.1.2",
|
||||||
"@syuilo/aiscript": "0.11.1",
|
"@syuilo/aiscript": "0.11.1",
|
||||||
"@tensorflow/tfjs": "^4.2.0",
|
|
||||||
"@tensorflow/tfjs-backend-webgl": "^4.2.0",
|
|
||||||
"@tensorflow/tfjs-core": "^4.2.0",
|
|
||||||
"adm-zip": "^0.5.10",
|
"adm-zip": "^0.5.10",
|
||||||
"ajv": "8.12.0",
|
"ajv": "8.12.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
|
@ -98,7 +94,6 @@
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.1",
|
"node-fetch": "3.3.1",
|
||||||
"nodemailer": "6.9.3",
|
"nodemailer": "6.9.3",
|
||||||
"nsfwjs": "2.4.2",
|
|
||||||
"oauth": "^0.10.0",
|
"oauth": "^0.10.0",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "^9.1.3",
|
"otpauth": "^9.1.3",
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class RemoteNsfwDetection1697663824168 implements MigrationInterface {
|
||||||
|
name = 'RemoteNsfwDetection1697663824168'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_3b33dff77bb64b23c88151d23e"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_8bdcd3dd2bddb78014999a16ce"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "maybeSensitive"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "maybePorn"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveMediaDetection"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."meta_sensitivemediadetection_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sensitiveMediaDetectionSensitivity"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."meta_sensitivemediadetectionsensitivity_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "setSensitiveFlagAutomatically"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableSensitiveMediaDetectionForVideos"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "autoSensitive"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ADD "autoSensitive" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "enableSensitiveMediaDetectionForVideos" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "setSensitiveFlagAutomatically" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."meta_sensitivemediadetectionsensitivity_enum" AS ENUM('medium', 'low', 'high', 'veryLow', 'veryHigh')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveMediaDetectionSensitivity" "public"."meta_sensitivemediadetectionsensitivity_enum" NOT NULL DEFAULT 'medium'`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."meta_sensitivemediadetection_enum" AS ENUM('none', 'all', 'local', 'remote')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "sensitiveMediaDetection" "public"."meta_sensitivemediadetection_enum" NOT NULL DEFAULT 'none'`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "drive_file" ADD "maybePorn" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "drive_file" ADD "maybeSensitive" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_8bdcd3dd2bddb78014999a16ce" ON "drive_file" ("maybePorn") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_3b33dff77bb64b23c88151d23e" ON "drive_file" ("maybeSensitive") `);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,12 @@
|
||||||
import * as fs from "node:fs";
|
import * as fs from "node:fs";
|
||||||
import * as crypto from "node:crypto";
|
import * as crypto from "node:crypto";
|
||||||
import { join } from "node:path";
|
|
||||||
import * as stream from "node:stream";
|
import * as stream from "node:stream";
|
||||||
import * as util from "node:util";
|
import * as util from "node:util";
|
||||||
import { FSWatcher } from "chokidar";
|
|
||||||
import { fileTypeFromFile } from "file-type";
|
import { fileTypeFromFile } from "file-type";
|
||||||
import probeImageSize from "probe-image-size";
|
import probeImageSize from "probe-image-size";
|
||||||
import FFmpeg from "fluent-ffmpeg";
|
|
||||||
import isSvg from "is-svg";
|
import isSvg from "is-svg";
|
||||||
import { type predictionType } from "nsfwjs";
|
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { encode } from "blurhash";
|
import { encode } from "blurhash";
|
||||||
import { detectSensitive } from "@/services/detect-sensitive.js";
|
|
||||||
import { createTempDir } from "./create-temp.js";
|
|
||||||
|
|
||||||
const pipeline = util.promisify(stream.pipeline);
|
const pipeline = util.promisify(stream.pipeline);
|
||||||
|
|
||||||
|
@ -27,8 +21,6 @@ export type FileInfo = {
|
||||||
height?: number;
|
height?: number;
|
||||||
orientation?: number;
|
orientation?: number;
|
||||||
blurhash?: string;
|
blurhash?: string;
|
||||||
sensitive: boolean;
|
|
||||||
porn: boolean;
|
|
||||||
warnings: string[];
|
warnings: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,12 +39,6 @@ const TYPE_SVG = {
|
||||||
*/
|
*/
|
||||||
export async function getFileInfo(
|
export async function getFileInfo(
|
||||||
path: string,
|
path: string,
|
||||||
opts: {
|
|
||||||
skipSensitiveDetection: boolean;
|
|
||||||
sensitiveThreshold?: number;
|
|
||||||
sensitiveThresholdForPorn?: number;
|
|
||||||
enableSensitiveMediaDetectionForVideos?: boolean;
|
|
||||||
},
|
|
||||||
): Promise<FileInfo> {
|
): Promise<FileInfo> {
|
||||||
const warnings = [] as string[];
|
const warnings = [] as string[];
|
||||||
|
|
||||||
|
@ -123,26 +109,6 @@ export async function getFileInfo(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let sensitive = false;
|
|
||||||
let porn = false;
|
|
||||||
|
|
||||||
if (!opts.skipSensitiveDetection) {
|
|
||||||
await detectSensitivity(
|
|
||||||
path,
|
|
||||||
type.mime,
|
|
||||||
opts.sensitiveThreshold ?? 0.5,
|
|
||||||
opts.sensitiveThresholdForPorn ?? 0.75,
|
|
||||||
opts.enableSensitiveMediaDetectionForVideos ?? false,
|
|
||||||
).then(
|
|
||||||
(value) => {
|
|
||||||
[sensitive, porn] = value;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
warnings.push(`detectSensitivity failed: ${error}`);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
size,
|
size,
|
||||||
md5,
|
md5,
|
||||||
|
@ -151,183 +117,10 @@ export async function getFileInfo(
|
||||||
height,
|
height,
|
||||||
orientation,
|
orientation,
|
||||||
blurhash,
|
blurhash,
|
||||||
sensitive,
|
|
||||||
porn,
|
|
||||||
warnings,
|
warnings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function detectSensitivity(
|
|
||||||
source: string,
|
|
||||||
mime: string,
|
|
||||||
sensitiveThreshold: number,
|
|
||||||
sensitiveThresholdForPorn: number,
|
|
||||||
analyzeVideo: boolean,
|
|
||||||
): Promise<[sensitive: boolean, porn: boolean]> {
|
|
||||||
let sensitive = false;
|
|
||||||
let porn = false;
|
|
||||||
|
|
||||||
function judgePrediction(
|
|
||||||
result: readonly predictionType[],
|
|
||||||
): [sensitive: boolean, porn: boolean] {
|
|
||||||
let sensitive = false;
|
|
||||||
let porn = false;
|
|
||||||
|
|
||||||
if (
|
|
||||||
(result.find((x) => x.className === "Sexy")?.probability ?? 0) >
|
|
||||||
sensitiveThreshold
|
|
||||||
)
|
|
||||||
sensitive = true;
|
|
||||||
if (
|
|
||||||
(result.find((x) => x.className === "Hentai")?.probability ?? 0) >
|
|
||||||
sensitiveThreshold
|
|
||||||
)
|
|
||||||
sensitive = true;
|
|
||||||
if (
|
|
||||||
(result.find((x) => x.className === "Porn")?.probability ?? 0) >
|
|
||||||
sensitiveThreshold
|
|
||||||
)
|
|
||||||
sensitive = true;
|
|
||||||
|
|
||||||
if (
|
|
||||||
(result.find((x) => x.className === "Porn")?.probability ?? 0) >
|
|
||||||
sensitiveThresholdForPorn
|
|
||||||
)
|
|
||||||
porn = true;
|
|
||||||
|
|
||||||
return [sensitive, porn];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (["image/jpeg", "image/png", "image/webp"].includes(mime)) {
|
|
||||||
const result = await detectSensitive(source);
|
|
||||||
if (result) {
|
|
||||||
[sensitive, porn] = judgePrediction(result);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
analyzeVideo &&
|
|
||||||
(mime === "image/apng" || mime.startsWith("video/"))
|
|
||||||
) {
|
|
||||||
const [outDir, disposeOutDir] = await createTempDir();
|
|
||||||
try {
|
|
||||||
const command = FFmpeg()
|
|
||||||
.input(source)
|
|
||||||
.inputOptions([
|
|
||||||
"-skip_frame",
|
|
||||||
"nokey", // 可能ならキーフレームのみを取得してほしいとする(そうなるとは限らない)
|
|
||||||
"-lowres",
|
|
||||||
"3", // 元の画質でデコードする必要はないので 1/8 画質でデコードしてもよいとする(そうなるとは限らない)
|
|
||||||
])
|
|
||||||
.noAudio()
|
|
||||||
.videoFilters([
|
|
||||||
{
|
|
||||||
filter: "select", // フレームのフィルタリング
|
|
||||||
options: {
|
|
||||||
e: "eq(pict_type,PICT_TYPE_I)", // I-Frame のみをフィルタする(VP9 とかはデコードしてみないとわからないっぽい)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filter: "blackframe", // 暗いフレームの検出
|
|
||||||
options: {
|
|
||||||
amount: "0", // 暗さに関わらず全てのフレームで測定値を取る
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filter: "metadata",
|
|
||||||
options: {
|
|
||||||
mode: "select", // フレーム選択モード
|
|
||||||
key: "lavfi.blackframe.pblack", // フレームにおける暗部の百分率(前のフィルタからのメタデータを参照する)
|
|
||||||
value: "50",
|
|
||||||
function: "less", // 50% 未満のフレームを選択する(50% 以上暗部があるフレームだと誤検知を招くかもしれないので)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
filter: "scale",
|
|
||||||
options: {
|
|
||||||
w: 299,
|
|
||||||
h: 299,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.format("image2")
|
|
||||||
.output(join(outDir, "%d.png"))
|
|
||||||
.outputOptions(["-vsync", "0"]); // 可変フレームレートにすることで穴埋めをさせない
|
|
||||||
const results: ReturnType<typeof judgePrediction>[] = [];
|
|
||||||
let frameIndex = 0;
|
|
||||||
let targetIndex = 0;
|
|
||||||
let nextIndex = 1;
|
|
||||||
for await (const path of asyncIterateFrames(outDir, command)) {
|
|
||||||
try {
|
|
||||||
const index = frameIndex++;
|
|
||||||
if (index !== targetIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
targetIndex = nextIndex;
|
|
||||||
nextIndex += index; // fibonacci sequence によってフレーム数制限を掛ける
|
|
||||||
const result = await detectSensitive(path);
|
|
||||||
if (result) {
|
|
||||||
results.push(judgePrediction(result));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
fs.promises.unlink(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sensitive =
|
|
||||||
results.filter((x) => x[0]).length >=
|
|
||||||
Math.ceil(results.length * sensitiveThreshold);
|
|
||||||
porn =
|
|
||||||
results.filter((x) => x[1]).length >=
|
|
||||||
Math.ceil(results.length * sensitiveThresholdForPorn);
|
|
||||||
} finally {
|
|
||||||
disposeOutDir();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [sensitive, porn];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function* asyncIterateFrames(
|
|
||||||
cwd: string,
|
|
||||||
command: FFmpeg.FfmpegCommand,
|
|
||||||
): AsyncGenerator<string, void> {
|
|
||||||
const watcher = new FSWatcher({
|
|
||||||
cwd,
|
|
||||||
disableGlobbing: true,
|
|
||||||
});
|
|
||||||
let finished = false;
|
|
||||||
command.once("end", () => {
|
|
||||||
finished = true;
|
|
||||||
watcher.close();
|
|
||||||
});
|
|
||||||
command.run();
|
|
||||||
for (let i = 1; true; i++) {
|
|
||||||
const current = `${i}.png`;
|
|
||||||
const next = `${i + 1}.png`;
|
|
||||||
const framePath = join(cwd, current);
|
|
||||||
if (await exists(join(cwd, next))) {
|
|
||||||
yield framePath;
|
|
||||||
} else if (!finished) {
|
|
||||||
watcher.add(next);
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
watcher.on("add", function onAdd(path) {
|
|
||||||
if (path === next) {
|
|
||||||
// 次フレームの書き出しが始まっているなら、現在フレームの書き出しは終わっている
|
|
||||||
watcher.unwatch(current);
|
|
||||||
watcher.off("add", onAdd);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
command.once("end", resolve); // 全てのフレームを処理し終わったなら、最終フレームである現在フレームの書き出しは終わっている
|
|
||||||
command.once("error", reject);
|
|
||||||
});
|
|
||||||
yield framePath;
|
|
||||||
} else if (await exists(framePath)) {
|
|
||||||
yield framePath;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function exists(path: string): Promise<boolean> {
|
function exists(path: string): Promise<boolean> {
|
||||||
return fs.promises.access(path).then(
|
return fs.promises.access(path).then(
|
||||||
() => true,
|
() => true,
|
||||||
|
|
|
@ -183,19 +183,6 @@ export class DriveFile {
|
||||||
})
|
})
|
||||||
public isSensitive: boolean;
|
public isSensitive: boolean;
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column("boolean", {
|
|
||||||
default: false,
|
|
||||||
comment: "Whether the DriveFile is NSFW. (predict)",
|
|
||||||
})
|
|
||||||
public maybeSensitive: boolean;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column("boolean", {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public maybePorn: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 外部の(信頼されていない)URLへの直リンクか否か
|
* 外部の(信頼されていない)URLへの直リンクか否か
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -253,33 +253,6 @@ export class Meta {
|
||||||
})
|
})
|
||||||
public recaptchaSecretKey: string | null;
|
public recaptchaSecretKey: string | null;
|
||||||
|
|
||||||
@Column("enum", {
|
|
||||||
enum: ["none", "all", "local", "remote"],
|
|
||||||
default: "none",
|
|
||||||
})
|
|
||||||
public sensitiveMediaDetection: "none" | "all" | "local" | "remote";
|
|
||||||
|
|
||||||
@Column("enum", {
|
|
||||||
enum: ["medium", "low", "high", "veryLow", "veryHigh"],
|
|
||||||
default: "medium",
|
|
||||||
})
|
|
||||||
public sensitiveMediaDetectionSensitivity:
|
|
||||||
| "medium"
|
|
||||||
| "low"
|
|
||||||
| "high"
|
|
||||||
| "veryLow"
|
|
||||||
| "veryHigh";
|
|
||||||
|
|
||||||
@Column("boolean", {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public setSensitiveFlagAutomatically: boolean;
|
|
||||||
|
|
||||||
@Column("boolean", {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public enableSensitiveMediaDetectionForVideos: boolean;
|
|
||||||
|
|
||||||
@Column("integer", {
|
@Column("integer", {
|
||||||
default: 1024,
|
default: 1024,
|
||||||
comment: "Drive capacity of a local user (MB)",
|
comment: "Drive capacity of a local user (MB)",
|
||||||
|
|
|
@ -182,11 +182,6 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public alwaysMarkNsfw: boolean;
|
public alwaysMarkNsfw: boolean;
|
||||||
|
|
||||||
@Column("boolean", {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public autoSensitive: boolean;
|
|
||||||
|
|
||||||
@Column("boolean", {
|
@Column("boolean", {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
|
@ -268,4 +263,4 @@ type IMentionedRemoteUsers = {
|
||||||
url?: string;
|
url?: string;
|
||||||
username: string;
|
username: string;
|
||||||
host: string;
|
host: string;
|
||||||
}[]
|
}[]
|
||||||
|
|
|
@ -539,7 +539,6 @@ export const UserRepository = db.getRepository(User).extend({
|
||||||
injectFeaturedNote: profile!.injectFeaturedNote,
|
injectFeaturedNote: profile!.injectFeaturedNote,
|
||||||
receiveAnnouncementEmail: profile!.receiveAnnouncementEmail,
|
receiveAnnouncementEmail: profile!.receiveAnnouncementEmail,
|
||||||
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
||||||
autoSensitive: profile!.autoSensitive,
|
|
||||||
carefulBot: profile!.carefulBot,
|
carefulBot: profile!.carefulBot,
|
||||||
autoAcceptFollowed: profile!.autoAcceptFollowed,
|
autoAcceptFollowed: profile!.autoAcceptFollowed,
|
||||||
noCrawle: profile!.noCrawle,
|
noCrawle: profile!.noCrawle,
|
||||||
|
|
|
@ -374,11 +374,6 @@ export const packedMeDetailedOnlySchema = {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
optional: false,
|
optional: false,
|
||||||
},
|
},
|
||||||
autoSensitive: {
|
|
||||||
type: "boolean",
|
|
||||||
nullable: true,
|
|
||||||
optional: false,
|
|
||||||
},
|
|
||||||
carefulBot: {
|
carefulBot: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -2,7 +2,6 @@ import config from "@/config/index.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
||||||
import define from "../../define.js";
|
import define from "../../define.js";
|
||||||
import { Exp } from "@tensorflow/tfjs";
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["meta"],
|
tags: ["meta"],
|
||||||
|
@ -266,26 +265,6 @@ export const meta = {
|
||||||
optional: true,
|
optional: true,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
},
|
},
|
||||||
sensitiveMediaDetection: {
|
|
||||||
type: "string",
|
|
||||||
optional: true,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
sensitiveMediaDetectionSensitivity: {
|
|
||||||
type: "string",
|
|
||||||
optional: true,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
setSensitiveFlagAutomatically: {
|
|
||||||
type: "boolean",
|
|
||||||
optional: true,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
enableSensitiveMediaDetectionForVideos: {
|
|
||||||
type: "boolean",
|
|
||||||
optional: true,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
proxyAccountId: {
|
proxyAccountId: {
|
||||||
type: "string",
|
type: "string",
|
||||||
optional: true,
|
optional: true,
|
||||||
|
@ -531,12 +510,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
secureMode: instance.secureMode,
|
secureMode: instance.secureMode,
|
||||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||||
recaptchaSecretKey: instance.recaptchaSecretKey,
|
recaptchaSecretKey: instance.recaptchaSecretKey,
|
||||||
sensitiveMediaDetection: instance.sensitiveMediaDetection,
|
|
||||||
sensitiveMediaDetectionSensitivity:
|
|
||||||
instance.sensitiveMediaDetectionSensitivity,
|
|
||||||
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
|
|
||||||
enableSensitiveMediaDetectionForVideos:
|
|
||||||
instance.enableSensitiveMediaDetectionForVideos,
|
|
||||||
proxyAccountId: instance.proxyAccountId,
|
proxyAccountId: instance.proxyAccountId,
|
||||||
twitterConsumerKey: instance.twitterConsumerKey,
|
twitterConsumerKey: instance.twitterConsumerKey,
|
||||||
twitterConsumerSecret: instance.twitterConsumerSecret,
|
twitterConsumerSecret: instance.twitterConsumerSecret,
|
||||||
|
|
|
@ -62,7 +62,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
noCrawle: profile.noCrawle,
|
noCrawle: profile.noCrawle,
|
||||||
preventAiLearning: profile.preventAiLearning,
|
preventAiLearning: profile.preventAiLearning,
|
||||||
alwaysMarkNsfw: profile.alwaysMarkNsfw,
|
alwaysMarkNsfw: profile.alwaysMarkNsfw,
|
||||||
autoSensitive: profile.autoSensitive,
|
|
||||||
carefulBot: profile.carefulBot,
|
carefulBot: profile.carefulBot,
|
||||||
injectFeaturedNote: profile.injectFeaturedNote,
|
injectFeaturedNote: profile.injectFeaturedNote,
|
||||||
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
|
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
|
||||||
|
|
|
@ -101,16 +101,6 @@ export const paramDef = {
|
||||||
enableRecaptcha: { type: "boolean" },
|
enableRecaptcha: { type: "boolean" },
|
||||||
recaptchaSiteKey: { type: "string", nullable: true },
|
recaptchaSiteKey: { type: "string", nullable: true },
|
||||||
recaptchaSecretKey: { type: "string", nullable: true },
|
recaptchaSecretKey: { type: "string", nullable: true },
|
||||||
sensitiveMediaDetection: {
|
|
||||||
type: "string",
|
|
||||||
enum: ["none", "all", "local", "remote"],
|
|
||||||
},
|
|
||||||
sensitiveMediaDetectionSensitivity: {
|
|
||||||
type: "string",
|
|
||||||
enum: ["medium", "low", "high", "veryLow", "veryHigh"],
|
|
||||||
},
|
|
||||||
setSensitiveFlagAutomatically: { type: "boolean" },
|
|
||||||
enableSensitiveMediaDetectionForVideos: { type: "boolean" },
|
|
||||||
proxyAccountId: { type: "string", format: "misskey:id", nullable: true },
|
proxyAccountId: { type: "string", format: "misskey:id", nullable: true },
|
||||||
maintainerName: { type: "string", nullable: true },
|
maintainerName: { type: "string", nullable: true },
|
||||||
maintainerEmail: { type: "string", nullable: true },
|
maintainerEmail: { type: "string", nullable: true },
|
||||||
|
@ -148,8 +138,6 @@ export const paramDef = {
|
||||||
smtpPort: { type: "integer", nullable: true },
|
smtpPort: { type: "integer", nullable: true },
|
||||||
smtpUser: { type: "string", nullable: true },
|
smtpUser: { type: "string", nullable: true },
|
||||||
smtpPass: { type: "string", nullable: true },
|
smtpPass: { type: "string", nullable: true },
|
||||||
swPublicKey: { type: "string", nullable: true },
|
|
||||||
swPrivateKey: { type: "string", nullable: true },
|
|
||||||
tosUrl: { type: "string", nullable: true },
|
tosUrl: { type: "string", nullable: true },
|
||||||
repositoryUrl: { type: "string" },
|
repositoryUrl: { type: "string" },
|
||||||
feedbackUrl: { type: "string" },
|
feedbackUrl: { type: "string" },
|
||||||
|
@ -348,24 +336,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
set.recaptchaSecretKey = ps.recaptchaSecretKey;
|
set.recaptchaSecretKey = ps.recaptchaSecretKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.sensitiveMediaDetection !== undefined) {
|
|
||||||
set.sensitiveMediaDetection = ps.sensitiveMediaDetection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.sensitiveMediaDetectionSensitivity !== undefined) {
|
|
||||||
set.sensitiveMediaDetectionSensitivity =
|
|
||||||
ps.sensitiveMediaDetectionSensitivity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.setSensitiveFlagAutomatically !== undefined) {
|
|
||||||
set.setSensitiveFlagAutomatically = ps.setSensitiveFlagAutomatically;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.enableSensitiveMediaDetectionForVideos !== undefined) {
|
|
||||||
set.enableSensitiveMediaDetectionForVideos =
|
|
||||||
ps.enableSensitiveMediaDetectionForVideos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.proxyAccountId !== undefined) {
|
if (ps.proxyAccountId !== undefined) {
|
||||||
set.proxyAccountId = ps.proxyAccountId;
|
set.proxyAccountId = ps.proxyAccountId;
|
||||||
}
|
}
|
||||||
|
@ -462,14 +432,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
set.errorImageUrl = ps.errorImageUrl;
|
set.errorImageUrl = ps.errorImageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.swPublicKey !== undefined) {
|
|
||||||
set.swPublicKey = ps.swPublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.swPrivateKey !== undefined) {
|
|
||||||
set.swPrivateKey = ps.swPrivateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.tosUrl !== undefined) {
|
if (ps.tosUrl !== undefined) {
|
||||||
set.ToSUrl = ps.tosUrl;
|
set.ToSUrl = ps.tosUrl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,6 @@ export const paramDef = {
|
||||||
injectFeaturedNote: { type: "boolean" },
|
injectFeaturedNote: { type: "boolean" },
|
||||||
receiveAnnouncementEmail: { type: "boolean" },
|
receiveAnnouncementEmail: { type: "boolean" },
|
||||||
alwaysMarkNsfw: { type: "boolean" },
|
alwaysMarkNsfw: { type: "boolean" },
|
||||||
autoSensitive: { type: "boolean" },
|
|
||||||
ffVisibility: { type: "string", enum: ["public", "followers", "private"] },
|
ffVisibility: { type: "string", enum: ["public", "followers", "private"] },
|
||||||
pinnedPageId: { type: "string", format: "misskey:id", nullable: true },
|
pinnedPageId: { type: "string", format: "misskey:id", nullable: true },
|
||||||
mutedWords: { type: "array" },
|
mutedWords: { type: "array" },
|
||||||
|
@ -213,8 +212,6 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
||||||
profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
||||||
if (typeof ps.alwaysMarkNsfw === "boolean")
|
if (typeof ps.alwaysMarkNsfw === "boolean")
|
||||||
profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
|
profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
|
||||||
if (typeof ps.autoSensitive === "boolean")
|
|
||||||
profileUpdates.autoSensitive = ps.autoSensitive;
|
|
||||||
if (ps.emailNotificationTypes !== undefined)
|
if (ps.emailNotificationTypes !== undefined)
|
||||||
profileUpdates.emailNotificationTypes = ps.emailNotificationTypes;
|
profileUpdates.emailNotificationTypes = ps.emailNotificationTypes;
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
import * as fs from "node:fs";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import { dirname } from "node:path";
|
|
||||||
import * as nsfw from "nsfwjs";
|
|
||||||
import si from "systeminformation";
|
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
|
||||||
const _dirname = dirname(_filename);
|
|
||||||
|
|
||||||
const REQUIRED_CPU_FLAGS = ["avx2", "fma"];
|
|
||||||
let isSupportedCpu: undefined | boolean = undefined;
|
|
||||||
|
|
||||||
let model: nsfw.NSFWJS;
|
|
||||||
|
|
||||||
export async function detectSensitive(
|
|
||||||
path: string,
|
|
||||||
): Promise<nsfw.predictionType[] | null> {
|
|
||||||
try {
|
|
||||||
if (isSupportedCpu === undefined) {
|
|
||||||
const cpuFlags = await getCpuFlags();
|
|
||||||
isSupportedCpu = REQUIRED_CPU_FLAGS.every((required) =>
|
|
||||||
cpuFlags.includes(required),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSupportedCpu) {
|
|
||||||
console.error("This CPU cannot use TensorFlow.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tf = await import("@tensorflow/tfjs-node");
|
|
||||||
|
|
||||||
if (model == null)
|
|
||||||
model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, {
|
|
||||||
size: 299,
|
|
||||||
});
|
|
||||||
|
|
||||||
const buffer = await fs.promises.readFile(path);
|
|
||||||
const image = (await tf.node.decodeImage(buffer, 3)) as any;
|
|
||||||
try {
|
|
||||||
const predictions = await model.classify(image);
|
|
||||||
return predictions;
|
|
||||||
} finally {
|
|
||||||
image.dispose();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getCpuFlags(): Promise<string[]> {
|
|
||||||
const str = await si.cpuFlags();
|
|
||||||
return str.split(/\s+/);
|
|
||||||
}
|
|
|
@ -396,7 +396,7 @@ async function expireOldFile(user: IRemoteUser, driveCapacity: number) {
|
||||||
|
|
||||||
for (const fileId of exceedFileIds) {
|
for (const fileId of exceedFileIds) {
|
||||||
const file = await DriveFiles.findOneBy({ id: fileId });
|
const file = await DriveFiles.findOneBy({ id: fileId });
|
||||||
deleteFile(file, true);
|
if (file) deleteFile(file, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,39 +448,7 @@ export async function addFile({
|
||||||
requestIp = null,
|
requestIp = null,
|
||||||
requestHeaders = null,
|
requestHeaders = null,
|
||||||
}: AddFileArgs): Promise<DriveFile> {
|
}: AddFileArgs): Promise<DriveFile> {
|
||||||
let skipNsfwCheck = false;
|
const info = await getFileInfo(path);
|
||||||
const instance = await fetchMeta();
|
|
||||||
if (user == null) skipNsfwCheck = true;
|
|
||||||
if (instance.sensitiveMediaDetection === "none") skipNsfwCheck = true;
|
|
||||||
if (
|
|
||||||
user &&
|
|
||||||
instance.sensitiveMediaDetection === "local" &&
|
|
||||||
Users.isRemoteUser(user)
|
|
||||||
)
|
|
||||||
skipNsfwCheck = true;
|
|
||||||
if (
|
|
||||||
user &&
|
|
||||||
instance.sensitiveMediaDetection === "remote" &&
|
|
||||||
Users.isLocalUser(user)
|
|
||||||
)
|
|
||||||
skipNsfwCheck = true;
|
|
||||||
|
|
||||||
const info = await getFileInfo(path, {
|
|
||||||
skipSensitiveDetection: skipNsfwCheck,
|
|
||||||
sensitiveThreshold: // 感度が高いほどしきい値は低くすることになる
|
|
||||||
instance.sensitiveMediaDetectionSensitivity === "veryHigh"
|
|
||||||
? 0.1
|
|
||||||
: instance.sensitiveMediaDetectionSensitivity === "high"
|
|
||||||
? 0.3
|
|
||||||
: instance.sensitiveMediaDetectionSensitivity === "low"
|
|
||||||
? 0.7
|
|
||||||
: instance.sensitiveMediaDetectionSensitivity === "veryLow"
|
|
||||||
? 0.9
|
|
||||||
: 0.5,
|
|
||||||
sensitiveThresholdForPorn: 0.75,
|
|
||||||
enableSensitiveMediaDetectionForVideos:
|
|
||||||
instance.enableSensitiveMediaDetectionForVideos,
|
|
||||||
});
|
|
||||||
logger.info(`${JSON.stringify(info)}`);
|
logger.info(`${JSON.stringify(info)}`);
|
||||||
|
|
||||||
// 現状 false positive が多すぎて実用に耐えない
|
// 現状 false positive が多すぎて実用に耐えない
|
||||||
|
@ -595,8 +563,6 @@ export async function addFile({
|
||||||
file.isLink = isLink;
|
file.isLink = isLink;
|
||||||
file.requestIp = requestIp;
|
file.requestIp = requestIp;
|
||||||
file.requestHeaders = requestHeaders;
|
file.requestHeaders = requestHeaders;
|
||||||
file.maybeSensitive = info.sensitive;
|
|
||||||
file.maybePorn = info.porn;
|
|
||||||
file.isSensitive = user
|
file.isSensitive = user
|
||||||
? Users.isLocalUser(user) && profile!.alwaysMarkNsfw
|
? Users.isLocalUser(user) && profile!.alwaysMarkNsfw
|
||||||
? true
|
? true
|
||||||
|
@ -605,10 +571,6 @@ export async function addFile({
|
||||||
: false
|
: false
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
if (info.sensitive && profile!.autoSensitive) file.isSensitive = true;
|
|
||||||
if (info.sensitive && instance.setSensitiveFlagAutomatically)
|
|
||||||
file.isSensitive = true;
|
|
||||||
|
|
||||||
if (url !== null) {
|
if (url !== null) {
|
||||||
file.src = url;
|
file.src = url;
|
||||||
|
|
||||||
|
|
|
@ -29,116 +29,6 @@
|
||||||
<XBotProtection />
|
<XBotProtection />
|
||||||
</FormFolder>
|
</FormFolder>
|
||||||
|
|
||||||
<FormFolder class="_formBlock">
|
|
||||||
<template #icon
|
|
||||||
><i class="ph-eye-slash ph-bold ph-lg"></i
|
|
||||||
></template>
|
|
||||||
<template #label>{{
|
|
||||||
i18n.ts.sensitiveMediaDetection
|
|
||||||
}}</template>
|
|
||||||
<template
|
|
||||||
v-if="sensitiveMediaDetection === 'all'"
|
|
||||||
#suffix
|
|
||||||
>{{ i18n.ts.all }}</template
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
v-else-if="sensitiveMediaDetection === 'local'"
|
|
||||||
#suffix
|
|
||||||
>{{ i18n.ts.localOnly }}</template
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
v-else-if="sensitiveMediaDetection === 'remote'"
|
|
||||||
#suffix
|
|
||||||
>{{ i18n.ts.remoteOnly }}</template
|
|
||||||
>
|
|
||||||
<template v-else #suffix>{{ i18n.ts.none }}</template>
|
|
||||||
|
|
||||||
<div class="_formRoot">
|
|
||||||
<span class="_formBlock">{{
|
|
||||||
i18n.ts._sensitiveMediaDetection.description
|
|
||||||
}}</span>
|
|
||||||
|
|
||||||
<FormRadios
|
|
||||||
v-model="sensitiveMediaDetection"
|
|
||||||
class="_formBlock"
|
|
||||||
>
|
|
||||||
<option value="none">{{ i18n.ts.none }}</option>
|
|
||||||
<option value="all">{{ i18n.ts.all }}</option>
|
|
||||||
<option value="local">
|
|
||||||
{{ i18n.ts.localOnly }}
|
|
||||||
</option>
|
|
||||||
<option value="remote">
|
|
||||||
{{ i18n.ts.remoteOnly }}
|
|
||||||
</option>
|
|
||||||
</FormRadios>
|
|
||||||
|
|
||||||
<FormRange
|
|
||||||
v-model="sensitiveMediaDetectionSensitivity"
|
|
||||||
:min="0"
|
|
||||||
:max="4"
|
|
||||||
:step="1"
|
|
||||||
:text-converter="(v) => `${v + 1}`"
|
|
||||||
class="_formBlock"
|
|
||||||
>
|
|
||||||
<template #label>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection.sensitivity
|
|
||||||
}}</template>
|
|
||||||
<template #caption>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection
|
|
||||||
.sensitivityDescription
|
|
||||||
}}</template>
|
|
||||||
</FormRange>
|
|
||||||
|
|
||||||
<FormSwitch
|
|
||||||
v-model="enableSensitiveMediaDetectionForVideos"
|
|
||||||
class="_formBlock"
|
|
||||||
>
|
|
||||||
<template #label
|
|
||||||
>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection
|
|
||||||
.analyzeVideos
|
|
||||||
}}<span class="_beta">{{
|
|
||||||
i18n.ts.beta
|
|
||||||
}}</span></template
|
|
||||||
>
|
|
||||||
<template #caption>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection
|
|
||||||
.analyzeVideosDescription
|
|
||||||
}}</template>
|
|
||||||
</FormSwitch>
|
|
||||||
|
|
||||||
<FormSwitch
|
|
||||||
v-model="setSensitiveFlagAutomatically"
|
|
||||||
class="_formBlock"
|
|
||||||
>
|
|
||||||
<template #label
|
|
||||||
>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection
|
|
||||||
.setSensitiveFlagAutomatically
|
|
||||||
}}
|
|
||||||
({{ i18n.ts.notRecommended }})</template
|
|
||||||
>
|
|
||||||
<template #caption>{{
|
|
||||||
i18n.ts._sensitiveMediaDetection
|
|
||||||
.setSensitiveFlagAutomaticallyDescription
|
|
||||||
}}</template>
|
|
||||||
</FormSwitch>
|
|
||||||
|
|
||||||
<!-- 現状 false positive が多すぎて実用に耐えない
|
|
||||||
<FormSwitch v-model="disallowUploadWhenPredictedAsPorn" class="_formBlock">
|
|
||||||
<template #label>{{ i18n.ts._sensitiveMediaDetection.disallowUploadWhenPredictedAsPorn }}</template>
|
|
||||||
</FormSwitch>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<FormButton primary class="_formBlock" @click="save"
|
|
||||||
><i
|
|
||||||
class="ph-floppy-disk-back ph-bold ph-lg"
|
|
||||||
></i>
|
|
||||||
{{ i18n.ts.save }}</FormButton
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</FormFolder>
|
|
||||||
|
|
||||||
<FormFolder class="_formBlock">
|
<FormFolder class="_formBlock">
|
||||||
<template #label>Active Email Validation</template>
|
<template #label>Active Email Validation</template>
|
||||||
<template v-if="enableActiveEmailValidation" #suffix
|
<template v-if="enableActiveEmailValidation" #suffix
|
||||||
|
@ -274,10 +164,6 @@ import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
let summalyProxy: string = $ref("");
|
let summalyProxy: string = $ref("");
|
||||||
let enableHcaptcha: boolean = $ref(false);
|
let enableHcaptcha: boolean = $ref(false);
|
||||||
let enableRecaptcha: boolean = $ref(false);
|
let enableRecaptcha: boolean = $ref(false);
|
||||||
let sensitiveMediaDetection: string = $ref("none");
|
|
||||||
let sensitiveMediaDetectionSensitivity: number = $ref(0);
|
|
||||||
let setSensitiveFlagAutomatically: boolean = $ref(false);
|
|
||||||
let enableSensitiveMediaDetectionForVideos: boolean = $ref(false);
|
|
||||||
let enableIpLogging: boolean = $ref(false);
|
let enableIpLogging: boolean = $ref(false);
|
||||||
let enableActiveEmailValidation: boolean = $ref(false);
|
let enableActiveEmailValidation: boolean = $ref(false);
|
||||||
|
|
||||||
|
@ -290,22 +176,6 @@ async function init() {
|
||||||
summalyProxy = meta.summalyProxy;
|
summalyProxy = meta.summalyProxy;
|
||||||
enableHcaptcha = meta.enableHcaptcha;
|
enableHcaptcha = meta.enableHcaptcha;
|
||||||
enableRecaptcha = meta.enableRecaptcha;
|
enableRecaptcha = meta.enableRecaptcha;
|
||||||
sensitiveMediaDetection = meta.sensitiveMediaDetection;
|
|
||||||
sensitiveMediaDetectionSensitivity =
|
|
||||||
meta.sensitiveMediaDetectionSensitivity === "veryLow"
|
|
||||||
? 0
|
|
||||||
: meta.sensitiveMediaDetectionSensitivity === "low"
|
|
||||||
? 1
|
|
||||||
: meta.sensitiveMediaDetectionSensitivity === "medium"
|
|
||||||
? 2
|
|
||||||
: meta.sensitiveMediaDetectionSensitivity === "high"
|
|
||||||
? 3
|
|
||||||
: meta.sensitiveMediaDetectionSensitivity === "veryHigh"
|
|
||||||
? 4
|
|
||||||
: 0;
|
|
||||||
setSensitiveFlagAutomatically = meta.setSensitiveFlagAutomatically;
|
|
||||||
enableSensitiveMediaDetectionForVideos =
|
|
||||||
meta.enableSensitiveMediaDetectionForVideos;
|
|
||||||
enableIpLogging = meta.enableIpLogging;
|
enableIpLogging = meta.enableIpLogging;
|
||||||
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
enableActiveEmailValidation = meta.enableActiveEmailValidation;
|
||||||
|
|
||||||
|
@ -317,21 +187,6 @@ async function init() {
|
||||||
function save() {
|
function save() {
|
||||||
os.apiWithDialog("admin/update-meta", {
|
os.apiWithDialog("admin/update-meta", {
|
||||||
summalyProxy,
|
summalyProxy,
|
||||||
sensitiveMediaDetection,
|
|
||||||
sensitiveMediaDetectionSensitivity:
|
|
||||||
sensitiveMediaDetectionSensitivity === 0
|
|
||||||
? "veryLow"
|
|
||||||
: sensitiveMediaDetectionSensitivity === 1
|
|
||||||
? "low"
|
|
||||||
: sensitiveMediaDetectionSensitivity === 2
|
|
||||||
? "medium"
|
|
||||||
: sensitiveMediaDetectionSensitivity === 3
|
|
||||||
? "high"
|
|
||||||
: sensitiveMediaDetectionSensitivity === 4
|
|
||||||
? "veryHigh"
|
|
||||||
: 0,
|
|
||||||
setSensitiveFlagAutomatically,
|
|
||||||
enableSensitiveMediaDetectionForVideos,
|
|
||||||
enableIpLogging,
|
enableIpLogging,
|
||||||
enableActiveEmailValidation,
|
enableActiveEmailValidation,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
|
@ -54,19 +54,6 @@
|
||||||
>
|
>
|
||||||
<template #label>{{ i18n.ts.alwaysMarkSensitive }}</template>
|
<template #label>{{ i18n.ts.alwaysMarkSensitive }}</template>
|
||||||
</FormSwitch>
|
</FormSwitch>
|
||||||
<FormSwitch
|
|
||||||
v-model="autoSensitive"
|
|
||||||
class="_formBlock"
|
|
||||||
@update:modelValue="saveProfile()"
|
|
||||||
>
|
|
||||||
<template #label
|
|
||||||
>{{ i18n.ts.enableAutoSensitive
|
|
||||||
}}<span class="_beta">{{ i18n.ts.beta }}</span></template
|
|
||||||
>
|
|
||||||
<template #caption>{{
|
|
||||||
i18n.ts.enableAutoSensitiveDescription
|
|
||||||
}}</template>
|
|
||||||
</FormSwitch>
|
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -93,7 +80,6 @@ const usage = ref<any>(null);
|
||||||
const capacity = ref<any>(null);
|
const capacity = ref<any>(null);
|
||||||
const uploadFolder = ref<any>(null);
|
const uploadFolder = ref<any>(null);
|
||||||
let alwaysMarkNsfw = $ref($i.alwaysMarkNsfw);
|
let alwaysMarkNsfw = $ref($i.alwaysMarkNsfw);
|
||||||
let autoSensitive = $ref($i.autoSensitive);
|
|
||||||
|
|
||||||
const meterStyle = computed(() => {
|
const meterStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
|
@ -140,8 +126,7 @@ function chooseUploadFolder() {
|
||||||
|
|
||||||
function saveProfile() {
|
function saveProfile() {
|
||||||
os.api("i/update", {
|
os.api("i/update", {
|
||||||
alwaysMarkNsfw: !!alwaysMarkNsfw,
|
alwaysMarkNsfw: !!alwaysMarkNsfw
|
||||||
autoSensitive: !!autoSensitive,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue